diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f918f6e40115c2fedd33bcd646caf51851fe980a..0000000000000000000000000000000000000000 --- a/.travis.yml +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (c) 2017-2020 Petr Vorel - -sudo: required -language: c -services: - - docker - -matrix: - include: - # 32 bit build - - os: linux - env: DISTRO=debian:stable VARIANT=i386 - compiler: gcc - - # cross compilation builds - - os: linux - env: DISTRO=debian:stable VARIANT=cross-compile ARCH=ppc64el TREE=out MAKE_INSTALL=1 - compiler: powerpc64le-linux-gnu-gcc - - - os: linux - env: DISTRO=debian:stable VARIANT=cross-compile ARCH=arm64 TREE=out - compiler: aarch64-linux-gnu-gcc - - - os: linux - env: DISTRO=debian:stable VARIANT=cross-compile ARCH=s390x TREE=out - compiler: s390x-linux-gnu-gcc - - # musl (native) - - os: linux - # Message: WARNING: xsltproc: cannot process http://docbook.sourceforge.net/release/xsl-ns/current/manpages/docbook.xsl - # doc/meson.build:70:1: ERROR: Problem encountered: Docs cannot be built: xsltproc does not work correctly - env: DISTRO=alpine:latest - compiler: gcc - - # build with minimal dependencies - - os: linux - env: DISTRO=debian:stable VARIANT=minimal TREE=out - compiler: clang - - # native non-intel - - os: linux - arch: ppc64le - compiler: gcc - env: DISTRO=debian:testing - - # other builds - - os: linux - env: DISTRO=fedora:rawhide MAKE_INSTALL=1 - compiler: clang - - - os: linux - env: DISTRO=centos:6 TREE=out - compiler: gcc - - - os: linux - env: DISTRO=debian:testing - compiler: gcc - - - os: linux - env: DISTRO=debian:oldstable - compiler: clang - - - os: linux - env: DISTRO=opensuse/tumbleweed - compiler: gcc - - - os: linux - env: DISTRO=opensuse/leap - compiler: gcc - - - os: linux - env: DISTRO=debian:oldstable - compiler: gcc - - - os: linux - env: DISTRO=debian:testing - compiler: clang - - - os: linux - env: DISTRO=ubuntu:eoan TREE=out - compiler: gcc - - - os: linux - env: DISTRO=ubuntu:xenial - compiler: gcc - - - os: linux - env: DISTRO=centos:latest - compiler: gcc - -before_install: - - df -hT - - DIR="/usr/src/ltp" - - printf "FROM $DISTRO\nRUN mkdir -p $DIR\nWORKDIR $DIR\nCOPY . $DIR\n" > Dockerfile - - cat Dockerfile - - docker build -t ltp . - -script: - - INSTALL="${DISTRO%%:*}" - - INSTALL="${INSTALL%%/*}" - - if [ "$MAKE_INSTALL" = 1 ]; then INSTALL_OPT="-i"; fi - - if [ ! "$TREE" ]; then TREE="in"; fi - - case $VARIANT in cross-compile*) BUILD="cross";; i386) BUILD="32";; *) BUILD="native";; esac - - # Tumbleweed requires newer Docker version - - > - if [ "${DISTRO//*\/}" = "tumbleweed" -o "$INSTALL" = "fedora" ]; then - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" - sudo apt-get update - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce - fi - - - docker run -t ltp /bin/sh -c "cd travis && ./$INSTALL.sh && if [ \"$VARIANT\" ]; then ARCH=\"$ARCH\" ./$INSTALL.$VARIANT.sh; fi && ../build.sh -o $TREE -t $BUILD -c $CC $INSTALL_OPT" diff --git a/COPYING b/COPYING old mode 100644 new mode 100755 diff --git a/INSTALL b/INSTALL old mode 100644 new mode 100755 index 120f030b5382073f4c2b21135f7dcbd2cf04df37..3bb37d60b9d3d84c45eb8d7937da103c084c995d --- a/INSTALL +++ b/INSTALL @@ -1,20 +1,23 @@ Requirements -------------------- +------------ Tools are needed for LTP compilation. They should be available as a package in any Linux distribution (no specific version is required). Debian / Ubuntu -# apt install gcc git make pkgconf autoconf automake bison flex m4 linux-headers-$(uname -r) libc6-dev -OpenSUSE / SLES -# zypper install gcc git make pkgconf autoconf automake bison flex m4 linux-glibc-devel glibc-devel + # apt install gcc git make pkgconf autoconf automake bison flex m4 linux-headers-$(uname -r) libc6-dev + +openSUSE / SLES + + # zypper install gcc git make pkg-config autoconf automake bison flex m4 linux-glibc-devel glibc-devel Fedora / CentOS / RHEL -# yum install gcc git make pkgconf autoconf automake bison flex m4 kernel-headers glibc-headers + + # yum install gcc git make pkgconf autoconf automake bison flex m4 kernel-headers glibc-headers These are minimal build requirements for git compilation. Some tests require -extra development files of some libraries, see travis/*.sh. There is also +extra development files of some libraries, see ci/*.sh. There is also support for other Linux distributions not listed here. autoconf, automake, m4 (autoconf requirement), git and pkgconf (or pkg-config @@ -27,14 +30,14 @@ does automatic detection of some library support. GNU Bison / Berkeley Yacc is required for ltp-scanner. Configuration -------------------- +------------- Configuration requires autoconf: $ cd $TOP_SRCDIR $ make autotools $ mkdir -p $TOP_BUILDDIR - $ cd $TOP_BUILDDIR && ./configure # configure args go here, e.g. CC=$CC, LDFLAGS=$LDFLAGS, etc + $ cd $TOP_BUILDDIR && $TOP_SRCDIR/configure # configure args go here, e.g. CC=$CC, LDFLAGS=$LDFLAGS, etc - $TOP_SRCDIR and $TOP_BUILDDIR are the same for in-build-tree scenarios. - $TOP_SRCDIR and $TOP_BUILDDIR differ for out-of-build-tree scenarios. @@ -43,10 +46,11 @@ See the In-build-tree and Out-of-build-tree sections below for more details on what to do next. Compiling LTP -------------------- +------------- In-build-tree -------------------- +------------- + In-build-tree support is when you build binaries (applications, binary objects) in the same directory where the source files reside. @@ -71,7 +75,8 @@ following information, iii. config.log Out-of-build-tree -------------------- +----------------- + Out-of-build-tree support is when you build binaries (applications, binary objects, generated files) outside of the directory where the source files reside. This is typically used when cross-compiling for multiple targets. @@ -103,12 +108,12 @@ items which need fixing in the LTP tree. Quick Start ----------- -1> tar xzf ltp-XXXXXXXX.tar.gz -2> cd ltp -3> ./configure -4> make all -5> make install -6> /opt/ltp/runltp + $ tar xzf ltp-XXXXXXXX.tar.gz + $ cd ltp + $ ./configure + $ make all + # make install + $ /opt/ltp/runltp *NOTE: - LTP assumes the existence of the nobody, bin, and daemon users and their @@ -146,56 +151,11 @@ contributions are welcome. in the CD-ROM drive. The corresponding tests will fail if either disk is missing. -5. The network tests are executed by running the network.sh script. The network - tests require some configuration for them to work correctly: - - i) First, there MUST be another test machine setup to act as the server - to these client side tests. This machine MUST have the LTP installed - in the same exact location, i.e. if the client has /root/ltp, then the - server must have /root/ltp. This is required because certain tests - expect to find server files in certain locations. Make sure to compile - the LTP on this server machine also. - - ii) Second, the server must be setup to allow the client to connect using - the "r" commands, such as rsh. This is done by simply creating/editing - the ".rhosts" file under /root. Place the hostname of the client - machine in this file to allow root to remotely connect without the use - of a password. If server has the PAM system security tool, you need - to add the following lines to /etc/securetty: - rlogin - rsh - rexec - pts/0 - pts/1 - : - pts/9 - - iii) Next, certain services must be activated in order for certain tests to - execute. The following services are activated via inetd/xinetd: - rlogind - ftpd - telnetd - echo (stream) - fingerd - rshd - Also, because certain RPC programs are tested, the "portmapper" daemon - MUST be started, as well as NFS server AND lock services. - - iv) Finally, before running the network.sh script, two variables must be - set: The "RHOST" variable should be set to the hostname of the server. - The "PASSWD" variable should be set to root's password on the server - machine. This is necessary for tests such as telnet01.sh and ftp01.sh. - - You can now successfully execute the network.sh script. - - You can run the test category which you are interested in, -h option shows - the list of the test category: - # ./network.sh -h - - For more info about howto run network.sh see testcases/network/README.md. +5. The network tests related installation see testcases/network/README.md. Cross compiling --------------- + To cross compile, you must specify the correct variables when running configure. e.g. CC, LDFLAGS, etc. For correct pkgconf / pkg-config detection you need to set @@ -207,6 +167,7 @@ command-line when running make. 32 bit build on 64 bit machine ------------------------------ + You need to set CFLAGS=-m32 LDFLAGS=-m32 and PKG_CONFIG_LIBDIR * RPM based distributions (openSUSE, Fedora, etc.) @@ -220,13 +181,14 @@ PKG_CONFIG_LIBDIR=/usr/lib32/pkgconfig CFLAGS=-m32 LDFLAGS=-m32 ./configure Android Users ------------- + Specify ANDROID=1 when calling make. Many tests which would otherwise work are currently not built because they share a directory with an incompatible test. The shell scripts expect /bin/sh to exist, so create a symlink. Variables in Makefile ----------------------- +--------------------- The conventions enforced are standard ones. Here's a quick summary: @@ -245,7 +207,7 @@ For other variables and more info about the build systems see doc/build-system-guide.txt. Common Issues ----------------------- +------------- Issue: When executing configure it says: diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index 768ca46066b630e80deb5c493b236aee4833ed32..d4399bae6ac1b8526e9ca8f288249e3404f8fe72 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # # Top-level Makefile for LTP. See INSTALL for more info. # -# Copyright (C) 2009-2010, Cisco Systems Inc. -# Copyright (C) 2010-2011, Linux Test Project. +# Copyright (c) Linux Test Project, 2009-2020 +# Copyright (c) Cisco Systems Inc., 2009-2010 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -62,7 +62,8 @@ $(1):: | $$(abs_top_builddir)/$$(basename $$(subst -,.,$(1))) endif endef -COMMON_TARGETS += testcases tools +COMMON_TARGETS += testcases tools metadata + # Don't want to nuke the original files if we're installing in-build-tree. ifneq ($(BUILD_TREE_STATE),$(BUILD_TREE_SRCDIR_INSTALL)) INSTALL_TARGETS += runtest scenario_groups testscripts @@ -75,6 +76,7 @@ BOOTSTRAP_TARGETS := $(sort $(COMMON_TARGETS) $(CLEAN_TARGETS) $(INSTALL_TARGETS CLEAN_TARGETS := $(addsuffix -clean,$(CLEAN_TARGETS)) INSTALL_TARGETS := $(addsuffix -install,$(INSTALL_TARGETS)) MAKE_TARGETS := $(addsuffix -all,$(filter-out lib,$(COMMON_TARGETS))) +CHECK_TARGETS := $(addsuffix -check,testcases lib) # There's no reason why we should run `all' twice. Otherwise we're just wasting # 3+ mins of useful CPU cycles on a modern machine, and even more time on an @@ -89,11 +91,7 @@ include-install: $(top_builddir)/include/config.h include/mk/config.mk include-a INSTALL_DIR := $(DESTDIR)/$(prefix) # DO NOT REMOVE THIS CALL (see clean_install_dir call below...)!!!! -ifdef MAKE_3_80_COMPAT -INSTALL_DIR := $(call MAKE_3_80_abspath,$(INSTALL_DIR)) -else INSTALL_DIR := $(abspath $(INSTALL_DIR)) -endif # build tree bootstrap targets and $(INSTALL_DIR) target. $(sort $(addprefix $(abs_top_builddir)/,$(BOOTSTRAP_TARGETS)) $(INSTALL_DIR) $(DESTDIR)/$(bindir)): @@ -108,6 +106,10 @@ $(MAKE_TARGETS) include-all lib-all libs-all: $(MAKE) -C "$(subst -all,,$@)" \ -f "$(abs_top_srcdir)/$(subst -all,,$@)/Makefile" all +$(CHECK_TARGETS): tools-all + $(MAKE) -C "$(subst -check,,$@)" \ + -f "$(abs_top_srcdir)/$(subst -check,,$@)/Makefile" check + # Let's not conflict with ac-clean, maintainer-clean, etc, so. $(filter-out include-clean,$(CLEAN_TARGETS)):: -$(MAKE) -C "$(subst -clean,,$@)" \ @@ -189,9 +191,39 @@ INSTALL_TARGETS += $(addprefix $(DESTDIR)/$(bindir)/,$(BINDIR_INSTALL_SCRIPTS)) $(INSTALL_TARGETS): $(INSTALL_DIR) $(DESTDIR)/$(bindir) +.PHONY: check +check: $(CHECK_TARGETS) + ## Install install: $(INSTALL_TARGETS) +## Test +define _test + @set -e; $(top_srcdir)/lib/newlib_tests/runtest.sh -b $(abs_builddir) $(1) +endef + +test: lib-all +ifneq ($(build),$(host)) + $(error running tests on cross-compile build not supported) +endif + $(call _test) + $(MAKE) test-metadata + +test-c: lib-all +ifneq ($(build),$(host)) + $(error running tests on cross-compile build not supported) +endif + $(call _test,-c) + +test-shell: lib-all +ifneq ($(build),$(host)) + $(error running tests on cross-compile build not supported) +endif + $(call _test,-s) + +test-metadata: metadata-all + $(MAKE) -C $(abs_srcdir)/metadata/ test + ## Help .PHONY: help help: diff --git a/Makefile.release b/Makefile.release old mode 100644 new mode 100755 diff --git a/OAT.xml b/OAT.xml old mode 100755 new mode 100644 index dfa0de51e33a5ddc0b753cc2e0b81a600cc5bc46..2320ef224dbf719666ff0a538604d6f3af32aeef --- a/OAT.xml +++ b/OAT.xml @@ -62,6 +62,10 @@ Note:If the text contains special characters, please escape them according to th + + + + @@ -70,6 +74,7 @@ Note:If the text contains special characters, please escape them according to th + diff --git a/README.OpenSource b/README.OpenSource index 3cbc4f6daef7d2aff6227d83e9af1f72c7be9e58..82346864c16c52a10176a71938c4af56fe86b122 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,7 +3,7 @@ "Name" : "ltp", "License" : "GPL V2.0", "License File" : "COPYING", - "Version Number" : "20200515", + "Version Number" : "20220121", "Owner" : "liuxun@huawei.com", "Upstream URL" : "https://github.com/linux-test-project/ltp", "Description" : "The LTP testsuite contains a collection of tools for testing the Linux kernel and related features." diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 56d10d450f1b8ce822ca3f85b4c2a0e6f81ed478..7764eb81ac410198c269d8dbff2ec2965a1295a3 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Quick guide to running the tests If you have git, autoconf, automake, m4, pkgconf / pkg-config, libc headers, linux kernel headers and other common development packages installed (see -INSTALL and travis/*.sh), the chances are the following will work: +INSTALL and ci/*.sh), the chances are the following will work: ``` $ git clone https://github.com/linux-test-project/ltp.git @@ -52,7 +52,7 @@ Now you can continue either with compiling and running a single test or with compiling and installing the whole testsuite. For optional library dependencies look into scripts for major distros in -`travis/` directory. You can also build whole LTP with `./build.sh` script. +`ci/` directory. You can also build whole LTP with `./build.sh` script. Shortcut to running a single test --------------------------------- @@ -178,8 +178,7 @@ https://github.com/linux-test-project/ltp/wiki/User-Guidelines. Network tests ------------- Network tests require certain setup, described in `testcases/network/README.md` -(online at https://github.com/linux-test-project/ltp/tree/master/testcases/network) -and `INSTALL`. +(online at https://github.com/linux-test-project/ltp/tree/master/testcases/network). Developers corner ================= @@ -204,8 +203,7 @@ list. Also note that these documents are available online at: Although we accept GitHub pull requests, the preferred way is sending patches to our mailing list. -It's a good idea to test patches on Travis CI before posting to mailing -list. Our travis setup covers various architectures and distributions in +It's a good idea to test patches on GitHub Actions before posting to mailing +list. Our GitHub Actions setup covers various architectures and distributions in order to make sure LTP compiles cleanly on most common configurations. -For testing you need to sign up to Travis CI, enable running builds on your LTP fork on -https://travis-ci.org/account/repositories and push your branch. +For testing you need to just to push your changes to your own LTP fork on GitHub. diff --git a/TODO b/TODO old mode 100644 new mode 100755 diff --git a/VERSION b/VERSION old mode 100644 new mode 100755 index 996d73f1867d89283f943a239d7ea5dc66b42af8..3f3ee5d7268f5d50d76021ce872a3b008e9b5dba --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -20200515 +20220121 diff --git a/build.sh b/build.sh index 50fb527e493578963e2941a9dcbc8861fb4c0bf0..1767cc21b7e85c2d2fb4d8261511a1b998d0a848 100755 --- a/build.sh +++ b/build.sh @@ -1,135 +1,157 @@ #!/bin/sh -# Copyright (c) 2017-2018 Petr Vorel -# Script for travis builds. -# -# TODO: Implement comparison of installed files. List of installed files can -# be used only for local builds as Travis currently doesn't support sharing -# file between jobs, see -# https://github.com/travis-ci/travis-ci/issues/6054 +# Copyright (c) 2017-2021 Petr Vorel +# Script for CI builds. set -e -CFLAGS="${CFLAGS:--Werror=implicit-function-declaration -fno-common}" +CFLAGS="${CFLAGS:--Wformat -Werror=format-security -Werror=implicit-function-declaration -Werror=return-type -fno-common}" CC="${CC:-gcc}" DEFAULT_PREFIX="$HOME/ltp-install" DEFAULT_BUILD="native" DEFAULT_TREE="in" -CONFIGURE_OPTS_IN_TREE="--with-open-posix-testsuite --with-realtime-testsuite" + +CONFIGURE_OPTS_IN_TREE="--with-open-posix-testsuite --with-realtime-testsuite $CONFIGURE_OPT_EXTRA" # TODO: open posix testsuite is currently broken in out-tree-build. Enable it once it's fixed. -CONFIGURE_OPTS_OUT_TREE="--with-realtime-testsuite" +CONFIGURE_OPTS_OUT_TREE="--with-realtime-testsuite $CONFIGURE_OPT_EXTRA" + +SRC_DIR="$(cd $(dirname $0); pwd)" +BUILD_DIR="$SRC_DIR/../ltp-build" + MAKE_OPTS="-j$(getconf _NPROCESSORS_ONLN)" +MAKE_OPTS_OUT_TREE="$MAKE_OPTS -C $BUILD_DIR -f $SRC_DIR/Makefile top_srcdir=$SRC_DIR top_builddir=$BUILD_DIR" -build_32() +run_configure() { - echo "===== 32-bit ${1}-tree build into $PREFIX =====" - CFLAGS="-m32 $CFLAGS" LDFLAGS="-m32 $LDFLAGS" - build $1 $2 + local configure="$1" + shift + + export CC CFLAGS LDFLAGS PKG_CONFIG_LIBDIR + echo "CC='$CC' CFLAGS='$CFLAGS' LDFLAGS='$LDFLAGS' PKG_CONFIG_LIBDIR='$PKG_CONFIG_LIBDIR'" + + echo "=== configure $configure $@ ===" + if ! $configure $@; then + echo "== ERROR: configure failed, config.log ==" + cat config.log + exit 1 + fi + + echo "== include/config.h ==" + cat include/config.h } -build_native() +configure_in_tree() { - echo "===== native ${1}-tree build into $PREFIX =====" - build $1 $2 + run_configure ./configure $CONFIGURE_OPTS_IN_TREE --prefix=$prefix $@ } -build_cross() +configure_out_tree() { - local host="${CC%-gcc}" - [ -n "$host" ] || \ - { echo "Missing CC variable, pass it with -c option." >&2; exit 1; } - - echo "===== cross-compile ${host} ${1}-tree build into $PREFIX =====" - build $1 $2 "--host=$host" CROSS_COMPILE="${host}-" + mkdir -p $BUILD_DIR + cd $BUILD_DIR + run_configure $SRC_DIR/configure $CONFIGURE_OPTS_OUT_TREE $@ } -build() +configure_32() { local tree="$1" - local install="$2" - shift 2 + local prefix="$2" + local arch="$(uname -m)" + local dir + + echo "===== 32-bit ${tree}-tree build into $prefix =====" + + if [ -z "$PKG_CONFIG_LIBDIR" ]; then + if [ "$arch" != "x86_64" ]; then + echo "ERROR: auto-detection not supported platform $arch, export PKG_CONFIG_LIBDIR!" + exit 1 + fi + + for dir in /usr/lib/i386-linux-gnu/pkgconfig \ + /usr/lib32/pkgconfig /usr/lib/pkgconfig; do + if [ -d "$dir" ]; then + PKG_CONFIG_LIBDIR="$dir" + break + fi + done + if [ -z "$PKG_CONFIG_LIBDIR" ]; then + echo "WARNING: PKG_CONFIG_LIBDIR not found, build might fail" + fi + fi - echo "=== autotools ===" - make autotools + CFLAGS="-m32 $CFLAGS" LDFLAGS="-m32 $LDFLAGS" - if [ "$tree" = "in" ]; then - build_in_tree $install $@ - else - build_out_tree $install $@ - fi + eval configure_${tree}_tree } -build_out_tree() +configure_native() { - local install="$1" - shift - - local tree="$PWD" - local build="$tree/../ltp-build" - local make_opts="$MAKE_OPTS -C $build -f $tree/Makefile top_srcdir=$tree top_builddir=$build" + local tree="$1" + local prefix="$2" - mkdir -p $build - cd $build - run_configure $tree/configure $CONFIGURE_OPTS_OUT_TREE $@ + echo "===== native ${tree}-tree build into $prefix =====" + eval configure_${tree}_tree +} - echo "=== build ===" - make $make_opts +configure_cross() +{ + local tree="$1" + local prefix="$2" + local host=$(basename "${CC%-gcc}") - if [ "$install" = 1 ]; then - echo "=== install ===" - make $make_opts DESTDIR="$PREFIX" SKIP_IDCHECK=1 install - else - echo "make install skipped, use -i to run it" + if [ "$host" = "gcc" ]; then + echo "Invalid CC variable for cross compilation: $CC (clang not supported)" >&2 + exit 1 fi + + echo "===== cross-compile ${host} ${1}-tree build into $prefix =====" + eval configure_${tree}_tree "--host=$host" } build_in_tree() { - local install="$1" - shift - - run_configure ./configure $CONFIGURE_OPTS_IN_TREE --prefix=$PREFIX $@ - - echo "=== build ===" make $MAKE_OPTS +} - if [ "$install" = 1 ]; then - echo "=== install ===" - make $MAKE_OPTS install - else - echo "make install skipped, use -i to run it" - fi +build_out_tree() +{ + cd $BUILD_DIR + make $MAKE_OPTS_OUT_TREE } -run_configure() +test_in_tree() { - local configure=$1 - shift + make $1 +} - export CC CFLAGS LDFLAGS - echo "CC='$CC' CFLAGS='$CFLAGS' LDFLAGS='$LDFLAGS'" +test_out_tree() +{ + cd $BUILD_DIR + make $MAKE_OPTS_OUT_TREE $1 +} - echo "=== configure $configure $@ ===" - if ! $configure $@; then - echo "== ERROR: configure failed, config.log ==" - cat config.log - exit 1 - fi +install_in_tree() +{ + make $MAKE_OPTS install +} - echo "== include/config.h ==" - cat include/config.h +install_out_tree() +{ + cd $BUILD_DIR + make $MAKE_OPTS_OUT_TREE DESTDIR="$prefix" SKIP_IDCHECK=1 install } usage() { cat << EOF Usage: -$0 [ -c CC ] [ -o TREE ] [ -p DIR ] [ -t TYPE ] +$0 [ -c CC ] [ -i ] [ -o TREE ] [ -p DIR ] [-r RUN ] [ -t TYPE ] $0 -h Options: -h Print this help --c CC Define compiler (\$CC variable) +-c CC Define compiler (\$CC variable), needed only for configure step +-i Run 'make install', needed only for install step -o TREE Specify build tree, default: $DEFAULT_TREE -p DIR Change installation directory. For in-tree build is this value passed to --prefix option of configure script. For out-of-tree build is this @@ -138,25 +160,42 @@ Options: DIR/PREFIX (i.e. DIR/opt/ltp). Default for in-tree build: '$DEFAULT_PREFIX' Default for out-of-tree build: '$DEFAULT_PREFIX/opt/ltp' --t TYPE Specify build type, default: $DEFAULT_BUILD +-r RUN Run only certain step (usable for CI), default: all +-t TYPE Specify build type, default: $DEFAULT_BUILD, only for configure step -BUILD TREE: +TREE: in in-tree build out out-of-tree build -BUILD TYPES: -32 32-bit in-tree build -cross cross-compile in-tree build (requires set compiler via -c switch) -native native in-tree build +TYPES: +32 32-bit build (PKG_CONFIG_LIBDIR auto-detection for x86_64) +cross cross-compile build (requires set compiler via -c switch) +native native build + +RUN: +autotools run only 'make autotools' +configure run only 'configure' +build run only 'make' +test run only 'make test' (not supported for cross-compile build) +test-c run only 'make test-c' (not supported for cross-compile build) +test-shell run only 'make test-shell' (not supported for cross-compile build) +install run only 'make install' + +Default configure options: +in-tree: $CONFIGURE_OPTS_IN_TREE +out-of-tree $CONFIGURE_OPTS_OUT_TREE + +configure options can extend the default with \$CONFIGURE_OPT_EXTRA environment variable EOF } -PREFIX="$DEFAULT_PREFIX" +prefix="$DEFAULT_PREFIX" build="$DEFAULT_BUILD" tree="$DEFAULT_TREE" -install=0 +install= +run= -while getopts "c:hio:p:t:" opt; do +while getopts "c:hio:p:r:t:" opt; do case "$opt" in c) CC="$OPTARG";; h) usage; exit 0;; @@ -165,7 +204,11 @@ while getopts "c:hio:p:t:" opt; do in|out) tree="$OPTARG";; *) echo "Wrong build tree '$OPTARG'" >&2; usage; exit 1;; esac;; - p) PREFIX="$OPTARG";; + p) prefix="$OPTARG";; + r) case "$OPTARG" in + autotools|configure|build|test|test-c|test-shell|install) run="$OPTARG";; + *) echo "Wrong run type '$OPTARG'" >&2; usage; exit 1;; + esac;; t) case "$OPTARG" in 32|cross|native) build="$OPTARG";; *) echo "Wrong build type '$OPTARG'" >&2; usage; exit 1;; @@ -174,13 +217,35 @@ while getopts "c:hio:p:t:" opt; do esac done -cd `dirname $0` +cd $SRC_DIR + +if [ -z "$run" -o "$run" = "autotools" ]; then + make autotools +fi + +if [ -z "$run" -o "$run" = "configure" ]; then + eval configure_$build $tree $prefix +fi + +if [ -z "$run" -o "$run" = "build" ]; then + echo "=== build ===" + eval build_${tree}_tree +fi -echo "=== ver_linux ===" -./ver_linux -echo +if [ -z "$run" -o "$run" = "test" -o "$run" = "test-c" -o "$run" = "test-shell" ]; then + if [ "$build" = "cross" ]; then + echo "cross-compile build, skipping running tests" >&2 + else + eval test_${tree}_tree $run + fi +fi -echo "=== compiler version ===" -$CC --version +if [ -z "$run" -o "$run" = "install" ]; then + if [ "$install" = 1 ]; then + eval install_${tree}_tree + else + echo "make install skipped, use -i to run it" + fi +fi -eval build_$build $tree $install +exit $? diff --git a/travis/alpine.sh b/ci/alpine.sh similarity index 68% rename from travis/alpine.sh rename to ci/alpine.sh index b2c1fff9eb4f60006260e05573649ff7bd6b21dc..d93a5761675173cb36af2e1a7cfed615d172d40f 100755 --- a/travis/alpine.sh +++ b/ci/alpine.sh @@ -1,15 +1,18 @@ #!/bin/sh -# Copyright (c) 2019-2020 Petr Vorel +# Copyright (c) 2019-2021 Petr Vorel set -ex apk update apk add \ acl-dev \ + asciidoc \ + asciidoctor \ autoconf \ automake \ clang \ gcc \ + git \ keyutils-dev \ libaio-dev \ libacl \ @@ -22,21 +25,19 @@ apk add \ musl-dev \ numactl-dev \ openssl-dev \ + perl-json \ pkgconfig cat /etc/os-release echo "WARNING: remove unsupported tests (until they're fixed)" -cd .. +cd $(dirname $0)/.. rm -rfv \ - testcases/kernel/sched/process_stress/process.c \ testcases/kernel/syscalls/confstr/confstr01.c \ testcases/kernel/syscalls/fmtmsg/fmtmsg01.c \ testcases/kernel/syscalls/getcontext/getcontext01.c \ - testcases/kernel/syscalls/getdents/getdents01.c \ - testcases/kernel/syscalls/getdents/getdents02.c \ testcases/kernel/syscalls/rt_tgsigqueueinfo/rt_tgsigqueueinfo01.c \ testcases/kernel/syscalls/timer_create/timer_create01.c \ - testcases/kernel/syscalls/timer_create/timer_create03.c \ - utils/benchmark/ebizzy-0.3 + testcases/kernel/syscalls/timer_create/timer_create03.c + cd - diff --git a/travis/centos.sh b/ci/centos.sh similarity index 100% rename from travis/centos.sh rename to ci/centos.sh diff --git a/travis/debian.cross-compile.sh b/ci/debian.cross-compile.sh similarity index 89% rename from travis/debian.cross-compile.sh rename to ci/debian.cross-compile.sh index 08c3805aaebdda6736308f6730b2c0e22c5798c8..0a7ef7710793ba0dbfbc521e026706da9d9577cf 100755 --- a/travis/debian.cross-compile.sh +++ b/ci/debian.cross-compile.sh @@ -11,7 +11,7 @@ case "$ARCH" in arm64) gcc_arch="aarch64";; ppc64el) gcc_arch="powerpc64le";; s390x) gcc_arch="$ARCH";; -*) echo "unsupported arch: '$1'!" >&2; exit 1;; +*) echo "unsupported arch: '$ARCH'!" >&2; exit 1;; esac dpkg --add-architecture $ARCH diff --git a/travis/debian.i386.sh b/ci/debian.i386.sh similarity index 100% rename from travis/debian.i386.sh rename to ci/debian.i386.sh diff --git a/travis/debian.minimal.sh b/ci/debian.minimal.sh similarity index 62% rename from travis/debian.minimal.sh rename to ci/debian.minimal.sh index 3f1941969eba512aaa9fbf5f2512f0d2355e2ffb..d2e5cc6f34724d033c261f51be1899a429f28d46 100755 --- a/travis/debian.minimal.sh +++ b/ci/debian.minimal.sh @@ -2,18 +2,22 @@ # Copyright (c) 2018-2020 Petr Vorel set -ex -apt remove -y \ +apt="apt remove -y" + +$apt \ + asciidoc \ + asciidoctor \ libacl1-dev \ libaio-dev \ libaio1 \ libcap-dev \ libcap2 \ libkeyutils-dev \ - libkeyutils1 \ libmm-dev \ libnuma-dev \ libnuma1 \ libselinux1-dev \ - libsepol1-dev \ - libssl-dev \ - libtirpc-dev + libsepol-dev \ + libssl-dev + +$apt asciidoc-base ruby-asciidoctor || true diff --git a/travis/debian.sh b/ci/debian.sh similarity index 65% rename from travis/debian.sh rename to ci/debian.sh index b759a95768c296ce1c7e6e7405406bf3a3bf0c92..f3dcb6e8d4f691781cc36891f0bf917ff5e92282 100755 --- a/travis/debian.sh +++ b/ci/debian.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2018-2020 Petr Vorel +# Copyright (c) 2018-2021 Petr Vorel set -ex # workaround for missing oldstable-updates repository @@ -8,8 +8,15 @@ grep -v oldstable-updates /etc/apt/sources.list > /tmp/sources.list && mv /tmp/s apt update -apt install -y --no-install-recommends \ +# workaround for Ubuntu impish asking to interactively configure tzdata +export DEBIAN_FRONTEND="noninteractive" + +apt="apt install -y --no-install-recommends" + +$apt \ acl-dev \ + asciidoc \ + asciidoctor \ autoconf \ automake \ build-essential \ @@ -17,6 +24,8 @@ apt install -y --no-install-recommends \ devscripts \ clang \ gcc \ + git \ + iproute2 \ libacl1 \ libacl1-dev \ libaio-dev \ @@ -25,6 +34,7 @@ apt install -y --no-install-recommends \ libcap2 \ libc6 \ libc6-dev \ + libjson-perl \ libkeyutils-dev \ libkeyutils1 \ libmm-dev \ @@ -32,11 +42,14 @@ apt install -y --no-install-recommends \ libnuma-dev \ libnuma1 \ libselinux1-dev \ - libsepol1-dev \ + libsepol-dev \ libssl-dev \ libtirpc-dev \ linux-libc-dev \ lsb-release \ pkg-config +$apt ruby-asciidoctor-pdf || true +$apt asciidoc-dblatex || true + df -hT diff --git a/travis/fedora.sh b/ci/fedora.sh similarity index 36% rename from travis/fedora.sh rename to ci/fedora.sh index 990a84daff98e409429c7e25948516ba54aae94f..dc1293aa59971f64c596096c0546f0d4f0f8bcbc 100755 --- a/travis/fedora.sh +++ b/ci/fedora.sh @@ -1,18 +1,27 @@ #!/bin/sh -# Copyright (c) 2018-2020 Petr Vorel +# Copyright (c) 2018-2021 Petr Vorel set -ex -yum -y install \ +yum="yum -y install" + +$yum \ + asciidoc \ autoconf \ automake \ make \ clang \ gcc \ + git \ findutils \ + iproute \ + numactl-devel \ libtirpc \ libtirpc-devel \ + perl-JSON \ + perl-libwww-perl \ pkg-config \ redhat-lsb-core -# CentOS 8 doesn't have libmnl-devel -yum -y install libmnl-devel || yum -y install libmnl +# CentOS 8 fixes +$yum libmnl-devel || $yum libmnl +$yum rubygem-asciidoctor || true diff --git a/travis/opensuse.sh b/ci/opensuse.sh similarity index 100% rename from travis/opensuse.sh rename to ci/opensuse.sh diff --git a/travis/tumbleweed.sh b/ci/tumbleweed.sh similarity index 55% rename from travis/tumbleweed.sh rename to ci/tumbleweed.sh index 4d5e9da799e3c0c7e832a22ef104cb3403ba8ab9..f1e7252f29a829251918164ac8e9e18d58f50c42 100755 --- a/travis/tumbleweed.sh +++ b/ci/tumbleweed.sh @@ -1,14 +1,19 @@ #!/bin/sh -# Copyright (c) 2018-2020 Petr Vorel +# Copyright (c) 2018-2021 Petr Vorel set -ex -zypper --non-interactive install --force-resolution --no-recommends \ +zyp="zypper --non-interactive install --force-resolution --no-recommends" + +$zyp \ + asciidoc \ autoconf \ automake \ clang \ findutils \ gcc \ + git \ gzip \ + iproute2 \ make \ kernel-default-devel \ keyutils-devel \ @@ -22,4 +27,7 @@ zypper --non-interactive install --force-resolution --no-recommends \ libtirpc-devel \ linux-glibc-devel \ lsb-release \ + perl-JSON \ pkg-config + +$zyp ruby2.7-rubygem-asciidoctor || $zyp ruby2.5-rubygem-asciidoctor || true diff --git a/travis/ubuntu.sh b/ci/ubuntu.sh similarity index 100% rename from travis/ubuntu.sh rename to ci/ubuntu.sh diff --git a/configure.ac b/configure.ac old mode 100644 new mode 100755 index 1d3ea58d0082e1cac0dac15a2d86cb775ee3ecbd..3c56d1922486b603e0ff707c74d92b5524c3a839 --- a/configure.ac +++ b/configure.ac @@ -13,9 +13,9 @@ AC_CONFIG_FILES([ \ execltp \ ]) -AM_MAINTAINER_MODE([enable]) +AC_ARG_VAR(HOSTCC, [The C compiler on the host]) -AM_CONDITIONAL(CROSS_COMPILATION, test x$cross_compiling = xyes) +AM_MAINTAINER_MODE([enable]) AC_CANONICAL_HOST @@ -30,25 +30,32 @@ AC_DEFUN([AC_PROG_STRIP], [AC_CHECK_TOOL(STRIP, strip, :)]) AC_PROG_STRIP AC_PROG_YACC +m4_ifndef([PKG_CHECK_EXISTS], + [m4_fatal([must install pkg-config or pkgconfig and pkg.m4 macro (usual dependency), see INSTALL])]) + AC_PREFIX_DEFAULT(/opt/ltp) AC_CHECK_DECLS([IFLA_NET_NS_PID],,,[#include ]) AC_CHECK_DECLS([MADV_MERGEABLE],,,[#include ]) AC_CHECK_DECLS([PR_CAPBSET_DROP, PR_CAPBSET_READ],,,[#include ]) +AC_CHECK_DECLS([SEM_STAT_ANY],,,[#include ]) -AC_CHECK_HEADERS([ \ +AC_CHECK_HEADERS_ONCE([ \ asm/ldt.h \ + emmintrin.h \ ifaddrs.h \ keyutils.h \ linux/can.h \ linux/cgroupstats.h \ linux/cryptouser.h \ + linux/close_range.h \ linux/dccp.h \ linux/fs.h \ linux/genetlink.h \ linux/if_alg.h \ linux/if_ether.h \ linux/if_packet.h \ + linux/io_uring.h \ linux/keyctl.h \ linux/mempolicy.h \ linux/module.h \ @@ -58,7 +65,6 @@ AC_CHECK_HEADERS([ \ linux/tty.h \ linux/types.h \ linux/userfaultfd.h \ - mm.h \ netinet/sctp.h \ pthread.h \ sys/epoll.h \ @@ -74,11 +80,14 @@ AC_CHECK_HEADERS([ \ ]) AC_CHECK_HEADERS(fts.h, [have_fts=1]) AC_SUBST(HAVE_FTS_H, $have_fts) +AC_CHECK_HEADERS(linux/vm_sockets.h, [], [], [#include ]) -AC_CHECK_FUNCS([ \ +AC_CHECK_FUNCS_ONCE([ \ clone3 \ + close_range \ copy_file_range \ epoll_pwait \ + epoll_pwait2 \ execveat \ fallocate \ fchownat \ @@ -87,6 +96,7 @@ AC_CHECK_FUNCS([ \ fsopen \ fspick \ fstatat \ + getauxval \ getdents \ getdents64 \ io_pgetevents \ @@ -94,6 +104,9 @@ AC_CHECK_FUNCS([ \ io_uring_register \ io_uring_enter \ kcmp \ + mallinfo \ + mallinfo2 \ + mallopt \ mkdirat \ mknodat \ modify_ldt \ @@ -110,12 +123,15 @@ AC_CHECK_FUNCS([ \ profil \ pwritev \ pwritev2 \ + quotactl_fd \ + rand_r \ readlinkat \ recvmmsg \ renameat \ renameat2 \ sched_getcpu \ sendmmsg \ + sethostid \ setns \ sigpending \ splice \ @@ -136,6 +152,10 @@ AC_CHECK_FUNCS(mkdtemp,[],AC_MSG_ERROR(mkdtemp() not found!)) AC_CHECK_MEMBERS([struct fanotify_event_info_fid.fsid.__val],,,[#include ]) AC_CHECK_MEMBERS([struct perf_event_mmap_page.aux_head],,,[#include ]) AC_CHECK_MEMBERS([struct sigaction.sa_sigaction],[],[],[#include ]) +AC_CHECK_MEMBERS([struct statx.stx_mnt_id],,,[ +#define _GNU_SOURCE +#include +]) AC_CHECK_MEMBERS([struct utsname.domainname],,,[ #define _GNU_SOURCE @@ -144,12 +164,21 @@ AC_CHECK_MEMBERS([struct utsname.domainname],,,[ AC_CHECK_TYPES([enum kcmp_type],,,[#include ]) AC_CHECK_TYPES([struct acct_v3],,,[#include ]) -AC_CHECK_TYPES([struct fanotify_event_info_fid],,,[#include ]) -AC_CHECK_TYPES([struct fanotify_event_info_header],,,[#include ]) +AC_CHECK_TYPES([struct af_alg_iv, struct sockaddr_alg],,,[# include ]) +AC_CHECK_TYPES([struct fanotify_event_info_fid, struct fanotify_event_info_error, + struct fanotify_event_info_header, struct fanotify_event_info_pidfd],,,[#include ]) AC_CHECK_TYPES([struct file_dedupe_range],,,[#include ]) + +AC_CHECK_TYPES([struct file_handle],,,[ +#define _GNU_SOURCE +#include +]) + AC_CHECK_TYPES([struct fs_quota_statv],,,[#include ]) AC_CHECK_TYPES([struct if_nextdqblk],,,[#include ]) AC_CHECK_TYPES([struct iovec],,,[#include ]) +AC_CHECK_TYPES([struct ipc64_perm],,,[#include ]) +AC_CHECK_TYPES([struct loop_config],,,[#include ]) AC_CHECK_TYPES([struct mmsghdr],,,[ #define _GNU_SOURCE @@ -157,27 +186,24 @@ AC_CHECK_TYPES([struct mmsghdr],,,[ #include ]) +AC_CHECK_TYPES([struct msqid64_ds],,,[#include ]) + AC_CHECK_TYPES([struct rlimit64],,,[ #define _LARGEFILE64_SOURCE #include ]) +AC_CHECK_TYPES([struct semid64_ds],,,[#include ]) +AC_CHECK_TYPES([struct shmid64_ds],,,[#include ]) + AC_CHECK_TYPES([struct statx, struct statx_timestamp],,,[ #define _GNU_SOURCE #include ]) AC_CHECK_TYPES([struct termio],,,[#include ]) - -AC_CHECK_TYPES([struct tpacket_req3],,,[ -#ifdef HAVE_LINUX_IF_PACKET_H -# include -#endif -]) - -AC_CHECK_TYPES([struct user_desc, struct modify_ldt_ldt_s],[],[],[ -#include -]) +AC_CHECK_TYPES([struct tpacket_req3],,,[# include ]) +AC_CHECK_TYPES([struct user_desc, struct modify_ldt_ldt_s],[],[],[#include ]) AC_CHECK_TYPES([struct xt_entry_match, struct xt_entry_target],,,[ #include @@ -187,9 +213,12 @@ AC_CHECK_TYPES([struct xt_entry_match, struct xt_entry_target],,,[ #include ]) +AC_CHECK_TYPES([struct __kernel_old_timeval, struct __kernel_old_timespec, struct __kernel_timespec, + struct __kernel_old_itimerspec, struct __kernel_itimerspec],,,[#include ]) + # Tools knobs -# Expect +# Bash AC_ARG_WITH([bash], [AC_HELP_STRING([--with-bash], [have the Bourne Again Shell interpreter])], @@ -202,6 +231,34 @@ else AC_SUBST([WITH_BASH],["no"]) fi +# metadata +AC_ARG_ENABLE([metadata], + [AC_HELP_STRING([--disable-metadata], + [Disable metadata generation (both HTML and PDF, default no)])], + [], [enable_metadata=yes] +) +AC_ARG_ENABLE([metadata_html], + [AC_HELP_STRING([--disable-metadata-html], + [Disable metadata HTML generation (default no)])], + [], [enable_metadata_html=yes] +) + +AC_ARG_ENABLE([metadata_pdf], + [AC_HELP_STRING([--enable-metadata-pdf], + [Enable metadata PDF generation (default no)])], + [], [enable_metadata_pdf=no] +) + +AC_ARG_WITH([metadata_generator], + [AC_HELP_STRING([--with-metadata-generator=asciidoc|asciidoctor], + [Specify metadata generator to use (default autodetect)])], + [with_metadata_generator=$withval], + [with_metadata_generator=detect] +) + +LTP_DOCPARSE + +# Expect AC_ARG_WITH([expect], [AC_HELP_STRING([--with-expect], [have the Tcl/expect library])], @@ -313,7 +370,7 @@ LTP_CHECK_SYSCALL_FCNTL if test "x$with_numa" = xyes; then LTP_CHECK_SYSCALL_NUMA - numa_error_msg="test requires libnuma >= 2 and it's development packages" + numa_error_msg="test requires libnuma development packages with LIBNUMA_API_VERSION >= 2" else numa_error_msg="NUMA support was disabled during build" fi @@ -328,3 +385,26 @@ test "x$with_tirpc" = xyes && LTP_CHECK_TIRPC LTP_DETECT_HOST_CPU AC_OUTPUT + +cat << EOF + +TESTSUITES +open posix testsuite: ${with_open_posix_testsuite:-no} +realtime testsuite: ${with_realtime_testsuite:-no} + +LIBRARIES +keyutils: ${have_keyutils:-no} +libacl: ${have_libacl:-no} +libaio: ${have_libaio:-no} (aio: ${have_aio:-no}) +libcap: $cap_libs (newer: ${has_newer_libcap:-no}) +libcrypto: $have_libcrypto (sha: ${have_sha:-no}) +libmnl: ${have_libmnl:-no} +libnuma: ${have_libnuma:-no} (headers: ${have_numa_headers:-no}, v2 headers: ${have_numa_headers_v2:-no}) +libtirpc: ${have_libtirpc:-no} +glibc SUN-RPC: ${have_rpc_glibc:-no} + +METADATA +metadata generator: $with_metadata_generator +HTML metadata: $with_metadata_html +PDF metadata: $with_metadata_pdf +EOF diff --git a/doc/Makefile b/doc/Makefile old mode 100644 new mode 100755 index e28df68535613da56f27fd8dde77afc883317a50..f7e4dd02130c9f6449cb9a83523fb9ae7d5d4a23 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,24 +1,6 @@ -# -# Doc Makefile. -# -# Copyright (C) 2009, Cisco Systems Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2009, Cisco Systems Inc. # Ngie Cooper, July 2009 -# top_srcdir ?= .. diff --git a/doc/build-system-guide.txt b/doc/build-system-guide.txt old mode 100644 new mode 100755 index c4b36239b4f228f087f8405a4e5d0fdc71e68a22..166f7fb92bcd28a486512f0675df2d0dc374a35f --- a/doc/build-system-guide.txt +++ b/doc/build-system-guide.txt @@ -158,6 +158,8 @@ $(LDFLAGS) : What to pass in to the linker, including -L arguments $(LDLIBS) : Libraries to pass to the linker (e.g. -lltp, etc). +$(LTPLDLIBS) : LTP internal libraries i.e. these in libs/ directory. + $(OPT_CFLAGS) : Optimization flags to pass into the C compiler, -O2, etc. If you specify -O2 or higher, you should also specify -fno-strict-aliasing, because of gcc diff --git a/doc/c-test-api.txt b/doc/c-test-api.txt new file mode 100755 index 0000000000000000000000000000000000000000..fa1f0fdca04a7caf5ba5f7f63cc5a1f6fb99dea2 --- /dev/null +++ b/doc/c-test-api.txt @@ -0,0 +1,2371 @@ +LTP C Test API +============== + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-Case-Tutorial[C Test Case Tutorial], + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API]. + +1 Writing a test in C +--------------------- + +1.1 Basic test structure +~~~~~~~~~~~~~~~~~~~~~~~~ + +Let's start with an example, following code is a simple test for a 'getenv()'. + +[source,c] +------------------------------------------------------------------------------- +/* + * This is test for basic functionality of getenv(). + * + * - create an env variable and verify that getenv() can get get it + * - call getenv() with nonexisting variable name, check that it returns NULL + */ + +#include "tst_test.h" + +#define ENV1 "LTP_TEST_ENV" +#define ENV2 "LTP_TEST_THIS_DOES_NOT_EXIST" +#define ENV_VAL "val" + +static void setup(void) +{ + if (setenv(ENV1, ENV_VAL, 1)) + tst_brk(TBROK | TERRNO, "setenv() failed"); +} + +static void test(void) +{ + char *ret; + + ret = getenv(ENV1); + + if (!ret) { + tst_res(TFAIL, "getenv(" ENV1 ") = NULL"); + goto next; + } + + if (!strcmp(ret, ENV_VAL)) { + tst_res(TPASS, "getenv(" ENV1 ") = '"ENV_VAL "'"); + } else { + tst_res(TFAIL, "getenv(" ENV1 ") = '%s', expected '" + ENV_VAL "'", ret); + } + +next: + ret = getenv(ENV2); + + if (ret) + tst_res(TFAIL, "getenv(" ENV2 ") = '%s'", ret); + else + tst_res(TPASS, "getenv(" ENV2 ") = NULL"); +} + +static struct tst_test test = { + .test_all = test, + .setup = setup, +}; +------------------------------------------------------------------------------- + +Each test includes the 'tst_test.h' header and must define the 'struct +tst_test test' structure. + +The overall test initialization is done in the 'setup()' function. + +The overall cleanup is done in a 'cleanup()' function. Here 'cleanup()' is +omitted as the test does not have anything to clean up. If cleanup is set in +the test structure it's called on test exit just before the test library +cleanup. That especially means that cleanup can be called at any point in a +test execution. For example even when a test setup step has failed, therefore +the 'cleanup()' function must be able to cope with unfinished initialization, +and so on. + +The test itself is done in the 'test()' function. The test function must work +fine if called in a loop. + +There are two types of a test function pointers in the test structure. The +first one is a '.test_all' pointer that is used when test is implemented as a +single function. Then there is a '.test' function along with the number of +tests '.tcnt' that allows for more detailed result reporting. If the '.test' +pointer is set the function is called '.tcnt' times with an integer parameter +in range of [0, '.tcnt' - 1]. + +IMPORTANT: Only one of '.test' and '.test_all' can be set at a time. + +Each test has a default timeout set to 300s. The default timeout can be +overridden by setting '.timeout' in the test structure or by calling +'tst_set_timeout()' in the test 'setup()'. There are a few testcases whose run +time may vary arbitrarily, for these timeout can be disabled by setting it to +-1. + +Test can find out how much time (in seconds) is remaining to timeout, +by calling 'tst_timeout_remaining()'. + +LAPI headers +++++++++++++ + +Use our LAPI headers ('include "lapi/foo.h"') to keep compatibility with old +distributions. LAPI header should always include original header. Older linux +headers were problematic, therefore we preferred to use libc headers. There are +still some bugs when combining certain glibc headers with linux headers, see +https://sourceware.org/glibc/wiki/Synchronizing_Headers. + +A word about the cleanup() callback ++++++++++++++++++++++++++++++++++++ + +There are a few rules that needs to be followed in order to write correct +cleanup() callback. + +1. Free only resources that were initialized. Keep in mind that callback can + be executed at any point in the test run. + +2. Make sure to free resources in the reverse order they were + initialized. (Some of the steps may not depend on others and everything + will work if there were swapped but let's keep it in order.) + +The first rule may seem complicated at first however, on the contrary, it's +quite easy. All you have to do is to keep track of what was already +initialized. For example file descriptors needs to be closed only if they were +assigned a valid file descriptor. For most of the things you need to create +extra flag that is set right after successful initialization though. Consider, +for example, test setup below. + +We also prefer cleaning up resources that would otherwise be released on the +program exit. There are two main reasons for this decision. Resources such as +file descriptors and mmaped memory could block umounting a block device in +cases where the test library has mounted a filesystem for the test temporary +directory. Not freeing allocated memory would upset static analysis and tools +such as valgrind and produce false-positives when checking for leaks in the +libc and other low level libraries. + +[source,c] +------------------------------------------------------------------------------- +static int fd0, fd1, mount_flag; + +#define MNTPOINT "mntpoint" +#define FILE1 "mntpoint/file1" +#define FILE2 "mntpoint/file2" + +static void setup(void) +{ + SAFE_MKDIR(MNTPOINT, 0777); + SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL); + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, 0); + mount_flag = 1; + + fd0 = SAFE_OPEN(cleanup, FILE1, O_CREAT | O_RDWR, 0666); + fd1 = SAFE_OPEN(cleanup, FILE2, O_CREAT | O_RDWR, 0666); +} +------------------------------------------------------------------------------- + +In this case the 'cleanup()' function may be invoked when any of the 'SAFE_*' +macros has failed and therefore must be able to work with unfinished +initialization as well. Since global variables are initialized to zero we can +just check that fd > 0 before we attempt to close it. The mount function +requires extra flag to be set after device was successfully mounted. + +[source,c] +------------------------------------------------------------------------------- +static void cleanup(void) +{ + if (fd1 > 0) + SAFE_CLOSE(fd1); + + if (fd0 > 0) + SAFE_CLOSE(fd0); + + if (mount_flag && tst_umouont(MNTPOINT)) + tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); +} +------------------------------------------------------------------------------- + +IMPORTANT: 'SAFE_MACROS()' used in cleanup *do not* exit the test. Failure + only produces a warning and the 'cleanup()' carries on. This is + intentional as we want to execute as much 'cleanup()' as possible. + +WARNING: Calling tst_brk() in test 'cleanup()' does not exit the test as well + and 'TBROK' is converted to 'TWARN'. + +NOTE: Creation and removal of the test temporary directory is handled in + the test library and the directory is removed recursively. Therefore + we do not have to remove files and directories in the test cleanup. + +1.2 Basic test interface +~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +void tst_res(int ttype, char *arg_fmt, ...); +------------------------------------------------------------------------------- + +Printf-like function to report test result, it's mostly used with ttype: + +|============================== +| 'TPASS' | Test has passed. +| 'TFAIL' | Test has failed. +| 'TINFO' | General message. +| 'TWARN' | Something went wrong but we decided to continue. Mostly used in cleanup functions. +|============================== + +The 'ttype' can be combined bitwise with 'TERRNO' or 'TTERRNO' to print +'errno', 'TST_ERR' respectively. + +[source,c] +------------------------------------------------------------------------------- +void tst_brk(int ttype, char *arg_fmt, ...); +------------------------------------------------------------------------------- + +Printf-like function to report error and exit the test, it can be used with ttype: + +|============================================================ +| 'TBROK' | Something has failed in test preparation phase. +| 'TCONF' | Test is not appropriate for current configuration + (syscall not implemented, unsupported arch, ...) +|============================================================ + +The 'ttype' can be combined bitwise with 'TERRNO' or 'TTERRNO' to print +'errno', 'TST_ERR' respectively. + +There are also 'TST_EXP_*()' macros that can simplify syscall unit tests to a +single line, use them whenever possible. These macros take a function call as +the first parameter and a printf-like format string and parameters as well. +These test macros then expand to a code that runs the call, checks the return +value and errno and reports the test result. + +[source,c] +------------------------------------------------------------------------------- +static void test(void) +{ + ... + TST_EXP_PASS(stat(fname, &statbuf), "stat(%s, ...)", fname); + + if (!TST_PASS) + return; + ... +} +------------------------------------------------------------------------------- + +The 'TST_EXP_PASS()' can be used for calls that return -1 on failure and 0 on +success. It will check for the return value and reports failure if the return +value is not equal to 0. The call also sets the 'TST_PASS' variable to 1 if +the call succeeeded. + +As seen above, this and similar macros take optional variadic arguments. These +begin with a format string and then appropriate values to be formatted. + +[source,c] +------------------------------------------------------------------------------- +static void test(void) +{ + ... + TST_EXP_FD(open(fname, O_RDONLY), "open(%s, O_RDONLY)", fname); + + SAFE_CLOSE(TST_RET); + ... +} +------------------------------------------------------------------------------- + +The 'TST_EXP_FD()' is the same as 'TST_EXP_PASS()' the only difference is that +the return value is expected to be a file descriptor so the call passes if +positive integer is returned. + +[source,c] +------------------------------------------------------------------------------- +static void test(void) +{ + ... + TST_EXP_FAIL(stat(fname, &statbuf), ENOENT, "stat(%s, ...)", fname); + ... +} +------------------------------------------------------------------------------- + +The 'TST_EXP_FAIL()' is similar to 'TST_EXP_PASS()' but it fails the test if +the call haven't failed with -1 and 'errno' wasn't set to the expected one +passed as the second argument. + +[source,c] +------------------------------------------------------------------------------- +static void test(void) +{ + ... + TST_EXP_FAIL2(msgget(key, flags), EINVAL, "msgget(%i, %i)", key, flags); + ... +} +------------------------------------------------------------------------------- + +The 'TST_EXP_FAIL2()' is the same as 'TST_EXP_FAIL()' except the return value is +expected to be non-negative integer if call passes. These macros build upon the ++TEST()+ macro and associated variables. + +[source,c] +------------------------------------------------------------------------------- +TEST(socket(AF_INET, SOCK_RAW, 1)); +if (TST_RET > -1) { + tst_res(TFAIL, "Created raw socket"); + SAFE_CLOSE(TST_RET); +} else if (TST_ERR != EPERM) { + tst_res(TFAIL | TTERRNO, + "Failed to create socket for wrong reason"); +} else { + tst_res(TPASS | TTERRNO, "Didn't create raw socket"); +} +------------------------------------------------------------------------------- + +The +TEST+ macro sets +TST_RET+ to its argument's return value and +TST_ERR+ to ++errno+. The +TTERNO+ flag can be used to print the error number's symbolic +value. + +No LTP library function or macro, except those in 'tst_test_macros.h', will +write to these variables (rule 'LTP-002'). So their values will not be changed +unexpectedly. + +[source,c] +------------------------------------------------------------------------------- +TST_EXP_POSITIVE(wait(&status)); + +if (!TST_PASS) + return; +------------------------------------------------------------------------------- + +If the return value of 'wait' is positive. This macro will print a pass result +and set +TST_PASS+ appropriately. If the return value is zero or negative, then +it will print fail. There are many similar macros to those shown here, please +see 'tst_test_macros.h'. + +[source,c] +------------------------------------------------------------------------------- +const char *tst_strsig(int sig); +------------------------------------------------------------------------------- + +Return the given signal number's corresponding string. + +[source,c] +------------------------------------------------------------------------------- +const char *tst_strerrno(int err); +------------------------------------------------------------------------------- + +Return the given errno number's corresponding string. Using this function to +translate 'errno' values to strings is preferred. You should not use the +'strerror()' function in the testcases. + +[source,c] +------------------------------------------------------------------------------- +const char *tst_strstatus(int status); +------------------------------------------------------------------------------- + +Returns string describing the status as returned by 'wait()'. + +WARNING: This function is not thread safe. + +[source,c] +------------------------------------------------------------------------------- +void tst_set_timeout(unsigned int timeout); +------------------------------------------------------------------------------- + +Allows for setting timeout per test iteration dynamically in the test setup(), +the timeout is specified in seconds. There are a few testcases whose runtime +can vary arbitrarily, these can disable timeouts by setting it to -1. + +[source,c] +------------------------------------------------------------------------------- +void tst_flush(void); +------------------------------------------------------------------------------- + +Flush output streams, handling errors appropriately. + +This function is rarely needed when you have to flush the output streams +before calling 'fork()' or 'clone()'. Note that the 'SAFE_FORK()' and 'SAFE_CLONE()' +calls this function automatically. See 2.4 FILE buffers and fork() for explanation +why is this needed. + +1.3 Test temporary directory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If '.needs_tmpdir' is set to '1' in the 'struct tst_test' unique test +temporary is created and it's set as the test working directory. Tests *MUST +NOT* create temporary files outside that directory. The flag is not needed to +be set when use these flags: '.all_filesystems', '.format_device', '.mntpoint', +'.mount_device' '.needs_checkpoints', '.needs_device', '.resource_file' +(these flags imply creating temporary directory). + +IMPORTANT: Close all file descriptors (that point to files in test temporary + directory, even the unlinked ones) either in the 'test()' function + or in the test 'cleanup()' otherwise the test may break temporary + directory removal on NFS (look for "NFS silly rename"). + +1.4 Safe macros +~~~~~~~~~~~~~~~ + +Safe macros aim to simplify error checking in test preparation. Instead of +calling system API functions, checking for their return value and aborting the +test if the operation has failed, you just use corresponding safe macro. + +Use them whenever it's possible. + +Instead of writing: + +[source,c] +------------------------------------------------------------------------------- + fd = open("/dev/null", O_RDONLY); + if (fd < 0) + tst_brk(TBROK | TERRNO, "opening /dev/null failed"); +------------------------------------------------------------------------------- + +You write just: + +[source,c] +------------------------------------------------------------------------------- + fd = SAFE_OPEN("/dev/null", O_RDONLY); +------------------------------------------------------------------------------- + +IMPORTANT: The SAFE_CLOSE() function also sets the passed file descriptor to -1 + after it's successfully closed. + +They can also simplify reading and writing of sysfs files, you can, for +example, do: + +[source,c] +------------------------------------------------------------------------------- + SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%lu", &pid_max); +------------------------------------------------------------------------------- + +See 'include/tst_safe_macros.h', 'include/tst_safe_stdio.h' and +'include/tst_safe_file_ops.h' and 'include/tst_safe_net.h' for a complete list. + +1.5 Test specific command line options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +struct tst_option { + char *optstr; + char **arg; + char *help; +}; +------------------------------------------------------------------------------- + +Test specific command line parameters can be passed with the 'NULL' terminated +array of 'struct tst_option'. The 'optstr' is the command line option i.e. "o" +or "o:" if option has a parameter. Only short options are supported. The 'arg' +is where 'optarg' is stored upon match. If option has no parameter it's set to +non-'NULL' value if option was present. The 'help' is a short help string. + +NOTE: The test parameters must not collide with common test parameters defined + in the library the currently used ones are +-i+, +-I+, +-C+, and +-h+. + +[source,c] +------------------------------------------------------------------------------- +int tst_parse_int(const char *str, int *val, int min, int max); +int tst_parse_long(const char *str, long *val, long min, long max); +int tst_parse_float(const char *str, float *val, float min, float max); +int tst_parse_filesize(const char *str, long long *val, long long min, long long max); +------------------------------------------------------------------------------- + +Helpers for parsing the strings returned in the 'struct tst_option'. + +Helpers return zero on success and 'errno', mostly 'EINVAL' or 'ERANGE', on +failure. + +Helpers functions are no-op if 'str' is 'NULL'. + +The valid range for result includes both 'min' and 'max'. + +In particular, 'tst_parse_filesize' function accepts prefix multiplies such as +"k/K for kilobytes, "m/M" for megabytes and "g/G" for gigabytes. For example, +10K are converted into 10240 bytes. + +.Example Usage +[source,c] +------------------------------------------------------------------------------- +#include +#include "tst_test.h" + +static char *str_threads; +static int threads = 10; + +static struct tst_option options[] = { + {"t:", &str_threads, "Number of threads (default 10)"}, + ... + {} +}; + +static void setup(void) +{ + if (tst_parse_int(str_threads, &threads, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of threads '%s'", str_threads); + + ... +} + +static void test_threads(void) +{ + ... + + for (i = 0; i < threads; i++) { + ... + } + + ... +} + +static struct tst_test test = { + ... + .options = options, + ... +}; +------------------------------------------------------------------------------- + + +1.6 Runtime kernel version detection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Testcases for newly added kernel functionality require kernel newer than a +certain version to run. All you need to skip a test on older kernels is to +set the '.min_kver' string in the 'struct tst_test' to a minimal required +kernel version, e.g. '.min_kver = "2.6.30"'. + +For more complicated operations such as skipping a test for a certain range +of kernel versions, following functions could be used: + +[source,c] +------------------------------------------------------------------------------- +int tst_kvercmp(int r1, int r2, int r3); + +struct tst_kern_exv { + char *dist_name; + char *extra_ver; +}; + +int tst_kvercmp2(int r1, int r2, int r3, struct tst_kern_exv *vers); +------------------------------------------------------------------------------- + +These two functions are intended for runtime kernel version detection. They +parse the output from 'uname()' and compare it to the passed values. + +The return value is similar to the 'strcmp()' function, i.e. zero means equal, +negative value means that the kernel is older than than the expected value and +positive means that it's newer. + +The second function 'tst_kvercmp2()' allows for specifying per-vendor table of +kernel versions as vendors typically backport fixes to their kernels and the +test may be relevant even if the kernel version does not suggests so. See +'testcases/kernel/syscalls/inotify/inotify04.c' for example usage. + +WARNING: The shell 'tst_kvercmp' maps the result into unsigned integer - the + process exit value. + +1.7 Fork()-ing +~~~~~~~~~~~~~~ + +Be wary that if the test forks and there were messages printed by the +'tst_*()' interfaces, the data may still be in libc/kernel buffers and these +*ARE NOT* flushed automatically. + +This happens when 'stdout' gets redirected to a file. In this case, the +'stdout' is not line buffered, but block buffered. Hence after a fork content +of the buffers will be printed by the parent and each of the children. + +To avoid that you should use 'SAFE_FORK()', 'SAFE_CLONE()' or 'tst_clone()'. + +IMPORTANT: You have to set the '.forks_child' flag in the test structure + if your testcase forks or calls 'SAFE_CLONE()'. + +1.8 Doing the test in the child process +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Results reported by 'tst_res()' are propagated to the parent test process via +block of shared memory. + +Calling 'tst_brk()' causes child process to exit with non-zero exit value. +Which means that it's safe to use 'SAFE_*()' macros in the child processes as +well. + +Children that outlive the 'test()' function execution are waited for in the +test library. Unclean child exit (killed by signal, non-zero exit value, etc.) +will cause the main test process to exit with 'tst_brk()', which especially +means that 'TBROK' propagated from a child process will cause the whole test +to exit with 'TBROK'. + +If a test needs a child that segfaults or does anything else that cause it to +exit uncleanly all you need to do is to wait for such children from the +'test()' function so that it's reaped before the main test exits the 'test()' +function. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +void tst_reap_children(void); +------------------------------------------------------------------------------- + +The 'tst_reap_children()' function makes the process wait for all of its +children and exits with 'tst_brk(TBROK, ...)' if any of them returned +a non zero exit code. + +When using 'SAFE_CLONE' or 'tst_clone', this may not work depending on +the parameters passed to clone. The following call to 'SAFE_CLONE' is +identical to 'fork()', so will work as expected. + +[source,c] +-------------------------------------------------------------------------------- +const struct tst_clone_args args = { + .exit_signal = SIGCHLD, +}; + +SAFE_CLONE(&args); +-------------------------------------------------------------------------------- + +If 'exit_signal' is set to something else, then this will break +'tst_reap_children'. It's not expected that all parameters to clone will +work with the LTP library unless specific action is taken by the test code. + +.Using 'tst_res()' from binaries started by 'exec()' +[source,c] +------------------------------------------------------------------------------- +/* test.c */ +#define _GNU_SOURCE +#include +#include "tst_test.h" + +static void do_test(void) +{ + char *const argv[] = {"test_exec_child", NULL}; + char path[4096]; + + if (tst_get_path("test_exec_child", path, sizeof(path))) + tst_brk(TCONF, "Couldn't find test_exec_child in $PATH"); + + execve(path, argv, environ); + + tst_res(TFAIL | TERRNO, "EXEC!"); +} + +static struct tst_test test = { + .test_all = do_test, + .child_needs_reinit = 1, +}; + +/* test_exec_child.c */ +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int main(void) +{ + tst_reinit(); + tst_res(TPASS, "Child passed!"); + return 0; +} +------------------------------------------------------------------------------- + +The 'tst_res()' function can be also used from binaries started by 'exec()', +the parent test process has to set the '.child_needs_reinit' flag so that the +library prepares for it and has to make sure the 'LTP_IPC_PATH' environment +variable is passed down, then the very fist thing the program has to call in +'main()' is 'tst_reinit()' that sets up the IPC. + +1.9 Fork() and Parent-child synchronization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As LTP tests are written for Linux, most of the tests involve fork()-ing and +parent-child process synchronization. LTP includes a checkpoint library that +provides wait/wake futex based functions. + +In order to use checkpoints the '.needs_checkpoints' flag in the 'struct +tst_test' must be set to '1', this causes the test library to initialize +checkpoints before the 'test()' function is called. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +TST_CHECKPOINT_WAIT(id) + +TST_CHECKPOINT_WAIT2(id, msec_timeout) + +TST_CHECKPOINT_WAKE(id) + +TST_CHECKPOINT_WAKE2(id, nr_wake) + +TST_CHECKPOINT_WAKE_AND_WAIT(id) +------------------------------------------------------------------------------- + +The checkpoint interface provides pair of wake and wait functions. The 'id' is +unsigned integer which specifies checkpoint to wake/wait for. As a matter of +fact it's an index to an array stored in a shared memory, so it starts on +'0' and there should be enough room for at least of hundred of them. + +The 'TST_CHECKPOINT_WAIT()' and 'TST_CHECKPOINT_WAIT2()' suspends process +execution until it's woken up or until timeout is reached. + +The 'TST_CHECKPOINT_WAKE()' wakes one process waiting on the checkpoint. +If no process is waiting the function retries until it success or until +timeout is reached. + +If timeout has been reached process exits with appropriate error message (uses +'tst_brk()'). + +The 'TST_CHECKPOINT_WAKE2()' does the same as 'TST_CHECKPOINT_WAKE()' but can +be used to wake precisely 'nr_wake' processes. + +The 'TST_CHECKPOINT_WAKE_AND_WAIT()' is a shorthand for doing wake and then +immediately waiting on the same checkpoint. + +Child processes created via 'SAFE_FORK()' are ready to use the checkpoint +synchronization functions, as they inherited the mapped page automatically. + +Child processes started via 'exec()', or any other processes not forked from +the test process must initialize the checkpoint by calling 'tst_reinit()'. + +For the details of the interface, look into the 'include/tst_checkpoint.h'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +/* + * Waits for process state change. + * + * The state is one of the following: + * + * R - process is running + * S - process is sleeping + * D - process sleeping uninterruptibly + * Z - zombie process + * T - process is traced + */ +TST_PROCESS_STATE_WAIT(pid, state, msec_timeout) +------------------------------------------------------------------------------- + +The 'TST_PROCESS_STATE_WAIT()' waits until process 'pid' is in requested +'state' or timeout is reached. The call polls +/proc/pid/stat+ to get this +information. A timeout of 0 will wait infinitely. + +On timeout -1 is returned and errno set to ETIMEDOUT. + +It's mostly used with state 'S' which means that process is sleeping in kernel +for example in 'pause()' or any other blocking syscall. + +1.10 Signals and signal handlers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to use signal handlers, keep the code short and simple. Don't +forget that the signal handler is called asynchronously and can interrupt the +code execution at any place. + +This means that problems arise when global state is changed both from the test +code and signal handler, which will occasionally lead to: + +* Data corruption (data gets into inconsistent state), this may happen, for + example, for any operations on 'FILE' objects. + +* Deadlock, this happens, for example, if you call 'malloc(2)', 'free(2)', + etc. from both the test code and the signal handler at the same time since + 'malloc' has global lock for it's internal data structures. (Be wary that + 'malloc(2)' is used by the libc functions internally too.) + +* Any other unreproducible and unexpected behavior. + +Quite common mistake is to call 'exit(3)' from a signal handler. Note that this +function is not signal-async-safe as it flushes buffers, etc. If you need to +exit a test immediately from a signal handler use '_exit(2)' instead. + +TIP: See 'man 7 signal' for the list of signal-async-safe functions. + +If a signal handler sets a variable, its declaration must be 'volatile', +otherwise compiler may misoptimize the code. This is because the variable may +not be changed in the compiler code flow analysis. There is 'sig_atomic_t' +type defined in C99 but this one *DOES NOT* imply 'volatile' (it's just a +'typedef' to 'int'). So the correct type for a flag that is changed from a +signal handler is either 'volatile int' or 'volatile sig_atomic_t'. + +If a crash (e.g. triggered by signal SIGSEGV) is expected in testing, you +can avoid creation of core files by calling tst_no_corefile() function. +This takes effect for process (and its children) which invoked it, unless +they subsequently modify RLIMIT_CORE. + +Note that LTP library will reap any processes that test didn't reap itself, +and report any non-zero exit code as failure. + +1.11 Kernel Modules +~~~~~~~~~~~~~~~~~~~ + +There are certain cases where the test needs a kernel part and userspace part, +happily, LTP can build a kernel module and then insert it to the kernel on test +start for you. See 'testcases/kernel/device-drivers/block' for details. + +1.12 Useful macros +~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +ARRAY_SIZE(arr) +------------------------------------------------------------------------------- + +Returns the size of statically defined array, i.e. +'(sizeof(arr) / sizeof(*arr))' + +[source,c] +------------------------------------------------------------------------------- +LTP_ALIGN(x, a) +------------------------------------------------------------------------------- + +Aligns the x to be next multiple of a. The a must be power of 2. + +1.13 Filesystem type detection and skiplist +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests are known to fail on certain filesystems (you cannot swap on TMPFS, +there are unimplemented 'fcntl()' etc.). + +If your test needs to be skipped on certain filesystems use the +'.skip_filesystems' field in the tst_test structure as follows: + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct tst_test test = { + ... + .skip_filesystems = (const char *const []) { + "tmpfs", + "ramfs", + "nfs", + NULL + }, +}; +------------------------------------------------------------------------------- + +When the '.all_filesystems' flag is set the '.skip_filesystems' list is passed +to the function that detects supported filesystems any listed filesystem is +not included in the resulting list of supported filesystems. + +If test needs to adjust expectations based on filesystem type it's also +possible to detect filesystem type at the runtime. This is preferably used +when only subset of the test is not applicable for a given filesystem. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void run(void) +{ + ... + + switch ((type = tst_fs_type("."))) { + case TST_NFS_MAGIC: + case TST_TMPFS_MAGIC: + case TST_RAMFS_MAGIC: + tst_brk(TCONF, "Subtest not supported on %s", + tst_fs_type_name(type)); + return; + break; + } + + ... +} +------------------------------------------------------------------------------- + +1.14 Thread-safety in the LTP library +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is safe to use library 'tst_res()' function in multi-threaded tests. + +Only the main thread must return from the 'test()' function to the test +library and that must be done only after all threads that may call any library +function has been terminated. That especially means that threads that may call +'tst_brk()' must terminate before the execution of the 'test()' function +returns to the library. This is usually done by the main thread joining all +worker threads at the end of the 'test()' function. Note that the main thread +will never get to the library code in a case that 'tst_brk()' was called from +one of the threads since it will sleep at least in 'pthread_join()' on the +thread that called the 'tst_brk()' till 'exit()' is called by 'tst_brk()'. + +The test-supplied cleanup function runs *concurrently* to the rest of the +threads in a case that cleanup was entered from 'tst_brk()'. Subsequent +threads entering 'tst_brk()' must be suspended or terminated at the start of +the user supplied cleanup function. It may be necessary to stop or exit +the rest of the threads before the test cleans up as well. For example threads +that create new files should be stopped before temporary directory is be +removed. + +Following code example shows thread safe cleanup function example using atomic +increment as a guard. The library calls its cleanup after the execution returns +from the user supplied cleanup and expects that only one thread returns from +the user supplied cleanup to the test library. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void cleanup(void) +{ + static int flag; + + if (tst_atomic_inc(&flag) != 1) + pthread_exit(NULL); + + /* if needed stop the rest of the threads here */ + + ... + + /* then do cleanup work */ + + ... + + /* only one thread returns to the library */ +} +------------------------------------------------------------------------------- + + +1.15 Testing with a block device +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests needs a block device (inotify tests, syscall 'EROFS' failures, +etc.). LTP library contains a code to prepare a testing device. + +If '.needs_device' flag in the 'struct tst_test' is set the 'tst_device' +structure is initialized with a path to a test device and default filesystem +to be used. + +You can also request minimal device size in megabytes by setting +'.dev_min_size' the device is guaranteed to have at least the requested size +then. + +If '.format_device' flag is set the device is formatted with a filesystem as +well. You can use '.dev_fs_type' to override the default filesystem type if +needed and pass additional options to mkfs via '.dev_fs_opts' and +'.dev_extra_opts' pointers. Note that '.format_device' implies '.needs_device' +there is no need to set both. + +If '.mount_device' is set, the device is mounted at '.mntpoint' which is used +to pass a directory name that will be created and used as mount destination. +You can pass additional flags and data to the mount command via '.mnt_flags' +and '.mnt_data' pointers. Note that '.mount_device' implies '.needs_device' +and '.format_device' so there is no need to set the later two. + +If '.needs_rofs' is set, read-only filesystem is mounted at '.mntpoint' this +one is supposed to be used for 'EROFS' tests. + +If '.all_filesystems' is set the test function is executed for all supported +filesystems. Supported filesystems are detected based on existence of the +'mkfs.$fs' helper and on kernel support to mount it. For each supported +filesystem the 'tst_device.fs_type' is set to the currently tested fs type, if +'.format_device' is set the device is formatted as well, if '.mount_device' is +set it's mounted at '.mntpoint'. Also the test timeout is reset for each +execution of the test function. This flag is expected to be used for filesystem +related syscalls that are at least partly implemented in the filesystem +specific code e.g. 'fallocate()'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +struct tst_device { + const char *dev; + const char *fs_type; +}; + +extern struct tst_device *tst_device; + +int tst_umount(const char *path); +------------------------------------------------------------------------------- + +In case that 'LTP_DEV' is passed to the test in an environment, the library +checks that the file exists and that it's a block device, if +'.device_min_size' is set the device size is checked as well. If 'LTP_DEV' +wasn't set or if size requirements were not met a temporary file is created +and attached to a free loop device. + +If there is no usable device and loop device couldn't be initialized the test +exits with 'TCONF'. + +The 'tst_umount()' function works exactly as 'umount(2)' but retries several +times on 'EBUSY'. This is because various desktop daemons (gvfsd-trash is known +for that) may be stupid enough to probe all newly mounted filesystem which +results in 'umount(2)' failing with 'EBUSY'. + +IMPORTANT: All testcases should use 'tst_umount()' instead of 'umount(2)' to + umount filesystems. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_find_free_loopdev(const char *path, size_t path_len); +------------------------------------------------------------------------------- + +This function finds a free loopdev and returns the free loopdev minor (-1 for no +free loopdev). If path is non-NULL, it will be filled with free loopdev path. +If you want to use a customized loop device, we can call 'tst_find_free_loopdev(NULL, 0)' +in tests to get a free minor number and then mknod. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +unsigned long tst_dev_bytes_written(const char *dev); +------------------------------------------------------------------------------- + +This function reads test block device stat file ('/sys/block//stat') and +returns the bytes written since the last invocation of this function. To avoid +FS deferred IO metadata/cache interference, we suggest doing "syncfs" before the +tst_dev_bytes_written first invocation. And an inline function named 'tst_dev_sync()' +is created for that intention. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +voud tst_find_backing_dev(const char *path, char *dev); +------------------------------------------------------------------------------- + +This function finds the block dev that this path belongs to, it uses stat function +to get the major/minor number of the path. Then scan them in '/proc/self/mountinfo' +and list 2th column value after ' - ' string as its block dev if match succeeds. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +uint64_t tst_get_device_size(const char *dev_path); +------------------------------------------------------------------------------- + +This function gets size of the given block device, it checks the 'dev_path' is +valid first, if yes, return the size in MB, otherwise return -1. + +1.16 Formatting a device with a filesystem +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void setup(void) +{ + ... + SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL); + ... +} +------------------------------------------------------------------------------- + +This function takes a path to a device, filesystem type and an array of extra +options passed to mkfs. + +The fs options 'fs_opts' should either be 'NULL' if there are none, or a +'NULL' terminated array of strings such as: ++const char *const opts[] = {"-b", "1024", NULL}+. + +The extra options 'extra_opts' should either be 'NULL' if there are none, or a +'NULL' terminated array of strings such as +{"102400", NULL}+; 'extra_opts' +will be passed after device name. e.g: +mkfs -t ext4 -b 1024 /dev/sda1 102400+ +in this case. + +Note that perfer to store the options which can be passed before or after device +name by 'fs_opts' array. + +1.17 Verifying a filesystem's free space +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests have size requirements for the filesystem's free space. If these +requirements are not satisfied, the tests should be skipped. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fs_has_free(const char *path, unsigned int size, unsigned int mult); +------------------------------------------------------------------------------- + +The 'tst_fs_has_free()' function returns 1 if there is enough space and 0 if +there is not. + +The 'path' is the pathname of any directory/file within a filesystem. + +The 'mult' is a multiplier, one of 'TST_BYTES', 'TST_KB', 'TST_MB' or 'TST_GB'. + +The required free space is calculated by 'size * mult', e.g. +'tst_fs_has_free("/tmp/testfile", 64, TST_MB)' will return 1 if the +filesystem, which '"/tmp/testfile"' is in, has 64MB free space at least, and 0 +if not. + +1.18 Files, directories and fs limits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests need to know the maximum count of links to a regular file or +directory, such as 'rename(2)' or 'linkat(2)' to test 'EMLINK' error. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fs_fill_hardlinks(const char *dir); +------------------------------------------------------------------------------- + +Try to get maximum count of hard links to a regular file inside the 'dir'. + +NOTE: This number depends on the filesystem 'dir' is on. + +This function uses 'link(2)' to create hard links to a single file until it +gets 'EMLINK' or creates 65535 links. If the limit is hit, the maximum number of +hardlinks is returned and the 'dir' is filled with hardlinks in format +"testfile%i", where i belongs to [0, limit) interval. If no limit is hit or if +'link(2)' failed with 'ENOSPC' or 'EDQUOT', zero is returned and previously +created files are removed. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fs_fill_subdirs(const char *dir); +------------------------------------------------------------------------------- + +Try to get maximum number of subdirectories in directory. + +NOTE: This number depends on the filesystem 'dir' is on. For current kernel, +subdir limit is not available for all filesystems (available for ext2, ext3, +minix, sysv and more). If the test runs on some other filesystems, like ramfs, +tmpfs, it will not even try to reach the limit and return 0. + +This function uses 'mkdir(2)' to create directories in 'dir' until it gets +'EMLINK' or creates 65535 directories. If the limit is hit, the maximum number +of subdirectories is returned and the 'dir' is filled with subdirectories in +format "testdir%i", where i belongs to [0, limit - 2) interval (because each +newly created dir has two links already - the '.' and the link from parent +dir). If no limit is hit or if 'mkdir(2)' failed with 'ENOSPC' or 'EDQUOT', +zero is returned and previously created directories are removed. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_dir_is_empty(const char *dir, int verbose); +------------------------------------------------------------------------------- + +Returns non-zero if directory is empty and zero otherwise. + +Directory is considered empty if it contains only '.' and '..'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +void tst_purge_dir(const char *path); +------------------------------------------------------------------------------- + +Deletes the contents of given directory but keeps the directory itself. Useful +for cleaning up the temporary directory and mount points between test cases or +test iterations. Terminates the program with 'TBROK' on error. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount); +------------------------------------------------------------------------------- + +Fill a file with specified pattern using file descriptor. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount); +------------------------------------------------------------------------------- + +Preallocate the specified amount of space using 'fallocate()'. Falls back to +'tst_fill_fd()' if 'fallocate()' fails. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount); +------------------------------------------------------------------------------- + +Creates/overwrites a file with specified pattern using file path. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_prealloc_file(const char *path, size_t bs, size_t bcount); +------------------------------------------------------------------------------- + +Create/overwrite a file and preallocate the specified amount of space for it. +The allocated space will not be initialized to any particular content. + +1.19 Getting an unused PID number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests require a 'PID', which is not used by the OS (does not belong to +any process within it). For example, kill(2) should set errno to 'ESRCH' if +it's passed such 'PID'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +pid_t tst_get_unused_pid(void); +------------------------------------------------------------------------------- + +Return a 'PID' value not used by the OS or any process within it. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_get_free_pids(void); +------------------------------------------------------------------------------- + +Returns number of unused pids in the system. Note that this number may be +different once the call returns and should be used only for rough estimates. + +1.20 Running executables +~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_cmd(const char *const argv[], + const char *stdout_path, + const char *stderr_path, + enum tst_cmd_flags flags); +------------------------------------------------------------------------------- + +'tst_cmd()' is a wrapper for 'vfork() + execvp()' which provides a way +to execute an external program. + +'argv[]' is a 'NULL' terminated array of strings starting with the program name +which is followed by optional arguments. + +'TST_CMD_PASS_RETVAL' enum 'tst_cmd_flags' makes 'tst_cmd()' +return the program exit code to the caller, otherwise 'tst_cmd()' exit the +tests on failure. 'TST_CMD_TCONF_ON_MISSING' check for program in '$PATH' and exit +with 'TCONF' if not found. + +In case that 'execvp()' has failed and the enum 'TST_CMD_PASS_RETVAL' flag was set, the +return value is '255' if 'execvp()' failed with 'ENOENT' and '254' otherwise. + +'stdout_path' and 'stderr_path' determine where to redirect the program +stdout and stderr I/O streams. + +The 'SAFE_CMD()' macro can be used automatic handling non-zero exits (exits +with 'TBROK') and 'ENOENT' (exits with 'TCONF'). + +.Example +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +const char *const cmd[] = { "ls", "-l", NULL }; + +... + /* Store output of 'ls -l' into log.txt */ + tst_cmd(cmd, "log.txt", NULL, 0); +... +------------------------------------------------------------------------------- + +1.21 Measuring elapsed time and helper functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include "tst_timer.h" + +void tst_timer_check(clockid_t clk_id); + +void tst_timer_start(clockid_t clk_id); + +void tst_timer_stop(void); + +struct timespec tst_timer_elapsed(void); + +long long tst_timer_elapsed_ms(void); + +long long tst_timer_elapsed_us(void); + +int tst_timer_expired_ms(long long ms); +------------------------------------------------------------------------------- + +The 'tst_timer_check()' function checks if specified 'clk_id' is suppored and +exits the test with 'TCONF' otherwise. It's expected to be used in test +'setup()' before any resources that needs to be cleaned up are initialized, +hence it does not include a cleanup function parameter. + +The 'tst_timer_start()' marks start time and stores the 'clk_id' for further +use. + +The 'tst_timer_stop()' marks the stop time using the same 'clk_id' as last +call to 'tst_timer_start()'. + +The 'tst_timer_elapsed*()' returns time difference between the timer start and +last timer stop in several formats and units. + +The 'tst_timer_expired_ms()' function checks if the timer started by +'tst_timer_start()' has been running longer than ms milliseconds. The function +returns non-zero if timer has expired and zero otherwise. + +IMPORTANT: The timer functions use 'clock_gettime()' internally which needs to + be linked with '-lrt' on older glibc. Please do not forget to add + 'LDLIBS+=-lrt' in Makefile. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" +#include "tst_timer.h" + +static void setup(void) +{ + ... + tst_timer_check(CLOCK_MONOTONIC); + ... +} + +static void run(void) +{ + ... + tst_timer_start(CLOCK_MONOTONIC); + ... + while (!tst_timer_expired_ms(5000)) { + ... + } + ... +} + +struct tst_test test = { + ... + .setup = setup, + .test_all = run, + ... +}; +------------------------------------------------------------------------------- + +Expiration timer example usage. + +[source,c] +------------------------------------------------------------------------------- +long long tst_timespec_to_us(struct timespec t); +long long tst_timespec_to_ms(struct timespec t); + +struct timeval tst_us_to_timeval(long long us); +struct timeval tst_ms_to_timeval(long long ms); + +int tst_timespec_lt(struct timespec t1, struct timespec t2); + +struct timespec tst_timespec_add_us(struct timespec t, long long us); + +struct timespec tst_timespec_diff(struct timespec t1, struct timespec t2); +long long tst_timespec_diff_us(struct timespec t1, struct timespec t2); +long long tst_timespec_diff_ms(struct timespec t1, struct timespec t2); + +struct timespec tst_timespec_abs_diff(struct timespec t1, struct timespec t2); +long long tst_timespec_abs_diff_us(struct timespec t1, struct timespec t2); +long long tst_timespec_abs_diff_ms(struct timespec t1, struct timespec t2); +------------------------------------------------------------------------------- + +The first four functions are simple inline conversion functions. + +The 'tst_timespec_lt()' function returns non-zero if 't1' is earlier than +'t2'. + +The 'tst_timespec_add_us()' function adds 'us' microseconds to the timespec +'t'. The 'us' is expected to be positive. + +The 'tst_timespec_diff*()' functions returns difference between two times, the +'t1' is expected to be later than 't2'. + +The 'tst_timespec_abs_diff*()' functions returns absolute value of difference +between two times. + +NOTE: All conversions to ms and us rounds the value. + +1.22 Datafiles +~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static const char *const res_files[] = { + "foo", + "bar", + NULL +}; + +static struct tst_test test = { + ... + .resource_files = res_files, + ... +} +------------------------------------------------------------------------------- + +If the test needs additional files to be copied to the test temporary +directory all you need to do is to list their filenames in the +'NULL' terminated array '.resource_files' in the tst_test structure. + +When resource files is set test temporary directory is created automatically, +there is need to set '.needs_tmpdir' as well. + +The test library looks for datafiles first, these are either stored in a +directory called +datafiles+ in the +$PWD+ at the start of the test or in ++$LTPROOT/testcases/data/${test_binary_name}+. If the file is not found the +library looks into +$LTPROOT/testcases/bin/+ and to +$PWD+ at the start of the +test. This ensures that the testcases can copy the file(s) effortlessly both +when test is started from the directory it was compiled in as well as when LTP +was installed. + +The file(s) are copied to the newly created test temporary directory which is +set as the test working directory when the 'test()' functions is executed. + +1.23 Code path tracing +~~~~~~~~~~~~~~~~~~~~~~ + +'tst_res' is a macro, so on when you define a function in one file: + +[source,c] +------------------------------------------------------------------------------- +int do_action(int arg) +{ + ... + + if (ok) { + tst_res(TPASS, "check passed"); + return 0; + } else { + tst_res(TFAIL, "check failed"); + return -1; + } +} +------------------------------------------------------------------------------- + +and call it from another file, the file and line reported by 'tst_res' in this +function will be from the former file. + +'TST_TRACE' can make the analysis of such situations easier. It's a macro which +inserts a call to 'tst_res(TINFO, ...)' in case its argument evaluates to +non-zero. In this call to 'tst_res(TINFO, ...)' the file and line will be +expanded using the actual location of 'TST_TRACE'. + +For example, if this another file contains: + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +if (TST_TRACE(do_action(arg))) { + ... +} +------------------------------------------------------------------------------- + +the generated output may look similar to: + +------------------------------------------------------------------------------- +common.h:9: FAIL: check failed +test.c:8: INFO: do_action(arg) failed +------------------------------------------------------------------------------- + +1.24 Tainted kernels +~~~~~~~~~~~~~~~~~~~~ + +If you need to detect whether a testcase triggers a kernel warning, bug or +oops, the following can be used to detect TAINT_W or TAINT_D: + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct tst_test test = { + ... + .taint_check = TST_TAINT_W | TST_TAINT_D, + ... +}; + +void run(void) +{ + ... + if (tst_taint_check() != 0) + tst_res(TFAIL, "kernel has issues"); + else + tst_res(TPASS, "kernel seems to be fine"); +} +------------------------------------------------------------------------------- + +To initialize taint checks, you have to set the taint flags you want to test +for in the 'taint_check' attribute of the tst_test struct. LTP library will +then automatically call 'tst_taint_init()' during test setup. The function +will generate a 'TCONF' if the requested flags are not fully supported on the +running kernel, and 'TBROK' if the kernel is already tainted before executing +the test. + +LTP library will then automatically check kernel taint at the end of testing. +If '.all_filesystems' is set in struct tst_test, taint check will be performed +after each file system and taint will abort testing early with 'TFAIL'. You +can optionally also call 'tst_taint_check()' during 'run()', which returns 0 +or the tainted flags set in '/proc/sys/kernel/tainted' as specified earlier. + +Depending on your kernel version, not all tainted-flags will be supported. + +For reference to tainted kernels, see kernel documentation: +Documentation/admin-guide/tainted-kernels.rst or +https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html + +1.25 Checksums +~~~~~~~~~~~~~~ + +CRC32c checksum generation is supported by LTP. In order to use it, the +test should include 'tst_checksum.h' header, then can call 'tst_crc32c()'. + +1.26 Checking kernel for the driver support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests may need specific kernel drivers, either compiled in, or built +as a module. If '.needs_drivers' points to a 'NULL' terminated array of kernel +module names these are all checked and the test exits with 'TCONF' on the +first missing driver. + +Since it relies on modprobe command, the check will be skipped if the command +itself is not available on the system. + +1.27 Saving & restoring /proc|sys values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LTP library can be instructed to save and restore value of specified +(/proc|sys) files. This is achieved by initialized tst_test struct +field 'save_restore'. It is a 'NULL' terminated array of strings where +each string represents a file, whose value is saved at the beginning +and restored at the end of the test. Only first line of a specified +file is saved and restored. + +Pathnames can be optionally prefixed to specify how strictly (during +'store') are handled errors: + +* (no prefix) - test ends with 'TCONF', if file doesn't exist +* '?' - test prints info message and continues, + if file doesn't exist or open/read fails +* '!' - test ends with 'TBROK', if file doesn't exist + +'restore' is always strict and will TWARN if it encounters any error. + +[source,c] +------------------------------------------------------------------------------- +static const char *save_restore[] = { + "/proc/sys/kernel/core_pattern", + NULL, +}; + +static void setup(void) +{ + FILE_PRINTF("/proc/sys/kernel/core_pattern", "/mypath"); +} + +static struct tst_test test = { + ... + .setup = setup, + .save_restore = save_restore, +}; +------------------------------------------------------------------------------- + +1.28 Parsing kernel .config +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generally testcases should attempt to autodetect as much kernel features as +possible based on the currently running kernel. We do have tst_check_driver() +to check if functionality that could be compiled as kernel module is present +on the system, disabled syscalls can be detected by checking for 'ENOSYS' +errno etc. + +However in rare cases core kernel features couldn't be detected based on the +kernel userspace API and we have to resort to parse the kernel .config. + +For this cases the test should set the 'NULL' terminated '.needs_kconfigs' +array of boolean expressions with constraints on the kconfig variables. The +boolean expression consits of variables, two binary operations '&' and '|', +negation '!' and correct sequence of parentesis '()'. Variables are expected +to be in a form of "CONFIG_FOO[=bar]". + +The test will continue to run if all expressions are evaluated to 'True'. +Missing variable is mapped to 'False' as well as variable with different than +specified value, e.g. 'CONFIG_FOO=bar' will evaluate to 'False' if the value +is anything else but 'bar'. If config variable is specified as plain +'CONFIG_FOO' it's evaluated to true it's set to any value (typically =y or =m). + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static const char *kconfigs[] = { + "CONFIG_X86_INTEL_UMIP | CONFIG_X86_UMIP", + NULL +}; + +static struct tst_test test = { + ... + .needs_kconfigs = kconfigs, + ... +}; +------------------------------------------------------------------------------- + +1.29 Changing the Wall Clock Time during test execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are some tests that, for different reasons, might need to change the +system-wide clock time. Whenever this happens, it is imperative that the clock +is restored, at the end of test's execution, taking in consideration the amount +of time elapsed during that test. + +In order for that to happen, struct tst_test has a variable called +"restore_wallclock" that should be set to "1" so LTP knows it should: (1) +initialize a monotonic clock during test setup phase and (2) use that monotonic +clock to fix the system-wide clock time at the test cleanup phase. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void setup(void) +{ + ... +} + +static void run(void) +{ + ... +} + +struct tst_test test = { + ... + .setup = setup, + .test_all = run, + .restore_wallclock = 1, + ... +}; +------------------------------------------------------------------------------- + +1.30 Testing similar syscalls in one test +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some cases kernel has several very similar syscalls that do either the same +or very similar job. This is most noticeable on i386 where we commonly have +two or three syscall versions. That is because i386 was first platform that +Linux was developed on and because of that most mistakes in API happened there +as well. However this is not limited to i386 at all, it's quite common that +version two syscall has added missing flags parameters or so. + +In such cases it does not make much sense to copy&paste the test code over and +over, rather than that the test library provides support for test variants. +The idea behind test variants is simple, we run the test several times each +time with different syscall variant. + +The implementation consist of test_variants integer that, if set, denotes number +of test variants. The test is then forked and executed test_variants times each +time with different value in global tst_variant variable. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static int do_foo(void) +{ + switch (tst_variant) { + case 0: + return foo(); + case 1: + return syscall(__NR_foo); + } + + return -1; +} + +static void run(void) +{ + ... + + TEST(do_foo); + + ... +} + +static void setup(void) +{ + switch (tst_variant) { + case 0: + tst_res(TINFO, "Testing foo variant 1"); + break; + case 1: + tst_res(TINFO, "Testing foo variant 2"); + break; + } +} + +struct tst_test test = { + ... + .setup = setup, + .test_all = run, + .test_variants = 2, + ... +}; +------------------------------------------------------------------------------- + +1.31 Guarded buffers +~~~~~~~~~~~~~~~~~~~~ + +The test library supports guarded buffers, which are buffers allocated so +that: + +* The end of the buffer is followed by a PROT_NONE page + +* The remainder of the page before the buffer is filled with random canary + data + +Which means that the any access after the buffer will yield a Segmentation +fault or EFAULT depending on if the access happened in userspace or the kernel +respectively. The canary before the buffer will also catch any write access +outside of the buffer. + +The purpose of the patch is to catch off-by-one bugs which happens when +buffers and structures are passed to syscalls. New tests should allocate +guarded buffers for all data passed to the tested syscall which are passed by +a pointer. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct foo *foo_ptr; +static struct iovec *iov; +static void *buf_ptr; +static char *id; +... + +static void run(void) +{ + ... + + foo_ptr->bar = 1; + foo_ptr->buf = buf_ptr; + + ... +} + +static void setup(void) +{ + ... + + id = tst_strdup(string); + + ... +} + +static struct tst_test test = { + ... + .bufs = (struct tst_buffers []) { + {&foo_ptr, .size = sizeof(*foo_ptr)}, + {&buf_ptr, .size = BUF_SIZE}, + {&iov, .iov_sizes = (int[]){128, 32, -1}, + {} + } +}; +------------------------------------------------------------------------------- + +Guarded buffers can be allocated on runtime in a test setup() by a +'tst_alloc()' or by 'tst_strdup()' as well as by filling up the .bufs array in +the tst_test structure. + +So far the tst_test structure supports allocating either a plain buffer by +setting up the size or struct iovec, which is allocated recursively including +the individual buffers as described by an '-1' terminated array of buffer +sizes. + +1.32 Adding and removing capabilities +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests may require the presence or absence of particular +capabilities. Using the API provided by 'tst_capability.h' the test author can +try to ensure that some capabilities are either present or absent during the +test. + +For example; below we try to create a raw socket, which requires +CAP_NET_ADMIN. During setup we should be able to do it, then during run it +should be impossible. The LTP capability library will check before setup that +we have this capability, then after setup it will drop it. + +[source,c] +-------------------------------------------------------------------------------- +#include "tst_test.h" +#include "tst_capability.h" +#include "tst_safe_net.h" + +#include "lapi/socket.h" + +static void run(void) +{ + TEST(socket(AF_INET, SOCK_RAW, 1)); + if (TST_RET > -1) { + tst_res(TFAIL, "Created raw socket"); + } else if (TST_ERR != EPERM) { + tst_res(TFAIL | TTERRNO, + "Failed to create socket for wrong reason"); + } else { + tst_res(TPASS | TTERRNO, "Didn't create raw socket"); + } +} + +static void setup(void) +{ + TEST(socket(AF_INET, SOCK_RAW, 1)); + if (TST_RET < 0) + tst_brk(TCONF | TTERRNO, "We don't have CAP_NET_RAW to begin with"); + + SAFE_CLOSE(TST_RET); +} + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_REQ, CAP_NET_RAW), + TST_CAP(TST_CAP_DROP, CAP_NET_RAW), + {} + }, +}; +-------------------------------------------------------------------------------- + +Look at the test struct at the bottom. We have filled in the 'caps' field with +a 'NULL' terminated array containing two 'tst_cap' structs. 'TST_CAP_REQ' +actions are executed before setup and 'TST_CAP_DROP' are executed after +setup. This means it is possible to both request and drop a capability. + +[source,c] +-------------------------------------------------------------------------------- +static struct tst_test test = { + .test_all = run, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_REQ, CAP_NET_RAW), + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), + {} + }, +}; +-------------------------------------------------------------------------------- + +Here we request 'CAP_NET_RAW', but drop 'CAP_SYS_ADMIN'. If the capability is +in the permitted set, but not the effective set, the library will try to +permit it. If it is not in the permitted set, then it will fail with 'TCONF'. + +This API does not require 'libcap' to be installed. However it has limited +features relative to 'libcap'. It only tries to add or remove capabilities +from the effective set. This means that tests which need to spawn child +processes may have difficulties ensuring the correct capabilities are +available to the children (see the capabilities (7) manual pages). + +However a lot of problems can be solved by using 'tst_cap_action(struct +tst_cap *cap)' directly which can be called at any time. This also helps if +you wish to drop a capability at the begining of setup. + +1.33 Reproducing race-conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a bug is caused by two tasks in the kernel racing and you wish to create a +regression test (or bug-fix validation test) then the 'tst_fuzzy_sync.h' +library should be used. + +It allows you to specify, in your code, two race windows. One window in each +thread's loop (triggering a race usually requires many iterations). These +windows show fuzzy-sync where the race can happen. They don't need to be +exact, hence the 'fuzzy' part. If the race condition is not immediately +triggered then the library will begin experimenting with different timings. + +[source,c] +-------------------------------------------------------------------------------- +#include "tst_fuzzy_sync.h" + +static struct tst_fzsync_pair fzsync_pair; + +static void setup(void) +{ + tst_fzsync_pair_init(&fzsync_pair); +} + +static void cleanup(void) +{ + tst_fzsync_pair_cleanup(&fzsync_pair); +} + +static void *thread_b(void *arg) +{ + while (tst_fzsync_run_b(&fzsync_pair)) { + + tst_fzsync_start_race_b(&fzsync_pair); + + /* This is the race window for thread B */ + + tst_fzsync_end_race_b(&fzsync_pair); + } + + return arg; +} + +static void thread_a(void) +{ + tst_fzsync_pair_reset(&fzsync_pair, thread_b); + + while (tst_fzsync_run_a(&fzsync_pair)) { + + tst_fzsync_start_race_a(&fzsync_pair); + + /* This is the race window for thread A */ + + tst_fzsync_end_race_a(&fzsync_pair); + } +} + +static struct tst_test test = { + .test_all = thread_a, + .setup = setup, + .cleanup = cleanup, +}; +-------------------------------------------------------------------------------- + +Above is a minimal template for a test using fuzzy-sync. In a simple case, you +just need to put the bits you want to race inbetween 'start_race' and +'end_race'. Meanwhile, any setup you need to do per-iteration goes outside the +windows. + +Fuzzy sync synchronises 'run_a' and 'run_b', which act as barriers, so that +neither thread can progress until the other has caught up with it. There is +also the 'pair_wait' function which can be used to add barriers in other +locations. Of course 'start/end_race_a/b' are also a barriers. + +The library decides how long the test should run for based on the timeout +specified by the user plus some other heuristics. + +For full documentation see the comments in 'include/tst_fuzzy_sync.h'. + +1.34 Reserving hugepages +~~~~~~~~~~~~~~~~~~~~~~~~ + +Many of the LTP tests need to use hugepage in their testing, this allows the +test can reserve hugepages from system only via '.request_hugepages = xx'. + +If set non-zero number of 'request_hugepages', test will try to reserve the +expected number of hugepage for testing in setup phase. If system does not +have enough hpage for using, it will try the best to reserve 80% available +number of hpages. With success test stores the reserved hugepage number in +'tst_hugepages'. For the system without hugetlb supporting, variable +'tst_hugepages' will be set to 0. If the hugepage number needs to be set to 0 +on supported hugetlb system, please use '.request_hugepages = TST_NO_HUGEPAGES'. + +Also, we do cleanup and restore work for the hpages resetting automatically. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void run(void) +{ + ... + + if (tst_hugepages == test.request_hugepages) + TEST(do_hpage_test); + else + ... + ... +} + +struct tst_test test = { + .test_all = run, + .request_hugepages = 2, + ... +}; +------------------------------------------------------------------------------- + +or, + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void run(void) +{ + ... +} + +static void setup(void) +{ +        if (tst_hugepages != test.requested_hugepages) +                tst_brk(TCONF, "..."); +} + +struct tst_test test = { + .test_all = run, + .request_hugepages = 2, + ... +}; +------------------------------------------------------------------------------- + +1.35 Checking for required commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Required commands can be checked with '.needs_cmds', which points to a 'NULL' +terminated array of strings such as: + +[source,c] +------------------------------------------------------------------------------- +.needs_cmds = (const char *const []) { + "useradd", + "userdel", + NULL +}, +------------------------------------------------------------------------------- + +Also can check required command version whether is satisfied by using 'needs_cmds' +such as: + +[source,c] +------------------------------------------------------------------------------- +.needs_cmds = (const char *const []) { + "mkfs.ext4 >= 1.43.0", + NULL +}, +------------------------------------------------------------------------------- + +Currently, we only support mkfs.ext4 command version check. +If you want to support more commands, please fill your own .parser and .table_get +method in the version_parsers structure of lib/tst_cmd.c. + +1.36 Assert sys or proc file value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Using TST_ASSERT_INT/STR(path, val) to assert that integer value or string stored in +the prefix field of file pointed by path equals to the value passed to this function. + +Also having a similar api pair TST_ASSERT_FILE_INT/STR(path, prefix, val) to assert +the field value of file. + +1.36 Using Control Group +~~~~~~~~~~~~~~~~~~~~~~~~ + +Some LTP tests need specific Control Group configurations. tst_cgroup.h provides +APIs to discover and use CGroups. There are many differences between CGroups API +V1 and V2. We encapsulate the details of configuring CGroups in high-level +functions which follow the V2 kernel API. Allowing one to use CGroups without +caring too much about the current system's configuration. + +Also, the LTP library will automatically mount/umount and configure the CGroup +hierarchies if that is required (e.g. if you run the tests from init with no +system manager). + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" +#include "tst_cgroup.h" + +static const struct tst_cgroup_group *cg; + +static void run(void) +{ + ... + // do test under cgroup + ... +} + +static void setup(void) +{ + tst_cgroup_require("memory", NULL); + cg = tst_cgroup_get_test_group(); + SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); + SAFE_CGROUP_PRINTF(cg, "memory.max", "%lu", MEMSIZE); + if (SAFE_CGROUP_HAS(cg, "memory.swap.max")) + SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%zu", memsw); +} + +static void cleanup(void) +{ + tst_cgroup_cleanup(); +} + +struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup, + ... +}; +------------------------------------------------------------------------------- + +Above, we first ensure the memory controller is available on the +test's CGroup with 'tst_cgroup_require'. We then get a structure, +'cg', which represents the test's CGroup. Note that +'tst_cgroup_get_test_group' should not be called many times, as it is +allocated in a guarded buffer (See section 2.2.31). Therefor it is +best to call it once in 'setup' and not 'run' because 'run' may be +repeated with the '-i' option. + +We then write the current processes PID into 'cgroup.procs', which +moves the current process into the test's CGroup. After which we set +the maximum memory size by writing to 'memory.max'. If the memory +controller is mounted on CGroups V1 then the library will actually +write to 'memory.limit_in_bytes'. As a general rule, if a file exists +on both CGroup versions, then we use the V2 naming. + +Some controller features, such as 'memory.swap', can be +disabled. Therefor we need to check if they exist before accessing +them. This can be done with 'SAFE_CGROUP_HAS' which can be called on +any control file or feature. + +Most tests only require setting a few limits similar to the above. In +such cases the differences between V1 and V2 are hidden. Setup and +cleanup is also mostly hidden. However things can get much worse. + +[source,c] +------------------------------------------------------------------------------- +static const struct tst_cgroup_group *cg; +static const struct tst_cgroup_group *cg_drain; +static struct tst_cgroup_group *cg_child; + +static void run(void) +{ + char buf[BUFSIZ]; + size_t mem = 0; + + cg_child = tst_cgroup_group_mk(cg, "child"); + SAFE_CGROUP_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + + if (!TST_CGROUP_VER_IS_V1(cg, "memory")) + SAFE_CGROUP_PRINT(cg, "cgroup.subtree_control", "+memory"); + if (!TST_CGROUP_VER_IS_V1(cg, "cpuset")) + SAFE_CGROUP_PRINT(cg, "cgroup.subtree_control", "+cpuset"); + + if (!SAFE_FORK()) { + SAFE_CGROUP_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + + if (SAFE_CGROUP_HAS(cg_child, "memory.swap")) + SAFE_CGROUP_SCANF(cg_child, "memory.swap.current", "%zu", &mem); + SAFE_CGROUP_READ(cg_child, "cpuset.mems", buf, sizeof(buf)); + + // Do something with cpuset.mems and memory.current values + ... + + exit(0); + } + + tst_reap_children(); + SAFE_CGROUP_PRINTF(cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cgroup_group_rm(cg_child); +} + +static void setup(void) +{ + tst_cgroup_require("memory", NULL); + tst_cgroup_require("cpuset", NULL); + + cg = tst_cgroup_get_test_group(); + cg_drain = tst_cgroup_get_drain_group(); +} + +static void cleanup(void) +{ + if (cg_child) { + SAFE_CGROUP_PRINTF(cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cgroup_group_rm(cg_child); + } + + tst_cgroup_cleanup(); +} + +struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup, + ... +}; +------------------------------------------------------------------------------- + +Starting with setup; we can see here that we also fetch the 'drain' +CGroup. This is a shared group (between parallel tests) which may +contain processes from other tests. It should have default settings and +these should not be changed by the test. It can be used to remove +processes from other CGroups incase the hierarchy root is not +accessible. + +In 'run', we first create a child CGroup with 'tst_cgroup_mk'. As we +create this CGroup in 'run' we should also remove it at the end of +run. We also need to check if it exists and remove it in cleanup as +well. Because there are 'SAFE_' functions which may jump to cleanup. + +We then move the main test process into the child CGroup. This is +important as it means that before we destroy the child CGroup we have +to move the main test process elsewhere. For that we use the 'drain' +group. + +Next we enable the memory and cpuset controller configuration on the +test CGroup's descendants (i.e. 'cg_child'). This allows each child to +have its own settings. The file 'cgroup.subtree_control' does not +exist on V1. Because it is possible to have both V1 and V2 active at +the same time. We can not simply check if 'subtree_control' exists +before writing to it. We have to check if a particular controller is +on V2 before trying to add it to 'subtree_control'. Trying to add a V1 +controller will result in 'ENOENT'. + +We then fork a child process and add this to the child CGroup. Within +the child process we try to read 'memory.swap.current'. It is possible +that the memory controller was compiled without swap support, so it is +necessary to check if 'memory.swap' is enabled. That is unless the +test will never reach the point where 'memory.swap.*' are used without +swap support. + +The parent process waits for the child process to be reaped before +destroying the child CGroup. So there is no need to transfer the child +to drain. However the parent process must be moved otherwise we will +get 'EBUSY' when trying to remove the child CGroup. + +Another example of an edge case is the following. + +[source,c] +------------------------------------------------------------------------------- + if (TST_CGROUP_VER_IS_V1(cg, "memory")) + SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%lu", ~0UL); + else + SAFE_CGROUP_PRINT(cg, "memory.swap.max", "max"); +------------------------------------------------------------------------------- + +CGroups V2 introduced a feature where 'memory[.swap].max' could be set to +"max". This does not appear to work on V1 'limit_in_bytes' however. For most +tests, simply using a large number is sufficient and there is no need to use +"max". Importantly though, one should be careful to read both the V1 and V2 +kernel docs. The LTP library can not handle all edge cases. It does the minimal +amount of work to make testing on both V1 and V2 feasible. + +1.37 Require minimum numbers of CPU for a testcase +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests require more than specific number of CPU. It can be defined with +`.min_cpus = N`. + +1.38 Test tags +~~~~~~~~~~~~~~ + +Test tags are name-value pairs that can hold any test metadata. + +We have additional support for CVE entries, git commit in mainline kernel, +stable kernel or glibc git repository. If a test is a regression test it +should include these tags. They are printed when test fails and exported +into documentation. + +CVE, mainline and stable kernel git commits in a regression test for a kernel bug: +[source,c] +------------------------------------------------------------------------------- +struct tst_test test = { + ... + .tags = (const struct tst_tag[]) { + {"linux-git", "9392a27d88b9"}, + {"linux-git", "ff002b30181d"}, + {"known-fail", "ustat() is known to fail with EINVAL on Btrfs"}, + {"linux-stable-git", "c4a23c852e80"}, + {"CVE", "2020-29373"}, + {} + } +}; +------------------------------------------------------------------------------- + +NOTE: We don't track all backports to stable kernel but just those which are + stable branch specific (unique), i.e. no commit in mainline. Example of + commits: c4a23c852e80, cac68d12c531. + +Glibc git commit in a regression test for a glibc bug: +[source,c] +------------------------------------------------------------------------------- +struct tst_test test = { + ... + .tags = (const struct tst_tag[]) { + {"glibc-git", "574500a108be"}, + {} + } +}; +------------------------------------------------------------------------------- + +1.39 Testing on the specific architecture +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Testcases for specific arch should be limited on that only being supported +platform to run, we now involve a .supported_archs to achieve this feature +in LTP library. All you need to run a test on the expected arch is to set +the '.supported_archs' array in the 'struct tst_test' to choose the required +arch list. e.g. + + .supported_archs = (const char *const []){"x86_64", "ppc64", NULL} + +This helps move the TCONF info from code to tst_test metadata as well. + +And, we also export a struct tst_arch to save the system architecture for +using in the whole test cases. + + extern const struct tst_arch { + char name[16]; + enum tst_arch_type type; + } tst_arch; + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct tst_test test = { + ... + .setup = setup, + .supported_archs = (const char *const []) { + "x86_64", + "ppc64", + "s390x", + NULL + }, +}; +------------------------------------------------------------------------------- + +2. Common problems +------------------ + +This chapter describes common problems/misuses and less obvious design patters +(quirks) in UNIX interfaces. Read it carefully :) + +2.1 umask() +~~~~~~~~~~~ + +I've been hit by this one several times already... When you create files +with 'open()' or 'creat()' etc, the mode specified as the last parameter *is +not* the mode the file is created with. The mode depends on current 'umask()' +settings which may clear some of the bits. If your test depends on specific +file permissions you need either to change umask to 0 or 'chmod()' the file +afterwards or use 'SAFE_TOUCH()' that does the 'chmod()' for you. + +2.2 access() +~~~~~~~~~~~~ + +If 'access(some_file, W_OK)' is executed by root, it will return success even +if the file doesn't have write permission bits set (the same holds for R_OK +too). For sysfs files you can use 'open()' as a workaround to check file +read/write permissions. It might not work for other filesystems, for these you +have to use 'stat()', 'lstat()' or 'fstat()'. + +2.3 umount() EBUSY +~~~~~~~~~~~~~~~~~~ + +Various desktop daemons (gvfsd-trash is known for that) may be stupid enough +to probe all newly mounted filesystem which results in 'umount(2)' failing +with 'EBUSY'; use 'tst_umount()' described in 1.19 that retries in this case +instead of plain 'umount(2)'. + +2.4 FILE buffers and fork() +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Be vary that if a process calls 'fork(2)' the child process inherits open +descriptors as well as copy of the parent memory so especially if there are +any open 'FILE' buffers with a data in them they may be written both by the +parent and children resulting in corrupted/duplicated data in the resulting +files. + +Also open 'FILE' streams are flushed and closed at 'exit(3)' so if your +program works with 'FILE' streams, does 'fork(2)', and the child may end up +calling 'exit(3)' you will likely end up with corrupted files. + +The solution to this problem is either simply call 'fflush(NULL)' that flushes +all open output 'FILE' streams just before doing 'fork(2)'. You may also use +'_exit(2)' in child processes which does not flush 'FILE' buffers and also +skips 'atexit(3)' callbacks. diff --git a/doc/c-test-tutorial-simple.txt b/doc/c-test-tutorial-simple.txt old mode 100644 new mode 100755 index 34b2142525e8df382f239878d545eb081985cff3..867c2653231dccbf752bfdf1ce3d34b8e1bb8f96 --- a/doc/c-test-tutorial-simple.txt +++ b/doc/c-test-tutorial-simple.txt @@ -1,6 +1,10 @@ C Test Case Tutorial ==================== +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API]. + This is a step-by-step tutorial on writing a simple C LTP test, where topics of the LTP and Linux kernel testing will be introduced gradually using a concrete example. Most sections will include exercises, some trivial and @@ -302,12 +306,11 @@ Wiki]). Is your +.gitignore+ correct? -3.3 Run checkpatch.pl on the source file -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +3.3 Run make check +~~~~~~~~~~~~~~~~~~ -The LTP follows the Linux style guidelines where possible. Check what happens -if you run +kernel/linux/scripts/checkpatch.pl --no-tree -f statx01.c+ and -correct any style issues. +Check coding style with `make check` + (more in https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#21-c-coding-style[C coding style]) 3.4 Install the LTP and run the test with runtest ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -763,7 +766,7 @@ failing due to some faulty logic. 6.1 What is wrong with the switch statement? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Were you paying attention? Also see the output of +checkpatch.pl+. +Were you paying attention? Also see the output of +make check+. 6.2 Test a feature unique to statx ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -791,9 +794,9 @@ of fallback logic in the build system. We can now get our test ready for submission. The first thing you need to do before considering submitting your test is run -+scripts/checkpatch.pl --no-tree -f+ on +statx01.c+. Again, we use the kernel -style guidelines where possible. Next you should create a new branch, this -will allow you to reshape your commit history without fear. ++make check-statx01+ or + make check+ in the test's directory. Again, we use +the kernel style guidelines where possible. Next you should create a new +branch, this will allow you to reshape your commit history without fear. After that we have the pleasure of doing an interactive 'rebase' to clean up our commit history. In its current form the test only really needs a single @@ -1061,9 +1064,12 @@ One important topic which has not been covered by this tutorial, is multi-process or multi-threaded testing. The LTP library functions work inside child processes and threads, but their semantics change slightly. There are also various helper functions for synchronising and forking processes. For -more information see the Test Writing Guidelines (either at -https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[the -Wiki] or in ./doc), in particular sections 2.2.7 to 2.2.10 and 2.2.13. +more information see +https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API], +in particular sections +https://github.com/linux-test-project/ltp/wiki/C-Test-API#17-fork-ing[1.7 Fork()-ing] to +https://github.com/linux-test-project/ltp/wiki/C-Test-API#110-signals-and-signal-handlers[1.10 Signals and signal handlers] and +https://github.com/linux-test-project/ltp/wiki/C-Test-API#114-thread-safety-in-the-ltp-library[1.14 Thread-safety in the LTP library]. When it comes time to submit a test, the preferred way to do it is on the mailing list although you can also use GitHub. The LTP follows similar rules diff --git a/doc/library-api-writing-guidelines.txt b/doc/library-api-writing-guidelines.txt old mode 100644 new mode 100755 index 5de35a7e29e37e4bf93d9096cf23f00c637b92e9..c820536814620debd90a7a3dd1cba2fe52b1c11f --- a/doc/library-api-writing-guidelines.txt +++ b/doc/library-api-writing-guidelines.txt @@ -1,6 +1,11 @@ LTP Library API Writing Guidelines ================================== +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API], + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API]. + 1. General Rules ---------------- @@ -16,10 +21,34 @@ Don't forget to update docs when you change the API. 2. C API -------- +2.1 LTP-001: Sources have tst_ prefix +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + API source code is in headers `include/*.h`, `include/lapi/*.h` (backward compatibility for old kernel and libc) and C sources in `lib/*.c`. Files have 'tst_' prefix. +2.2 LTP-002: TST_RET and TST_ERR are not modified +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The test author is guaranteed that the test API will not modify these +variables. This prevents silent errors where the return value and +errno are overwritten before the test has chance to check them. + +The macros which are clearly intended to update these variables. That +is +TEST+ and those in 'tst_test_macros.h'. Are of course allowed to +update these variables. + +2.3 LTP-003: Externally visible library symbols have the tst_ prefix +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Functions, types and variables in the public test API should have the +tst_ prefix. With some exceptions for symbols already prefixed with +safe_ or ltp_. + +Static (private) symbols should not have the prefix. + + 3. Shell API ------------ diff --git a/doc/ltp-run-files.txt b/doc/ltp-run-files.txt old mode 100644 new mode 100755 index c290869878793828bfe951753af89d4003357993..3f405b3877d1cbfbbb3cd85ab91f1cf517532e42 --- a/doc/ltp-run-files.txt +++ b/doc/ltp-run-files.txt @@ -56,9 +56,7 @@ if run network tests flag is passed these additional tests are run - nfs To test filesystem with LVM -- ltpfslvm.sh -w/o LVM -- ltpfsnolvm.sh +- testscripts/lvmtest.sh Device Mapper tests - ltpdmmapper.sh @@ -71,7 +69,6 @@ other filesystem or disk type tests - autofs1.sh - autofs4.sh - diskio.sh - - exportfs.sh - isofs.sh - sysfs.sh diff --git a/doc/maintainer-patch-review-checklist.txt b/doc/maintainer-patch-review-checklist.txt new file mode 100755 index 0000000000000000000000000000000000000000..4e10dc514b10d09c07a9e0f15189e88e544f77d6 --- /dev/null +++ b/doc/maintainer-patch-review-checklist.txt @@ -0,0 +1,59 @@ +# Maintainer Patch Review Checklist + +Patchset should be tested locally and ideally also in maintainer's fork in +GitHub Actions on GitHub. + +NOTE: Travis does only build testing, passing the CI means only that the + test compiles fine on variety of different distributions and + releases. + +The test should be executed at least once locally and should PASS as well. + +Commit messages should have + +* Author's `Signed-off-by` tag +* Committer's `Reviewed-by` or `Signed-off-by` tag +* Check also mailing lists for other reviewers / testers tags, notes and failure reports +* `Fixes: hash` if it fixes particular LTP commit +* `Fixes: #N` if it fixes github issue number N, so it's automatically closed + +After patch is accepted or rejected, set correct state and archive in +https://patchwork.ozlabs.org/project/ltp/list/[LTP patchwork instance]. + +Also update `.github/workflows/wiki-mirror.yml` script which mirrors +`doc/*.txt` to LTP wiki (git URL https://github.com/linux-test-project/ltp.wiki.git) +if new wiki page is added. + +## New tests +New test should + +* Have a record in runtest file +* Test should work fine with more than one iteration + (e.g. run with `-i 100`) +* Have a brief description +* License: the default license for new tests is GPL v2 or later, use + GPL-2.0-or-later; the licence for test (e.g. GPL-2.0) should not change + unless test is completely rewritten +* Old copyrights should be kept unless test is completely rewritten + +### C tests +* Use new https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#22-writing-a-test-in-c[C API] +* Test binaries are added into corresponding '.gitignore' files +* Check coding style with `make check` + (more in https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#21-c-coding-style[C coding style]) +* Docparse documentation +* If a test is a regression test it should include tags + (more in https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#2238-test-tags[Test tags]) +* When rewriting old tests, https://en.wikipedia.org/wiki/%CE%9CClinux[uClinux] + support should be removed (project has been discontinued). + E.g. remove `#ifdef UCLINUX`, replace `FORK_OR_VFORK()` with simple `fork()` or `SAFE_FORK()`. + +### Shell tests +* Use new https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#23-writing-a-testcase-in-shell[shell API] +* Check coding style with `make check` + (more in https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#132-shell-coding-style[Shell coding style]) +* If a test is a regression test it should include related kernel or glibc commits as a comment + +## LTP library +For patchset touching library please check also +https://github.com/linux-test-project/ltp/wiki/LTP-Library-API-Writing-Guidelines[LTP Library API Writing Guidelines]. diff --git a/doc/man1/Makefile b/doc/man1/Makefile old mode 100644 new mode 100755 diff --git a/doc/man1/doio.1 b/doc/man1/doio.1 old mode 100644 new mode 100755 diff --git a/doc/man1/iogen.1 b/doc/man1/iogen.1 old mode 100644 new mode 100755 diff --git a/doc/man1/ltp-bump.1 b/doc/man1/ltp-bump.1 old mode 100644 new mode 100755 diff --git a/doc/man1/ltp-pan.1 b/doc/man1/ltp-pan.1 old mode 100644 new mode 100755 diff --git a/doc/man3/Makefile b/doc/man3/Makefile old mode 100644 new mode 100755 diff --git a/doc/man3/parse_opts.3 b/doc/man3/parse_opts.3 old mode 100644 new mode 100755 diff --git a/doc/man3/parse_ranges.3 b/doc/man3/parse_ranges.3 old mode 100644 new mode 100755 diff --git a/doc/man3/random_range.3 b/doc/man3/random_range.3 old mode 100644 new mode 100755 diff --git a/doc/man3/random_range_seed.3 b/doc/man3/random_range_seed.3 old mode 100644 new mode 100755 diff --git a/doc/man3/tst_res.3 b/doc/man3/tst_res.3 old mode 100644 new mode 100755 diff --git a/doc/man3/tst_sig.3 b/doc/man3/tst_sig.3 old mode 100644 new mode 100755 diff --git a/doc/man3/tst_tmpdir.3 b/doc/man3/tst_tmpdir.3 old mode 100644 new mode 100755 diff --git a/doc/man3/usctest.3 b/doc/man3/usctest.3 old mode 100644 new mode 100755 diff --git a/doc/mini-howto-building-ltp-from-git.txt b/doc/mini-howto-building-ltp-from-git.txt old mode 100644 new mode 100755 diff --git a/doc/namespaces-helper-tools.txt b/doc/namespaces-helper-tools.txt old mode 100644 new mode 100755 diff --git a/doc/network-c-api.txt b/doc/network-c-api.txt new file mode 100755 index 0000000000000000000000000000000000000000..e910d159f9488fad2ff1560ec1a3e397c83f352e --- /dev/null +++ b/doc/network-c-api.txt @@ -0,0 +1,476 @@ +LTP C Test Network API +====================== + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-Case-Tutorial[C Test Case Tutorial], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API], + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API]. + +LTP library includes helper functions for configuring sockets and setting up +network devices. + +1 Configuring sockets +--------------------- + +1.1 Safe syscall variants +~~~~~~~~~~~~~~~~~~~~~~~~~ + ++#include "tst_safe_net.h"+ + +Most common standard syscalls and libc functions for configuring sockets have a +"safe" variant in LTP library which will call +tst_brk()+ if the underlying +system function fails. See +https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API]. The +safe function names are in uppercase with the +SAFE_+ prefix (e.g. the safe +variant of +socket()+ is called +SAFE_SOCKET()+). For most safe functions, the +parameters and return type are identical to the standard system function: + +- +SAFE_SOCKET()+ +- +SAFE_SOCKETPAIR()+ +- +SAFE_GETSOCKOPT()+ +- +SAFE_SETSOCKOPT()+ +- +SAFE_BIND()+ +- +SAFE_LISTEN()+ +- +SAFE_ACCEPT()+ +- +SAFE_CONNECT()+ +- +SAFE_GETSOCKNAME()+ +- +SAFE_GETHOSTNAME()+ +- +SAFE_GETADDRINFO()+ + +A few safe functions have extra parameters for quick return value validation. +The ellipsis (+...+) represents the standard parameters of the underlying system +function: + +* +SAFE_SEND(char strict, ...)+ +* +SAFE_SENDTO(char strict, ...)+ +** If +strict+ is non-zero, the return value must be equal to the data length + argument. Otherwise the test will fail and exit. + +* +SAFE_SENDMSG(size_t msg_len, ...)+ +* +SAFE_RECV(size_t msg_len, ...)+ +* +SAFE_RECVMSG(size_t msg_len, ...)+ +** If +msg_len+ is non-zero, the return value must be equal to the +msg_len+ + argument. Otherwise the test will fail and exit. + +There are also some custom functions for simpler configuration and queries: + +- +int SAFE_SETSOCKOPT_INT(int sockfd, int level, int optname, int value)+ – + Simple setsockopt() variant for passing integers by value. + +- +int TST_GETSOCKPORT(int sockfd)+ – Get port number (in host byte order) of a + bound socket. + +- +unsigned short TST_GET_UNUSED_PORT(int family, int type)+ – Get a random + port number (in network byte order) which is currently closed for the given + socket family and type. Note that another application may open the port while + the test is still running. The test user is responsible for setting up test + environment without such interference. + +1.2 Address conversion functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++#include "tst_net.h"+ + +LTP library also provides helper functions for quick initialization of socket +address structures: + +- +void tst_get_in_addr(const char *ip_str, struct in_addr *ip)+ – Convert + human-readable IPv4 address string +ip_str+ to binary representation in + network byte order. The converted value will be stored in the second argument. + +- +void tst_get_in6_addr(const char *ip_str, struct in6_addr *ip6)+ – Convert + human-readable IPv6 address string +ip_str+ to binary representation in + network byte order. The converted value will be stored in the second argument. + +- +socklen_t tst_get_connect_address(int sock, struct sockaddr_storage *addr)+ – + Find the address which can be used to send data to bound socket +sock+ from + another socket. The address will be stored in the second argument. This + function automatically converts wildcard bind address to localhost. Returns + size of the address in bytes. + +- +void tst_init_sockaddr_inet(struct sockaddr_in *sa, const char *ip_str, + uint16_t port)+ – Initialize socket address structure +sa+ using + human-readable IPv4 address +ip_str+ and port number +port+ in host byte + order. + +- +void tst_init_sockaddr_inet_bin(struct sockaddr_in *sa, uint32_t ip_val, + uint16_t port)+ – Initialize socket address structure +sa+ using binary IPv4 + address +ip_val+ and port number +port+, both in host byte order. + +- +void tst_init_sockaddr_inet6(struct sockaddr_in6 *sa, const char *ip_str, + uint16_t port)+ – Initialize socket address structure +sa+ using + human-readable IPv6 address +ip_str+ and port number +port+ in host byte + order. + +- +void tst_init_sockaddr_inet6_bin(struct sockaddr_in6 *sa, const struct + in6_addr *ip_val, uint16_t port)+ – Initialize socket address structure +sa+ + using binary IPv6 address +ip_val+ and port number +port+, both in host byte + order. + +.Example Usage +[source,c] +------------------------------------------------------------------------------- + +#include +#include + +#include "tst_test.h" +#include "tst_safe_net.h" +#include "tst_net.h" + +static int sockfd = -1; + +static void setup(void) +{ + struct sockaddr_in addr; + + tst_init_sockaddr_inet_bin(&addr, INADDR_ANY, 0); + sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + SAFE_SETSOCKOPT_INT(sockfd, SOL_SOCKET, SO_SNDBUF, 4096); + SAFE_BIND(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + SAFE_LISTEN(sockfd, 8); +} + +------------------------------------------------------------------------------- + +2 Configuring network devices +----------------------------- + ++#include "tst_netdevice.h"+ + +When opening a localhost socket isn't enough and the test needs special device +or routing configuration, the netdevice library can create the required network +setup without calling external programs. Internally, the netdevice functions +use a rtnetlink socket to communicate with the kernel. + +All of these functions will call +tst_brk()+ on failure, unless stated +otherwise. Error values described below are returned only during test cleanup +stage. + +2.1 Network device management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- +int NETDEV_INDEX_BY_NAME(const char *ifname)+ – Returns the device index for + the given device name, or -1 on error. + +- +int NETDEV_SET_STATE(const char *ifname, int up)+ – Enable or disable a + network device +ifname+. Returns 0 on success, -1 on error. + +- +int CREATE_VETH_PAIR(const char *ifname1, const char *ifname2)+ – Creates a + connected pair of virtual network devices with given device names. Returns 1 + on success, 0 on error. Add +"CONFIG_VETH"+ to +test.needs_kconfigs+ if your + test calls this function. + +- +int NETDEV_ADD_DEVICE(const char *ifname, const char *devtype)+ - Creates + a new network device named +ifname+ of specified device type. Returns 1 on + success, 0 on error. + +- +int NETDEV_REMOVE_DEVICE(const char *ifname)+ – Removes network device + +ifname+. Returns 1 on success, 0 on error. + +2.2 Network address management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- +int NETDEV_ADD_ADDRESS(const char \*ifname, unsigned int family, const void + *address, unsigned int prefix, size_t addrlen, unsigned int flags)+ – Adds + new address to network device +ifname+. This is a low-level function which + allows setting any type of address. You must specify the protocol +family+, + address length in bytes (+addrlen+) and network prefix length (+prefix+). The + +address+ itself must be in binary representation in network byte order. You + can also pass rtnetlink flags from the +IFA_F_*+ group. Returns 1 on success, + 0 on error. + +- +int NETDEV_ADD_ADDRESS_INET(const char *ifname, in_addr_t address, unsigned + int prefix, unsigned int flags)+ – Adds new IPv4 address to network device + +ifname+. Parameters have the same meaning as in +NETDEV_ADD_ADDRESS()+. + Returns 1 on success, 0 on error. + +- +int NETDEV_REMOVE_ADDRESS(const char *ifname, unsigned int family, const + void *address, size_t addrlen)+ – Removes the specified address from network + device +ifname+. Parameters have the same meaning as in + +NETDEV_ADD_ADDRESS()+. Returns 1 on success, 0 on error. + +- +int NETDEV_REMOVE_ADDRESS_INET(const char *ifname, in_addr_t address)+ – + Removes specified IPv4 +address+ (in network byte order) from network device + +ifname+. Returns 1 on success, 0 on error. + +2.3 Network namespace device assignment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +WARNING: Moving a network device to another namespace will erase previous + configuration. Move the device to the correct namespace first, then + configure it. + +- +int NETDEV_CHANGE_NS_FD(const char *ifname, int nsfd)+ – Moves network + device +ifname+ to network namespace designated by open file descriptor + +nsfd+. Returns 1 on success, 0 on error. + +- +int NETDEV_CHANGE_NS_PID(const char *ifname, pid_t nspid)+ – Moves network + device +ifname+ to the network namespace currently used by process +nspid+. + Returns 1 on success, 0 on error. + +2.4 Routing table management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- +int NETDEV_ADD_ROUTE(const char *ifname, unsigned int family, const void + *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, + unsigned int dstprefix, size_t dstlen, const void *gateway, size_t + gatewaylen)+ – Adds new route to the main routing table. This is a low-level + function which allows creating routes for any protocol. You must specify the + protocol +family+ and either network device name +ifname+ or +gateway+ + address. Both packet source address +srcaddr+ and destination address + +dstaddr+ are optional. You must also specify the corresponding length + and prefix argument for any address which is not +NULL+. All addresses must + be in binary representation in network byte order. Returns 1 on success, + 0 on error. + +- +int NETDEV_ADD_ROUTE_INET(const char *ifname, in_addr_t srcaddr, unsigned + int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t + gateway)+ – Adds new IPv4 route to the main routing table. Parameters have + the same meaning as in +NETDEV_ADD_ROUTE()+. If you do not want to set + explicit +gateway+ address, set it to 0. If the routing rule should ignore + the source or destination address, set the corresponding prefix argument + to 0. Returns 1 on success, 0 on error. + +- +int NETDEV_REMOVE_ROUTE(const char *ifname, unsigned int family, const void + *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, + unsigned int dstprefix, size_t dstlen, const void *gateway, size_t + gatewaylen)+ – Removes a route from the main routing table. Parameters have + the same meaning as in +NETDEV_ADD_ROUTE()+. Returns 1 on success, 0 on + error. + +- +int NETDEV_REMOVE_ROUTE_INET(const char *ifname, in_addr_t srcaddr, + unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t + gateway)+ – Removes IPv4 route from the main routing table. Parameters have + the same meaning as in +NETDEV_ADD_ROUTE_INET()+. Returns 1 on success, + 0 on error. + +.Example Usage +[source,c] +------------------------------------------------------------------------------- +#include +#include +#include "tst_test.h" +#include "tst_netdevice.h" + +... + +static void setup(void) +{ + CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2"); + NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(DSTADDR), NETMASK, + IFA_F_NOPREFIXROUTE); + NETDEV_SET_STATE("ltp_veth2", 1); + NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(SRCNET), NETMASK, 0); + + NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(SRCADDR), NETMASK, + IFA_F_NOPREFIXROUTE); + NETDEV_SET_STATE("ltp_veth1", 1); + NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(DSTNET), NETMASK, 0); + ... +} +------------------------------------------------------------------------------- + +3 rtnetlink API +--------------- + ++#include "tst_rtnetlink.h"+ + +The rtnetlink library provides helper functions for constructing and sending +arbitrary messages and parsing kernel responses. + +All of the functions below will call +tst_brk()+ on failure, unless stated +otherwise. Error values described below are returned only during test cleanup +stage. + +3.1 Data structures +~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +struct tst_rtnl_context; + +struct tst_rtnl_attr_list { + unsigned short type; + const void *data; + ssize_t len; + const struct tst_rtnl_attr_list *sublist; +}; + +struct tst_rtnl_message { + struct nlmsghdr *header; + struct nlmsgerr *err; + void *payload; + size_t payload_size; +}; +------------------------------------------------------------------------------- + ++struct tst_rtnl_context+ is an opaque rtnetlink socket with buffer for +constructing and sending arbitrary messages using the functions described +below. Create a new context using +RTNL_CREATE_CONTEXT()+, then free it using ++RTNL_DESTROY_CONTEXT()+ when you're done with it. + ++struct tst_rtnl_attr_list+ is a helper structure for defining complex +rtnetlink message attribute payloads, including nested attribute lists. Every +list and sublist defined using this structure is terminated by item with +negative +len+. + +- +type+ is the attribute type that will be stored in +struct rtattr.rta_type+. + +- +data+ contains arbitrary attribute payload. + +- +len+ contains length of the +data+ attribute in bytes. If +data+ is +NULL+, + set +len+ to 0. The last item in a list or sublist must have negative length. + +- +sublist+ contains a nested attribute list which will be appended after + +data+ as part of the attribute payload. +struct rtattr.rta_len+ will be + calculated automatically with proper alignment, do _not_ add the sublist size + to the +len+ field. If you do not want to add nested attributes, set + +sublist+ to +NULL+. + ++struct tst_rtnl_message+ is a structure holding partially parsed rtnetlink +messages received from the kernel. +RTNL_RECV()+ returns an array of these +structures with the last item having +NULL+ in the +header+ field. Call ++RTNL_FREE_MESSAGE()+ to free a message list returned by +RTNL_RECV()+. + +- +header+ is the netlink header structure of the message. +NULL+ in the header + field terminates a list of messages. + +- +err+ points to the payload of +NLMSG_ERROR+ messages. It is set to +NULL+ + for all other message types. + +- +payload+ is a pointer to message data. + +- +payload_size+ is the length of +payload+ data in bytes. + +3.2 Sending and receiving messages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- +struct tst_rtnl_context *RTNL_CREATE_CONTEXT(void)+ – Creates a new + rtnetlink communication context for use with the functions described below. + Returns +NULL+ on error. + +- +void RTNL_FREE_MESSAGE(struct tst_rtnl_message *msg)+ – Frees an array of + messages returned by +RTNL_RECV()+. + +- +void RTNL_DESTROY_CONTEXT(struct tst_rtnl_context *ctx)+ – Closes a + communication context created by +RTNL_CREATE_CONTEXT()+. + +- +int RTNL_SEND(struct tst_rtnl_context *ctx)+ – Sends all messages waiting + in +ctx+ buffer to the kernel. If there are multiple messages to send, a new + +NLMSG_DONE+ message will be added automatically. Returns the number of + bytes sent on success. Return 0 or negative value on error. + +- +int RTNL_SEND_VALIDATE(struct tst_rtnl_context *ctx)+ – Sends all messages + just like +RTNL_SEND()+, then receives the response from the kernel and + validates results of requests sent with the +NLM_F_ACK+ flag. This function + calls +tst_brk()+ as usual if communication fails but it will return error + status without terminating the test if one of the received messages contains + error code. See +RTNL_CHECK_ACKS()+ below for explanation of the return + value. + +- +int RTNL_WAIT(struct tst_rtnl_context *ctx)+ – Waits until data becomes + available to read from the rtnetlink socket (timeout: 1 second). Returns 1 + if there is data to read, 0 on timeout or -1 on error. + +- +struct tst_rtnl_message *RTNL_RECV(struct tst_rtnl_context *ctx)+ – Receives + rtnetlink messages from the kernel. The messages are received in non-blocking + mode so calling +RTNL_WAIT()+ first is recommended. Returns an array of + partially parsed messages terminated by an item with +NULL+ in the +header+ + field. On error or when there are no messages to receive, returns +NULL+. + Call +RTNL_FREE_MESSAGE()+ to free the returned data. + +- +int RTNL_CHECK_ACKS(struct tst_rtnl_context *ctx, struct tst_rtnl_message + *response)+ – Validate results of requests sent with the +NLM_F_ACK+ flag. + Do not call +RTNL_ADD_MESSAGE()+ between +RTNL_SEND()+ and + +RTNL_CHECK_ACKS()+ because it will reset the state of +ctx+ and prevent + result validation. Returns 1 if all messages sent with the +NLM_F_ACK+ flag + have a corresponding message in +response+ and the error code is 0. If any + of the expected response messages is missing, this function will call + +tst_brk()+ (or return 0 during test cleanup phase). If any of the response + messages has non-zero error code, this function will return 0 and store the + first non-zero error code in global variable +tst_rtnl_errno+ (sign-flipped + just like regular libc +errno+). + +3.3 Creating messages +~~~~~~~~~~~~~~~~~~~~~ + +- +int RTNL_ADD_MESSAGE(struct tst_rtnl_context *ctx, const struct nlmsghdr + *header, const void *payload, size_t payload_size)+ – Adds new rtnetlink + message to +ctx+ buffer. You need to provide message +header+ and optional + +payload+. +payload_size+ is the size of +payload+ data in bytes. If you + don't want to add any payload data, set +payload+ to +NULL+ and + +payload_size+ to 0. This function will automatically fill the +nlmsg_len+, + +nlmsg_seq+ and +nlmsg_pid+ fields of the new message header. You don't need + to set those. It'll also automatically add +NLM_F_MULTI+ flag when needed. + Returns 1 on success, 0 on error. Note that the first call of + +RTNL_ADD_MESSAGE()+ after +RTNL_SEND()+ will reset the state of +ctx+ + and +RTNL_CHECK_ACKS()+ will not work correctly until the next +RTNL_SEND()+. + +- +int RTNL_ADD_ATTR(struct tst_rtnl_context *ctx, unsigned short type, const + void *data, unsigned short len)+ – Adds new attribute to the last message + in +ctx+ buffer. See +RTNL_ADD_MESSAGE()+. You need to provide attribute + +type+ which will be stored in +struct rtattr.rta_type+, optional payload + +data+ and payload size +len+ in bytes. If you don't want to add any payload, + set +data+ to +NULL+ and +len+ to 0. Returns 1 on success, 0 on error. + +- +int RTNL_ADD_ATTR_STRING(struct tst_rtnl_context *ctx, unsigned short type, + const char *data)+ – Adds new string attribute to the last message in +ctx+ + buffer. Parameters and return value are the same as for +RTNL_ADD_ATTR()+, + except the payload length is calculated using +strlen()+. + +- +int RTNL_ADD_ATTR_LIST(struct tst_rtnl_context *ctx, const struct + tst_rtnl_attr_list *list)+ – Adds a list of attributes to the last message + in +ctx+ buffer. See description of +struct tst_rtnl_attr_list+ and + +RTNL_ADD_MESSAGE()+ above. Returns the number of added attributes on + success (nested attributes are not counted), -1 on error. + +.Example Usage +[source,c] +------------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_rtnetlink.h" +#include "tst_netdevice.h" + +... + +void setup(void) +{ + struct tst_rtnl_context *ctx; + int index, ret; + in_addr_t addr; + + struct nlmsghdr header = { + .nlmsg_type = RTM_NEWADDR, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | + NLM_F_EXCL + }; + + struct ifaddrmsg info = { + .ifa_family = AF_INET, + .ifa_prefixlen = 24 + }; + + index = NETDEV_INDEX_BY_NAME("ltp_veth1"); + info.ifa_index = index; + + ctx = RTNL_CREATE_CONTEXT(); + RTNL_ADD_MESSAGE(ctx, &header, &info, sizeof(info)); + addr = inet_addr("192.168.123.45"); + RTNL_ADD_ATTR(ctx, IFA_LOCAL, &addr, sizeof(addr)); + ret = RTNL_SEND_VALIDATE(ctx); + RTNL_DESTROY_CONTEXT(ctx); + + if (!ret) { + tst_brk(TBROK, "Failed to set ltp_veth1 address"); + } +} +------------------------------------------------------------------------------- diff --git a/doc/nommu-notes.txt b/doc/nommu-notes.txt old mode 100644 new mode 100755 diff --git a/doc/rules.tsv b/doc/rules.tsv new file mode 100755 index 0000000000000000000000000000000000000000..66dbdeccf22e27170f596bbac206bb54967e44ac --- /dev/null +++ b/doc/rules.tsv @@ -0,0 +1,6 @@ +ID DESCRIPTION +LTP-001 Library source files have tst_ prefix +LTP-002 TST_RET and TST_ERR are never modified by test library functions +LTP-003 Externally visible library symbols have the tst_ prefix +LTP-004 Test executable symbols are marked static +LTP-005 Array must terminate with a sentinel value (i.e. NULL or '{}') diff --git a/doc/shell-test-api.txt b/doc/shell-test-api.txt new file mode 100755 index 0000000000000000000000000000000000000000..e082808f7e78c7b762ff70d371ebfa761c746d29 --- /dev/null +++ b/doc/shell-test-api.txt @@ -0,0 +1,763 @@ +LTP Shell Test API +================== + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API]. + +1 Writing a testcase in shell +----------------------------- + +LTP supports testcases to be written in a portable shell too. + +There is a shell library modeled closely to the C interface at +'testcases/lib/tst_test.sh'. + +WARNING: All identifiers starting with 'TST_' or 'tst_' are reserved for the + test library. + +1.1 Basic test interface +~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# This is a basic test for true shell builtin + +TST_TESTFUNC=do_test +. tst_test.sh + +do_test() +{ + true + ret=$? + + if [ $ret -eq 0 ]; then + tst_res TPASS "true returned 0" + else + tst_res TFAIL "true returned $ret" + fi +} + +tst_run +------------------------------------------------------------------------------- + +TIP: To execute this test the 'tst_test.sh' library must be in '$PATH'. If you + are executing the test from a git checkout you can run it as + 'PATH="$PATH:../../lib" ./foo01.sh' + +The shell library expects test setup, cleanup and the test function executing +the test in the '$TST_SETUP', '$TST_CLEANUP' and '$TST_TESTFUNC' variables. + +Both '$TST_SETUP' and '$TST_CLEANUP' are optional. + +The '$TST_TESTFUNC' may be called several times if more than one test +iteration was requested by passing right command line options to the test. + +The '$TST_CLEANUP' may be called even in the middle of the setup and must be +able to clean up correctly even in this situation. The easiest solution for +this is to keep track of what was initialized and act accordingly in the +cleanup. + +WARNING: Similar to the C library, calling 'tst_brk' in the $TST_CLEANUP does + not exit the test and 'TBROK' is converted to 'TWARN'. + +Notice also the 'tst_run' shell API function called at the end of the test that +actually starts the test. + +WARNING: cleanup function is called only after 'tst_run' has been started. +Calling 'tst_brk' in shell libraries, e.g. 'tst_test.sh' or 'tst_net.sh' does +not trigger calling it. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Example test with tests in separate functions + +TST_TESTFUNC=test +TST_CNT=2 +. tst_test.sh + +test1() +{ + tst_res TPASS "Test $1 passed" +} + +test2() +{ + tst_res TPASS "Test $1 passed" +} + +tst_run +# output: +# foo 1 TPASS: Test 1 passed +# foo 2 TPASS: Test 2 passed +------------------------------------------------------------------------------- + +If '$TST_CNT' is set, the test library looks if there are functions named +'$\{TST_TESTFUNC\}1', ..., '$\{TST_TESTFUNC\}$\{TST_CNT\}' and if these are +found they are executed one by one. The test number is passed to it in the '$1'. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Example test with tests in a single function + +TST_TESTFUNC=do_test +TST_CNT=2 +. tst_test.sh + +do_test() +{ + case $1 in + 1) tst_res TPASS "Test $1 passed";; + 2) tst_res TPASS "Test $1 passed";; + esac +} + +tst_run +# output: +# foo 1 TPASS: Test 1 passed +# foo 2 TPASS: Test 2 passed +------------------------------------------------------------------------------- + +Otherwise, if '$TST_CNT' is set but there is no '$\{TST_TESTFUNC\}1', etc., +the '$TST_TESTFUNC' is executed '$TST_CNT' times and the test number is passed +to it in the '$1'. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Example test with tests in a single function, using $TST_TEST_DATA and +# $TST_TEST_DATA_IFS + +TST_TESTFUNC=do_test +TST_TEST_DATA="foo:bar:d dd" +TST_TEST_DATA_IFS=":" +. tst_test.sh + +do_test() +{ + tst_res TPASS "Test $1 passed with data '$2'" +} + +tst_run +# output: +# foo 1 TPASS: Test 1 passed with data 'foo' +# foo 2 TPASS: Test 1 passed with data 'bar' +# foo 3 TPASS: Test 1 passed with data 'd dd' +------------------------------------------------------------------------------- + +It's possible to pass data for function with '$TST_TEST_DATA'. Optional +'$TST_TEST_DATA_IFS' is used for splitting, default value is space. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Example test with tests in a single function, using $TST_TEST_DATA and $TST_CNT + +TST_TESTFUNC=do_test +TST_CNT=2 +TST_TEST_DATA="foo bar" +. tst_test.sh + +do_test() +{ + case $1 in + 1) tst_res TPASS "Test $1 passed with data '$2'";; + 2) tst_res TPASS "Test $1 passed with data '$2'";; + esac +} + +tst_run +# output: +# foo 1 TPASS: Test 1 passed with data 'foo' +# foo 2 TPASS: Test 2 passed with data 'foo' +# foo 3 TPASS: Test 1 passed with data 'bar' +# foo 4 TPASS: Test 2 passed with data 'bar' +------------------------------------------------------------------------------- + +'$TST_TEST_DATA' can be used with '$TST_CNT'. If '$TST_TEST_DATA_IFS' not specified, +space as default value is used. Of course, it's possible to use separate functions. + +1.2 Library environment variables and functions for shell +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similarily to the C library various checks and preparations can be requested +simply by setting right '$TST_NEEDS_FOO'. + +[options="header"] +|============================================================================= +| Variable name | Action done +| 'TST_NEEDS_ROOT' | Exit the test with 'TCONF' unless executed under root. +| | Alternatively the 'tst_require_root' command can be used. +| 'TST_NEEDS_TMPDIR' | Create test temporary directory and cd into it. +| 'TST_NEEDS_DEVICE' | Prepare test temporary device, the path to testing + device is stored in '$TST_DEVICE' variable. + The option implies 'TST_NEEDS_TMPDIR'. +| 'TST_NEEDS_CMDS' | String with command names that has to be present for + the test (see below). +| 'TST_NEEDS_MODULE' | Test module name needed for the test (see below). +| 'TST_NEEDS_DRIVERS' | Checks kernel drivers support for the test. +| 'TST_NEEDS_KCONFIGS' | Checks kernel kconfigs support for the test (see below). +| 'TST_NEEDS_KCONFIGS_IFS' | Used for splitting '$TST_NEEDS_KCONFIGS' variable, + default value is comma, it only supports single character. +| 'TST_TIMEOUT' | Maximum timeout set for the test in sec. Must be int >= 1, + or -1 (special value to disable timeout), default is 300. + Variable is meant be set in tests, not by user. + It's an equivalent of `tst_test.timeout` in C, can be set + via 'tst_set_timeout(timeout)' after test has started. +|============================================================================= + +[options="header"] +|============================================================================= +| Function name | Action done +| 'tst_set_timeout(timeout)' | Maximum timeout set for the test in sec. + See 'TST_TIMEOUT' variable. +|============================================================================= + +NOTE: Network tests (see testcases/network/README.md) use additional variables +and functions in 'tst_net.sh'. + +Checking for presence of commands ++++++++++++++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +... + +TST_NEEDS_CMDS="modinfo modprobe" +. tst_test.sh + +... + +------------------------------------------------------------------------------- + +Setting '$TST_NEEDS_CMDS' to a string listing required commands will check for +existence each of them and exits the test with 'TCONF' on first missing. + +Alternatively the 'tst_require_cmds()' function can be used to do the same on +runtime, since sometimes we need to the check at runtime too. + +'tst_check_cmds()' can be used for requirements just for a particular test +as it doesn't exit (it issues 'tst_res TCONF'). Expected usage is: + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +TST_TESTFUNC=do_test +. tst_test.sh + +do_test() +{ + tst_check_cmds cmd || return + cmd --foo + ... +} + +tst_run +------------------------------------------------------------------------------- + +Locating kernel modules ++++++++++++++++++++++++ + +The LTP build system can build kernel modules as well, setting +'$TST_NEEDS_MODULE' to module name will cause the library to look for the +module in a few possible paths. + +If module was found the path to it will be stored into '$TST_MODPATH' +variable, if module wasn't found the test will exit with 'TCONF'. + +Alternatively the 'tst_require_module()' function can be used to do the same +at runtime. + +1.3 Optional command line parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Optional test command line parameters + +TST_OPTS="af:" +TST_USAGE=usage +TST_PARSE_ARGS=parse_args +TST_TESTFUNC=do_test + +. tst_test.sh + +ALTERNATIVE=0 +MODE="foo" + +usage() +{ + cat << EOF +usage: $0 [-a] [-f ] + +OPTIONS +-a Enable support for alternative foo +-f Specify foo or bar mode +EOF +} + +parse_args() +{ + case $1 in + a) ALTERNATIVE=1;; + f) MODE="$2";; + esac +} + +do_test() +{ + ... +} + +tst_run +------------------------------------------------------------------------------- + +The 'getopts' string for optional parameters is passed in the '$TST_OPTS' +variable. There are a few default parameters that cannot be used by a test, +these can be listed with passing help '-h' option to any test. + +The function that prints the usage is passed in '$TST_USAGE', the help for +the options implemented in the library is appended when usage is printed. + +Lastly the function '$PARSE_ARGS' is called with the option name in the '$1' +and, if option has argument, its value in the '$2'. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Optional test positional parameters + +TST_POS_ARGS=3 +TST_USAGE=usage +TST_TESTFUNC=do_test + +. tst_test.sh + +usage() +{ + cat << EOF +usage: $0 [min] [max] [size] + +EOF +} + +min="$1" +max="$2" +size="$3" + +do_test() +{ + ... +} + +tst_run +------------------------------------------------------------------------------- + +You can also request a number of positional parameters by setting the +'$TST_POS_ARGS' variable. If you do, these will be available as they were +passed directly to the script in '$1', '$2', ..., '$n'. + +1.4 Useful library functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Retrieving configuration variables +++++++++++++++++++++++++++++++++++ + +You may need to retrieve configuration values such as PAGESIZE, there is +'getconf' but as some system may not have it, you are advised to use +'tst_getconf' instead. Note that it implements subset of 'getconf' +system variables used by the testcases only. + +[source,sh] +------------------------------------------------------------------------------- +# retrieve PAGESIZE +pagesize=`tst_getconf PAGESIZE` +------------------------------------------------------------------------------- + +Sleeping for subsecond intervals +++++++++++++++++++++++++++++++++ + +Albeit there is a sleep command available basically everywhere not all +implementations can support sleeping for less than one second. And most of the +time sleeping for a second is too much. Therefore LTP includes 'tst_sleep' +that can sleep for defined amount of seconds, milliseconds or microseconds. + +[source,sh] +------------------------------------------------------------------------------- +# sleep for 100 milliseconds +tst_sleep 100ms +------------------------------------------------------------------------------- + +Retry a function call multiple times +++++++++++++++++++++++++++++++++++++ + +Sometimes an LTP test needs to retry a function call multiple times because +the system is not ready to process it successfully on the first try. The LTP +library has useful tools to handle the call retry automatically. +'TST_RETRY_FUNC()' will keep retrying for up to 1 second. If you want a custom +time limit use 'TST_RETRY_FN_EXP_BACKOFF()'. Both methods return the value +returned by the last 'FUNC' call. + +The delay between retries starts at 1 microsecond and doubles after each call. +The retry loop ends when the function call succeeds or when the next delay +exceeds the specified time (1 second for 'TST_RETRY_FUNC()'). The maximum +delay is multiplied by TST_TIMEOUT_MUL. The total cumulative delay may be up +to twice as long as the adjusted maximum delay. + +The C version of 'TST_RETRY_FUNC()' is a macro which takes two arguments: + +* 'FUNC' is the complete function call with arguments which should be retried + multiple times. +* 'SUCCESS_CHECK' is a macro or function which will validate 'FUNC' return + value. 'FUNC' call was successful if 'SUCCESS_CHECK(ret)' evaluates to + non-zero. + +Both retry methods clear 'errno' before every 'FUNC' call so your +'SUCCESS_CHECK' can look for specific error codes as well. The LTP library +also includes predefined 'SUCCESS_CHECK' macros for the most common call +conventions: + +* 'TST_RETVAL_EQ0()' - The call was successful if 'FUNC' returned 0 or NULL +* 'TST_RETVAL_NOTNULL()' - The call was successful if 'FUNC' returned any + value other than 0 or NULL. +* 'TST_RETVAL_GE0()' - The call was successful if 'FUNC' returned value >= 0. + +[source,c] +------------------------------------------------------------------------------- +/* Keep trying for 1 second */ +TST_RETRY_FUNC(FUNC, SUCCESS_CHECK) + +/* Keep trying for up to 2*N seconds */ +TST_RETRY_FN_EXP_BACKOFF(FUNC, SUCCESS_CHECK, N) +------------------------------------------------------------------------------- + +The shell version of 'TST_RETRY_FUNC()' is simpler and takes slightly +different arguments: + +* 'FUNC' is a string containing the complete function or program call with + arguments. +* 'EXPECTED_RET' is a single expected return value. 'FUNC' call was successful + if the return value is equal to EXPECTED_RET. + +[source,sh] +------------------------------------------------------------------------------- +# Keep trying for 1 second +TST_RETRY_FUNC "FUNC arg1 arg2 ..." "EXPECTED_RET" + +# Keep trying for up to 2*N seconds +TST_RETRY_FN_EXP_BACKOFF "FUNC arg1 arg2 ..." "EXPECTED_RET" "N" +------------------------------------------------------------------------------- + +Checking for integers ++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +# returns zero if passed an integer parameter, non-zero otherwise +tst_is_int "$FOO" +------------------------------------------------------------------------------- + +Checking for integers and floating point numbers +++++++++++++++++++++++++++++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +# returns zero if passed an integer or floating point number parameter, +# non-zero otherwise +tst_is_num "$FOO" +------------------------------------------------------------------------------- + +Obtaining random numbers +++++++++++++++++++++++++ + +There is no '$RANDOM' in portable shell, use 'tst_random' instead. + +[source,sh] +------------------------------------------------------------------------------- +# get random integer between 0 and 1000 (including 0 and 1000) +tst_random 0 1000 +------------------------------------------------------------------------------- + +Formatting device with a filesystem ++++++++++++++++++++++++++++++++++++ + +The 'tst_mkfs' helper will format device with the filesystem. + +[source,sh] +------------------------------------------------------------------------------- +# format test device with ext2 +tst_mkfs ext2 $TST_DEVICE +# default params are $TST_FS_TYPE $TST_DEVICE +tst_mkfs +# optional parameters +tst_mkfs ext4 /dev/device -T largefile +------------------------------------------------------------------------------- + +Mounting and unmounting filesystems ++++++++++++++++++++++++++++++++++++ + +The 'tst_mount' and 'tst_umount' helpers are a safe way to mount/umount +a filesystem. + +The 'tst_mount' mounts '$TST_DEVICE' of '$TST_FS_TYPE' (optional) to +'$TST_MNTPOINT' (defaults to mntpoint), optionally using the +'$TST_MNT_PARAMS'. The '$TST_MNTPOINT' directory is created if it didn't +exist prior to the function call. + +If the path passed (optional, must be absolute path, defaults to '$TST_MNTPOINT') +to the 'tst_umount' is not mounted (present in '/proc/mounts') it's noop. +Otherwise it retries to umount the filesystem a few times on failure. +This is a workaround since there are daemons dumb enough to probe all newly +mounted filesystems, and prevents them from being umounted shortly after they +were mounted. + +ROD and ROD_SILENT +++++++++++++++++++ + +These functions supply the 'SAFE_MACROS' used in C although they work and are +named differently. + +[source,sh] +------------------------------------------------------------------------------- +ROD_SILENT command arg1 arg2 ... + +# is shorthand for: + +command arg1 arg2 ... > /dev/null 2>&1 +if [ $? -ne 0 ]; then + tst_brk TBROK "..." +fi + + +ROD command arg1 arg2 ... + +# is shorthand for: + +ROD arg1 arg2 ... +if [ $? -ne 0 ]; then + tst_brk TBROK "..." +fi +------------------------------------------------------------------------------- + +WARNING: Keep in mind that output redirection (to a file) happens in the + caller rather than in the ROD function and cannot be checked for + write errors by the ROD function. + +As a matter of a fact doing +ROD echo a > /proc/cpuinfo+ would work just fine +since the 'ROD' function will only get the +echo a+ part that will run just +fine. + +[source,sh] +------------------------------------------------------------------------------- +# Redirect output to a file with ROD +ROD echo foo \> bar +------------------------------------------------------------------------------- + +Note the '>' is escaped with '\', this causes that the '>' and filename are +passed to the 'ROD' function as parameters and the 'ROD' function contains +code to split '$@' on '>' and redirects the output to the file. + +EXPECT_PASS{,_BRK} and EXPECT_FAIL{,_BRK} ++++++++++++++++++++++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +EXPECT_PASS command arg1 arg2 ... [ \> file ] +EXPECT_FAIL command arg1 arg2 ... [ \> file ] +------------------------------------------------------------------------------- + +'EXPECT_PASS' calls 'tst_res TPASS' if the command exited with 0 exit code, +and 'tst_res TFAIL' otherwise. 'EXPECT_FAIL' does vice versa. + +Output redirection rules are the same as for the 'ROD' function. In addition +to that, 'EXPECT_FAIL' always redirects the command's stderr to '/dev/null'. + +There are also 'EXPECT_PASS_BRK' and 'EXPECT_FAIL_BRK', which works the same way +except breaking a test when unexpected action happen. + +It's possible to detect whether expected value happened: +[source,sh] +------------------------------------------------------------------------------- +if ! EXPECT_PASS command arg1 2\> /dev/null; then + continue +fi +------------------------------------------------------------------------------- + +tst_kvcmp ++++++++++ + +This command compares the currently running kernel version given conditions +with syntax similar to the shell test command. + +[source,sh] +------------------------------------------------------------------------------- +# Exit the test if kernel version is older or equal to 2.6.8 +if tst_kvcmp -le 2.6.8; then + tst_brk TCONF "Kernel newer than 2.6.8 is needed" +fi + +# Exit the test if kernel is newer than 3.8 and older than 4.0.1 +if tst_kvcmp -gt 3.8 -a -lt 4.0.1; then + tst_brk TCONF "Kernel must be older than 3.8 or newer than 4.0.1" +fi +------------------------------------------------------------------------------- + +[options="header"] +|======================================================================= +| expression | description +| -eq kver | Returns true if kernel version is equal +| -ne kver | Returns true if kernel version is not equal +| -gt kver | Returns true if kernel version is greater +| -ge kver | Returns true if kernel version is greater or equal +| -lt kver | Returns true if kernel version is lesser +| -le kver | Returns true if kernel version is lesser or equal +| -a | Does logical and between two expressions +| -o | Does logical or between two expressions +|======================================================================= + +The format for kernel version has to either be with one dot e.g. '2.6' or with +two dots e.g. '4.8.1'. + +.tst_fs_has_free +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +... + +# whether current directory has 100MB free space at least. +if ! tst_fs_has_free . 100MB; then + tst_brkm TCONF "Not enough free space" +fi + +... +------------------------------------------------------------------------------- + +The 'tst_fs_has_free' shell interface returns 0 if the specified free space is +satisfied, 1 if not, and 2 on error. + +The second argument supports suffixes kB, MB and GB, the default unit is Byte. + +.tst_retry +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +... + +# Retry ping command three times +tst_retry "ping -c 1 127.0.0.1" + +if [ $? -ne 0 ]; then + tst_resm TFAIL "Failed to ping 127.0.0.1" +else + tst_resm TPASS "Successfully pinged 127.0.0.1" +fi + +... +------------------------------------------------------------------------------- + +The 'tst_retry' function allows you to retry a command after waiting small +amount of time until it succeeds or until given amount of retries has been +reached (default is three attempts). + +1.5 Restarting daemons +~~~~~~~~~~~~~~~~~~~~~~ + +Restarting system daemons is a complicated task for two reasons. + +* There are different init systems + (SysV init, systemd, etc...) + +* Daemon names are not unified between distributions + (apache vs httpd, cron vs crond, various syslog variations) + +To solve these problems LTP has 'testcases/lib/daemonlib.sh' library that +provides functions to start/stop/query daemons as well as variables that store +correct daemon name. + +.Supported operations +|============================================================================== +| start_daemon() | Starts daemon, name is passed as first parameter. +| stop_daemon() | Stops daemon, name is passed as first parameter. +| restart_daemon() | Restarts daemon, name is passed as first parameter. +| status_daemon() | Detect daemon status (exit code: 0: running, 1: not running). +|============================================================================== + +.Variables with detected names +|============================================================================== +| CROND_DAEMON | Cron daemon name (cron, crond). +| SYSLOG_DAEMON | Syslog daemon name (syslog, syslog-ng, rsyslog). +|============================================================================== + +.Cron daemon restart example +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Cron daemon restart example + +TCID=cron01 +TST_COUNT=1 +. test.sh +. daemonlib.sh + +... + +restart_daemon $CROND_DAEMON + +... + +tst_exit +------------------------------------------------------------------------------- + +1.6 Access to the checkpoint interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The shell library provides an implementation of the checkpoint interface +compatible with the C version. All 'TST_CHECKPOINT_*' functions are available. + +In order to initialize checkpoints '$TST_NEEDS_CHECKPOINTS' must be set to '1' +before the inclusion of 'tst_test.sh': + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +TST_NEEDS_CHECKPOINTS=1 +. tst_test.sh +------------------------------------------------------------------------------- + +Since both the implementations are compatible, it's also possible to start +a child binary process from a shell test and synchronize with it. This process +must have checkpoints initialized by calling 'tst_reinit()'. + +1.7 Parsing kernel .config +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The shell library provides an implementation of the kconfig parsing interface +compatible with the C version. + +It's possible to pass kernel kconfig list for tst_require_kconfigs API with +'$TST_NEEDS_KCONFIGS'. +Optional '$TST_NEEDS_KCONFIGS_IFS' is used for splitting, default value is comma. + +------------------------------------------------------------------------------- +#!/bin/sh +TST_NEEDS_KCONFIGS="CONFIG_EXT4_FS, CONFIG_QUOTACTL=y" + +. tst_test.sh +------------------------------------------------------------------------------- diff --git a/doc/supported-kernel-libc-versions.txt b/doc/supported-kernel-libc-versions.txt new file mode 100755 index 0000000000000000000000000000000000000000..7adaf4d1409a4de3df14da3aed82318894be1844 --- /dev/null +++ b/doc/supported-kernel-libc-versions.txt @@ -0,0 +1,66 @@ +Supported kernel, libc, toolchain versions +========================================== + +1. Build testing with GitHub Actions +------------------------------------ + +We test master branch in https://github.com/linux-test-project/ltp/actions[GitHub Actions] +to ensure LTP builds on various distributions including old, current and bleeding edge. +We test both gcc and clang toolchains, various architectures with cross-compilation. +For list of tested distros see +https://github.com/linux-test-project/ltp/blob/master/.github/workflows/ci.yml[.github/workflows/ci.yml]. + + +NOTE: GitHub Actions does only build testing, passing the CI means only that + the test compiles fine on variety of different distributions and releases. + GitHub Actions also uses the latest distribution image of a particular release. + +1.1 Oldest tested distributions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[align="center",options="header"] +|============================================================== +| Distro | kernel | glibc | gcc | clang +| CentOS 7 | 3.10 | 2.17 | 4.8.5 | - +| Ubuntu 16.04 LTS xenial | 4.4 | 2.23 | 5.3.1 | - +| Debian 9 stretch (oldstable) | 4.9.30 | 2.24 | 6.3.0 | 3.8 +|============================================================== + +Older distributions are not officially supported, which means that it +may or may not work. It all depends on your luck. It should be possible +to compile latest LTP even on slightly older distributions than we +support with a few manual tweaks, e.g. disabling manually tests for +newly added syscalls, etc. Trivial fixes/workarounds may be accepted, +but users are encouraged to move to a newer distro. + +If latest LTP cannot be compiled even with some amount of workarounds, +you may result to older LTP releases, however these are _not_ supported +in any way. Also if you are trying to run LTP on more than 10 years old +distribution you may as well reconsider you life choices. + +1.2 Tested architectures +~~~~~~~~~~~~~~~~~~~~~~~~ + +[align="center",options="header"] +|================================== +| arch | build +| x86_64 | native +| x86 emulation | native +| aarch64 | cross compilation +| ppc64le | cross compilation +| s390x | cross compilation +|================================== + +1.3 Supported libc +~~~~~~~~~~~~~~~~~~ + +[align="center",options="header"] +|================================== +| Libc | Note +| https://www.gnu.org/software/libc/[GNU C Library (glibc)] | Targetted libc, tested both compilation and actual test results. +| https://uclibc-ng.org/[uClibc-ng] | Although not being tested it should work as well as it attempt to maintain a glibc compatible interface. +| https://www.uclibc.org/[uClibc] | Older https://www.uclibc.org/[uClibc] might have problems. +| https://musl.libc.org/[musl] | Not yet fully supported (see + https://github.com/linux-test-project/ltp/blob/master/ci/alpine.sh[CI script] + for list of files which need to be deleted in order to compile under musl). +| binder (Android) | Please use https://android.googlesource.com/platform/external/ltp/[AOSP fork]. diff --git a/doc/test-writing-guidelines.txt b/doc/test-writing-guidelines.txt old mode 100644 new mode 100755 index bda9bcfd5c3534494ede1a94a66ef5e3bfcff780..1fa751ed5ccee8ff447ef3185ca03baedb21c6d7 --- a/doc/test-writing-guidelines.txt +++ b/doc/test-writing-guidelines.txt @@ -1,32 +1,110 @@ LTP Test Writing Guidelines =========================== -This document describes LTP guidelines and LTP test interface and is intended -for anybody who want to write or modify a LTP testcase. It's not a definitive -guide and it's not, by any means, a substitute for common sense. +This document describes LTP guidelines and is intended for anybody who want to +write or modify a LTP testcase. It's not a definitive guide and it's not, by +any means, a substitute for common sense. -1. General Rules ----------------- +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API], + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API], + https://github.com/linux-test-project/ltp/wiki/LTP-Library-API-Writing-Guidelines[LTP Library API Writing Guidelines]. -1.1 Simplicity -~~~~~~~~~~~~~~ +Rules and recommendations which are "machine checkable" should be +tagged with an ID like +LTP-XXX+. There will be a corresponding entry +in +https://github.com/linux-test-project/ltp/tree/master/doc/rules.tsv[doc/rules.tsv]. When +you run 'make check' or 'make check-test' it will display these IDs as +a reference. + +1. Guide to clean and understandable code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For testcases it's required that the source code is as easy to follow as +possible. When a test starts to fail the failure has to be analyzed, clean +test codebase makes this task much easier and quicker. + +Here are some hints on how to write clean and understandable code, a few of +these points are further discussed below: + +* First of all *Keep things simple* + +* Keep function and variable names short but descriptive + +* Keep functions reasonably short and focused on a single task + +* Do not overcomment + +* Be consistent + +* Avoid deep nesting + +* DRY + +1.1 Keep things simple +~~~~~~~~~~~~~~~~~~~~~~ For all it's worth keep the testcases simple or better as simple as possible. + The kernel and libc are tricky beasts and the complexity imposed by their interfaces is quite high. Concentrate on the interface you want to test and -follow the UNIX philosophy. It's a good idea to make the test as -self-contained as possible too (it should not depend on tools or libraries -that are not widely available). +follow the UNIX philosophy. + +It's a good idea to make the test as self-contained as possible too, ideally +tests should not depend on tools or libraries that are not widely available. Do not reinvent the wheel! * Use LTP standard interface + * Do not add custom PASS/FAIL reporting functions -* Do not write Makefiles from scratch, - use LTP build system instead, etc. -1.2 Code duplication -~~~~~~~~~~~~~~~~~~~~ +* Do not write Makefiles from scratch, use LTP build system instead + +* Etc. + +1.2 Keep functions and variable names short +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Choosing a good name for an API functions or even variables is a difficult +task do not underestimate it. + +There are a couple of customary names for different things that help people to +understand code, for example: + +* For loop variables are usually named with a single letter 'i', 'j', ... + +* File descriptors 'fd' or 'fd_foo'. + +* Number of bytes stored in file are usually named as 'size' or 'len' + +* Etc. + +1.3 Do not overcomment +~~~~~~~~~~~~~~~~~~~~~~ + +Comments can sometimes save you day but they can easily do more harm than +good. There has been several cases where comments and actual implementation +drifted slowly apart which yielded into API misuses and hard to find bugs. +Remember there is only one thing worse than no documentation, wrong +documentation. + +Ideally everybody should write code that is obvious, which unfortunately isn't +always possible. If there is a code that requires to be commented keep it +short and to the point. These comments should explain *why* and not *how* +things are done. + +Never ever comment the obvious. + +In case of LTP testcases it's customary to add an asciidoc formatted comment +paragraph with highlevel test description at the beginning of the file right +under the GPL SPDX header. This helps other people to understand the overall +goal of the test before they dive into the technical details. It's also +exported into generated documentation hence it should mostly explain what is +tested. + +1.4 DRY (Code duplication) +~~~~~~~~~~~~~~~~~~~~~~~~~~ Copy & paste is a good servant but very poor master. If you are about to copy a large part of the code from one testcase to another, think what would happen if @@ -37,24 +115,36 @@ The same goes for short but complicated parts, whenever you are about to copy & paste a syscall wrapper that packs arguments accordingly to machine architecture or similarly complicated code, put it into a header instead. -1.3 Coding style -~~~~~~~~~~~~~~~~ +2 Coding style +~~~~~~~~~~~~~~ + +2.1 C coding style +^^^^^^^^^^^^^^^^^^ -1.3.1 C coding style -^^^^^^^^^^^^^^^^^^^^ +LTP adopted Linux kernel coding style: +https://www.kernel.org/doc/html/latest/process/coding-style.html -LTP adopted Linux kernel coding style. If you aren't familiar with its rules -locate 'linux/Documentation/CodingStyle' in the kernel sources and read it, -it's a well written introduction. +If you aren't familiar with its rules please read it, it's a well written +introduction. -There is also a checkpatch (see 'linux/scripts/checkpatch.pl') script that can -be used to check your patches before the submission. +Run `make check` in the test's directory and/or use `make check-$TCID`, +it uses (among other checks) our vendored version of +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/scripts/checkpatch.pl[checkpatch.pl] +script from kernel git tree. -NOTE: If checkpatch does not report any problems, the code still may be wrong - as the tool only looks for common mistakes. +NOTE: If `make check` does not report any problems, the code still may be wrong + as all tools used for checking only look for common mistakes. -1.3.2 Shell coding style -^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.1 LTP-004: Test executable symbols are marked static +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Test executables should not export symbols unnecessarily. This means +that all top-level variables and functions should be marked with the +static keyword. The only visible symbols should be those included from +shared object files. + +2.2 Shell coding style +^^^^^^^^^^^^^^^^^^^^^^ When writing testcases in shell write in *portable shell* only, it's a good idea to try to run the test using alternative shell (alternative to bash, for @@ -70,9 +160,13 @@ to 'dash' by default or install 'dash' on your favorite distribution and use it to run the tests. If your distribution lacks 'dash' package you can always compile it from http://gondor.apana.org.au/~herbert/dash/files/[source]. -Debian also has nice devscript +Run `make check` in the test's directory and/or use `make check-$TCID.sh`, +it uses (among other checks) our vendored version of https://salsa.debian.org/debian/devscripts/raw/master/scripts/checkbashisms.pl[checkbashism.pl] -that can be used to check for non-portable shell code. +from Debian, that is used to check for non-portable shell code. + +NOTE: If `make check` does not report any problems, the code still may be wrong + as `checkbashisms.pl` used for checking only looks for common mistakes. Here are some common sense style rules for shell @@ -89,26 +183,8 @@ Here are some common sense style rules for shell * Be consistent -1.4 Commenting code -~~~~~~~~~~~~~~~~~~~ - -Comments can sometimes save you day but they can easily do more harm than -good. There has been several cases where comments and actual implementation -were drifting slowly apart which yielded into API misuses and hard to find -bugs. Remember there is only one thing worse than no documentation, wrong -documentation. - -Generally everybody should write code that is obvious (which unfortunately -isn't always possible). If there is a code that needs to be commented keep it -short and to the point. Never ever comment the obvious. - -In case of LTP testcases it's customary to add a paragraph with highlevel test -description somewhere at the beginning of the file (usually right under the GPL -header). This helps other people to understand the overall goal of the test -before they dive into the technical details. - -1.5 Backwards compatibility -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +3 Backwards compatibility +~~~~~~~~~~~~~~~~~~~~~~~~~ LTP test should be as backward compatible as possible. Think of an enterprise distributions with long term support (more than five years since the initial @@ -117,48 +193,53 @@ toolchain supplied by the manufacturer. Therefore LTP test for more current features should be able to cope with older systems. It should at least compile fine and if it's not appropriate for the -configuration it should return 'TCONF' (see test interface description below). +configuration it should return 'TCONF'. There are several types of checks we use: The *configure script* is usually used to detect availability of a function -declarations in system headers. It's used to disable tests at compile time. - -We also have runtime kernel version detection that can be used to disable -tests at runtime. +declarations in system headers. It's used to disable tests at compile time or +to enable fallback definitions. Checking the *errno* value is another type of runtime check. Most of the syscalls returns either 'EINVAL' or 'ENOSYS' when syscall was not implemented or was disabled upon kernel compilation. +LTP has kernel version detection that can be used to disable tests at runtime, +unfortunately kernel version does not always corresponds to a well defined +feature set as distributions tend to backport hundreds of patches while the +kernel version stays the same. Use with caution. + +Lately we added kernel '.config' parser, a test can define a boolean +expression of kernel config variables that has to be satisfied in order for a +test to run. This is mostly used for kernel namespaces at the moment. + Sometimes it also makes sense to define a few macros instead of creating configure test. One example are Linux specific POSIX clock ids in 'include/lapi/posix_clocks.h'. -1.6 Dealing with messed up legacy code +3.1 Dealing with messed up legacy code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LTP contains a lot of old and messy code and we are cleaning it up as fast as -we can but despite the efforts there is still a lot. If you start modifying -old or a messed up testcase and your changes are more complicated than simple -typo fixes you should do a cleanup first (in a separate patch). It's easier to -review the changes if you separate the formatting fixes from the changes that -affects the test behavior. +LTP still contains a lot of old and messy code and we are cleaning it up as +fast as we can but despite the decade of efforts there is still a lot. If you +start modifying old or a messy testcase and your changes are more complicated +than simple typo fixes you should convert the test into a new library first. -The same goes for moving files. If you need a rename or move file do it in a -separate patch. +It's also much easier to review the changes if you split them into a smaller +logical groups. The same goes for moving files. If you need a rename or move +file do it in a separate patch. -1.7 License -~~~~~~~~~~~ +4 License +~~~~~~~~~ Code contributed to LTP should be licensed under GPLv2+ (GNU GPL version 2 or -any later version). Use `SPDX-License-Identifier: GPL-2.0-or-later`. +any later version). -2. Writing a testcase ---------------------- +Use `SPDX-License-Identifier: GPL-2.0-or-later` -2.1 LTP Structure -~~~~~~~~~~~~~~~~~ +5 LTP Structure +~~~~~~~~~~~~~~~ The structure of LTP is quite simple. Each test is a binary written either in portable shell or C. The test gets a configuration via environment variables @@ -167,13 +248,14 @@ stdout and reports overall success/failure via the exit value. Tests are generally placed under the 'testcases/' directory. Everything that is a syscall or (slightly confusingly) libc syscall wrapper goes under -'testcases/kernel/syscalls/'. Then there is 'testcases/open_posix_testsuite' -which is a well maintained fork of the upstream project that has been dead -since 2005 and also a number of directories with tests for more specific -features. +'testcases/kernel/syscalls/'. -2.1.1 Runtest Files -^^^^^^^^^^^^^^^^^^^ +Then there is 'testcases/open_posix_testsuite/' which is a well maintained fork +of the upstream project that has been dead since 2005 and also a number of +directories with tests for more specific features. + +5.1 Runtest Files +^^^^^^^^^^^^^^^^^ The list of tests to be executed is stored in runtest files under the 'runtest/' directory. The default set of runtest files to be executed is @@ -188,8 +270,8 @@ IMPORTANT: The runtest files should have one entry per a test. Creating a wrapper that runs all your tests and adding it as a single test into runtest file is strongly discouraged. -2.1.2 Datafiles -^^^^^^^^^^^^^^^ +5.2 Datafiles +^^^^^^^^^^^^^ If your test needs datafiles to work, these should be put into a subdirectory named 'datafiles' and installed into the 'testcases/data/$TCID' directory (to @@ -219,8 +301,8 @@ The path is constructed according to these rules: See 'testcases/commands/file/' for example. -2.1.3 Subexecutables -^^^^^^^^^^^^^^^^^^^^ +5.3 Subexecutables +^^^^^^^^^^^^^^^^^^ If you test needs to execute a binary, place it in the same directory as the testcase and name the file starting with '${test_binary_name}_'. Once the @@ -230,2614 +312,20 @@ binaries is added to the '$PATH' and you can execute it just by its name. TIP: If you need to execute such test from the LTP tree, you can add path to current directory to '$PATH' manually with: 'PATH="$PATH:$PWD" ./foo01'. -2.2 Writing a test in C -~~~~~~~~~~~~~~~~~~~~~~~ - -2.2.1 Basic test structure -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Let's start with an example, following code is a simple test for a 'getenv()'. - -[source,c] -------------------------------------------------------------------------------- -/* - * This is test for basic functionality of getenv(). - * - * - create an env variable and verify that getenv() can get get it - * - call getenv() with nonexisting variable name, check that it returns NULL - */ - -#include "tst_test.h" - -#define ENV1 "LTP_TEST_ENV" -#define ENV2 "LTP_TEST_THIS_DOES_NOT_EXIST" -#define ENV_VAL "val" - -static void setup(void) -{ - if (setenv(ENV1, ENV_VAL, 1)) - tst_brk(TBROK | TERRNO, "setenv() failed"); -} - -static void test(void) -{ - char *ret; - - ret = getenv(ENV1); - - if (!ret) { - tst_res(TFAIL, "getenv(" ENV1 ") = NULL"); - goto next; - } - - if (!strcmp(ret, ENV_VAL)) { - tst_res(TPASS, "getenv(" ENV1 ") = '"ENV_VAL "'"); - } else { - tst_res(TFAIL, "getenv(" ENV1 ") = '%s', expected '" - ENV_VAL "'", ret); - } - -next: - ret = getenv(ENV2); - - if (ret) - tst_res(TFAIL, "getenv(" ENV2 ") = '%s'", ret); - else - tst_res(TPASS, "getenv(" ENV2 ") = NULL"); -} - -static struct tst_test test = { - .test_all = test, - .setup = setup, -}; -------------------------------------------------------------------------------- - -Each test includes the 'tst_test.h' header and must define the 'struct -tst_test test' structure. - -The overall test initialization is done in the 'setup()' function. - -The overall cleanup is done in a 'cleanup()' function. Here 'cleanup()' is -omitted as the test does not have anything to clean up. If cleanup is set in -the test structure it's called on test exit just before the test library -cleanup. That especially means that cleanup can be called at any point in a -test execution. For example even when a test setup step has failed, therefore -the 'cleanup()' function must be able to cope with unfinished initialization, -and so on. - -The test itself is done in the 'test()' function. The test function must work -fine if called in a loop. - -There are two types of a test function pointers in the test structure. The -first one is a '.test_all' pointer that is used when test is implemented as a -single function. Then there is a '.test' function along with the number of -tests '.tcnt' that allows for more detailed result reporting. If the '.test' -pointer is set the function is called '.tcnt' times with an integer parameter -in range of [0, '.tcnt' - 1]. - -IMPORTANT: Only one of '.test' and '.test_all' can be set at a time. - -Each test has a default timeout set to 300s. The default timeout can be -overridden by setting '.timeout' in the test structure or by calling -'tst_set_timeout()' in the test 'setup()'. There are a few testcases whose run -time may vary arbitrarily, for these timeout can be disabled by setting it to --1. - -Test can find out how much time (in seconds) is remaining to timeout, -by calling 'tst_timeout_remaining()'. - -LAPI headers -++++++++++++ - -Use our LAPI headers ('include "lapi/foo.h"') to keep compatibility with old -distributions. LAPI header should always include original header. Older linux -headers were problematic, therefore we preferred to use libc headers. There are -still some bugs when combining certain glibc headers with linux headers, see -https://sourceware.org/glibc/wiki/Synchronizing_Headers. - -A word about the cleanup() callback -+++++++++++++++++++++++++++++++++++ - -There are a few rules that needs to be followed in order to write correct -cleanup() callback. - -1. Free only resources that were initialized. Keep in mind that callback can - be executed at any point in the test run. - -2. Make sure to free resources in the reverse order they were - initialized. (Some of the steps may not depend on others and everything - will work if there were swapped but let's keep it in order.) - -The first rule may seem complicated at first however, on the contrary, it's -quite easy. All you have to do is to keep track of what was already -initialized. For example file descriptors needs to be closed only if they were -assigned a valid file descriptor. For most of the things you need to create -extra flag that is set right after successful initialization though. Consider, -for example, test setup below. - -We also prefer cleaning up resources that would otherwise be released on the -program exit. There are two main reasons for this decision. Resources such as -file descriptors and mmaped memory could block umounting a block device in -cases where the test library has mounted a filesystem for the test temporary -directory. Not freeing allocated memory would upset static analysis and tools -such as valgrind and produce false-positives when checking for leaks in the -libc and other low level libraries. - -[source,c] -------------------------------------------------------------------------------- -static int fd0, fd1, mount_flag; - -#define MNTPOINT "mntpoint" -#define FILE1 "mntpoint/file1" -#define FILE2 "mntpoint/file2" - -static void setup(void) -{ - SAFE_MKDIR(MNTPOINT, 0777); - SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL); - SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, 0); - mount_flag = 1; - - fd0 = SAFE_OPEN(cleanup, FILE1, O_CREAT | O_RDWR, 0666); - fd1 = SAFE_OPEN(cleanup, FILE2, O_CREAT | O_RDWR, 0666); -} -------------------------------------------------------------------------------- - -In this case the 'cleanup()' function may be invoked when any of the 'SAFE_*' -macros has failed and therefore must be able to work with unfinished -initialization as well. Since global variables are initialized to zero we can -just check that fd > 0 before we attempt to close it. The mount function -requires extra flag to be set after device was successfully mounted. - -[source,c] -------------------------------------------------------------------------------- -static void cleanup(void) -{ - if (fd1 > 0) - SAFE_CLOSE(fd1); - - if (fd0 > 0) - SAFE_CLOSE(fd0); - - if (mount_flag && tst_umouont(MNTPOINT)) - tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); -} -------------------------------------------------------------------------------- - -IMPORTANT: 'SAFE_MACROS()' used in cleanup *do not* exit the test. Failure - only produces a warning and the 'cleanup()' carries on. This is - intentional as we want to execute as much 'cleanup()' as possible. - -WARNING: Calling tst_brk() in test 'cleanup()' does not exit the test as well - and 'TBROK' is converted to 'TWARN'. - -NOTE: Creation and removal of the test temporary directory is handled in - the test library and the directory is removed recursively. Therefore - we do not have to remove files and directories in the test cleanup. - -2.2.2 Basic test interface -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -[source,c] -------------------------------------------------------------------------------- -void tst_res(int ttype, char *arg_fmt, ...); -------------------------------------------------------------------------------- - -Printf-like function to report test result, it's mostly used with ttype: - -|============================== -| 'TPASS' | Test has passed. -| 'TFAIL' | Test has failed. -| 'TINFO' | General message. -| 'TWARN' | Something went wrong but we decided to continue. Mostly used in cleanup functions. -|============================== - -The 'ttype' can be combined bitwise with 'TERRNO' or 'TTERRNO' to print -'errno', 'TST_ERR' respectively. - -[source,c] -------------------------------------------------------------------------------- -void tst_brk(int ttype, char *arg_fmt, ...); -------------------------------------------------------------------------------- - -Printf-like function to report error and exit the test, it can be used with ttype: - -|============================================================ -| 'TBROK' | Something has failed in test preparation phase. -| 'TCONF' | Test is not appropriate for current configuration - (syscall not implemented, unsupported arch, ...) -|============================================================ - -The 'ttype' can be combined bitwise with 'TERRNO' or 'TTERRNO' to print -'errno', 'TST_ERR' respectively. - -[source,c] -------------------------------------------------------------------------------- -const char *tst_strsig(int sig); -------------------------------------------------------------------------------- - -Return the given signal number's corresponding string. - -[source,c] -------------------------------------------------------------------------------- -const char *tst_strerrno(int err); -------------------------------------------------------------------------------- - -Return the given errno number's corresponding string. Using this function to -translate 'errno' values to strings is preferred. You should not use the -'strerror()' function in the testcases. - -[source,c] -------------------------------------------------------------------------------- -const char *tst_strstatus(int status); -------------------------------------------------------------------------------- - -Returns string describing the status as returned by 'wait()'. - -WARNING: This function is not thread safe. - -[source,c] -------------------------------------------------------------------------------- -void tst_set_timeout(unsigned int timeout); -------------------------------------------------------------------------------- - -Allows for setting timeout per test iteration dynamically in the test setup(), -the timeout is specified in seconds. There are a few testcases whose runtime -can vary arbitrarily, these can disable timeouts by setting it to -1. - -[source,c] -------------------------------------------------------------------------------- -void tst_flush(void); -------------------------------------------------------------------------------- - -Flush output streams, handling errors appropriately. - -This function is rarely needed when you have to flush the output streams -before calling 'fork()' or 'clone()'. Note that the 'SAFE_FORK()' calls this -function automatically. See 3.4 FILE buffers and fork() for explanation why is -this needed. - -2.2.3 Test temporary directory -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If '.needs_tmpdir' is set to '1' in the 'struct tst_test' unique test -temporary is created and it's set as the test working directory. Tests *MUST -NOT* create temporary files outside that directory. The flag is not needed to -be set when use these flags: '.all_filesystems', '.format_device', '.mntpoint', -'.mount_device' '.needs_checkpoints', '.needs_device', '.resource_file' -(these flags imply creating temporary directory). - -IMPORTANT: Close all file descriptors (that point to files in test temporary - directory, even the unlinked ones) either in the 'test()' function - or in the test 'cleanup()' otherwise the test may break temporary - directory removal on NFS (look for "NFS silly rename"). - -2.2.4 Safe macros -^^^^^^^^^^^^^^^^^ - -Safe macros aim to simplify error checking in test preparation. Instead of -calling system API functions, checking for their return value and aborting the -test if the operation has failed, you just use corresponding safe macro. - -Use them whenever it's possible. - -Instead of writing: - -[source,c] -------------------------------------------------------------------------------- - fd = open("/dev/null", O_RDONLY); - if (fd < 0) - tst_brk(TBROK | TERRNO, "opening /dev/null failed"); -------------------------------------------------------------------------------- - -You write just: - -[source,c] -------------------------------------------------------------------------------- - fd = SAFE_OPEN("/dev/null", O_RDONLY); -------------------------------------------------------------------------------- - -IMPORTANT: The SAFE_CLOSE() function also sets the passed file descriptor to -1 - after it's successfully closed. - -They can also simplify reading and writing of sysfs files, you can, for -example, do: - -[source,c] -------------------------------------------------------------------------------- - SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%lu", &pid_max); -------------------------------------------------------------------------------- - -See 'include/tst_safe_macros.h', 'include/tst_safe_stdio.h' and -'include/tst_safe_file_ops.h' and 'include/tst_safe_net.h' for a complete list. - -2.2.5 Test specific command line options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -[source,c] -------------------------------------------------------------------------------- -struct tst_option { - char *optstr; - char **arg; - char *help; -}; -------------------------------------------------------------------------------- - -Test specific command line parameters can be passed with the 'NULL' terminated -array of 'struct tst_option'. The 'optstr' is the command line option i.e. "o" -or "o:" if option has a parameter. Only short options are supported. The 'arg' -is where 'optarg' is stored upon match. If option has no parameter it's set to -non-'NULL' value if option was present. The 'help' is a short help string. - -NOTE: The test parameters must not collide with common test parameters defined - in the library the currently used ones are +-i+, +-I+, +-C+, and +-h+. - -[source,c] -------------------------------------------------------------------------------- -int tst_parse_int(const char *str, int *val, int min, int max); -int tst_parse_float(const char *str, float *val, float min, float max); -------------------------------------------------------------------------------- - -Helpers for parsing the strings returned in the 'struct tst_option'. - -Both return zero on success and 'errno', mostly 'EINVAL' or 'ERANGE', on -failure. - -Both functions are no-op if 'str' is 'NULL'. - -The valid range for result includes both 'min' and 'max'. - -.Example Usage -[source,c] -------------------------------------------------------------------------------- -#include -#include "tst_test.h" - -static char *str_threads; -static int threads = 10; - -static struct tst_option options[] = { - {"t:", &str_threads, "Number of threads (default 10)"}, - ... - {NULL, NULL, NULL} -}; - -static void setup(void) -{ - if (tst_parse_int(str_threads, &threads, 1, INT_MAX)) - tst_brk(TBROK, "Invalid number of threads '%s'", str_threads); - - ... -} - -static void test_threads(void) -{ - ... - - for (i = 0; i < threads; i++) { - ... - } - - ... -} - -static struct tst_test test = { - ... - .options = options, - ... -}; -------------------------------------------------------------------------------- - - -2.2.6 Runtime kernel version detection -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Testcases for newly added kernel functionality require kernel newer than a -certain version to run. All you need to skip a test on older kernels is to -set the '.min_kver' string in the 'struct tst_test' to a minimal required -kernel version, e.g. '.min_kver = "2.6.30"'. - -For more complicated operations such as skipping a test for a certain range -of kernel versions, following functions could be used: - -[source,c] -------------------------------------------------------------------------------- -int tst_kvercmp(int r1, int r2, int r3); - -struct tst_kern_exv { - char *dist_name; - char *extra_ver; -}; - -int tst_kvercmp2(int r1, int r2, int r3, struct tst_kern_exv *vers); -------------------------------------------------------------------------------- - -These two functions are intended for runtime kernel version detection. They -parse the output from 'uname()' and compare it to the passed values. - -The return value is similar to the 'strcmp()' function, i.e. zero means equal, -negative value means that the kernel is older than than the expected value and -positive means that it's newer. - -The second function 'tst_kvercmp2()' allows for specifying per-vendor table of -kernel versions as vendors typically backport fixes to their kernels and the -test may be relevant even if the kernel version does not suggests so. See -'testcases/kernel/syscalls/inotify/inotify04.c' for example usage. - -WARNING: The shell 'tst_kvercmp' maps the result into unsigned integer - the - process exit value. - -2.2.7 Fork()-ing -^^^^^^^^^^^^^^^^ - -Be wary that if the test forks and there were messages printed by the -'tst_*()' interfaces, the data may still be in libc/kernel buffers and these -*ARE NOT* flushed automatically. - -This happens when 'stdout' gets redirected to a file. In this case, the -'stdout' is not line buffered, but block buffered. Hence after a fork content -of the buffers will be printed by the parent and each of the children. - -To avoid that you should use 'SAFE_FORK()'. - -IMPORTANT: You have to set the '.forks_child' flag in the test structure - if your testcase forks. - -2.2.8 Doing the test in the child process -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Results reported by 'tst_res()' are propagated to the parent test process via -block of shared memory. - -Calling 'tst_brk()' causes child process to exit with non-zero exit value. -Which means that it's safe to use 'SAFE_*()' macros in the child processes as -well. - -Children that outlive the 'test()' function execution are waited for in the -test library. Unclean child exit (killed by signal, non-zero exit value, etc.) -will cause the main test process to exit with 'tst_brk()', which especially -means that 'TBROK' propagated from a child process will cause the whole test -to exit with 'TBROK'. - -If a test needs a child that segfaults or does anything else that cause it to -exit uncleanly all you need to do is to wait for such children from the -'test()' function so that it's reaped before the main test exits the 'test()' -function. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -void tst_reap_children(void); -------------------------------------------------------------------------------- - -The 'tst_reap_children()' function makes the process wait for all of its -children and exits with 'tst_brk(TBROK, ...)' if any of them returned -a non zero exit code. - -.Using 'tst_res()' from binaries started by 'exec()' -[source,c] -------------------------------------------------------------------------------- -/* test.c */ -#define _GNU_SOURCE -#include -#include "tst_test.h" - -static void do_test(void) -{ - char *const argv[] = {"test_exec_child", NULL}; - char path[4096]; - - if (tst_get_path("test_exec_child", path, sizeof(path))) - tst_brk(TCONF, "Couldn't find test_exec_child in $PATH"); - - execve(path, argv, environ); - - tst_res(TFAIL | TERRNO, "EXEC!"); -} - -static struct tst_test test = { - .test_all = do_test, - .child_needs_reinit = 1, -}; - -/* test_exec_child.c */ -#define TST_NO_DEFAULT_MAIN -#include "tst_test.h" - -int main(void) -{ - tst_reinit(); - tst_res(TPASS, "Child passed!"); - return 0; -} -------------------------------------------------------------------------------- - -The 'tst_res()' function can be also used from binaries started by 'exec()', -the parent test process has to set the '.child_needs_reinit' flag so that the -library prepares for it and has to make sure the 'LTP_IPC_PATH' environment -variable is passed down, then the very fist thing the program has to call in -'main()' is 'tst_reinit()' that sets up the IPC. - -2.2.9 Fork() and Parent-child synchronization -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -As LTP tests are written for Linux, most of the tests involve fork()-ing and -parent-child process synchronization. LTP includes a checkpoint library that -provides wait/wake futex based functions. - -In order to use checkpoints the '.needs_checkpoints' flag in the 'struct -tst_test' must be set to '1', this causes the test library to initialize -checkpoints before the 'test()' function is called. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -TST_CHECKPOINT_WAIT(id) - -TST_CHECKPOINT_WAIT2(id, msec_timeout) - -TST_CHECKPOINT_WAKE(id) - -TST_CHECKPOINT_WAKE2(id, nr_wake) - -TST_CHECKPOINT_WAKE_AND_WAIT(id) -------------------------------------------------------------------------------- - -The checkpoint interface provides pair of wake and wait functions. The 'id' is -unsigned integer which specifies checkpoint to wake/wait for. As a matter of -fact it's an index to an array stored in a shared memory, so it starts on -'0' and there should be enough room for at least of hundred of them. - -The 'TST_CHECKPOINT_WAIT()' and 'TST_CHECKPOINT_WAIT2()' suspends process -execution until it's woken up or until timeout is reached. - -The 'TST_CHECKPOINT_WAKE()' wakes one process waiting on the checkpoint. -If no process is waiting the function retries until it success or until -timeout is reached. - -If timeout has been reached process exits with appropriate error message (uses -'tst_brk()'). - -The 'TST_CHECKPOINT_WAKE2()' does the same as 'TST_CHECKPOINT_WAKE()' but can -be used to wake precisely 'nr_wake' processes. - -The 'TST_CHECKPOINT_WAKE_AND_WAIT()' is a shorthand for doing wake and then -immediately waiting on the same checkpoint. - -Child processes created via 'SAFE_FORK()' are ready to use the checkpoint -synchronization functions, as they inherited the mapped page automatically. - -Child processes started via 'exec()', or any other processes not forked from -the test process must initialize the checkpoint by calling 'tst_reinit()'. - -For the details of the interface, look into the 'include/tst_checkpoint.h'. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -/* - * Waits for process state change. - * - * The state is one of the following: - * - * R - process is running - * S - process is sleeping - * D - process sleeping uninterruptibly - * Z - zombie process - * T - process is traced - */ -TST_PROCESS_STATE_WAIT(pid, state, msec_timeout) -------------------------------------------------------------------------------- - -The 'TST_PROCESS_STATE_WAIT()' waits until process 'pid' is in requested -'state' or timeout is reached. The call polls +/proc/pid/stat+ to get this -information. A timeout of 0 will wait infinitely. - -On timeout -1 is returned and errno set to ETIMEDOUT. - -It's mostly used with state 'S' which means that process is sleeping in kernel -for example in 'pause()' or any other blocking syscall. - -2.2.10 Signals and signal handlers -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If you need to use signal handlers, keep the code short and simple. Don't -forget that the signal handler is called asynchronously and can interrupt the -code execution at any place. - -This means that problems arise when global state is changed both from the test -code and signal handler, which will occasionally lead to: - -* Data corruption (data gets into inconsistent state), this may happen, for - example, for any operations on 'FILE' objects. - -* Deadlock, this happens, for example, if you call 'malloc(2)', 'free(2)', - etc. from both the test code and the signal handler at the same time since - 'malloc' has global lock for it's internal data structures. (Be wary that - 'malloc(2)' is used by the libc functions internally too.) - -* Any other unreproducible and unexpected behavior. - -Quite common mistake is to call 'exit(3)' from a signal handler. Note that this -function is not signal-async-safe as it flushes buffers, etc. If you need to -exit a test immediately from a signal handler use '_exit(2)' instead. - -TIP: See 'man 7 signal' for the list of signal-async-safe functions. - -If a signal handler sets a variable, its declaration must be 'volatile', -otherwise compiler may misoptimize the code. This is because the variable may -not be changed in the compiler code flow analysis. There is 'sig_atomic_t' -type defined in C99 but this one *DOES NOT* imply 'volatile' (it's just a -'typedef' to 'int'). So the correct type for a flag that is changed from a -signal handler is either 'volatile int' or 'volatile sig_atomic_t'. - -If a crash (e.g. triggered by signal SIGSEGV) is expected in testing, you -can avoid creation of core files by calling tst_no_corefile() function. -This takes effect for process (and its children) which invoked it, unless -they subsequently modify RLIMIT_CORE. - -Note that LTP library will reap any processes that test didn't reap itself, -and report any non-zero exit code as failure. - -2.2.11 Kernel Modules -^^^^^^^^^^^^^^^^^^^^^ - -There are certain cases where the test needs a kernel part and userspace part, -happily, LTP can build a kernel module and then insert it to the kernel on test -start for you. See 'testcases/kernel/device-drivers/block' for details. - -2.2.12 Useful macros -^^^^^^^^^^^^^^^^^^^^^ - -[source,c] -------------------------------------------------------------------------------- -ARRAY_SIZE(arr) -------------------------------------------------------------------------------- - -Returns the size of statically defined array, i.e. -'(sizeof(arr) / sizeof(*arr))' - -[source,c] -------------------------------------------------------------------------------- -LTP_ALIGN(x, a) -------------------------------------------------------------------------------- - -Aligns the x to be next multiple of a. The a must be power of 2. - -2.2.13 Filesystem type detection -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Some tests are known to fail on certain filesystems (you cannot swap on TMPFS, -there are unimplemented 'fcntl()' etc.). - -If your test needs to be skipped on certain filesystems, use the interface -below: - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - - /* - * Unsupported only on NFS. - */ - if (tst_fs_type(".") == TST_NFS_MAGIC) - tst_brk(TCONF, "Test not supported on NFS filesystem"); - - - /* - * Unsupported on NFS, TMPFS and RAMFS - */ - long type; - - switch ((type = tst_fs_type("."))) { - case TST_NFS_MAGIC: - case TST_TMPFS_MAGIC: - case TST_RAMFS_MAGIC: - tst_brk(TCONF, "Test not supported on %s filesystem", - tst_fs_type_name(type)); - break; - } -------------------------------------------------------------------------------- - -2.2.14 Thread-safety in the LTP library -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -It is safe to use library 'tst_res()' function in multi-threaded tests. - -Only the main thread must return from the 'test()' function to the test -library and that must be done only after all threads that may call any library -function has been terminated. That especially means that threads that may call -'tst_brk()' must terminate before the execution of the 'test()' function -returns to the library. This is usually done by the main thread joining all -worker threads at the end of the 'test()' function. Note that the main thread -will never get to the library code in a case that 'tst_brk()' was called from -one of the threads since it will sleep at least in 'pthread_join()' on the -thread that called the 'tst_brk()' till 'exit()' is called by 'tst_brk()'. - -The test-supplied cleanup function runs *concurrently* to the rest of the -threads in a case that cleanup was entered from 'tst_brk()'. Subsequent -threads entering 'tst_brk()' must be suspended or terminated at the start of -the user supplied cleanup function. It may be necessary to stop or exit -the rest of the threads before the test cleans up as well. For example threads -that create new files should be stopped before temporary directory is be -removed. - -Following code example shows thread safe cleanup function example using atomic -increment as a guard. The library calls its cleanup after the execution returns -from the user supplied cleanup and expects that only one thread returns from -the user supplied cleanup to the test library. +6 Test Contribution Checklist +------------------------------ -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Maintainer-Patch-Review-Checklist[Maintainer Patch Review Checklist]. -static void cleanup(void) -{ - static int flag; - - if (tst_atomic_inc(&flag) != 1) - pthread_exit(NULL); - - /* if needed stop the rest of the threads here */ - - ... - - /* then do cleanup work */ - - ... - - /* only one thread returns to the library */ -} -------------------------------------------------------------------------------- - - -2.2.15 Testing with a block device -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Some tests needs a block device (inotify tests, syscall 'EROFS' failures, -etc.). LTP library contains a code to prepare a testing device. - -If '.needs_device' flag in the 'struct tst_test' is set the 'tst_device' -structure is initialized with a path to a test device and default filesystem -to be used. - -You can also request minimal device size in megabytes by setting -'.dev_min_size' the device is guaranteed to have at least the requested size -then. - -If '.format_device' flag is set the device is formatted with a filesystem as -well. You can use '.dev_fs_type' to override the default filesystem type if -needed and pass additional options to mkfs via '.dev_fs_opts' and -'.dev_extra_opts' pointers. Note that '.format_device' implies '.needs_device' -there is no need to set both. - -If '.mount_device' is set, the device is mounted at '.mntpoint' which is used -to pass a directory name that will be created and used as mount destination. -You can pass additional flags and data to the mount command via '.mnt_flags' -and '.mnt_data' pointers. Note that '.mount_device' implies '.needs_device' -and '.format_device' so there is no need to set the later two. - -If '.needs_rofs' is set, read-only filesystem is mounted at '.mntpoint' this -one is supposed to be used for 'EROFS' tests. - -If '.all_filesystems' is set the test function is executed for all supported -filesystems. Supported filesystems are detected based on existence of the -'mkfs.$fs' helper and on kernel support to mount it. For each supported -filesystem the 'tst_device.fs_type' is set to the currently tested fs type, if -'.format_device' is set the device is formatted as well, if '.mount_device' is -set it's mounted at '.mntpoint'. Also the test timeout is reset for each -execution of the test function. This flag is expected to be used for filesystem -related syscalls that are at least partly implemented in the filesystem -specific code e.g. fallocate(). - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -struct tst_device { - const char *dev; - const char *fs_type; -}; - -extern struct tst_device *tst_device; - -int tst_umount(const char *path); -------------------------------------------------------------------------------- - -In case that 'LTP_DEV' is passed to the test in an environment, the library -checks that the file exists and that it's a block device, if -'.device_min_size' is set the device size is checked as well. If 'LTP_DEV' -wasn't set or if size requirements were not met a temporary file is created -and attached to a free loop device. - -If there is no usable device and loop device couldn't be initialized the test -exits with 'TCONF'. - -The 'tst_umount()' function works exactly as 'umount(2)' but retries several -times on 'EBUSY'. This is because various desktop daemons (gvfsd-trash is known -for that) may be stupid enough to probe all newly mounted filesystem which -results in 'umount(2)' failing with 'EBUSY'. - -IMPORTANT: All testcases should use 'tst_umount()' instead of 'umount(2)' to - umount filesystems. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_find_free_loopdev(const char *path, size_t path_len); -------------------------------------------------------------------------------- - -This function finds a free loopdev and returns the free loopdev minor (-1 for no -free loopdev). If path is non-NULL, it will be filled with free loopdev path. -If you want to use a customized loop device, we can call tst_find_free_loopdev -(NULL, 0) in tests to get a free minor number and then mknod. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -unsigned long tst_dev_bytes_written(const char *dev); -------------------------------------------------------------------------------- - -This function reads test block device stat file (/sys/block//stat) and -returns the bytes written since the last invocation of this function. To avoid -FS deferred IO metadata/cache interference, we suggest doing "syncfs" before the -tst_dev_bytes_written first invocation. And an inline function named tst_dev_sync -is created for that intention. - -2.2.16 Formatting a device with a filesystem -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -static void setup(void) -{ - ... - SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL); - ... -} -------------------------------------------------------------------------------- - -This function takes a path to a device, filesystem type and an array of extra -options passed to mkfs. - -The fs options 'fs_opts' should either be 'NULL' if there are none, or a -'NULL' terminated array of strings such as: -+const char *const opts[] = {"-b", "1024", NULL}+. - -The extra options 'extra_opts' should either be 'NULL' if there are none, or a -'NULL' terminated array of strings such as +{"102400", NULL}+; 'extra_opts' -will be passed after device name. e.g: +mkfs -t ext4 -b 1024 /dev/sda1 102400+ -in this case. - -Note that perfer to store the options which can be passed before or after device -name by 'fs_opts' array. - -2.2.17 Verifying a filesystem's free space -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Some tests have size requirements for the filesystem's free space. If these -requirements are not satisfied, the tests should be skipped. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_fs_has_free(const char *path, unsigned int size, unsigned int mult); -------------------------------------------------------------------------------- - -The 'tst_fs_has_free()' function returns 1 if there is enough space and 0 if -there is not. - -The 'path' is the pathname of any directory/file within a filesystem. - -The 'mult' is a multiplier, one of 'TST_BYTES', 'TST_KB', 'TST_MB' or 'TST_GB'. - -The required free space is calculated by 'size * mult', e.g. -'tst_fs_has_free("/tmp/testfile", 64, TST_MB)' will return 1 if the -filesystem, which '"/tmp/testfile"' is in, has 64MB free space at least, and 0 -if not. - -2.2.18 Files, directories and fs limits -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Some tests need to know the maximum count of links to a regular file or -directory, such as 'rename(2)' or 'linkat(2)' to test 'EMLINK' error. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_fs_fill_hardlinks(const char *dir); -------------------------------------------------------------------------------- - -Try to get maximum count of hard links to a regular file inside the 'dir'. - -NOTE: This number depends on the filesystem 'dir' is on. - -This function uses 'link(2)' to create hard links to a single file until it -gets 'EMLINK' or creates 65535 links. If the limit is hit, the maximum number of -hardlinks is returned and the 'dir' is filled with hardlinks in format -"testfile%i", where i belongs to [0, limit) interval. If no limit is hit or if -'link(2)' failed with 'ENOSPC' or 'EDQUOT', zero is returned and previously -created files are removed. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_fs_fill_subdirs(const char *dir); -------------------------------------------------------------------------------- - -Try to get maximum number of subdirectories in directory. - -NOTE: This number depends on the filesystem 'dir' is on. For current kernel, -subdir limit is not available for all filesystems (available for ext2, ext3, -minix, sysv and more). If the test runs on some other filesystems, like ramfs, -tmpfs, it will not even try to reach the limit and return 0. - -This function uses 'mkdir(2)' to create directories in 'dir' until it gets -'EMLINK' or creates 65535 directories. If the limit is hit, the maximum number -of subdirectories is returned and the 'dir' is filled with subdirectories in -format "testdir%i", where i belongs to [0, limit - 2) interval (because each -newly created dir has two links already - the '.' and the link from parent -dir). If no limit is hit or if 'mkdir(2)' failed with 'ENOSPC' or 'EDQUOT', -zero is returned and previously created directories are removed. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_dir_is_empty(const char *dir, int verbose); -------------------------------------------------------------------------------- - -Returns non-zero if directory is empty and zero otherwise. - -Directory is considered empty if it contains only '.' and '..'. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -void tst_purge_dir(const char *path); -------------------------------------------------------------------------------- - -Deletes the contents of given directory but keeps the directory itself. Useful -for cleaning up the temporary directory and mount points between test cases or -test iterations. Terminates the program with 'TBROK' on error. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount); -------------------------------------------------------------------------------- - -Fill a file with specified pattern using file descriptor. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount); -------------------------------------------------------------------------------- - -Creates/overwrites a file with specified pattern using file path. - -2.2.19 Getting an unused PID number -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Some tests require a 'PID', which is not used by the OS (does not belong to -any process within it). For example, kill(2) should set errno to 'ESRCH' if -it's passed such 'PID'. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -pid_t tst_get_unused_pid(void); -------------------------------------------------------------------------------- - -Return a 'PID' value not used by the OS or any process within it. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_get_free_pids(void); -------------------------------------------------------------------------------- - -Returns number of unused pids in the system. Note that this number may be -different once the call returns and should be used only for rough estimates. - -2.2.20 Running executables -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -int tst_cmd(const char *const argv[], - const char *stdout_path, - const char *stderr_path, - enum tst_cmd_flags flags); -------------------------------------------------------------------------------- - -'tst_cmd()' is a wrapper for 'vfork() + execvp()' which provides a way -to execute an external program. - -'argv[]' is a 'NULL' terminated array of strings starting with the program name -which is followed by optional arguments. - -'TST_CMD_PASS_RETVAL' enum 'tst_cmd_flags' makes 'tst_cmd()' -return the program exit code to the caller, otherwise 'tst_cmd()' exit the -tests on failure. 'TST_CMD_TCONF_ON_MISSING' check for program in '$PATH' and exit -with 'TCONF' if not found. - -In case that 'execvp()' has failed and the enum 'TST_CMD_PASS_RETVAL' flag was set, the -return value is '255' if 'execvp()' failed with 'ENOENT' and '254' otherwise. - -'stdout_path' and 'stderr_path' determine where to redirect the program -stdout and stderr I/O streams. - -The 'SAFE_CMD()' macro can be used automatic handling non-zero exits (exits -with 'TBROK') and 'ENOENT' (exits with 'TCONF'). - -.Example -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -const char *const cmd[] = { "ls", "-l", NULL }; - -... - /* Store output of 'ls -l' into log.txt */ - tst_cmd(cmd, "log.txt", NULL, 0); -... -------------------------------------------------------------------------------- - -2.2.21 Measuring elapsed time and helper functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -[source,c] -------------------------------------------------------------------------------- -#include "tst_timer.h" - -void tst_timer_check(clockid_t clk_id); - -void tst_timer_start(clockid_t clk_id); - -void tst_timer_stop(void); - -struct timespec tst_timer_elapsed(void); - -long long tst_timer_elapsed_ms(void); - -long long tst_timer_elapsed_us(void); - -int tst_timer_expired_ms(long long ms); -------------------------------------------------------------------------------- - -The 'tst_timer_check()' function checks if specified 'clk_id' is suppored and -exits the test with 'TCONF' otherwise. It's expected to be used in test -'setup()' before any resources that needs to be cleaned up are initialized, -hence it does not include a cleanup function parameter. - -The 'tst_timer_start()' marks start time and stores the 'clk_id' for further -use. - -The 'tst_timer_stop()' marks the stop time using the same 'clk_id' as last -call to 'tst_timer_start()'. - -The 'tst_timer_elapsed*()' returns time difference between the timer start and -last timer stop in several formats and units. - -The 'tst_timer_expired_ms()' function checks if the timer started by -'tst_timer_start()' has been running longer than ms milliseconds. The function -returns non-zero if timer has expired and zero otherwise. - -IMPORTANT: The timer functions use 'clock_gettime()' internally which needs to - be linked with '-lrt' on older glibc. Please do not forget to add - 'LDLIBS+=-lrt' in Makefile. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" -#include "tst_timer.h" - -static void setup(void) -{ - ... - tst_timer_check(CLOCK_MONOTONIC); - ... -} - -static void run(void) -{ - ... - tst_timer_start(CLOCK_MONOTONIC); - ... - while (!tst_timer_expired_ms(5000)) { - ... - } - ... -} - -struct tst_test test = { - ... - .setup = setup, - .test_all = run, - ... -}; -------------------------------------------------------------------------------- - -Expiration timer example usage. - -[source,c] -------------------------------------------------------------------------------- -long long tst_timespec_to_us(struct timespec t); -long long tst_timespec_to_ms(struct timespec t); - -struct timeval tst_us_to_timeval(long long us); -struct timeval tst_ms_to_timeval(long long ms); - -int tst_timespec_lt(struct timespec t1, struct timespec t2); - -struct timespec tst_timespec_add_us(struct timespec t, long long us); - -struct timespec tst_timespec_diff(struct timespec t1, struct timespec t2); -long long tst_timespec_diff_us(struct timespec t1, struct timespec t2); -long long tst_timespec_diff_ms(struct timespec t1, struct timespec t2); - -struct timespec tst_timespec_abs_diff(struct timespec t1, struct timespec t2); -long long tst_timespec_abs_diff_us(struct timespec t1, struct timespec t2); -long long tst_timespec_abs_diff_ms(struct timespec t1, struct timespec t2); -------------------------------------------------------------------------------- - -The first four functions are simple inline conversion functions. - -The 'tst_timespec_lt()' function returns non-zero if 't1' is earlier than -'t2'. - -The 'tst_timespec_add_us()' function adds 'us' microseconds to the timespec -'t'. The 'us' is expected to be positive. - -The 'tst_timespec_diff*()' functions returns difference between two times, the -'t1' is expected to be later than 't2'. - -The 'tst_timespec_abs_diff*()' functions returns absolute value of difference -between two times. - -NOTE: All conversions to ms and us rounds the value. - -2.2.22 Datafiles -^^^^^^^^^^^^^^^^ - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -static const char *const res_files[] = { - "foo", - "bar", - NULL -}; - -static struct tst_test test = { - ... - .resource_files = res_files, - ... -} -------------------------------------------------------------------------------- - -If the test needs additional files to be copied to the test temporary -directory all you need to do is to list their filenames in the -'NULL' terminated array '.resource_files' in the tst_test structure. - -When resource files is set test temporary directory is created automatically, -there is need to set '.needs_tmpdir' as well. - -The test library looks for datafiles first, these are either stored in a -directory called +datafiles+ in the +$PWD+ at the start of the test or in -+$LTPROOT/testcases/data/${test_binary_name}+. If the file is not found the -library looks into +$LTPROOT/testcases/bin/+ and to +$PWD+ at the start of the -test. This ensures that the testcases can copy the file(s) effortlessly both -when test is started from the directory it was compiled in as well as when LTP -was installed. - -The file(s) are copied to the newly created test temporary directory which is -set as the test working directory when the 'test()' functions is executed. - -2.2.23 Code path tracing -^^^^^^^^^^^^^^^^^^^^^^^^ - -'tst_res' is a macro, so on when you define a function in one file: - -[source,c] -------------------------------------------------------------------------------- -int do_action(int arg) -{ - ... - - if (ok) { - tst_res(TPASS, "check passed"); - return 0; - } else { - tst_res(TFAIL, "check failed"); - return -1; - } -} -------------------------------------------------------------------------------- - -and call it from another file, the file and line reported by 'tst_res' in this -function will be from the former file. - -'TST_TRACE' can make the analysis of such situations easier. It's a macro which -inserts a call to 'tst_res(TINFO, ...)' in case its argument evaluates to -non-zero. In this call to 'tst_res(TINFO, ...)' the file and line will be -expanded using the actual location of 'TST_TRACE'. - -For example, if this another file contains: - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -if (TST_TRACE(do_action(arg))) { - ... -} -------------------------------------------------------------------------------- - -the generated output may look similar to: - -------------------------------------------------------------------------------- -common.h:9: FAIL: check failed -test.c:8: INFO: do_action(arg) failed -------------------------------------------------------------------------------- - -2.2.24 Tainted kernels -^^^^^^^^^^^^^^^^^^^^^^ - -If you need to detect, if a testcase triggers a kernel warning, bug or oops, -the following can be used to detect TAINT_W or TAINT_D: - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" -#include "tst_taint.h" - -void setup(void) -{ - ... - tst_taint_init(TST_TAINT_W | TST_TAINT_D); - ... -} -... -void run(void) -{ - ... - if (tst_taint_check() == 0) - tst_res(TPASS, "kernel is not tainted"); - else - tst_res(TFAIL, "kernel is tainted"); -} -------------------------------------------------------------------------------- - -You have to call 'tst_taint_init()' with non-zero flags first, preferably during -setup(). The function will generate a 'TCONF' if the requested flags are not -fully supported on the running kernel, and 'TBROK' if either a zero mask was -supplied or if the kernel is already tainted before executing the test. - -Then you can call 'tst_taint_check()' during 'run()', which returns 0 or the -tainted flags set in '/proc/sys/kernel/tainted' as specified earlier. - -Depending on your kernel version, not all tainted-flags will be supported. - -For reference to tainted kernels, see kernel documentation: -Documentation/admin-guide/tainted-kernels.rst or -https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html - -2.2.25 Checksums -^^^^^^^^^^^^^^^^ - -CRC32c checksum generation is supported by LTP. In order to use it, the -test should include 'tst_checksum.h' header, then can call 'tst_crc32c()'. - -2.2.26 Checking kernel for the driver support -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Some tests may need specific kernel drivers, either compiled in, or built -as a module. If '.needs_drivers' points to a 'NULL' terminated array of kernel -module names these are all checked and the test exits with 'TCONF' on the -first missing driver. - -Since it relies on modprobe command, the check will be skipped if the command -itself is not available on the system. - -2.2.27 Saving & restoring /proc|sys values -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -LTP library can be instructed to save and restore value of specified -(/proc|sys) files. This is achieved by initialized tst_test struct -field 'save_restore'. It is a 'NULL' terminated array of strings where -each string represents a file, whose value is saved at the beginning -and restored at the end of the test. Only first line of a specified -file is saved and restored. - -Pathnames can be optionally prefixed to specify how strictly (during -'store') are handled errors: - -* (no prefix) - test ends with 'TCONF', if file doesn't exist -* '?' - test prints info message and continues, - if file doesn't exist or open/read fails -* '!' - test ends with 'TBROK', if file doesn't exist - -'restore' is always strict and will TWARN if it encounters any error. - -[source,c] -------------------------------------------------------------------------------- -static const char *save_restore[] = { - "/proc/sys/kernel/core_pattern", - NULL, -}; - -static void setup(void) -{ - FILE_PRINTF("/proc/sys/kernel/core_pattern", "/mypath"); -} - -static struct tst_test test = { - ... - .setup = setup, - .save_restore = save_restore, -}; -------------------------------------------------------------------------------- - -2.2.28 Parsing kernel .config -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Generally testcases should attempt to autodetect as much kernel features as -possible based on the currently running kernel. We do have tst_check_driver() -to check if functionality that could be compiled as kernel module is present -on the system, disabled syscalls can be detected by checking for 'ENOSYS' -errno etc. - -However in rare cases core kernel features couldn't be detected based on the -kernel userspace API and we have to resort to kernel .config parsing. - -For this cases the test should set the 'NULL' terminated needs_kconfig array -of kernel config options required for the test. The config option can be -specified either as plain "CONFIG_FOO" in which case it's sufficient for the -test continue if it's set to any value (typically =y or =m). Or with a value -as "CONFIG_FOO=bar" in which case the value has to match as well. The test is -aborted with 'TCONF' if any of the required options were not set. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -static const char *kconfigs[] = { - "CONFIG_X86_INTEL_UMIP", - NULL -}; - -static struct tst_test test = { - ... - .needs_kconfigs = kconfigs, - ... -}; -------------------------------------------------------------------------------- - -2.2.29 Changing the Wall Clock Time during test execution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -There are some tests that, for different reasons, might need to change the -system-wide clock time. Whenever this happens, it is imperative that the clock -is restored, at the end of test's execution, taking in consideration the amount -of time elapsed during that test. - -In order for that to happen, struct tst_test has a variable called -"restore_wallclock" that should be set to "1" so LTP knows it should: (1) -initialize a monotonic clock during test setup phase and (2) use that monotonic -clock to fix the system-wide clock time at the test cleanup phase. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -static void setup(void) -{ - ... -} - -static void run(void) -{ - ... -} - -struct tst_test test = { - ... - .setup = setup, - .test_all = run, - .restore_wallclock = 1, - ... -}; -------------------------------------------------------------------------------- - -2.2.30 Testing similar syscalls in one test -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In some cases kernel has several very similar syscalls that do either the same -or very similar job. This is most noticeable on i386 where we commonly have -two or three syscall versions. That is because i386 was first platform that -Linux was developed on and because of that most mistakes in API happened there -as well. However this is not limited to i386 at all, it's quite common that -version two syscall has added missing flags parameters or so. - -In such cases it does not make much sense to copy&paste the test code over and -over, rather than that the test library provides support for test variants. -The idea behind test variants is simple, we run the test several times each -time with different syscall variant. - -The implementation consist of test_variant integer that, if set, denotes number -of test variants. The test is then forked and executed test_variant times each -time with different value in global tst_variant variable. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -static int do_foo(void) -{ - switch (tst_variant) { - case 0: - return foo(); - case 1: - return syscall(__NR_foo); - } - - return -1; -} - -static void run(void) -{ - ... - - TEST(do_foo); - - ... -} - -static void setup(void) -{ - switch (tst_variant) { - case 0: - tst_res(TINFO, "Testing foo variant 1"); - break; - case 1: - tst_res(TINFO, "Testing foo variant 2"); - break; - } -} - -struct tst_test test = { - ... - .setup = setup, - .test_all = run, - .test_variants = 2, - ... -}; -------------------------------------------------------------------------------- - -2.2.31 Guarded buffers -^^^^^^^^^^^^^^^^^^^^^^ - -The test library supports guarded buffers, which are buffers allocated so -that: - -* The end of the buffer is followed by a PROT_NONE page - -* The remainder of the page before the buffer is filled with random canary - data - -Which means that the any access after the buffer will yield a Segmentation -fault or EFAULT depending on if the access happened in userspace or the kernel -respectively. The canary before the buffer will also catch any write access -outside of the buffer. - -The purpose of the patch is to catch off-by-one bugs which happens when -buffers and structures are passed to syscalls. New tests should allocate -guarded buffers for all data passed to the tested syscall which are passed by -a pointer. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -static struct foo *foo_ptr; -static struct iovec *iov; -static void *buf_ptr; -static char *id; -... - -static void run(void) -{ - ... - - foo_ptr->bar = 1; - foo_ptr->buf = buf_ptr; - - ... -} - -static void setup(void) -{ - ... - - id = tst_strdup(string); - - ... -} - -static struct tst_test test = { - ... - .bufs = (struct tst_buffers []) { - {&foo_ptr, .size = sizeof(*foo_ptr)}, - {&buf_ptr, .size = BUF_SIZE}, - {&iov, .iov_sizes = (int[]){128, 32, -1}, - {} - } -}; -------------------------------------------------------------------------------- - -Guarded buffers can be allocated on runtime in a test setup() by a -'tst_alloc()' or by 'tst_strdup()' as well as by filling up the .bufs array in -the tst_test structure. - -So far the tst_test structure supports allocating either a plain buffer by -setting up the size or struct iovec, which is allocated recursively including -the individual buffers as described by an '-1' terminated array of buffer -sizes. - -2.2.32 Adding and removing capabilities -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Some tests may require the presence or absence of particular -capabilities. Using the API provided by 'tst_capability.h' the test author can -try to ensure that some capabilities are either present or absent during the -test. - -For example; below we try to create a raw socket, which requires -CAP_NET_ADMIN. During setup we should be able to do it, then during run it -should be impossible. The LTP capability library will check before setup that -we have this capability, then after setup it will drop it. - -[source,c] --------------------------------------------------------------------------------- -#include "tst_test.h" -#include "tst_capability.h" -#include "tst_safe_net.h" - -#include "lapi/socket.h" - -static void run(void) -{ - TEST(socket(AF_INET, SOCK_RAW, 1)); - if (TST_RET > -1) { - tst_res(TFAIL, "Created raw socket"); - } else if (TST_ERR != EPERM) { - tst_res(TFAIL | TTERRNO, - "Failed to create socket for wrong reason"); - } else { - tst_res(TPASS | TTERRNO, "Didn't create raw socket"); - } -} - -static void setup(void) -{ - TEST(socket(AF_INET, SOCK_RAW, 1)); - if (TST_RET < 0) - tst_brk(TCONF | TTERRNO, "We don't have CAP_NET_RAW to begin with"); - - SAFE_CLOSE(TST_RET); -} - -static struct tst_test test = { - .setup = setup, - .test_all = run, - .caps = (struct tst_cap []) { - TST_CAP(TST_CAP_REQ, CAP_NET_RAW), - TST_CAP(TST_CAP_DROP, CAP_NET_RAW), - {} - }, -}; --------------------------------------------------------------------------------- - -Look at the test struct at the bottom. We have filled in the 'caps' field with -a 'NULL' terminated array containing two 'tst_cap' structs. 'TST_CAP_REQ' -actions are executed before setup and 'TST_CAP_DROP' are executed after -setup. This means it is possible to both request and drop a capability. - -[source,c] --------------------------------------------------------------------------------- -static struct tst_test test = { - .test_all = run, - .caps = (struct tst_cap []) { - TST_CAP(TST_CAP_REQ, CAP_NET_RAW), - TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), - {} - }, -}; --------------------------------------------------------------------------------- - -Here we request 'CAP_NET_RAW', but drop 'CAP_SYS_ADMIN'. If the capability is -in the permitted set, but not the effective set, the library will try to -permit it. If it is not in the permitted set, then it will fail with 'TCONF'. - -This API does not require 'libcap' to be installed. However it has limited -features relative to 'libcap'. It only tries to add or remove capabilities -from the effective set. This means that tests which need to spawn child -processes may have difficulties ensuring the correct capabilities are -available to the children (see the capabilities (7) manual pages). - -However a lot of problems can be solved by using 'tst_cap_action(struct -tst_cap *cap)' directly which can be called at any time. This also helps if -you wish to drop a capability at the begining of setup. - -2.2.33 Reproducing race-conditions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If a bug is caused by two tasks in the kernel racing and you wish to create a -regression test (or bug-fix validation test) then the 'tst_fuzzy_sync.h' -library should be used. - -It allows you to specify, in your code, two race windows. One window in each -thread's loop (triggering a race usually requires many iterations). These -windows show fuzzy-sync where the race can happen. They don't need to be -exact, hence the 'fuzzy' part. If the race condition is not immediately -triggered then the library will begin experimenting with different timings. - -[source,c] --------------------------------------------------------------------------------- -#include "tst_fuzzy_sync.h" - -static struct tst_fzsync_pair fzsync_pair; - -static void setup(void) -{ - tst_fzsync_pair_init(&fzsync_pair); -} - -static void cleanup(void) -{ - tst_fzsync_pair_cleanup(&fzsync_pair); -} - -static void *thread_b(void *arg) -{ - while (tst_fzsync_run_b(&fzsync_pair)) { - - tst_fzsync_start_race_b(&fzsync_pair); - - /* This is the race window for thread B */ - - tst_fzsync_end_race_b(&fzsync_pair); - } - - return arg; -} - -static void thread_a(void) -{ - tst_fzsync_pair_reset(&fzsync_pair, thread_b); - - while (tst_fzsync_run_a(&fzsync_pair)) { - - tst_fzsync_start_race_a(&fzsync_pair); - - /* This is the race window for thread A */ - - tst_fzsync_end_race_a(&fzsync_pair); - } -} - -static struct tst_test test = { - .test_all = thread_a, - .setup = setup, - .cleanup = cleanup, -}; --------------------------------------------------------------------------------- - -Above is a minimal template for a test using fuzzy-sync. In a simple case, you -just need to put the bits you want to race inbetween 'start_race' and -'end_race'. Meanwhile, any setup you need to do per-iteration goes outside the -windows. - -Fuzzy sync synchronises 'run_a' and 'run_b', which act as barriers, so that -neither thread can progress until the other has caught up with it. There is -also the 'pair_wait' function which can be used to add barriers in other -locations. Of course 'start/end_race_a/b' are also a barriers. - -The library decides how long the test should run for based on the timeout -specified by the user plus some other heuristics. - -For full documentation see the comments in 'include/tst_fuzzy_sync.h'. - -2.2.34 Reserving hugepages -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Many of the LTP tests need to use hugepage in their testing, this allows the -test can reserve hugepages from system only via '.request_hugepages = xx'. - -If set non-zero number of 'request_hugepages', test will try to reserve the -expected number of hugepage for testing in setup phase. If system does not -have enough hpage for using, it will try the best to reserve 80% available -number of hpages. With success test stores the reserved hugepage number in -'tst_hugepages'. For the system without hugetlb supporting, variable -'tst_hugepages' will be set to 0. - -Also, we do cleanup and restore work for the hpages resetting automatically. - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -static void run(void) -{ - ... - - if (tst_hugepages == test.request_hugepages) - TEST(do_hpage_test); - else - ... - ... -} - -struct tst_test test = { - .test_all = run, - .request_hugepages = 2, - ... -}; -------------------------------------------------------------------------------- - -or, - -[source,c] -------------------------------------------------------------------------------- -#include "tst_test.h" - -static void run(void) -{ - ... -} - -static void setup(void) -{ -        if (tst_hugepages != test.requested_hugepages) -                tst_brk(TCONF, "..."); -} - -struct tst_test test = { - .test_all = run, - .request_hugepages = 2, - ... -}; -------------------------------------------------------------------------------- - -2.2.35 Checking for required commands -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Required commands can be checked with '.needs_cmds', which points to a 'NULL' -terminated array of strings such as: - -[source,c] -------------------------------------------------------------------------------- -.needs_cmds = (const char *const []) { - "useradd", - "userdel", - NULL -}, -------------------------------------------------------------------------------- - -2.2.36 Assert sys or proc file value -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Using TST_ASSERT_INT/STR(path, val) to assert that integer value or string stored in -the prefix field of file pointed by path equals to the value passed to this function. - -Also having a similar api pair TST_ASSERT_FILE_INT/STR(path, prefix, val) to assert -the field value of file. - -2.3 Writing a testcase in shell -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -LTP supports testcases to be written in a portable shell too. - -There is a shell library modeled closely to the C interface at -'testcases/lib/tst_test.sh'. - -WARNING: All identifiers starting with TST_ or tst_ are reserved for the - test library. - -2.3.1 Basic test interface -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later -# This is a basic test for true shell builtin - -TST_TESTFUNC=do_test -. tst_test.sh - -do_test() -{ - true - ret=$? - - if [ $ret -eq 0 ]; then - tst_res TPASS "true returned 0" - else - tst_res TFAIL "true returned $ret" - fi -} - -tst_run -------------------------------------------------------------------------------- - -TIP: To execute this test the 'tst_test.sh' library must be in '$PATH'. If you - are executing the test from a git checkout you can run it as - 'PATH="$PATH:../../lib" ./foo01.sh' - -The shell library expects test setup, cleanup and the test function executing -the test in the '$TST_SETUP', '$TST_CLEANUP' and '$TST_TESTFUNC' variables. - -Both '$TST_SETUP' and '$TST_CLEANUP' are optional. - -The '$TST_TESTFUNC' may be called several times if more than one test -iteration was requested by passing right command line options to the test. - -The '$TST_CLEANUP' may be called even in the middle of the setup and must be -able to clean up correctly even in this situation. The easiest solution for -this is to keep track of what was initialized and act accordingly in the -cleanup. - -WARNING: Similar to the C library, calling tst_brk() in the $TST_CLEANUP does - not exit the test and 'TBROK' is converted to 'TWARN'. - -Notice also the 'tst_run' function called at the end of the test that actually -starts the test. - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later -# Example test with tests in separate functions - -TST_TESTFUNC=test -TST_CNT=2 -. tst_test.sh - -test1() -{ - tst_res TPASS "Test $1 passed" -} - -test2() -{ - tst_res TPASS "Test $1 passed" -} - -tst_run -# output: -# foo 1 TPASS: Test 1 passed -# foo 2 TPASS: Test 2 passed -------------------------------------------------------------------------------- - -If '$TST_CNT' is set, the test library looks if there are functions named -'$\{TST_TESTFUNC\}1', ..., '$\{TST_TESTFUNC\}$\{TST_CNT\}' and if these are -found they are executed one by one. The test number is passed to it in the '$1'. - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later -# Example test with tests in a single function - -TST_TESTFUNC=do_test -TST_CNT=2 -. tst_test.sh - -do_test() -{ - case $1 in - 1) tst_res TPASS "Test $1 passed";; - 2) tst_res TPASS "Test $1 passed";; - esac -} - -tst_run -# output: -# foo 1 TPASS: Test 1 passed -# foo 2 TPASS: Test 2 passed -------------------------------------------------------------------------------- - -Otherwise, if '$TST_CNT' is set but there is no '$\{TST_TESTFUNC\}1', etc., -the '$TST_TESTFUNC' is executed '$TST_CNT' times and the test number is passed -to it in the '$1'. - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later -# Example test with tests in a single function, using $TST_TEST_DATA and -# $TST_TEST_DATA_IFS - -TST_TESTFUNC=do_test -TST_TEST_DATA="foo:bar:d dd" -TST_TEST_DATA_IFS=":" -. tst_test.sh - -do_test() -{ - tst_res TPASS "Test $1 passed with data '$2'" -} - -tst_run -# output: -# foo 1 TPASS: Test 1 passed with data 'foo' -# foo 2 TPASS: Test 1 passed with data 'bar' -# foo 3 TPASS: Test 1 passed with data 'd dd' -------------------------------------------------------------------------------- - -It's possible to pass data for function with '$TST_TEST_DATA'. Optional -'$TST_TEST_DATA_IFS' is used for splitting, default value is space. - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later -# Example test with tests in a single function, using $TST_TEST_DATA and $TST_CNT - -TST_TESTFUNC=do_test -TST_CNT=2 -TST_TEST_DATA="foo bar" -. tst_test.sh - -do_test() -{ - case $1 in - 1) tst_res TPASS "Test $1 passed with data '$2'";; - 2) tst_res TPASS "Test $1 passed with data '$2'";; - esac -} - -tst_run -# output: -# foo 1 TPASS: Test 1 passed with data 'foo' -# foo 2 TPASS: Test 2 passed with data 'foo' -# foo 3 TPASS: Test 1 passed with data 'bar' -# foo 4 TPASS: Test 2 passed with data 'bar' -------------------------------------------------------------------------------- - -'$TST_TEST_DATA' can be used with '$TST_CNT'. If '$TST_TEST_DATA_IFS' not specified, -space as default value is used. Of course, it's possible to use separate functions. - -2.3.2 Library environment variables for shell -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Similarily to the C library various checks and preparations can be requested -simply by setting right '$TST_NEEDS_FOO'. - -[options="header"] -|============================================================================= -| Variable name | Action done -| 'TST_NEEDS_ROOT' | Exit the test with 'TCONF' unless executed under root. -| | Alternatively the 'tst_require_root' command can be used. -| 'TST_NEEDS_TMPDIR' | Create test temporary directory and cd into it. -| 'TST_NEEDS_DEVICE' | Prepare test temporary device, the path to testing - device is stored in '$TST_DEVICE' variable. - The option implies 'TST_NEEDS_TMPDIR'. -| 'TST_NEEDS_CMDS' | String with command names that has to be present for - the test (see below). -| 'TST_NEEDS_MODULE' | Test module name needed for the test (see below). -| 'TST_NEEDS_DRIVERS'| Checks kernel drivers support for the test. -| 'TST_TIMEOUT' | Maximum timeout set for the test in sec. Must be int >= 1, - or -1 (special value to disable timeout), default is 300. - Variable is meant be set in tests, not by user. - It's equivalent of `tst_test.timeout` in C. -|============================================================================= - -NOTE: Network tests (see testcases/network/README.md) use additional variables -in 'tst_net.sh'. - -Checking for presence of commands -+++++++++++++++++++++++++++++++++ - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh - -... - -TST_NEEDS_CMDS="modinfo modprobe" -. tst_test.sh - -... - -------------------------------------------------------------------------------- - -Setting '$TST_NEEDS_CMDS' to a string listing required commands will check for -existence each of them and exits the test with 'TCONF' on first missing. - -Alternatively the 'tst_require_cmds()' function can be used to do the same on -runtime, since sometimes we need to the check at runtime too. - -'tst_check_cmds()' can be used for requirements just for a particular test -as it doesn't exit (it issues 'tst_res TCONF'). Expected usage is: -... - -TST_TESTFUNC=do_test -. tst_test.sh - -do_test() -{ - tst_check_cmds cmd || return - cmd --foo - ... -} - -tst_run -... - -Locating kernel modules -+++++++++++++++++++++++ - -The LTP build system can build kernel modules as well, setting -'$TST_NEEDS_MODULE' to module name will cause the library to look for the -module in a few possible paths. - -If module was found the path to it will be stored into '$TST_MODPATH' -variable, if module wasn't found the test will exit with 'TCONF'. - -Alternatively the 'tst_require_module()' function can be used to do the same -at runtime. - -2.3.3 Optional command line parameters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later -# Optional test command line parameters - -TST_OPTS="af:" -TST_USAGE=usage -TST_PARSE_ARGS=parse_args -TST_TESTFUNC=do_test - -. tst_test.sh - -ALTERNATIVE=0 -MODE="foo" - -usage() -{ - cat << EOF -usage: $0 [-a] [-f ] - -OPTIONS --a Enable support for alternative foo --f Specify foo or bar mode -EOF -} - -parse_args() -{ - case $1 in - a) ALTERNATIVE=1;; - f) MODE="$2";; - esac -} - -do_test() -{ - ... -} - -tst_run -------------------------------------------------------------------------------- - -The 'getopts' string for optional parameters is passed in the '$TST_OPTS' -variable. There are a few default parameters that cannot be used by a test, -these can be listed with passing help '-h' option to any test. - -The function that prints the usage is passed in '$TST_USAGE', the help for -the options implemented in the library is appended when usage is printed. - -Lastly the function '$PARSE_ARGS' is called with the option name in the '$1' -and, if option has argument, its value in the '$2'. - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later -# Optional test positional parameters - -TST_POS_ARGS=3 -TST_USAGE=usage -TST_TESTFUNC=do_test - -. tst_test.sh - -usage() -{ - cat << EOF -usage: $0 [min] [max] [size] - -EOF -} - -min="$1" -max="$2" -size="$3" - -do_test() -{ - ... -} - -tst_run -------------------------------------------------------------------------------- - -You can also request a number of positional parameters by setting the -'$TST_POS_ARGS' variable. If you do, these will be available as they were -passed directly to the script in '$1', '$2', ..., '$n'. - -2.3.4 Useful library functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Retrieving configuration variables -++++++++++++++++++++++++++++++++++ - -You may need to retrieve configuration values such as PAGESIZE, there is -'getconf' but as some system may not have it, you are advised to use -'tst_getconf' instead. Note that it implements subset of 'getconf' -system variables used by the testcases only. - -[source,sh] -------------------------------------------------------------------------------- -# retrieve PAGESIZE -pagesize=`tst_getconf PAGESIZE` -------------------------------------------------------------------------------- - -Sleeping for subsecond intervals -++++++++++++++++++++++++++++++++ - -Albeit there is a sleep command available basically everywhere not all -implementations can support sleeping for less than one second. And most of the -time sleeping for a second is too much. Therefore LTP includes 'tst_sleep' -that can sleep for defined amount of seconds, milliseconds or microseconds. - -[source,sh] -------------------------------------------------------------------------------- -# sleep for 100 milliseconds -tst_sleep 100ms -------------------------------------------------------------------------------- - -Retry a function call multiple times -++++++++++++++++++++++++++++++++++++ - -Sometimes an LTP test needs to retry a function call multiple times because -the system is not ready to process it successfully on the first try. The LTP -library has useful tools to handle the call retry automatically. -'TST_RETRY_FUNC()' will keep retrying for up to 1 second. If you want a custom -time limit use 'TST_RETRY_FN_EXP_BACKOFF()'. Both methods return the value -returned by the last 'FUNC' call. - -The delay between retries starts at 1 microsecond and doubles after each call. -The retry loop ends when the function call succeeds or when the next delay -exceeds the specified time (1 second for 'TST_RETRY_FUNC()'). The maximum -delay is multiplied by TST_TIMEOUT_MUL. The total cumulative delay may be up -to twice as long as the adjusted maximum delay. - -The C version of 'TST_RETRY_FUNC()' is a macro which takes two arguments: - -* 'FUNC' is the complete function call with arguments which should be retried - multiple times. -* 'SUCCESS_CHECK' is a macro or function which will validate 'FUNC' return - value. 'FUNC' call was successful if 'SUCCESS_CHECK(ret)' evaluates to - non-zero. - -Both retry methods clear 'errno' before every 'FUNC' call so your -'SUCCESS_CHECK' can look for specific error codes as well. The LTP library -also includes predefined 'SUCCESS_CHECK' macros for the most common call -conventions: - -* 'TST_RETVAL_EQ0()' - The call was successful if 'FUNC' returned 0 or NULL -* 'TST_RETVAL_NOTNULL()' - The call was successful if 'FUNC' returned any - value other than 0 or NULL. -* 'TST_RETVAL_GE0()' - The call was successful if 'FUNC' returned value >= 0. - -[source,c] -------------------------------------------------------------------------------- -/* Keep trying for 1 second */ -TST_RETRY_FUNC(FUNC, SUCCESS_CHECK) - -/* Keep trying for up to 2*N seconds */ -TST_RETRY_FN_EXP_BACKOFF(FUNC, SUCCESS_CHECK, N) -------------------------------------------------------------------------------- - -The shell version of 'TST_RETRY_FUNC()' is simpler and takes slightly -different arguments: - -* 'FUNC' is a string containing the complete function or program call with - arguments. -* 'EXPECTED_RET' is a single expected return value. 'FUNC' call was successful - if the return value is equal to EXPECTED_RET. - -[source,sh] -------------------------------------------------------------------------------- -# Keep trying for 1 second -TST_RETRY_FUNC "FUNC arg1 arg2 ..." "EXPECTED_RET" - -# Keep trying for up to 2*N seconds -TST_RETRY_FN_EXP_BACKOFF "FUNC arg1 arg2 ..." "EXPECTED_RET" "N" -------------------------------------------------------------------------------- - -Checking for integers -+++++++++++++++++++++ - -[source,sh] -------------------------------------------------------------------------------- -# returns zero if passed an integer parameter, non-zero otherwise -tst_is_int "$FOO" -------------------------------------------------------------------------------- - -Checking for integers and floating point numbers -++++++++++++++++++++++++++++++++++++++++++++++++ - -[source,sh] -------------------------------------------------------------------------------- -# returns zero if passed an integer or floating point number parameter, -# non-zero otherwise -tst_is_num "$FOO" -------------------------------------------------------------------------------- - -Obtaining random numbers -++++++++++++++++++++++++ - -There is no '$RANDOM' in portable shell, use 'tst_random' instead. - -[source,sh] -------------------------------------------------------------------------------- -# get random integer between 0 and 1000 (including 0 and 1000) -tst_random 0 1000 -------------------------------------------------------------------------------- - -Formatting device with a filesystem -+++++++++++++++++++++++++++++++++++ - -The 'tst_mkfs' helper will format device with the filesystem. - -[source,sh] -------------------------------------------------------------------------------- -# format test device with ext2 -tst_mkfs ext2 $TST_DEVICE -# default params are $TST_FS_TYPE $TST_DEVICE -tst_mkfs -# optional parameters -tst_mkfs ext4 /dev/device -T largefile -------------------------------------------------------------------------------- - -Mounting and unmounting filesystems -+++++++++++++++++++++++++++++++++++ - -The 'tst_mount' and 'tst_umount' helpers are a safe way to mount/umount -a filesystem. - -The 'tst_mount' mounts '$TST_DEVICE' of '$TST_FS_TYPE' (optional) to -'$TST_MNTPOINT' (defaults to mntpoint), optionally using the -'$TST_MNT_PARAMS'. The '$TST_MNTPOINT' directory is created if it didn't -exist prior to the function call. - -If the path passed (optional, defaults to '$TST_DEVICE') to the 'tst_umount' is -not mounted (present in '/proc/mounts') it's noop. -Otherwise it retries to umount the filesystem a few times on a failure, which -is a workaround since there are a daemons dumb enough to probe all newly -mounted filesystems, which prevents them from umounting shortly after they -were mounted. - -ROD and ROD_SILENT -++++++++++++++++++ - -These functions supply the 'SAFE_MACROS' used in C although they work and are -named differently. - -[source,sh] -------------------------------------------------------------------------------- -ROD_SILENT command arg1 arg2 ... - -# is shorthand for: - -command arg1 arg2 ... > /dev/null 2>&1 -if [ $? -ne 0 ]; then - tst_brk TBROK "..." -fi - - -ROD command arg1 arg2 ... - -# is shorthand for: - -ROD arg1 arg2 ... -if [ $? -ne 0 ]; then - tst_brk TBROK "..." -fi -------------------------------------------------------------------------------- - -WARNING: Keep in mind that output redirection (to a file) happens in the - caller rather than in the ROD function and cannot be checked for - write errors by the ROD function. - -As a matter of a fact doing +ROD echo a > /proc/cpuinfo+ would work just fine -since the 'ROD' function will only get the +echo a+ part that will run just -fine. - -[source,sh] -------------------------------------------------------------------------------- -# Redirect output to a file with ROD -ROD echo foo \> bar -------------------------------------------------------------------------------- - -Note the '>' is escaped with '\', this causes that the '>' and filename are -passed to the 'ROD' function as parameters and the 'ROD' function contains -code to split '$@' on '>' and redirects the output to the file. - -EXPECT_PASS{,_BRK} and EXPECT_FAIL{,_BRK} -+++++++++++++++++++++++++++++++++++++++++ - -[source,sh] -------------------------------------------------------------------------------- -EXPECT_PASS command arg1 arg2 ... [ \> file ] -EXPECT_FAIL command arg1 arg2 ... [ \> file ] -------------------------------------------------------------------------------- - -'EXPECT_PASS' calls 'tst_res TPASS' if the command exited with 0 exit code, -and 'tst_res TFAIL' otherwise. 'EXPECT_FAIL' does vice versa. - -Output redirection rules are the same as for the 'ROD' function. In addition -to that, 'EXPECT_FAIL' always redirects the command's stderr to '/dev/null'. - -There are also 'EXPECT_PASS_BRK' and 'EXPECT_FAIL_BRK', which works the same way -except breaking a test when unexpected action happen. - -It's possible to detect whether expected value happened: -[source,sh] -------------------------------------------------------------------------------- -if ! EXPECT_PASS command arg1 2\> /dev/null; then - continue -fi -------------------------------------------------------------------------------- - -tst_kvcmp -+++++++++ - -This command compares the currently running kernel version given conditions -with syntax similar to the shell test command. - -[source,sh] -------------------------------------------------------------------------------- -# Exit the test if kernel version is older or equal to 2.6.8 -if tst_kvcmp -le 2.6.8; then - tst_brk TCONF "Kernel newer than 2.6.8 is needed" -fi - -# Exit the test if kernel is newer than 3.8 and older than 4.0.1 -if tst_kvcmp -gt 3.8 -a -lt 4.0.1; then - tst_brk TCONF "Kernel must be older than 3.8 or newer than 4.0.1" -fi -------------------------------------------------------------------------------- - -[options="header"] -|======================================================================= -| expression | description -| -eq kver | Returns true if kernel version is equal -| -ne kver | Returns true if kernel version is not equal -| -gt kver | Returns true if kernel version is greater -| -ge kver | Returns true if kernel version is greater or equal -| -lt kver | Returns true if kernel version is lesser -| -le kver | Returns true if kernel version is lesser or equal -| -a | Does logical and between two expressions -| -o | Does logical or between two expressions -|======================================================================= - -The format for kernel version has to either be with one dot e.g. '2.6' or with -two dots e.g. '4.8.1'. - -.tst_fs_has_free -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh - -... - -# whether current directory has 100MB free space at least. -if ! tst_fs_has_free . 100MB; then - tst_brkm TCONF "Not enough free space" -fi - -... -------------------------------------------------------------------------------- - -The 'tst_fs_has_free' shell interface returns 0 if the specified free space is -satisfied, 1 if not, and 2 on error. - -The second argument supports suffixes kB, MB and GB, the default unit is Byte. - -.tst_retry -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh - -... - -# Retry ping command three times -tst_retry "ping -c 1 127.0.0.1" - -if [ $? -ne 0 ]; then - tst_resm TFAIL "Failed to ping 127.0.0.1" -else - tst_resm TPASS "Successfully pinged 127.0.0.1" -fi - -... -------------------------------------------------------------------------------- - -The 'tst_retry' function allows you to retry a command after waiting small -amount of time until it succeeds or until given amount of retries has been -reached (default is three attempts). - -2.3.5 Restarting daemons -^^^^^^^^^^^^^^^^^^^^^^^^ - -Restarting system daemons is a complicated task for two reasons. - -* There are different init systems - (SysV init, systemd, etc...) - -* Daemon names are not unified between distributions - (apache vs httpd, cron vs crond, various syslog variations) - -To solve these problems LTP has 'testcases/lib/daemonlib.sh' library that -provides functions to start/stop/query daemons as well as variables that store -correct daemon name. - -.Supported operations -|============================================================================== -| start_daemon() | Starts daemon, name is passed as first parameter. -| stop_daemon() | Stops daemon, name is passed as first parameter. -| restart_daemon() | Restarts daemon, name is passed as first parameter. -| status_daemon() | Detect daemon status (exit code: 0: running, 1: not running). -|============================================================================== - -.Variables with detected names -|============================================================================== -| CROND_DAEMON | Cron daemon name (cron, crond). -| SYSLOG_DAEMON | Syslog daemon name (syslog, syslog-ng, rsyslog). -|============================================================================== - -.Cron daemon restart example -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later -# Cron daemon restart example - -TCID=cron01 -TST_COUNT=1 -. test.sh -. daemonlib.sh - -... - -restart_daemon $CROND_DAEMON - -... - -tst_exit -------------------------------------------------------------------------------- - -2.3.6 Access to the checkpoint interface -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The shell library provides an implementation of the checkpoint interface -compatible with the C version. All 'TST_CHECKPOINT_*' functions are available. - -In order to initialize checkpoints '$TST_NEEDS_CHECKPOINTS' must be set to '1' -before the inclusion of 'test.sh': - -[source,sh] -------------------------------------------------------------------------------- -#!/bin/sh - -TST_NEEDS_CHECKPOINTS=1 -. test.sh -------------------------------------------------------------------------------- - -Since both the implementations are compatible, it's also possible to start -a child binary process from a shell test and synchronize with it. This process -must have checkpoints initialized by calling 'tst_reinit()'. - -3. Common problems ------------------- - -This chapter describes common problems/misuses and less obvious design patters -(quirks) in UNIX interfaces. Read it carefully :) - -3.1 umask() -~~~~~~~~~~~ - -I've been hit by this one several times already... When you create files -with 'open()' or 'creat()' etc, the mode specified as the last parameter *is -not* the mode the file is created with. The mode depends on current 'umask()' -settings which may clear some of the bits. If your test depends on specific -file permissions you need either to change umask to 0 or 'chmod()' the file -afterwards or use 'SAFE_TOUCH()' that does the 'chmod()' for you. - -3.2 access() -~~~~~~~~~~~ - -If 'access(some_file, W_OK)' is executed by root, it will return success even -if the file doesn't have write permission bits set (the same holds for R_OK -too). For sysfs files you can use 'open()' as a workaround to check file -read/write permissions. It might not work for other filesystems, for these you -have to use 'stat()', 'lstat()' or 'fstat()'. - -3.3 umount() EBUSY -~~~~~~~~~~~~~~~~~~ - -Various desktop daemons (gvfsd-trash is known for that) may be stupid enough -to probe all newly mounted filesystem which results in 'umount(2)' failing -with 'EBUSY'; use 'tst_umount()' described in 2.2.19 that retries in this case -instead of plain 'umount(2)'. - -3.4 FILE buffers and fork() -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Be vary that if a process calls 'fork(2)' the child process inherits open -descriptors as well as copy of the parent memory so especially if there are -any open 'FILE' buffers with a data in them they may be written both by the -parent and children resulting in corrupted/duplicated data in the resulting -files. - -Also open 'FILE' streams are flushed and closed at 'exit(3)' so if your -program works with 'FILE' streams, does 'fork(2)', and the child may end up -calling 'exit(3)' you will likely end up with corrupted files. - -The solution to this problem is either simply call 'fflush(NULL)' that flushes -all open output 'FILE' streams just before doing 'fork(2)'. You may also use -'_exit(2)' in child processes which does not flush 'FILE' buffers and also -skips 'atexit(3)' callbacks. - -4. Test Contribution Checklist ------------------------------- - -1. Test compiles and runs fine (check with -i 10 too) -2. Checkpatch does not report any errors -3. The runtest entires are in place -4. Test files are added into corresponding .gitignore files +1. Test compiles and runs fine (check with `-i 10` too) +2. `make check` does not emit any warnings for the test you are working on + (hint: run it in the test's directory and/or use `make check-$TCID`) +3. The runtest entries are in place +4. Test binaries are added into corresponding '.gitignore' files 5. Patches apply over the latest git - -4.1 About .gitignore files +6.1 About .gitignore files ~~~~~~~~~~~~~~~~~~~~~~~~~~ There are numerous '.gitignore' files in the LTP tree. Usually there is a diff --git a/doc/user-guide.txt b/doc/user-guide.txt old mode 100644 new mode 100755 index 13865bc8862abe3692849d3bb5b37fc38e4731f1..b1ab13832ee7f49bdf495243fb4a094f2ea8cfac --- a/doc/user-guide.txt +++ b/doc/user-guide.txt @@ -1,7 +1,7 @@ LTP User Guidelines =================== -For compiling and installing and running the tests see `README.md`. +For compiling, installing and running the tests see `README.md`. For running LTP network tests see `testcases/network/README.md`. 1. Library environment variables @@ -10,16 +10,27 @@ For running LTP network tests see `testcases/network/README.md`. |============================================================================== | 'KCONFIG_PATH' | The path to the kernel config file, (if not set, it tries the usual paths '/boot/config-RELEASE' or '/proc/config.gz'). +| 'KCONFIG_SKIP_CHECK' | Skip kernel config check if variable set (not set by default). | 'LTPROOT' | Prefix for installed LTP, the default is '/opt/ltp'. | 'LTP_COLORIZE_OUTPUT' | Force colorized output behaviour. 'y' or '1': always colorize 'n' or '0': never colorize. +| 'LTP_DEV' | Path to the block device to be used + (C: '.needs_device = 1', shell: 'TST_NEEDS_DEVICE=1'). +| 'LTP_SINGLE_FS_TYPE' | Testing only - specifies filesystem instead all + supported (for tests with '.all_filesystems'). +| 'LTP_DEV_FS_TYPE' | Filesystem used for testing (default: 'ext2'). | 'LTP_TIMEOUT_MUL' | Multiply timeout, must be number >= 1 (> 1 is useful for slow machines to avoid unexpected timeout). Variable is also used in shell tests, but ceiled to int. +| 'LTP_VIRT_OVERRIDE' | Overrides virtual machine detection in the test + library. Setting it to empty string tell the library + that system is not a virtual machine. Other possible + values are 'kvm', 'xen', 'zvm' and 'microsoft' that + describe different types supervisors. | 'PATH' | It's required to addjust path: `PATH="$PATH:$LTPROOT/testcases/bin"` -| 'TMPDIR' | Base directory for template directory, which is required by C tests - `tst_test->needs_tmpdir=1` (or others) or shell 'TST_NEEDS_TMPDIR=1'). +| 'TMPDIR' | Base directory for template directory (C: '.needs_tmpdir = 1' + and others, which imply it, shell: 'TST_NEEDS_TMPDIR=1'). | 'TST_NO_CLEANUP' | Disable running test cleanup (defined in 'TST_CLEANUP'). |============================================================================== diff --git a/docparse/.gitignore b/docparse/.gitignore new file mode 100755 index 0000000000000000000000000000000000000000..d786a4762b7ece766bfb8db6ab9b112262413273 --- /dev/null +++ b/docparse/.gitignore @@ -0,0 +1,5 @@ +/*.txt +/docbook-xsl.css +/metadata.html +/metadata.pdf +/metadata.chunked/ diff --git a/docparse/Makefile b/docparse/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..e6e9f05ba8be5717b738b4572f3b4206e70e7250 --- /dev/null +++ b/docparse/Makefile @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019 Cyril Hrubis +# Copyright (c) 2020 Petr Vorel + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/functions.mk + +ifeq ($(METADATA_GENERATOR),asciidoctor) +METADATA_GENERATOR_CMD := asciidoctor +METADATA_GENERATOR_PARAMS := -d book metadata.txt +METADATA_GENERATOR_PARAMS_HTML := -b xhtml +METADATA_GENERATOR_PARAMS_PDF := -b pdf -r asciidoctor-pdf +else ifeq ($(METADATA_GENERATOR),asciidoc) +METADATA_GENERATOR_CMD := a2x +METADATA_GENERATOR_PARAMS := --xsltproc-opts "--stringparam toc.section.depth 1" -d book -L --resource="$(PWD)" metadata.txt +METADATA_GENERATOR_PARAMS_HTML := -f xhtml +METADATA_GENERATOR_PARAMS_PDF := -f pdf +METADATA_GENERATOR_PARAMS_HTML_CHUNKED := -f chunked +else ifeq ($(METADATA_GENERATOR),) +$(error 'METADATA_GENERATOR' not not configured, run ./configure in the root directory) +else +$(error '$(METADATA_GENERATOR)' not supported, only asciidoctor and asciidoc are supported) +endif + +ifdef VERBOSE +METADATA_GENERATOR_PARAMS += -v +endif + +CLEAN_TARGETS := *.css *.js *.txt + +ifeq ($(WITH_METADATA_HTML),yes) +MAKE_TARGETS += metadata.html +ifneq ($(METADATA_GENERATOR_PARAMS_HTML_CHUNKED),) +MAKE_TARGETS += metadata.chunked +endif +endif + +ifeq ($(WITH_METADATA_PDF),yes) +MAKE_TARGETS += metadata.pdf +endif + +INSTALL_DIR = metadata +INSTALL_TARGETS = *.css *.js + +ifndef METADATA_GENERATOR +METADATA_GENERATOR := asciidoctor +endif + +txt: ${abs_top_builddir}/metadata/ltp.json + $(abs_srcdir)/testinfo.pl $< + +ifeq ($(WITH_METADATA_HTML),yes) +metadata.html: txt + $(METADATA_GENERATOR_CMD) $(METADATA_GENERATOR_PARAMS) $(METADATA_GENERATOR_PARAMS_HTML) + +ifneq ($(METADATA_GENERATOR_PARAMS_HTML_CHUNKED),) +metadata.chunked: txt + $(METADATA_GENERATOR_CMD) $(METADATA_GENERATOR_PARAMS) $(METADATA_GENERATOR_PARAMS_HTML_CHUNKED) +endif +endif + +ifeq ($(WITH_METADATA_PDF),yes) +metadata.pdf: txt + $(METADATA_GENERATOR_CMD) $(METADATA_GENERATOR_PARAMS) $(METADATA_GENERATOR_PARAMS_PDF) +endif + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/docparse/README.md b/docparse/README.md new file mode 100755 index 0000000000000000000000000000000000000000..db156e64dc88021634c7c9a36aa28a0ff20999e2 --- /dev/null +++ b/docparse/README.md @@ -0,0 +1,248 @@ +Motivation for metadata extraction +================================== + +Exporting documentation +----------------------- + +This allow us to build browsable documentation for the testcases, e.g. a +catalogue of test information that would be searchable etc. At this point there +is a single page generated from the extracted data that tries to outline the +intent. + + +Propagating test requirements +----------------------------- + +Some subtests require different hardware resources/software versions/etc. the +test execution framework needs to consume these so that it can locate proper +hardware, install proper software, etc. + +Some examples of requirements are: + +* Test needs at least 1GB of RAM. + +* Test needs a block device at least 512MB in size + +* Test needs a NUMA machine with two memory nodes and at least 300 free pages on each node + +* Test needs i2c eeprom connected on a i2c bus + +* Test needs two serial ports connected via null-modem cable + + +With this information extracted from the tests the testrunner can then map the +requirements on the available machines in a lab and select a proper machine for +the particular (sub)set of testcases as well as supply a particular test with +additional information needed for the test, such as address of the i2c device, +paths to the serial devices, etc. In the case of virtual machines the test could +also dynamically prepare the correct environment for the test on demand. + + +Parallel test execution +----------------------- + +An LTP testrun on a modern hardware wastes most of the machine resources +because the testcases are running sequentially. However in order to execute +tests in parallel we need to know which system resources are utilized by a +given test, as obviously we cannot run two tests that monopolize the same +resource. In some cases we would also need to partition the system resource +accordingly, e.g. if we have two memory stress tests running at the same time +we will need to cap each of these tests on half of the available memory, or +make sure that sum of the memory used by these two tests is not greater an +available memory. + +Examples of such tests are: + +* Tests that mess with global system state + - system time (e.g. settimeofday() test and leap second test) + - SysV SHM + - ... + +* Tests that use block device + +* Tests that work with a particular hardware resource + - i2c eeprom test + - serial port tests + - ... + +Exporting test runtime/timeout to the testrunner +------------------------------------------------ + +Currently most of the testrunners usually do not know for how long is the test +supposed to run, this means that we have to guess some upper limit on how long +a test is supposed to run. The value is usually twice of the maximal runtime +for all testcases or whole suite or even larger. This means that we are wasting +time in the case that the test ends up stuck and we could have failed it much +sooner in most of the cases. This becomes quite important for a kernel +regression tests that do crash the host, if the information that the test is +supposed to crash a kernel under a minute is exported to the testrunner we can +reboot the machine much faster in an event of a crash. + +Getting rid of runtest files +---------------------------- + +This would also allow us to get rid of the unflexible and hard to maintain +runtest files. Once this system is in place we will have a list of all tests +along with their respective metadata - which means that we will be able to +generate subsets of the test easily on the fly. + +In order to achieve this we need two things: + +Each test will describe which syscall/functionality it tests in the metadata. +Then we could define groups of tests based on that. I.e. instead of having +syscall runtest file we would ask the testrunner to run all test that have a +defined which syscall they test, or whose filename matches a particular syscall name. + +Secondly we will have to store the test variants in the test metadata instead +of putting them in a file that is unrelated to the test. + +For example: + +* To run CVE related test we would select testcases with CVE tag + +* To run IPC test we will define a list of IPC syscalls and run all syscall + test that are in the list + +* And many more... + + +Implementation +============== + +The docparser is implemented as a minimal C tokenizer that can parse and +extract code comments and C structures. The docparser then runs over all C +sources in the testcases directory and if tst\_test structure is present in the +source it's parsed and the result is included in the resulting metadata. + +During parsing the metadata is stored in a simple key/value storage that more +or less follows C structure layout, i.e. can include hash, array, and string. +Once the parsing is finished the result is filtered so that only interesting +fields of the tst\_test structure are included and then converted into JSON +output. + +This process produces one big JSON file with metadata for all tests, that +is then installed along with the testcases. This would then be used by the +testrunner. + +The test requirements are stored in the tst\_test structure either as +bitflags, integers or arrays of strings: + +```c +struct tst_test test = { + ... + /* tests needs to run with UID=0 */ + .needs_root = 1, + + /* + * Tests needs a block device at least 1024MB in size and also + * mkfs.ext4 installed. + */ + .needs_device = 1, + .dev_min_size = 1024, + .dev_fs_type = ext4, + + /* Indicates that the test is messing with system wall clock */ + .restore_wallclock = 1, + + /* Tests needs uinput either compiled in or loaded as a module */ + .needs_drivers = (const char *[]) { + "uinput", + NULL + }, + + /* Tests needs enabled kernel config flags */ + .needs_kconfigs = (const char *[]) { + "CONFIG_X86_INTEL_UMIP=y", + NULL + }, + + /* Additional array of key value pairs */ + .tags = (const struct tst_tag[]) { + {"linux-git", "43a6684519ab"}, + {"CVE", "2017-2671"}, + {NULL, NULL} + } +}; +``` + +The test documentation is stored in a special comment such as: + +``` +/*\ + * Test description + * + * This is a test description. + * Consisting of several lines. + */ +``` + +Which will yield following JSON output: + +```json + "testcaseXY": { + "needs_root": "1", + "needs_device": "1", + "dev_min_size": "1024", + "dev_fs_type": "ext4", + "restore_wallclock": "1", + "needs_drivers": [ + "uinput", + ], + "needs_kconfigs": [ + "CONFIG_X86_INTEL_UMIP=y", + ], + "tags": [ + [ + "linux-git", + "43a6684519ab" + ], + [ + "CVE", + "2017-2671" + ], + ], + "doc": [ + "Test description", + "", + "This is a test description.", + "Consisting of several lines." + ], + "fname": "testcases/kernel/syscalls/foo/testcaseXY.c" + }, +``` + +The final JSON file is JSON object of test descriptions indexed by a test name +with a header describing the testsuite: + +```json +{ + "testsuite": "Linux Test Project", + "testsuite_short": "LTP", + "url": "https://github.com/linux-test-project/ltp/", + "scm_url_base": "https://github.com/linux-test-project/ltp/tree/master/", + "timeout": 300, + "version": "20200930", + "tests": { + "testcaseXY": { + ... + }, + ... + } +} +``` + +Open Points +=========== + +There are stil some loose ends. Mostly it's not well defined where to put +things and how to format them. + +* Some of the hardware requirements are already listed in the tst\_test. Should + we put all of them there? + +* What would be the format for test documentation and how to store things such + as test variants there? + +So far this proof of concept generates a metadata file. I guess that we need +actual consumers which will help to settle things down, I will try to look into +making use of this in the runltp-ng at least as a reference implementation. diff --git a/docparse/testinfo.pl b/docparse/testinfo.pl new file mode 100755 index 0000000000000000000000000000000000000000..67e435d794db6a51f7cfdc7364e9c3ab165becb2 --- /dev/null +++ b/docparse/testinfo.pl @@ -0,0 +1,521 @@ +#!/usr/bin/perl +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019 Cyril Hrubis +# Copyright (c) 2020-2021 Petr Vorel + +use strict; +use warnings; + +use JSON qw(decode_json); +use Cwd qw(abs_path); +use File::Basename qw(dirname); + +use constant OUTDIR => dirname(abs_path($0)); + +# tags which expect git tree, also need constant for URL +our @TAGS_GIT = ("linux-git", "linux-stable-git", "glibc-git"); + +# tags should map these in lib/tst_test.c +use constant LINUX_GIT_URL => "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id="; +use constant LINUX_STABLE_GIT_URL => "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id="; +use constant GLIBC_GIT_URL => "https://sourceware.org/git/?p=glibc.git;a=commit;h="; +use constant CVE_DB_URL => "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-"; + +sub load_json +{ + my ($fname, $mode) = @_; + local $/; + + open(my $fh, '<', $fname) or die("Can't open $fname $!"); + + return <$fh>; +} + +sub log_info +{ + my $msg = shift; + print STDERR "INFO: $msg\n"; +} + +sub log_warn +{ + my $msg = shift; + print STDERR "WARN: $msg\n"; +} + +sub print_asciidoc_page +{ + my ($fh, $json, $title, $content) = @_; + + print $fh <{'testsuite'}->{'url'}); + $content .= print_defined("Version", $json->{'testsuite'}->{'version'}); + $content .= print_defined("Default timeout", $json->{'defaults'}->{'timeout'}, "seconds"); + + return $content; +} + +sub uniq { + my %seen; + grep !$seen{$_}++, @_; +} + +sub get_test_names +{ + my @names = @{$_[0]}; + my ($letter, $prev_letter); + my $content; + + for my $name (sort @names) { + $letter = substr($name, 0, 1); + if (defined($prev_letter) && $letter ne $prev_letter) { + $content .= "\n"; + } + + $content .= reference($name, delimiter => " "); + $prev_letter = $letter; + } + $content .= "\n"; + + return $content; +} + +sub get_test_letters +{ + my @names = @{$_[0]}; + my $letter; + my $prev_letter = ""; + my $content; + + for (@names) { + $_ = substr($_, 0, 1); + } + @names = uniq(@names); + + for my $letter (@names) { + $content .= reference($letter); + } + $content .= "\n"; + + return $content; +} + +sub tag2title +{ + my $tag = shift; + return code(".$tag"); +} + +sub get_filters +{ + my $json = shift; + my %data; + + while (my ($k, $v) = each %{$json->{'tests'}}) { + for my $j (keys %{$v}) { + next if ($j eq 'fname' || $j eq 'doc'); + $data{$j} = () unless (defined($data{$j})); + + if ($j eq 'tags') { + for my $tags (@{$v}{'tags'}) { + for my $tag (@$tags) { + my $k2 = $$tag[0]; + my $v2 = $$tag[1]; + $data{$j}{$k2} = () unless (defined($data{$j}{$k2})); + push @{$data{$j}{$k2}}, $k unless grep{$_ eq $k} @{$data{$j}{$k2}}; + } + } + } else { + push @{$data{$j}}, $k unless grep{$_ eq $k} @{$data{$j}}; + } + } + } + return \%data; +} + +sub content_filter +{ + my $k = $_[0]; + my $title = $_[1]; + my $desc = $_[2]; + my $h = $_[3]; + my ($letter, $prev_letter, $content); + + $content = label($k); + $content .= $title; + $content .= paragraph("Tests containing $desc flag."); + + $content .= get_test_names(\@{$h}); + + return $content; +} + +sub content_filters +{ + my $json = shift; + my $data = get_filters($json); + my %h = %$data; + my $content; + + for my $k (sort keys %$data) { + my $title = tag2title($k); + if (ref($h{$k}) eq 'HASH') { + $content .= label($k); + $content .= h2($title); + for my $k2 (sort keys %{$h{$k}}) { + my $title2 = code($k2); + $content .= content_filter($k2, h3($title2), "$title $title2", $h{$k}{$k2}); + } + } else { + $content .= content_filter($k, h2($title), $title, \@{$h{$k}}); + } + } + + return $content; +} + +sub tag2env +{ + my $tag = shift; + $tag =~ s/-/_/g; + return uc($tag); +} + +sub detect_git +{ + my %data; + + for my $tag (@TAGS_GIT) { + my $env = tag2env($tag); + + unless (defined $ENV{$env} && $ENV{$env}) { + log_warn("git repository $tag not defined. Define it in \$$env"); + next; + } + + unless (-d $ENV{$env}) { + log_warn("\$$env does not exit ('$ENV{$env}')"); + next; + } + + if (system("which git >/dev/null")) { + log_warn("git not in \$PATH ('$ENV{'PATH'}')"); + next; + } + + chdir($ENV{$env}); + if (!system("git log -1 > /dev/null")) { + log_info("using '$ENV{$env}' as $env repository"); + $data{$tag} = $ENV{$env}; + } else { + log_warn("git failed, git not installed or \$$env is not a git repository? ('$ENV{$env}')"); + } + chdir(OUTDIR); + } + + return \%data; +} + +sub content_all_tests +{ + my $json = shift; + my @names = sort keys %{$json->{'tests'}}; + my $letters = paragraph(get_test_letters(\@names)); + my $git_url = detect_git(); + my $tmp = undef; + my $printed = ""; + my $content; + + $content .= paragraph("Total $#names tests."); + $content .= $letters; + $content .= get_test_names(\@names); + + for my $name (@names) { + my $letter = substr($name, 0, 1); + + if ($printed ne $letter) { + $content .= label($letter); + $content .= h2($letter); + $printed = $letter; + } + + $content .= hr() if (defined($tmp)); + $content .= label($name); + $content .= h3($name); + $content .= $letters; + + if (defined($json->{'testsuite'}->{'scm_url_base'}) && + defined($json->{'tests'}{$name}{fname})) { + $content .= paragraph(html_a(tag_url("fname", $json->{'tests'}{$name}{fname}, + $json->{'testsuite'}->{'scm_url_base'}), "source")); + } + + if (defined $json->{'tests'}{$name}{doc}) { + for my $doc (@{$json->{'tests'}{$name}{doc}}) { + + # fix formatting for asciidoc [DOCUMENTATION] => *Documentation* + if ($doc =~ s/^\[(.*)\]$/$1/) { + $doc = paragraph(bold(ucfirst(lc($doc)))); + } + + $content .= "$doc\n"; + } + $content .= "\n"; + } + + if ($json->{'tests'}{$name}{timeout}) { + if ($json->{'tests'}{$name}{timeout} eq -1) { + $content .= paragraph("Test timeout is disabled"); + } else { + $content .= paragraph("Test timeout is $json->{'tests'}{$name}{timeout} seconds"); + } + } else { + $content .= paragraph("Test timeout defaults to $json->{'defaults'}->{'timeout'} seconds"); + } + + my $tmp2 = undef; + for my $k (sort keys %{$json->{'tests'}{$name}}) { + my $v = $json->{'tests'}{$name}{$k}; + next if ($k eq "tags" || $k eq "fname" || $k eq "doc"); + if (!defined($tmp2)) { + $content .= table . "|Key|Value\n\n" + } + + $content .= "|" . reference($k, text => tag2title($k)) . "\n|"; + + if (ref($v) eq 'ARRAY') { + # two dimensional array + if (ref(@$v[0]) eq 'ARRAY') { + for my $v2 (@$v) { + $content .= paragraph(table_escape(join(' ', @$v2))); + } + } else { + # one dimensional array + $content .= table_escape(join(', ', @$v)); + } + } else { + # plain content + $content .= table_escape($v); + } + + $content .= "\n"; + + $tmp2 = 1; + } + if (defined($tmp2)) { + $content .= table . "\n"; + } + + $tmp2 = undef; + my %commits; + my @sorted_tags = sort { $a->[0] cmp $b->[0] } @{$json->{'tests'}{$name}{tags} // []}; + + for my $tag (@sorted_tags) { + if (!defined($tmp2)) { + $content .= table . "|Tag|Info\n" + } + my $k = @$tag[0]; + my $v = @$tag[1]; + my $url; + + if (defined($$git_url{$k})) { + $commits{$k} = () unless (defined($commits{$k})); + unless (defined($commits{$k}{$v})) { + chdir($$git_url{$k}); + $commits{$k}{$v} = `git log --pretty=format:'%s' -1 $v`; + chdir(OUTDIR); + } + $v .= ' ("' . $commits{$k}{$v} . '")'; + } + + $url = tag_url($k, @$tag[1]); + if ($url) { + $v = html_a($url, $v); + } + + # tag value value can be split into more lines if too long + # i.e. URL in known-fail + for (@$tag[2 .. $#$tag]) { + $v .= " $_"; + } + + $content .= "\n|" . reference($k) . "\n|$v\n"; + $tmp2 = 1; + } + if (defined($tmp2)) { + $content .= table . "\n"; + } + + $tmp = 1; + } + + return $content; +} + + +my $json = decode_json(load_json($ARGV[0])); + +my $config = [ + { + file => "about.txt", + title => h2("About $json->{'testsuite'}->{'name'}"), + content => \&content_about, + }, + { + file => "filters.txt", + title => h1("Test filtered by used flags"), + content => \&content_filters, + }, + { + file => "all-tests.txt", + title => h1("All tests"), + content => \&content_all_tests, + }, +]; + +sub print_asciidoc_main +{ + my $config = shift; + my $file = "metadata.txt"; + my $content; + + open(my $fh, '>', $file) or die("Can't open $file $!"); + + $content = <{'testsuite'}->{'short_name'} . " test catalog"), $content); +} + +for my $c (@{$config}) { + open(my $fh, '>', $c->{'file'}) or die("Can't open $c->{'file'} $!"); + print_asciidoc_page($fh, $json, $c->{'title'}, $c->{'content'}->($json)); +} + +print_asciidoc_main($config); diff --git a/include/Makefile b/include/Makefile old mode 100644 new mode 100755 index 7588e660033fa0de580529e95ae154f332207253..25e96df9b8cdd7d1d7e6f19925bf2160d682f0d9 --- a/include/Makefile +++ b/include/Makefile @@ -1,24 +1,6 @@ -# -# include Makefile. -# -# Copyright (C) 2009, Cisco Systems Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2009, Cisco Systems Inc. # Ngie Cooper, July 2009 -# top_srcdir ?= .. diff --git a/testcases/kernel/syscalls/ipc/lib/ipcmsg.h b/include/ipcmsg.h old mode 100644 new mode 100755 similarity index 100% rename from testcases/kernel/syscalls/ipc/lib/ipcmsg.h rename to include/ipcmsg.h diff --git a/testcases/kernel/syscalls/ipc/lib/ipcsem.h b/include/ipcsem.h old mode 100644 new mode 100755 similarity index 98% rename from testcases/kernel/syscalls/ipc/lib/ipcsem.h rename to include/ipcsem.h index 6a37672a7480e5cb653940af120335d6b31206a3..09a0b3cbe70e3625c6c52b521572678d1a106b82 --- a/testcases/kernel/syscalls/ipc/lib/ipcsem.h +++ b/include/ipcsem.h @@ -29,7 +29,7 @@ #include #include "test.h" -#include "lapi/semun.h" +#include "lapi/sem.h" void cleanup(void); void setup(void); diff --git a/testcases/kernel/syscalls/ipc/lib/ipcshm.h b/include/ipcshm.h old mode 100644 new mode 100755 similarity index 100% rename from testcases/kernel/syscalls/ipc/lib/ipcshm.h rename to include/ipcshm.h diff --git a/include/lapi/.gitignore b/include/lapi/.gitignore old mode 100644 new mode 100755 diff --git a/include/lapi/abisize.h b/include/lapi/abisize.h old mode 100644 new mode 100755 index 9e6622ca16d36f9d38a19c8cc666fbb363d49efc..d19d73f0bae7d9125679e2a68e9aadacc2ed90bf --- a/include/lapi/abisize.h +++ b/include/lapi/abisize.h @@ -5,8 +5,8 @@ * Petr Vorel */ -#ifndef ABISIZE_H__ -#define ABISIZE_H__ +#ifndef LAPI_ABISIZE_H__ +#define LAPI_ABISIZE_H__ /* __WORDSIZE replacement */ #if defined(__LP64__) || defined(_LP64) @@ -28,4 +28,4 @@ (defined(__aarch64__) && defined(__ILP32__)) || \ defined(TST_ABI64) -#endif /* ABISIZE_H__ */ +#endif /* LAPI_ABISIZE_H__ */ diff --git a/include/lapi/acct.h b/include/lapi/acct.h old mode 100644 new mode 100755 index c81b78b442b9e1ddad78918a89189f5e52ec14ba..6c521118e27679d34d081ac2cb5166aadb9e8ec5 --- a/include/lapi/acct.h +++ b/include/lapi/acct.h @@ -1,7 +1,7 @@ //SPDX-License-Identifier: GPL-2.0-or-later -#ifndef LAPI_ACCT_H -#define LAPI_ACCT_H +#ifndef LAPI_ACCT_H__ +#define LAPI_ACCT_H__ #include #include "config.h" @@ -71,4 +71,4 @@ enum { # endif #endif /* HAVE_STRUCT_ACCT_V3 */ -#endif /* LAPI_ACCT_H */ +#endif /* LAPI_ACCT_H__ */ diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h old mode 100644 new mode 100755 index 22b13b47ba13c86587b2727f81760cdb41a92d18..f9e50c6b7fcb861a5006c7c86e3473450f777252 --- a/include/lapi/bpf.h +++ b/include/lapi/bpf.h @@ -8,8 +8,8 @@ * some eBPF testing without any external dependencies. */ -#ifndef BPF_H -# define BPF_H +#ifndef LAPI_BPF_H__ +#define LAPI_BPF_H__ #include @@ -27,6 +27,7 @@ #define BPF_JNE 0x50 /* jump != */ #define BPF_SIZE(code) ((code) & 0x18) +#define BPF_B 0x10 /* 8-bit */ #define BPF_W 0x00 /* 32-bit */ #define BPF_DW 0x18 /* double word (64-bit) */ @@ -37,8 +38,10 @@ #define BPF_OP(code) ((code) & 0xf0) #define BPF_ADD 0x00 #define BPF_SUB 0x10 +#define BPF_DIV 0x30 #define BPF_LSH 0x60 #define BPF_RSH 0x70 +#define BPF_MOD 0x90 #define BPF_JEQ 0x10 @@ -449,6 +452,14 @@ enum bpf_func_id { .off = 0, \ .imm = 0 }) +#define BPF_ALU32_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + #define BPF_ALU64_IMM(OP, DST, IMM) \ ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ @@ -457,6 +468,14 @@ enum bpf_func_id { .off = 0, \ .imm = IMM }) +#define BPF_ALU32_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + #define BPF_MOV64_REG(DST, SRC) \ ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_MOV | BPF_X, \ @@ -465,6 +484,14 @@ enum bpf_func_id { .off = 0, \ .imm = 0 }) +#define BPF_MOV32_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + #define BPF_LD_IMM64(DST, IMM) \ BPF_LD_IMM64_RAW(DST, 0, IMM) @@ -564,4 +591,4 @@ static inline int bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size) } /* End copy from tools/lib/bpf */ -#endif /* BPF_H */ +#endif /* LAPI_BPF_H__ */ diff --git a/include/lapi/capability.h b/include/lapi/capability.h old mode 100644 new mode 100755 index fde27efd3645521cc3208e844d19ef5efaa8b5c9..8cabd0f280be836647579a48be3cfee161b18b85 --- a/include/lapi/capability.h +++ b/include/lapi/capability.h @@ -3,8 +3,8 @@ * Copyright (c) 2019 Richard Palethorpe */ -#ifndef LAPI_CAPABILITY_H -#define LAPI_CAPABILITY_H +#ifndef LAPI_CAPABILITY_H__ +#define LAPI_CAPABILITY_H__ #include "config.h" @@ -24,6 +24,10 @@ # define CAP_NET_RAW 13 #endif +#ifndef CAP_SYS_CHROOT +# define CAP_SYS_CHROOT 18 +#endif + #ifndef CAP_SYS_ADMIN # define CAP_SYS_ADMIN 21 #endif @@ -40,6 +44,10 @@ # define CAP_SYS_RESOURCE 24 #endif +#ifndef CAP_BPF +# define CAP_BPF 39 +#endif + #ifndef CAP_TO_INDEX # define CAP_TO_INDEX(x) ((x) >> 5) #endif @@ -48,4 +56,4 @@ # define CAP_TO_MASK(x) (1 << ((x) & 31)) #endif -#endif +#endif /* LAPI_CAPABILITY_H__ */ diff --git a/include/lapi/clone.h b/include/lapi/clone.h old mode 100644 new mode 100755 index 2b8cbdbe08e0f2100a6570ecf3b939eda466b884..437d1376f990e69a665f3522e92b4d3ff23681f2 --- a/include/lapi/clone.h +++ b/include/lapi/clone.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "config.h" #include "lapi/syscalls.h" @@ -26,7 +27,7 @@ struct clone_args { uint64_t __attribute__((aligned(8))) tls; }; -int clone3(struct clone_args *args, size_t size) +static inline int clone3(struct clone_args *args, size_t size) { return tst_syscall(__NR_clone3, args, size); } @@ -36,12 +37,18 @@ int clone3(struct clone_args *args, size_t size) #define CLONE_PIDFD 0x00001000 /* set if a pidfd should be placed in parent */ #endif -void clone3_supported_by_kernel(void) +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif + +static inline void clone3_supported_by_kernel(void) { + long ret; + if ((tst_kvercmp(5, 3, 0)) < 0) { /* Check if the syscall is backported on an older kernel */ - TEST(syscall(__NR_clone3, NULL, 0)); - if (TST_RET == -1 && TST_ERR == ENOSYS) + ret = syscall(__NR_clone3, NULL, 0); + if (ret == -1 && errno == ENOSYS) tst_brk(TCONF, "Test not supported on kernel version < v5.3"); } } diff --git a/include/lapi/close_range.h b/include/lapi/close_range.h new file mode 100755 index 0000000000000000000000000000000000000000..19db52d3d42b239e00fe303f06e2837376d8b4b9 --- /dev/null +++ b/include/lapi/close_range.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2021 SUSE LLC */ + +#ifndef LAPI_CLOSE_RANGE__ +# define LAPI_CLOSE_RANGE__ + +# include "lapi/syscalls.h" + +# ifdef HAVE_LINUX_CLOSE_RANGE_H +# include +# endif + +# ifndef CLOSE_RANGE_UNSHARE +# define CLOSE_RANGE_UNSHARE (1U << 1) +# endif + +# ifndef CLOSE_RANGE_CLOEXEC +# define CLOSE_RANGE_CLOEXEC (1U << 2) +# endif + +# ifndef HAVE_CLOSE_RANGE +static inline int close_range(unsigned int fd, unsigned int max_fd, + unsigned int flags) +{ + return tst_syscall(__NR_close_range, fd, max_fd, flags); +} +# endif +#endif /* LAPI_CLOSE_RANGE_H__ */ diff --git a/include/lapi/common_timers.h b/include/lapi/common_timers.h old mode 100644 new mode 100755 index b783beff4f8b7186d72925a0f03070df3fd2ba55..8d88ac47a2acb94b96004d5282f2f5b29fd92a3a --- a/include/lapi/common_timers.h +++ b/include/lapi/common_timers.h @@ -4,15 +4,15 @@ * Keep all the common defines/checks for the timer tests here */ -#ifndef __COMMON_TIMERS_H__ -#define __COMMON_TIMERS_H__ +#ifndef LAPI_COMMON_TIMERS_H__ +#define LAPI_COMMON_TIMERS_H__ #include "config.h" #include "lapi/syscalls.h" #include "lapi/posix_clocks.h" #ifndef NSEC_PER_SEC -#define NSEC_PER_SEC (1000000000L) +#define NSEC_PER_SEC (1000000000LL) #endif static const clock_t clock_list[] = { @@ -78,4 +78,4 @@ static inline int have_cputime_timers(void) */ typedef int kernel_timer_t; -#endif +#endif /* LAPI_COMMON_TIMERS_H__ */ diff --git a/include/lapi/cpuset.h b/include/lapi/cpuset.h old mode 100644 new mode 100755 index 8f7136c3b546753cf4762aae3ab51b8b682aa2c8..f4d62e3ee61d25a6ac9c11aade7dad46f28d844d --- a/include/lapi/cpuset.h +++ b/include/lapi/cpuset.h @@ -17,8 +17,8 @@ #define _GNU_SOURCE #include -#ifndef LTP_CPUSET_H -#define LTP_CPUSET_H +#ifndef LAPI_CPUSET_H__ +#define LAPI_CPUSET_H__ #ifndef CPU_ALLOC #define CPU_ALLOC(ncpus) malloc(sizeof(cpu_set_t)); \ @@ -48,4 +48,4 @@ if (ncpus > CPU_SETSIZE) { \ #define CPU_ISSET_S(cpu, size, mask) CPU_ISSET(cpu, mask) #endif -#endif /* LTP_CPUSET_H */ +#endif /* LAPI_CPUSET_H__ */ diff --git a/include/lapi/cryptouser.h b/include/lapi/cryptouser.h old mode 100644 new mode 100755 index e92fe96fb9b45dd2f18df30620c08fcce7c50e9f..31d1c345345ad875ee277fc4afdc3457013adb23 --- a/include/lapi/cryptouser.h +++ b/include/lapi/cryptouser.h @@ -3,8 +3,8 @@ * Copyright (c) 2018 Richard Palethorpe */ -#ifndef CRYPTOUSER_H__ -#define CRYPTOUSER_H__ +#ifndef LAPI_CRYPTOUSER_H__ +#define LAPI_CRYPTOUSER_H__ #ifdef HAVE_LINUX_CRYPTOUSER_H # include @@ -179,4 +179,4 @@ struct crypto_report_acomp { # define CRYPTO_ALG_TYPE_ACOMPRESS_MASK 0x0000000e #endif -#endif /* CRYPTOUSER_H__ */ +#endif /* LAPI_CRYPTOUSER_H__ */ diff --git a/include/lapi/dccp.h b/include/lapi/dccp.h old mode 100644 new mode 100755 diff --git a/include/lapi/epoll.h b/include/lapi/epoll.h old mode 100644 new mode 100755 index 899eeb9d427315a2aff89d6fb31f858efe548fe3..fc068ae20c80c588f36f937aa7aad432dc651720 --- a/include/lapi/epoll.h +++ b/include/lapi/epoll.h @@ -1,13 +1,58 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* +/* SPDX-License-Identifier: GPL-2.0-or-later + * * Copyright (c) 2016 Cyril Hrubis + * Copyright (c) 2021 Xie Ziyao */ #ifndef LAPI_EPOLL_H__ #define LAPI_EPOLL_H__ +#include "lapi/syscalls.h" +#include "tst_timer.h" + #ifndef EPOLL_CLOEXEC -# define EPOLL_CLOEXEC 02000000 +#define EPOLL_CLOEXEC 02000000 +#endif + +static inline void epoll_pwait_supported(void) +{ + /* allow the tests to fail early */ + tst_syscall(__NR_epoll_pwait); +} + +#ifndef HAVE_EPOLL_PWAIT +static inline int epoll_pwait(int epfd, struct epoll_event *events, + int maxevents, int timeout, + const sigset_t *sigmask) +{ + return tst_syscall(__NR_epoll_pwait, epfd, events, maxevents, + timeout, sigmask, _NSIG / 8); +} +#endif + +static inline void epoll_pwait2_supported(void) +{ + /* allow the tests to fail early */ + tst_syscall(__NR_epoll_pwait2); +} + +#ifndef HAVE_EPOLL_PWAIT2 +static inline int epoll_pwait2(int epfd, struct epoll_event *events, + int maxevents, const struct timespec *timeout, + const sigset_t *sigmask) +{ + if (timeout == NULL) + return tst_syscall(__NR_epoll_pwait2, epfd, events, maxevents, + NULL, sigmask, _NSIG / 8); + + struct __kernel_timespec ts; + + ts.tv_sec = timeout->tv_sec; + ts.tv_nsec = timeout->tv_nsec; + + return tst_syscall(__NR_epoll_pwait2, epfd, events, maxevents, + &ts, sigmask, _NSIG / 8); +} #endif #endif /* LAPI_EPOLL_H__ */ diff --git a/include/lapi/execveat.h b/include/lapi/execveat.h old mode 100644 new mode 100755 index a7406f7c017e4f0b178d482b28b791dc87df2cb4..de4963b3f7d0b494fd0174c5ba9c77575d92074c --- a/include/lapi/execveat.h +++ b/include/lapi/execveat.h @@ -3,20 +3,20 @@ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. */ -#ifndef EXECVEAT_H -#define EXECVEAT_H +#ifndef LAPI_EXECVEAT_H__ +#define LAPI_EXECVEAT_H__ #include #include "config.h" #include "lapi/syscalls.h" #if !defined(HAVE_EXECVEAT) -int execveat(int dirfd, const char *pathname, - char *const argv[], char *const envp[], - int flags) +static inline int execveat(int dirfd, const char *pathname, + char *const argv[], char *const envp[], + int flags) { return tst_syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); } #endif -#endif /* EXECVEAT_H */ +#endif /* LAPI_EXECVEAT_H__ */ diff --git a/include/lapi/fallocate.h b/include/lapi/fallocate.h old mode 100644 new mode 100755 index 72f52c78f5c79fb06fac14fd2311072abde40a23..92b6994a43d7c6a7aa3fa625200fcb10bb7bf6ae --- a/include/lapi/fallocate.h +++ b/include/lapi/fallocate.h @@ -4,8 +4,8 @@ * Copyright (c) 2014 Fujitsu Ltd. */ -#ifndef FALLOCATE_H -#define FALLOCATE_H +#ifndef LAPI_FALLOCATE_H__ +#define LAPI_FALLOCATE_H__ #include #include @@ -57,4 +57,4 @@ static inline long fallocate(int fd, int mode, loff_t offset, loff_t len) } #endif -#endif /* FALLOCATE_H */ +#endif /* LAPI_FALLOCATE_H__ */ diff --git a/include/lapi/fcntl.h b/include/lapi/fcntl.h old mode 100644 new mode 100755 index 576a18daf1dcc1d285ed1dd34c4532a94109cb68..8a0a893f978ecd7552c1438870fd5e75b61cbde3 --- a/include/lapi/fcntl.h +++ b/include/lapi/fcntl.h @@ -3,9 +3,10 @@ * Copyright (c) 2014 Cyril Hrubis */ -#ifndef __LAPI_FCNTL_H__ -#define __LAPI_FCNTL_H__ +#ifndef LAPI_FCNTL_H__ +#define LAPI_FCNTL_H__ +#include "config.h" #include #include @@ -136,4 +137,17 @@ # define SPLICE_F_NONBLOCK 2 #endif -#endif /* __LAPI_FCNTL_H__ */ +#ifndef MAX_HANDLE_SZ +# define MAX_HANDLE_SZ 128 +#endif + +#ifndef HAVE_STRUCT_FILE_HANDLE +struct file_handle { + unsigned int handle_bytes; + int handle_type; + /* File identifier. */ + unsigned char f_handle[0]; +}; +#endif /* HAVE_STRUCT_FILE_HANDLE */ + +#endif /* LAPI_FCNTL_H__ */ diff --git a/include/lapi/fnmatch.h b/include/lapi/fnmatch.h old mode 100644 new mode 100755 index 9628ac4407993fb7372f6b583aa1938b888bb7a1..3bfd6e71e22d89f8f1c4c48674170d94788aedfb --- a/include/lapi/fnmatch.h +++ b/include/lapi/fnmatch.h @@ -4,11 +4,11 @@ * Author: Rafael David Tinoco */ -#ifndef FNMATCH_H__ -#define FNMATCH_H__ +#ifndef LAPI_FNMATCH_H__ +#define LAPI_FNMATCH_H__ #ifndef FNM_EXTMATCH #define FNM_EXTMATCH 0 #endif -#endif +#endif /* LAPI_FNMATCH_H__ */ diff --git a/include/lapi/fs.h b/include/lapi/fs.h old mode 100644 new mode 100755 index 430d21f27158b183d14935ab01cc5bb31c127ca0..aafeab4451a7e0c0bfebf769a1991c52ee541e0c --- a/include/lapi/fs.h +++ b/include/lapi/fs.h @@ -14,8 +14,8 @@ #include #include "lapi/abisize.h" -#ifndef LAPI_FS_H -#define LAPI_FS_H +#ifndef LAPI_FS_H__ +#define LAPI_FS_H__ #ifndef FS_IOC_GETFLAGS #define FS_IOC_GETFLAGS _IOR('f', 1, long) @@ -63,4 +63,4 @@ static inline loff_t tst_max_lfs_filesize(void) #endif } -#endif +#endif /* LAPI_FS_H__ */ diff --git a/include/lapi/fsmount.h b/include/lapi/fsmount.h old mode 100644 new mode 100755 index 09a2c1611866cbe4047bc5f5f3174543328ff213..fa2530675575dbf8f9b10dfd9dffc23d14b35190 --- a/include/lapi/fsmount.h +++ b/include/lapi/fsmount.h @@ -4,8 +4,8 @@ * Author: Viresh Kumar */ -#ifndef FSMOUNT_H__ -#define FSMOUNT_H__ +#ifndef LAPI_FSMOUNT_H__ +#define LAPI_FSMOUNT_H__ #include #include @@ -16,37 +16,38 @@ #include "lapi/syscalls.h" #ifndef HAVE_FSOPEN -int fsopen(const char *fsname, unsigned int flags) +static inline int fsopen(const char *fsname, unsigned int flags) { return tst_syscall(__NR_fsopen, fsname, flags); } #endif /* HAVE_FSOPEN */ #ifndef HAVE_FSCONFIG -int fsconfig(int fd, unsigned int cmd, const char *key, - const void *value, int aux) +static inline int fsconfig(int fd, unsigned int cmd, const char *key, + const void *value, int aux) { return tst_syscall(__NR_fsconfig, fd, cmd, key, value, aux); } #endif /* HAVE_FSCONFIG */ #ifndef HAVE_FSMOUNT -int fsmount(int fd, unsigned int flags, unsigned int mount_attrs) +static inline int fsmount(int fd, unsigned int flags, unsigned int mount_attrs) { return tst_syscall(__NR_fsmount, fd, flags, mount_attrs); } #endif /* HAVE_FSMOUNT */ #ifndef HAVE_FSPICK -int fspick(int dirfd, const char *pathname, unsigned int flags) +static inline int fspick(int dirfd, const char *pathname, unsigned int flags) { return tst_syscall(__NR_fspick, dirfd, pathname, flags); } #endif /* HAVE_FSPICK */ #ifndef HAVE_MOVE_MOUNT -int move_mount(int from_dirfd, const char *from_pathname, int to_dirfd, - const char *to_pathname, unsigned int flags) +static inline int move_mount(int from_dirfd, const char *from_pathname, + int to_dirfd, const char *to_pathname, + unsigned int flags) { return tst_syscall(__NR_move_mount, from_dirfd, from_pathname, to_dirfd, to_pathname, flags); @@ -54,7 +55,7 @@ int move_mount(int from_dirfd, const char *from_pathname, int to_dirfd, #endif /* HAVE_MOVE_MOUNT */ #ifndef HAVE_OPEN_TREE -int open_tree(int dirfd, const char *pathname, unsigned int flags) +static inline int open_tree(int dirfd, const char *pathname, unsigned int flags) { return tst_syscall(__NR_open_tree, dirfd, pathname, flags); } @@ -130,16 +131,18 @@ enum fsconfig_command { #endif /* OPEN_TREE_CLONE */ -void fsopen_supported_by_kernel(void) +static inline void fsopen_supported_by_kernel(void) { + long ret; + if ((tst_kvercmp(5, 2, 0)) < 0) { /* Check if the syscall is backported on an older kernel */ - TEST(syscall(__NR_fsopen, NULL, 0)); - if (TST_RET != -1) - SAFE_CLOSE(TST_RET); - else if (TST_ERR == ENOSYS) + ret = syscall(__NR_fsopen, NULL, 0); + if (ret != -1) + SAFE_CLOSE(ret); + else if (errno == ENOSYS) tst_brk(TCONF, "Test not supported on kernel version < v5.2"); } } -#endif /* FSMOUNT_H__ */ +#endif /* LAPI_FSMOUNT_H__ */ diff --git a/include/lapi/futex.h b/include/lapi/futex.h old mode 100644 new mode 100755 index 72209e4c9834f3dcf1f0fd5b7ad275578b5ac57b..00b26c355939e1d9fe1fbcc3d90bba0b23acfde3 --- a/include/lapi/futex.h +++ b/include/lapi/futex.h @@ -10,4 +10,8 @@ typedef volatile uint32_t futex_t; +#if !defined(SYS_futex) && defined(SYS_futex_time64) +#define SYS_futex SYS_futex_time64 +#endif + #endif /* LAPI_FUTEX_H__ */ diff --git a/include/lapi/getrandom.h b/include/lapi/getrandom.h old mode 100644 new mode 100755 index 83e0a0e053edd7a32393dd10510500b9141d5a9d..c654ca1ac9b6f801a84ffb5b8cf69af6ca5ff293 --- a/include/lapi/getrandom.h +++ b/include/lapi/getrandom.h @@ -3,8 +3,8 @@ * Copyright (c) 2015 Linux Test Project */ -#ifndef __GETRANDOM_H__ -#define __GETRANDOM_H__ +#ifndef LAPI_GETRANDOM_H__ +#define LAPI_GETRANDOM_H__ #include "config.h" @@ -27,4 +27,4 @@ # define GRND_RANDOM 0x0002 #endif -#endif /* __GETRANDOM_H__ */ +#endif /* LAPI_GETRANDOM_H__ */ diff --git a/include/lapi/if_addr.h b/include/lapi/if_addr.h new file mode 100755 index 0000000000000000000000000000000000000000..0f7e44784e9905c8fc570a933d6abb0f587cb428 --- /dev/null +++ b/include/lapi/if_addr.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Petr Vorel + */ + +#ifndef LAPI_IF_ADDR_H__ +#define LAPI_IF_ADDR_H__ + +#include + +#ifndef IFA_FLAGS +# define IFA_FLAGS 8 +#endif + +#ifndef IFA_F_NOPREFIXROUTE +# define IFA_F_NOPREFIXROUTE 0x200 +#endif + +#endif /* LAPI_IF_ADDR_H__ */ diff --git a/include/lapi/if_alg.h b/include/lapi/if_alg.h old mode 100644 new mode 100755 index 5a74df99b8d6218c0f27bf79ee36bb26d445ab81..466957e9ed98473bab3f9f3c27886a5139e964fa --- a/include/lapi/if_alg.h +++ b/include/lapi/if_alg.h @@ -3,14 +3,15 @@ * Copyright 2019 Google LLC */ -#ifndef IF_ALG_H__ -#define IF_ALG_H__ +#ifndef LAPI_IF_ALG_H__ +#define LAPI_IF_ALG_H__ #ifdef HAVE_LINUX_IF_ALG_H # include -#else +#endif # include +#ifndef HAVE_STRUCT_SOCKADDR_ALG struct sockaddr_alg { uint16_t salg_family; uint8_t salg_type[14]; @@ -18,21 +19,41 @@ struct sockaddr_alg { uint32_t salg_mask; uint8_t salg_name[64]; }; +#endif +#ifndef HAVE_STRUCT_AF_ALG_IV struct af_alg_iv { uint32_t ivlen; uint8_t iv[0]; }; +#endif -#define ALG_SET_KEY 1 -#define ALG_SET_IV 2 -#define ALG_SET_OP 3 -#define ALG_SET_AEAD_ASSOCLEN 4 -#define ALG_SET_AEAD_AUTHSIZE 5 +#ifndef ALG_SET_KEY +# define ALG_SET_KEY 1 +#endif -#define ALG_OP_DECRYPT 0 -#define ALG_OP_ENCRYPT 1 +#ifndef ALG_SET_IV +# define ALG_SET_IV 2 +#endif -#endif /* !HAVE_LINUX_IF_ALG_H */ +#ifndef ALG_SET_OP +# define ALG_SET_OP 3 +#endif -#endif /* IF_ALG_H__ */ +#ifndef ALG_SET_AEAD_ASSOCLEN +# define ALG_SET_AEAD_ASSOCLEN 4 +#endif + +#ifndef ALG_SET_AEAD_AUTHSIZE +# define ALG_SET_AEAD_AUTHSIZE 5 +#endif + +#ifndef ALG_OP_DECRYPT +# define ALG_OP_DECRYPT 0 +#endif + +#ifndef ALG_OP_ENCRYPT +# define ALG_OP_ENCRYPT 1 +#endif + +#endif /* LAPI_IF_ALG_H__ */ diff --git a/include/lapi/if_ether.h b/include/lapi/if_ether.h new file mode 100755 index 0000000000000000000000000000000000000000..536d1863a093ee3b225902725f4973813b866762 --- /dev/null +++ b/include/lapi/if_ether.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 SUSE LLC + */ + +#ifndef LAPI_IF_ETHER_H__ +#define LAPI_IF_ETHER_H__ + +#include "config.h" + +#ifdef HAVE_LINUX_IF_ETHER_H +# include +#endif + +#ifndef ETH_P_ALL +# define ETH_P_ALL 0x0003 +#endif + +#endif /* LAPI_IF_ETHER_H__ */ diff --git a/include/lapi/if_packet.h b/include/lapi/if_packet.h old mode 100644 new mode 100755 index c077b564d892d717ced978f7c95a79593889b32e..8c6c2e0e2f6c55e8cff39699221de9e68c835759 --- a/include/lapi/if_packet.h +++ b/include/lapi/if_packet.h @@ -4,15 +4,51 @@ * Author: Jinhui huang */ -#ifndef __LAPI_IF_PACKET_H__ -#define __LAPI_IF_PACKET_H__ +#ifndef LAPI_IF_PACKET_H__ +#define LAPI_IF_PACKET_H__ + +#include "config.h" + +#ifdef HAVE_LINUX_IF_PACKET_H +# include +#endif + +#ifndef PACKET_RX_RING +# define PACKET_RX_RING 5 +#endif + +#ifndef PACKET_VERSION +# define PACKET_VERSION 10 +#endif + +#ifndef PACKET_RESERVE +# define PACKET_RESERVE 12 +#endif + +#ifndef PACKET_VNET_HDR +# define PACKET_VNET_HDR 15 +#endif #ifndef PACKET_FANOUT -#define PACKET_FANOUT 18 +# define PACKET_FANOUT 18 #endif #ifndef PACKET_FANOUT_ROLLOVER -#define PACKET_FANOUT_ROLLOVER 3 +# define PACKET_FANOUT_ROLLOVER 3 +#endif + +#ifndef HAVE_STRUCT_TPACKET_REQ3 +# define TPACKET_V3 2 + +struct tpacket_req3 { + unsigned int tp_block_size; + unsigned int tp_block_nr; + unsigned int tp_frame_size; + unsigned int tp_frame_nr; + unsigned int tp_retire_blk_tov; + unsigned int tp_sizeof_priv; + unsigned int tp_feature_req_word; +}; #endif -#endif /* __LAPI_IF_PACKET_H__ */ +#endif /* LAPI_IF_PACKET_H__ */ diff --git a/include/lapi/init_module.h b/include/lapi/init_module.h new file mode 100755 index 0000000000000000000000000000000000000000..8c820059a7586b0ac26f425d02228ab5c1fe4fb7 --- /dev/null +++ b/include/lapi/init_module.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_INIT_MODULE_H__ +#define LAPI_INIT_MODULE_H__ + +#include "config.h" +#include "lapi/syscalls.h" +#include "tst_test.h" + +static inline int init_module(void *module_image, unsigned long len, + const char *param_values) +{ + return tst_syscall(__NR_init_module, module_image, len, param_values); +} + +static inline int finit_module(int fd, const char *param_values, int flags) +{ + return tst_syscall(__NR_finit_module, fd, param_values, flags); +} + +static inline void finit_module_supported_by_kernel(void) +{ + long ret; + + if ((tst_kvercmp(3, 8, 0)) < 0) { + /* Check if the syscall is backported on an older kernel */ + ret = syscall(__NR_finit_module, 0, "", 0); + if (ret == -1 && errno == ENOSYS) + tst_brk(TCONF, "Test not supported on kernel version < v3.8"); + } +} + +#endif /* LAPI_INIT_MODULE_H__ */ diff --git a/include/lapi/io_pgetevents.h b/include/lapi/io_pgetevents.h old mode 100644 new mode 100755 index 3c9d5b2d7618db5674d9fbd89f83def1ba246484..4ab13a6d461bd11a3f12b01703678b35618ca7a7 --- a/include/lapi/io_pgetevents.h +++ b/include/lapi/io_pgetevents.h @@ -4,8 +4,8 @@ * Author: Viresh Kumar */ -#ifndef IO_PGETEVENTS_H -#define IO_PGETEVENTS_H +#ifndef LAPI_IO_PGETEVENTS_H__ +#define LAPI_IO_PGETEVENTS_H__ #include #include @@ -16,15 +16,20 @@ #ifdef HAVE_LIBAIO #include -#ifndef HAVE_IO_PGETEVENTS -int io_pgetevents(io_context_t ctx, long min_nr, long max_nr, - struct io_event *events, struct timespec *timeout, - sigset_t *sigmask) +static inline int sys_io_pgetevents(io_context_t ctx, long min_nr, long max_nr, + struct io_event *events, void *timeout, sigset_t *sigmask) { return tst_syscall(__NR_io_pgetevents, ctx, min_nr, max_nr, events, timeout, sigmask); } -#endif /* HAVE_IO_PGETEVENTS */ + +static inline int sys_io_pgetevents_time64(io_context_t ctx, long min_nr, long max_nr, + struct io_event *events, void *timeout, sigset_t *sigmask) +{ + return tst_syscall(__NR_io_pgetevents_time64, ctx, min_nr, max_nr, + events, timeout, sigmask); +} + #endif /* HAVE_LIBAIO */ -#endif /* IO_PGETEVENTS_H */ +#endif /* LAPI_IO_PGETEVENTS_H__ */ diff --git a/include/lapi/io_uring.h b/include/lapi/io_uring.h old mode 100644 new mode 100755 index 5fde58e22cd4ca2f2f0fbc9d323f8074bb2184c1..397324511c7ec8e1f44caa82ae96d1205e3d3d61 --- a/include/lapi/io_uring.h +++ b/include/lapi/io_uring.h @@ -6,8 +6,8 @@ * Mostly copied/adapted from */ -#ifndef IO_URING_H__ -#define IO_URING_H__ +#ifndef LAPI_IO_URING_H__ +#define LAPI_IO_URING_H__ #include #include @@ -18,8 +18,16 @@ #include "lapi/syscalls.h" +#ifdef HAVE_LINUX_IO_URING_H +#include +#endif + #ifndef IOSQE_FIXED_FILE +#ifndef __kernel_rwf_t +typedef int __kernel_rwf_t; +#endif + /* * IO submission data structure (Submission Queue Entry) */ @@ -63,8 +71,6 @@ enum { IOSQE_FIXED_FILE_BIT, IOSQE_IO_DRAIN_BIT, IOSQE_IO_LINK_BIT, - IOSQE_IO_HARDLINK_BIT, - IOSQE_ASYNC_BIT, }; /* @@ -76,10 +82,6 @@ enum { #define IOSQE_IO_DRAIN (1U << IOSQE_IO_DRAIN_BIT) /* links next sqe */ #define IOSQE_IO_LINK (1U << IOSQE_IO_LINK_BIT) -/* like LINK, but stronger */ -#define IOSQE_IO_HARDLINK (1U << IOSQE_IO_HARDLINK_BIT) -/* always go async */ -#define IOSQE_ASYNC (1U << IOSQE_ASYNC_BIT) /* * io_uring_setup() flags @@ -254,10 +256,21 @@ struct io_uring_probe { #endif /* IOSQE_FIXED_FILE */ +#ifndef IOSQE_IO_HADRLINK +/* like LINK, but stronger */ +#define IOSQE_IO_HARDLINK_BIT 3 +#define IOSQE_IO_HARDLINK (1U << IOSQE_IO_HARDLINK_BIT) +#endif /* IOSQE_IO_HADRLINK */ + +#ifndef IOSQE_ASYNC +/* always go async */ +#define IOSQE_ASYNC_BIT 4 +#define IOSQE_ASYNC (1U << IOSQE_ASYNC_BIT) +#endif /* IOSQE_ASYNC */ #ifndef HAVE_IO_URING_REGISTER -int io_uring_register(int fd, unsigned int opcode, void *arg, - unsigned int nr_args) +static inline int io_uring_register(int fd, unsigned int opcode, void *arg, + unsigned int nr_args) { return tst_syscall(__NR_io_uring_register, fd, opcode, arg, nr_args); } @@ -265,19 +278,33 @@ int io_uring_register(int fd, unsigned int opcode, void *arg, #ifndef HAVE_IO_URING_SETUP -int io_uring_setup(unsigned int entries, struct io_uring_params *p) +static inline int io_uring_setup(unsigned int entries, + struct io_uring_params *p) { return tst_syscall(__NR_io_uring_setup, entries, p); } #endif /* HAVE_IO_URING_SETUP */ #ifndef HAVE_IO_URING_ENTER -int io_uring_enter(int fd, unsigned int to_submit, unsigned int min_complete, - unsigned int flags, sigset_t *sig) +static inline int io_uring_enter(int fd, unsigned int to_submit, + unsigned int min_complete, unsigned int flags, sigset_t *sig) { return tst_syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, sig, _NSIG / 8); } #endif /* HAVE_IO_URING_ENTER */ -#endif /* IO_URING_H__ */ +static inline void io_uring_setup_supported_by_kernel(void) +{ + long ret; + if ((tst_kvercmp(5, 1, 0)) < 0) { + ret = syscall(__NR_io_uring_setup, NULL, 0); + if (ret != -1) + SAFE_CLOSE(ret); + else if (errno == ENOSYS) + tst_brk(TCONF, + "Test not supported on kernel version < v5.1"); + } +} + +#endif /* LAPI_IO_URING_H__ */ diff --git a/include/lapi/ioctl.h b/include/lapi/ioctl.h old mode 100644 new mode 100755 index ecd250290794bf24945dfe9ca85e0b7e941bb5be..f91a9e68c1e13bd08f684e91a9b3b3cdff2d8f64 --- a/include/lapi/ioctl.h +++ b/include/lapi/ioctl.h @@ -4,8 +4,8 @@ * Copyright (c) 2020 Petr Vorel */ -#ifndef IOCTL_H__ -#define IOCTL_H__ +#ifndef LAPI_IOCTL_H__ +#define LAPI_IOCTL_H__ #include "config.h" #include @@ -37,4 +37,4 @@ struct termio }; #endif /* HAVE_STRUCT_TERMIO */ -#endif /* IOCTL_H__ */ +#endif /* LAPI_IOCTL_H__ */ diff --git a/include/lapi/ioctl_ns.h b/include/lapi/ioctl_ns.h old mode 100644 new mode 100755 index 2fb4f4cfb5fe73df63717adf028276e197f48f51..9c81d5ce20f299e8e8d6565317c608f805dc74c9 --- a/include/lapi/ioctl_ns.h +++ b/include/lapi/ioctl_ns.h @@ -3,8 +3,8 @@ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com */ -#ifndef IOCTL_NS_H__ -#define IOCTL_NS_H__ +#ifndef LAPI_IOCTL_NS_H__ +#define LAPI_IOCTL_NS_H__ #include @@ -25,4 +25,4 @@ #endif -#endif /* IOCTL_NS_H__ */ +#endif /* LAPI_IOCTL_NS_H__ */ diff --git a/include/lapi/iovec.h b/include/lapi/iovec.h old mode 100644 new mode 100755 index d479e9f850d80d54188725a66cb169a1ce00cfb3..8d9fe1036ebc50994e4e53b456eeb586332c83d3 --- a/include/lapi/iovec.h +++ b/include/lapi/iovec.h @@ -3,8 +3,8 @@ * Copyright (c) 2014 Cyril Hrubis */ -#ifndef IOVEC_H -#define IOVEC_H +#ifndef LAPI_IOVEC_H__ +#define LAPI_IOVEC_H__ #include "config.h" @@ -17,4 +17,4 @@ struct iovec { # include #endif -#endif /* IOVEC_H */ +#endif /* LAPI_IOVEC_H__ */ diff --git a/include/lapi/ip_tables.h b/include/lapi/ip_tables.h new file mode 100755 index 0000000000000000000000000000000000000000..d0ed33324863e942fa2aceff4adef9f17b83958a --- /dev/null +++ b/include/lapi/ip_tables.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef LAPI_IP_TABLES__ +#define LAPI_IP_TABLES__ + +#include "config.h" + +#include +#include + +#ifndef HAVE_STRUCT_XT_ENTRY_MATCH +struct xt_entry_match { + union { + struct { + uint16_t match_size; + char name[29]; + uint8_t revision; + } user; + struct { + uint16_t match_size; + void *match; + } kernel; + uint16_t match_size; + } u; + unsigned char data[0]; +}; +#endif + +#ifndef HAVE_STRUCT_XT_ENTRY_TARGET +struct xt_entry_target { + union { + struct { + uint16_t target_size; + char name[29]; + uint8_t revision; + } user; + struct { + uint16_t target_size; + void *target; + } kernel; + uint16_t target_size; + } u; + unsigned char data[0]; +}; +#endif + +#endif /* LAPI_IP_TABLES__ */ diff --git a/include/lapi/ipcbuf.h b/include/lapi/ipcbuf.h new file mode 100755 index 0000000000000000000000000000000000000000..ee0a9bafb0040ad1e905e103e0cccb77db111e0f --- /dev/null +++ b/include/lapi/ipcbuf.h @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_IPCBUF_H__ +#define LAPI_IPCBUF_H__ + +#include "config.h" +#include "lapi/posix_types.h" + +#ifndef HAVE_IPC64_PERM + +#if defined(__hppa__) +#define HAVE_IPC64_PERM +/* + * The ipc64_perm structure for PA-RISC is almost identical to + * kern_ipc_perm as we have always had 32-bit UIDs and GIDs in the kernel. + * 'seq' has been changed from long to int so that it's the same size + * on 64-bit kernels as on 32-bit ones. + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_uid_t cuid; + __kernel_gid_t cgid; +#if __BITS_PER_LONG != 64 + unsigned short int __pad1; +#endif + __kernel_mode_t mode; + unsigned short int __pad2; + unsigned short int seq; + unsigned int __pad3; + unsigned long long int __unused1; + unsigned long long int __unused2; +}; +#endif /* __hppa__ */ + +#if defined(__powerpc__) || defined(__powerpc64__) +#define HAVE_IPC64_PERM +/* + * The ipc64_perm structure for the powerpc is identical to + * kern_ipc_perm as we have always had 32-bit UIDs and GIDs in the + * kernel. Note extra padding because this structure is passed back + * and forth between kernel and user space. Pad space is left for: + * - 1 32-bit value to fill up for 8-byte alignment + * - 2 miscellaneous 64-bit values + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_uid_t cuid; + __kernel_gid_t cgid; + __kernel_mode_t mode; + unsigned int seq; + unsigned int __pad1; + unsigned long long __unused1; + unsigned long long __unused2; +}; + +#endif /* defined(__powerpc__) || defined(__powerpc64__) */ + +#if defined(__s390__) +#define HAVE_IPC64_PERM +/* + * The user_ipc_perm structure for S/390 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; +#ifndef __s390x__ + unsigned short __pad2; +#endif /* ! __s390x__ */ + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* defined(__powerpc__) || defined(__powerpc64__) */ + +#if defined(__sparc__) +#define HAVE_IPC64_PERM +/* + * The ipc64_perm structure for sparc/sparc64 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit seq + * - on sparc for 32 bit mode (it is 32 bit on sparc64) + * - 2 miscellaneous 64-bit values + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; +#ifndef __arch64__ + unsigned short __pad0; +#endif + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned long long __unused1; + unsigned long long __unused2; +}; + +#endif /* __sparc__ */ + +#if defined(__xtensa__) +#define HAVE_IPC64_PERM +/* + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + unsigned long seq; + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __xtensa__ */ + +#ifndef HAVE_IPC64_PERM +/* + * The generic ipc64_perm structure: + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * ipc64_perm was originally meant to be architecture specific, but + * everyone just ended up making identical copies without specific + * optimizations, so we may just as well all use the same one. + * + * Pad space is left for: + * - 32-bit mode_t on architectures that only had 16 bit + * - 32-bit seq + * - 2 miscellaneous 32-bit values + */ + +struct ipc64_perm { + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + /* pad if mode_t is u16: */ + unsigned char __pad1[4 - sizeof(__kernel_mode_t)]; + unsigned short seq; + unsigned short __pad2; + __kernel_ulong_t __unused1; + __kernel_ulong_t __unused2; +}; + +#endif /* ipc64_perm */ + +#endif /* HAVE_IPC64_PERM */ + +#endif /* LAPI_IPCBUF_H__ */ diff --git a/include/lapi/keyctl.h b/include/lapi/keyctl.h old mode 100644 new mode 100755 index c53876e961ad58573d31f440f0d18fc466653bee..d899345c9f0a74cb8a2327578d65e76bad6f5fb9 --- a/include/lapi/keyctl.h +++ b/include/lapi/keyctl.h @@ -3,8 +3,8 @@ * Copyright (c) 2017 Cyril Hrubis */ -#ifndef KEYCTL_H__ -#define KEYCTL_H__ +#ifndef LAPI_KEYCTL_H__ +#define LAPI_KEYCTL_H__ #include "config.h" @@ -175,4 +175,4 @@ static inline key_serial_t keyctl_join_session_keyring(const char *name) { # define KEY_OTH_ALL 0x0000003f #endif /* !KEY_POS_VIEW */ -#endif /* KEYCTL_H__ */ +#endif /* LAPI_KEYCTL_H__ */ diff --git a/include/lapi/loop.h b/include/lapi/loop.h old mode 100644 new mode 100755 index c693286136a314aab6b0a3d7da943a32a9afff4e..c663eea1ae523412f5f0605027a0d85284d7e67f --- a/include/lapi/loop.h +++ b/include/lapi/loop.h @@ -3,9 +3,10 @@ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. * Author: Yang Xu */ -#ifndef LAPI_LOOP_H -#define LAPI_LOOP_H +#ifndef LAPI_LOOP_H__ +#define LAPI_LOOP_H__ +#include "config.h" #include #include @@ -29,4 +30,26 @@ # define LOOP_SET_BLOCK_SIZE 0x4C09 #endif +#ifndef LOOP_CONFIGURE +# define LOOP_CONFIGURE 0x4C0A #endif + +#ifndef HAVE_STRUCT_LOOP_CONFIG +/* + * struct loop_config - Complete configuration for a loop device. + * @fd: fd of the file to be used as a backing file for the loop device. + * @block_size: block size to use; ignored if 0. + * @info: struct loop_info64 to configure the loop device with. + * + * This structure is used with the LOOP_CONFIGURE ioctl, and can be used to + * atomically setup and configure all loop device parameters at once. + */ +struct loop_config { + __u32 fd; + __u32 block_size; + struct loop_info64 info; + __u64 __reserved[8]; +}; +#endif + +#endif /* LAPI_LOOP_H__ */ diff --git a/include/lapi/membarrier.h b/include/lapi/membarrier.h old mode 100644 new mode 100755 index 2b6c57fb353e22252aac780c7844aa295042c8c2..eda63cd8a71889e8e9a45fab9827b9f5175e77fd --- a/include/lapi/membarrier.h +++ b/include/lapi/membarrier.h @@ -4,8 +4,8 @@ * Author: Rafael David Tinoco */ -#ifndef LAPI_MEMBARRIER_H -#define LAPI_MEMBARRIER_H +#ifndef LAPI_MEMBARRIER_H__ +#define LAPI_MEMBARRIER_H__ /* * Having is enough to know if the test should run or @@ -27,4 +27,4 @@ enum membarrier_cmd { MEMBARRIER_CMD_SHARED = MEMBARRIER_CMD_GLOBAL, }; -#endif +#endif /* LAPI_MEMBARRIER_H__ */ diff --git a/include/lapi/memfd.h b/include/lapi/memfd.h old mode 100644 new mode 100755 index e38e671bb0b3229a7c0994a0befb43c6d3b0cdec..57b6cd83d80c84abec5d0f38828a5bdba9073496 --- a/include/lapi/memfd.h +++ b/include/lapi/memfd.h @@ -3,8 +3,8 @@ * Copyright (C) 2017 Red Hat, Inc. */ -#ifndef LAPI_MEMFD_H -#define LAPI_MEMFD_H +#ifndef LAPI_MEMFD_H__ +#define LAPI_MEMFD_H__ /* flags for memfd_create(2) (unsigned int) */ #ifndef MFD_CLOEXEC @@ -47,4 +47,4 @@ #define MFD_HUGE_16GB (34 << 26) #endif -#endif +#endif /* LAPI_MEMFD_H__ */ diff --git a/include/lapi/mkdirat.h b/include/lapi/mkdirat.h old mode 100644 new mode 100755 index bb8c6d8695c00abf660693deb2a52a2af114c7de..4d452d684ae91f315b429a9e5ab2b8d888ec3f27 --- a/include/lapi/mkdirat.h +++ b/include/lapi/mkdirat.h @@ -3,18 +3,18 @@ * Copyright (c) 2014 Cyril Hrubis */ -#ifndef __MKDIRAT_H__ -#define __MKDIRAT_H__ +#ifndef LAPI_MKDIRAT_H__ +#define LAPI_MKDIRAT_H__ #include "config.h" #include "lapi/syscalls.h" #include "lapi/fcntl.h" #ifndef HAVE_MKDIRAT -int mkdirat(int dirfd, const char *dirname, int mode) +static inline int mkdirat(int dirfd, const char *dirname, int mode) { return ltp_syscall(__NR_mkdirat, dirfd, dirname, mode); } #endif -#endif /* __MKDIRAT_H__ */ +#endif /* LAPI_MKDIRAT_H__ */ diff --git a/include/lapi/mlock2.h b/include/lapi/mlock2.h old mode 100644 new mode 100755 index fa2b2de07cf13cfed1de5a7470a0467bea29308a..7b180eadad005ff151c4eaa748441bf9f6775bf3 --- a/include/lapi/mlock2.h +++ b/include/lapi/mlock2.h @@ -5,7 +5,7 @@ */ #ifndef LAPI_MLOCK2_H__ -# define LAPI_MLOCK2_H__ +#define LAPI_MLOCK2_H__ #include diff --git a/include/lapi/mmap.h b/include/lapi/mmap.h old mode 100644 new mode 100755 index b3db9412839a55e6390c54ff34642471a7f518b8..12845b76edb873b9f289eefbe56e9578162d92f7 --- a/include/lapi/mmap.h +++ b/include/lapi/mmap.h @@ -66,6 +66,16 @@ # define MADV_KEEPONFORK 19 #endif +#ifndef MAP_FIXED_NOREPLACE + +#ifdef __alpha__ +# define MAP_FIXED_NOREPLACE 0x200000 +#else +# define MAP_FIXED_NOREPLACE 0x100000 +#endif + +#endif /* MAP_FIXED_NOREPLACE */ + #ifdef HAVE_SYS_SHM_H # include # define MMAP_GRANULARITY SHMLBA diff --git a/include/lapi/mount.h b/include/lapi/mount.h old mode 100644 new mode 100755 index b8ae1f59469bceb805a8a89f881122c582050429..29054eef93f56dc5d7273e161a3762fb8f18a0dc --- a/include/lapi/mount.h +++ b/include/lapi/mount.h @@ -3,8 +3,8 @@ * Copyright (c) 2015 Cui Bixuan */ -#ifndef __MOUNT_H__ -#define __MOUNT_H__ +#ifndef LAPI_MOUNT_H__ +#define LAPI_MOUNT_H__ #ifndef MS_REC #define MS_REC 16384 @@ -30,4 +30,4 @@ #define UMOUNT_NOFOLLOW 8 #endif -#endif /* __MOUNT_H__ */ +#endif /* LAPI_MOUNT_H__ */ diff --git a/include/lapi/msg.h b/include/lapi/msg.h new file mode 100755 index 0000000000000000000000000000000000000000..ab37cdaac29be7eafcd656390a8a73fcf6bd104c --- /dev/null +++ b/include/lapi/msg.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +#ifndef LAPI_MSG_H__ +#define LAPI_MSG_H__ + +#include + +#ifndef MSG_COPY +# define MSG_COPY 040000 /* copy (not remove) all queue messages */ +#endif + +#ifndef MSG_STAT_ANY +# define MSG_STAT_ANY 13 +#endif + +#endif /* LAPI_MSG_H__ */ diff --git a/include/lapi/msgbuf.h b/include/lapi/msgbuf.h new file mode 100755 index 0000000000000000000000000000000000000000..9736b99bf4b6ef8d67756102d26662731107ee65 --- /dev/null +++ b/include/lapi/msgbuf.h @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_MSGBUF_H__ +#define LAPI_MSGBUF_H__ + +#include "lapi/posix_types.h" +#include +#include "tst_timer.h" +#include "ipcbuf.h" + +#ifndef HAVE_MSQID64_DS + +#if defined(__mips__) +#define HAVE_MSQID64_DS + +#if __BITS_PER_LONG == 64 +/* + * The msqid64_ds structure for the MIPS architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous unsigned long values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + long msg_stime; /* last msgsnd time */ + long msg_rtime; /* last msgrcv time */ + long msg_ctime; /* last change time */ + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; +#elif defined (__MIPSEB__) +#define HAVE_MSQID64_DS_TIME_HIGH +struct msqid64_ds { + struct ipc64_perm msg_perm; + unsigned long msg_stime_high; + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_rtime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_ctime_high; + unsigned long msg_ctime; /* last change time */ + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; +#elif defined (__MIPSEL__) +#define HAVE_MSQID64_DS_TIME_HIGH +struct msqid64_ds { + struct ipc64_perm msg_perm; + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_stime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_rtime_high; + unsigned long msg_ctime; /* last change time */ + unsigned long msg_ctime_high; + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; +#endif + +#endif /* __mips__ */ + +#if defined(__hppa__) +#define HAVE_MSQID64_DS +/* + * The msqid64_ds structure for parisc architecture, copied from sparc. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; +#if __BITS_PER_LONG == 64 + long msg_stime; /* last msgsnd time */ + long msg_rtime; /* last msgrcv time */ + long msg_ctime; /* last change time */ +#else +#define HAVE_MSQID64_DS_TIME_HIGH + unsigned long msg_stime_high; + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_rtime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_ctime_high; + unsigned long msg_ctime; /* last change time */ +#endif + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __hppa__ */ + +#if defined(__powerpc__) || defined(__powerpc64__) +#define HAVE_MSQID64_DS +/* + * The msqid64_ds structure for the PowerPC architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; +#ifdef __powerpc64__ + long msg_stime; /* last msgsnd time */ + long msg_rtime; /* last msgrcv time */ + long msg_ctime; /* last change time */ +#else +#define HAVE_MSQID64_DS_TIME_HIGH + unsigned long msg_stime_high; + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_rtime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_ctime_high; + unsigned long msg_ctime; /* last change time */ +#endif + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* defined(__powerpc__) || defined(__powerpc64__) */ + +#if defined(__sparc__) +#define HAVE_MSQID64_DS +/* + * The msqid64_ds structure for sparc64 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ +struct msqid64_ds { + struct ipc64_perm msg_perm; +#if defined(__arch64__) + long msg_stime; /* last msgsnd time */ + long msg_rtime; /* last msgrcv time */ + long msg_ctime; /* last change time */ +#else +#define HAVE_MSQID64_DS_TIME_HIGH + unsigned long msg_stime_high; + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_rtime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_ctime_high; + unsigned long msg_ctime; /* last change time */ +#endif + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __sparc__ */ + +#if defined(__x86_64__) && defined(__ILP32__) +#define HAVE_MSQID64_DS +/* + * The msqid64_ds structure for x86 architecture with x32 ABI. + * + * On x86-32 and x86-64 we can just use the generic definition, but + * x32 uses the same binary layout as x86_64, which is differnet + * from other 32-bit architectures. + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_long_t msg_stime; /* last msgsnd time */ + __kernel_long_t msg_rtime; /* last msgrcv time */ + __kernel_long_t msg_ctime; /* last change time */ + __kernel_ulong_t msg_cbytes; /* current number of bytes on queue */ + __kernel_ulong_t msg_qnum; /* number of messages in queue */ + __kernel_ulong_t msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + __kernel_ulong_t __unused4; + __kernel_ulong_t __unused5; +}; + +#endif /* defined(__x86_64__) && defined(__ILP32__) */ + +#if defined(__xtensa__) +#define HAVE_MSQID64_DS +/* + * The msqid64_ds structure for the Xtensa architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; +#ifdef __XTENSA_EB__ +#define HAVE_MSQID64_DS_TIME_HIGH + unsigned long msg_stime_high; + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_rtime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_ctime_high; + unsigned long msg_ctime; /* last change time */ +#elif defined(__XTENSA_EL__) +#define HAVE_MSQID64_DS_TIME_HIGH + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_stime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_rtime_high; + unsigned long msg_ctime; /* last change time */ + unsigned long msg_ctime_high; +#else +# error processor byte order undefined! +#endif + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* __xtensa__ */ + +#ifndef HAVE_MSQID64_DS +/* + * generic msqid64_ds structure. + * + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * msqid64_ds was originally meant to be architecture specific, but + * everyone just ended up making identical copies without specific + * optimizations, so we may just as well all use the same one. + * + * 64 bit architectures use a 64-bit long time field here, while + * 32 bit architectures have a pair of unsigned long values. + * On big-endian systems, the lower half is in the wrong place. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; +#if __BITS_PER_LONG == 64 + long msg_stime; /* last msgsnd time */ + long msg_rtime; /* last msgrcv time */ + long msg_ctime; /* last change time */ +#else +#define HAVE_MSQID64_DS_TIME_HIGH + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_stime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_rtime_high; + unsigned long msg_ctime; /* last change time */ + unsigned long msg_ctime_high; +#endif + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* msqid64_ds */ + +#endif /* HAVE_MSQID64_DS */ + +#endif /* LAPI_MSGBUF_H__ */ diff --git a/include/lapi/name_to_handle_at.h b/include/lapi/name_to_handle_at.h new file mode 100755 index 0000000000000000000000000000000000000000..bdc59b5497e88450b2c4001b89756f85ed90fb88 --- /dev/null +++ b/include/lapi/name_to_handle_at.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_NAME_TO_HANDLE_AT_H__ +#define LAPI_NAME_TO_HANDLE_AT_H__ + +#include +#include "config.h" +#include "lapi/syscalls.h" +#include "lapi/fcntl.h" +#include "tst_buffers.h" +#include "tst_test.h" + +#ifndef HAVE_NAME_TO_HANDLE_AT +static inline int name_to_handle_at(int dfd, const char *pathname, + struct file_handle *handle, + int *mount_id, int flags) +{ + return tst_syscall(__NR_name_to_handle_at, dfd, pathname, handle, + mount_id, flags); +} + +static inline int open_by_handle_at(int mount_fd, struct file_handle *handle, + int flags) +{ + return tst_syscall(__NR_open_by_handle_at, mount_fd, handle, flags); +} +#endif /* HAVE_NAME_TO_HANDLE_AT */ + +/* Returns a valid pointer on success, NULL on errors */ +static inline struct file_handle * +allocate_file_handle(int dfd, const char *pathname) +{ + long ret; + struct file_handle fh = {}, *fhp; + int mount_id; + + /* + * Make an initial call to name_to_handle_at() to discover the size + * required for the file handle. + */ + ret = name_to_handle_at(dfd, pathname, &fh, &mount_id, 0); + if (ret != -1 || errno != EOVERFLOW) { + tst_res(TFAIL | TERRNO, + "name_to_handle_at() should fail with EOVERFLOW"); + return NULL; + } + + /* Valid file handle */ + fhp = tst_alloc(sizeof(*fhp) + fh.handle_bytes); + fhp->handle_type = fh.handle_type; + fhp->handle_bytes = fh.handle_bytes; + + return fhp; +} + +#endif /* LAPI_NAME_TO_HANDLE_AT_H__ */ diff --git a/include/lapi/namespaces_constants.h b/include/lapi/namespaces_constants.h old mode 100644 new mode 100755 index 8f73c43026fb606eb9dadd4e5783f81e7672131d..447f16c5bda4ed58bf2ac65f52ca896225b32883 --- a/include/lapi/namespaces_constants.h +++ b/include/lapi/namespaces_constants.h @@ -3,8 +3,8 @@ * Copyright (c) 2015 Red Hat, Inc. */ -#ifndef __NAMESPACES_CONSTANTS_H__ -#define __NAMESPACES_CONSTANTS_H__ +#ifndef LAPI_NAMESPACES_CONSTANTS_H__ +#define LAPI_NAMESPACES_CONSTANTS_H__ #ifndef CLONE_NEWIPC # define CLONE_NEWIPC 0x08000000 @@ -28,4 +28,4 @@ # define CLONE_NEWTIME 0x00000080 #endif -#endif /* __NAMESPACES_CONSTANTS_H__ */ +#endif /* LAPI_NAMESPACES_CONSTANTS_H__ */ diff --git a/include/lapi/netinet_in.h b/include/lapi/netinet_in.h old mode 100644 new mode 100755 diff --git a/include/lapi/numaif.h b/include/lapi/numaif.h new file mode 100755 index 0000000000000000000000000000000000000000..4362b75c1a72b024da3ae81f8a4da80551b87870 --- /dev/null +++ b/include/lapi/numaif.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Linux Test Project + */ + +#ifndef LAPI_NUMAIF_H__ +#define LAPI_NUMAIF_H__ + +#ifndef MPOL_LOCAL +# define MPOL_LOCAL 4 +#endif + +#endif /* LAPI_NUMAIF_H__ */ diff --git a/include/lapi/openat2.h b/include/lapi/openat2.h old mode 100644 new mode 100755 index 62da1a04c8bc0471630521823293562f105ba054..03327bdb77bc81cb708ff9c011499bc0a12529ce --- a/include/lapi/openat2.h +++ b/include/lapi/openat2.h @@ -4,8 +4,8 @@ * Author: Viresh Kumar */ -#ifndef OPENAT2_H -#define OPENAT2_H +#ifndef LAPI_OPENAT2_H__ +#define LAPI_OPENAT2_H__ #include #include @@ -47,7 +47,8 @@ struct open_how { be scoped inside the dirfd (similar to chroot(2)). */ -int openat2(int dfd, const char *pathname, struct open_how *how, size_t size) +static inline int openat2(int dfd, const char *pathname, + struct open_how *how, size_t size) { return tst_syscall(__NR_openat2, dfd, pathname, how, size); } @@ -59,14 +60,16 @@ struct open_how_pad { uint64_t pad; }; -void openat2_supported_by_kernel(void) +static inline void openat2_supported_by_kernel(void) { + long ret; + if ((tst_kvercmp(5, 6, 0)) < 0) { /* Check if the syscall is backported on an older kernel */ - TEST(syscall(__NR_openat2, -1, NULL, NULL, 0)); - if (TST_RET == -1 && TST_ERR == ENOSYS) + ret = syscall(__NR_openat2, -1, NULL, NULL, 0); + if (ret == -1 && errno == ENOSYS) tst_brk(TCONF, "Test not supported on kernel version < v5.6"); } } -#endif /* OPENAT2_H */ +#endif /* LAPI_OPENAT2_H__ */ diff --git a/include/lapi/personality.h b/include/lapi/personality.h old mode 100644 new mode 100755 index 6b4b7ebf360c49a4c9818f35ce08edbdc7c10690..2cbb5dceb73fc33a19a34651e760fcef8c58b62d --- a/include/lapi/personality.h +++ b/include/lapi/personality.h @@ -7,8 +7,8 @@ * but in musl macros are used. */ -#ifndef PERSONALITY_H -#define PERSONALITY_H +#ifndef LAPI_PERSONALITY_H__ +#define LAPI_PERSONALITY_H__ #include @@ -20,4 +20,4 @@ # define READ_IMPLIES_EXEC 0x0400000 #endif -#endif /* PERSONALITY_H */ +#endif /* LAPI_PERSONALITY_H__ */ diff --git a/include/lapi/pidfd_open.h b/include/lapi/pidfd_open.h old mode 100644 new mode 100755 index 9f532f86e18e140abd816b224fdd046cd14600a2..9806c73d49d5847046ba43d9362528172af3c631 --- a/include/lapi/pidfd_open.h +++ b/include/lapi/pidfd_open.h @@ -4,8 +4,8 @@ * Author: Viresh Kumar */ -#ifndef PIDFD_OPEN_H -#define PIDFD_OPEN_H +#ifndef LAPI_PIDFD_OPEN_H__ +#define LAPI_PIDFD_OPEN_H__ #include #include @@ -15,10 +15,10 @@ #include "config.h" #ifndef HAVE_PIDFD_OPEN -int pidfd_open(pid_t pid, unsigned int flags) +static inline int pidfd_open(pid_t pid, unsigned int flags) { return tst_syscall(__NR_pidfd_open, pid, flags); } #endif -#endif /* PIDFD_OPEN_H */ +#endif /* LAPI_PIDFD_OPEN_H__ */ diff --git a/include/lapi/pidfd_send_signal.h b/include/lapi/pidfd_send_signal.h old mode 100644 new mode 100755 index 8352d2adf7875617d19d675e972cb7d26e69fc70..7426a91dad58a685148dc8050be3a320b1cf148d --- a/include/lapi/pidfd_send_signal.h +++ b/include/lapi/pidfd_send_signal.h @@ -4,8 +4,8 @@ * Author: Christian Amann */ -#ifndef PIDFD_SEND_SIGNAL_H -#define PIDFD_SEND_SIGNAL_H +#ifndef LAPI_PIDFD_SEND_SIGNAL_H__ +#define LAPI_PIDFD_SEND_SIGNAL_H__ #include "tst_test.h" #include "lapi/syscalls.h" @@ -17,11 +17,11 @@ static inline void pidfd_send_signal_supported(void) } #ifndef HAVE_PIDFD_SEND_SIGNAL -static int pidfd_send_signal(int pidfd, int sig, siginfo_t *info, - unsigned int flags) +static inline int pidfd_send_signal(int pidfd, int sig, siginfo_t *info, + unsigned int flags) { return tst_syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); } #endif /* HAVE_PIDFD_SEND_SIGNAL */ -#endif /* PIDFD_SEND_SIGNAL_H */ +#endif /* LAPI_PIDFD_SEND_SIGNAL_H__ */ diff --git a/include/lapi/posix_clocks.h b/include/lapi/posix_clocks.h old mode 100644 new mode 100755 index ae2139fe3acd8d227feaf2b9408df64ffa2f6344..d16f182eb368bef47b038d781cb7319472b8a8d4 --- a/include/lapi/posix_clocks.h +++ b/include/lapi/posix_clocks.h @@ -6,8 +6,8 @@ #include -#ifndef POSIX_CLOCKS_H__ -#define POSIX_CLOCKS_H__ +#ifndef LAPI_POSIX_CLOCKS_H__ +#define LAPI_POSIX_CLOCKS_H__ #define MAX_CLOCKS 16 @@ -39,4 +39,4 @@ #define CLOCK_TAI 11 #endif -#endif /* POSIX_CLOCKS_H__ */ +#endif /* LAPI_POSIX_CLOCKS_H__ */ diff --git a/include/lapi/posix_types.h b/include/lapi/posix_types.h new file mode 100755 index 0000000000000000000000000000000000000000..44f6697a9da998d381ac637dce3f67cb76e76d6f --- /dev/null +++ b/include/lapi/posix_types.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2014-2019 + */ + +#ifndef LAPI_POSIX_TYPES_H__ +#define LAPI_POSIX_TYPES_H__ + +#include + +#ifndef __kernel_long_t +# if defined(__x86_64__) && defined(__ILP32__) +typedef long long __kernel_long_t; +typedef unsigned long long __kernel_ulong_t; +# else +typedef long __kernel_long_t; +typedef unsigned long __kernel_ulong_t; +# endif +#endif + +#endif /* LAPI_POSIX_TYPES_H__ */ diff --git a/include/lapi/prctl.h b/include/lapi/prctl.h old mode 100644 new mode 100755 index 4499df0302c2448480aa557e6e930cc88b496c71..fa5922231ddecc51ff1a9a7200c4a7a0a8109a6d --- a/include/lapi/prctl.h +++ b/include/lapi/prctl.h @@ -5,7 +5,7 @@ */ #ifndef LAPI_PRCTL_H__ -# define LAPI_PRCTL_H__ +#define LAPI_PRCTL_H__ #include diff --git a/include/lapi/preadv2.h b/include/lapi/preadv2.h old mode 100644 new mode 100755 index 538ed72181012317fc0a5ab6750818ee60cd2b87..db89547e2db0bbc193d99efaf5f5c2b76b2a18c2 --- a/include/lapi/preadv2.h +++ b/include/lapi/preadv2.h @@ -4,8 +4,8 @@ * Author: Xiao Yang */ -#ifndef PREADV2_H -#define PREADV2_H +#ifndef LAPI_PREADV2_H__ +#define LAPI_PREADV2_H__ #include "config.h" #include "lapi/syscalls.h" @@ -19,12 +19,12 @@ /* LO_HI_LONG taken from glibc */ # define LO_HI_LONG(val) (long) (val), (long) (((uint64_t) (val)) >> 32) -ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, - int flags) +static inline ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt, + off_t offset, int flags) { return tst_syscall(__NR_preadv2, fd, iov, iovcnt, LO_HI_LONG(offset), flags); } #endif -#endif /* PREADV2_H */ +#endif /* LAPI_PREADV2_H__ */ diff --git a/include/lapi/pwritev2.h b/include/lapi/pwritev2.h old mode 100644 new mode 100755 index 305e48e028d1602d694a32e156c5a02131d88ebc..48b53f463b33161b6bbc9156261c7ea00c3209e0 --- a/include/lapi/pwritev2.h +++ b/include/lapi/pwritev2.h @@ -4,8 +4,8 @@ * Author: Jinhui Huang */ -#ifndef PWRITEV2_H -#define PWRITEV2_H +#ifndef LAPI_PWRITEV2_H__ +#define LAPI_PWRITEV2_H__ #include "config.h" #include "lapi/syscalls.h" @@ -15,12 +15,12 @@ /* LO_HI_LONG taken from glibc */ # define LO_HI_LONG(val) (long) (val), (long) (((uint64_t) (val)) >> 32) -ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, - int flags) +static inline ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, + off_t offset, int flags) { return tst_syscall(__NR_pwritev2, fd, iov, iovcnt, LO_HI_LONG(offset), flags); } #endif -#endif /* PWRITEV2_H */ +#endif /* LAPI_PWRITEV2_H__ */ diff --git a/include/lapi/quotactl.h b/include/lapi/quotactl.h old mode 100644 new mode 100755 index c1ec9d6e1f376f67d7adb67639180698bef9ed09..739a856163d5df31589940af9a02a7abf1d434c2 --- a/include/lapi/quotactl.h +++ b/include/lapi/quotactl.h @@ -1,14 +1,23 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2017-2019 Fujitsu Ltd. + * Copyright (c) 2017-2021 FUJITSU LIMITED. All rights reserved * Author: Xiao Yang - * Author: Yang Xu + * Author: Yang Xu */ #ifndef LAPI_QUOTACTL_H__ #define LAPI_QUOTACTL_H__ +#include "config.h" #include +#include "lapi/syscalls.h" + +#ifndef HAVE_QUOTACTL_FD +static inline int quotactl_fd(int fd, int cmd, int id, caddr_t addr) +{ + return tst_syscall(__NR_quotactl_fd, fd, cmd, id, addr); +} +#endif #ifdef HAVE_STRUCT_IF_NEXTDQBLK # include @@ -75,4 +84,12 @@ struct fs_quota_statv { # define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */ #endif +#ifndef QFMT_VFS_V0 +# define QFMT_VFS_V0 2 +#endif + +#ifndef QFMT_VFS_V1 +# define QFMT_VFS_V1 4 +#endif + #endif /* LAPI_QUOTACTL_H__ */ diff --git a/include/lapi/readdir.h b/include/lapi/readdir.h old mode 100644 new mode 100755 index 84e77ae0abc119e7a979bfbebabc7d18d3c370d2..ec82604a1e84b786d4c8c75716af0e58220af483 --- a/include/lapi/readdir.h +++ b/include/lapi/readdir.h @@ -4,8 +4,8 @@ * Author: Zeng Linggang */ -#ifndef READDIR_H -#define READDIR_H +#ifndef LAPI_READDIR_H__ +#define LAPI_READDIR_H__ #include @@ -16,4 +16,4 @@ struct old_linux_dirent { char d_name[NAME_MAX+1]; /* filename (null-terminated) */ }; -#endif /* READDIR_H */ +#endif /* LAPI_READDIR_H__ */ diff --git a/include/lapi/readlinkat.h b/include/lapi/readlinkat.h old mode 100644 new mode 100755 index 5a3a7b2d6056e3887187e59cc420488ef818c86b..bf1564823e8cf67908c930b7819249c83dff2054 --- a/include/lapi/readlinkat.h +++ b/include/lapi/readlinkat.h @@ -3,18 +3,19 @@ * Copyright (c) 2014 Cyril Hrubis */ -#ifndef __READLINKAT_H__ -#define __READLINKAT_H__ +#ifndef LAPI_READLINKAT_H__ +#define LAPI_READLINKAT_H__ #include "config.h" #include "lapi/syscalls.h" #include "lapi/fcntl.h" #ifndef HAVE_READLINKAT -int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) +static inline int readlinkat(int dirfd, const char *pathname, + char *buf, size_t bufsiz) { return ltp_syscall(__NR_readlinkat, dirfd, pathname, buf, bufsiz); } #endif -#endif /* __READLINKAT_H__ */ +#endif /* LAPI_READLINKAT_H__ */ diff --git a/include/lapi/renameat.h b/include/lapi/renameat.h old mode 100644 new mode 100755 index 66d3e214014df7eca4895eb47c5fdc7ec6df1c88..0a9e8e5956c93b732fc84cd3145fbf176c5d9c67 --- a/include/lapi/renameat.h +++ b/include/lapi/renameat.h @@ -4,20 +4,20 @@ * Copyright (c) 2014 Fujitsu Ltd. */ -#ifndef RENAMEAT_H -#define RENAMEAT_H +#ifndef LAPI_RENAMEAT_H__ +#define LAPI_RENAMEAT_H__ #include #include "config.h" #include "lapi/syscalls.h" #if !defined(HAVE_RENAMEAT) -int renameat(int olddirfd, const char *oldpath, int newdirfd, - const char *newpath) +static inline int renameat(int olddirfd, const char *oldpath, int newdirfd, + const char *newpath) { return ltp_syscall(__NR_renameat, olddirfd, oldpath, newdirfd, newpath); } #endif -#endif /* RENAMEAT_H */ +#endif /* LAPI_RENAMEAT_H__ */ diff --git a/include/lapi/rt_sigaction.h b/include/lapi/rt_sigaction.h old mode 100644 new mode 100755 index 3af91362f6c8bd97b18918fed2686014dbf77cd5..f368c07d8c43796c7abcb6855475f45018025257 --- a/include/lapi/rt_sigaction.h +++ b/include/lapi/rt_sigaction.h @@ -6,8 +6,8 @@ * Author: Ngie Cooper */ -#ifndef LTP_RT_SIGACTION_H -#define LTP_RT_SIGACTION_H +#ifndef LAPI_RT_SIGACTION_H__ +#define LAPI_RT_SIGACTION_H__ #include "ltp_signal.h" @@ -242,4 +242,4 @@ static int ltp_rt_sigaction(int signum, const struct sigaction *act, return ret; } -#endif /* LTP_RT_SIGACTION_H */ +#endif /* LAPI_RT_SIGACTION_H__ */ diff --git a/include/lapi/rtnetlink.h b/include/lapi/rtnetlink.h new file mode 100755 index 0000000000000000000000000000000000000000..089bf1a0d7cf2e1f001cd4659772b34ed6288509 --- /dev/null +++ b/include/lapi/rtnetlink.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2021 Petr Vorel */ + +#ifndef LAPI_RTNETLINK_H__ +# define LAPI_RTNETLINK_H__ + +#include +#include "lapi/if_addr.h" + +#endif /* LAPI_RTNETLINK_H__ */ diff --git a/include/lapi/safe_rt_signal.h b/include/lapi/safe_rt_signal.h old mode 100644 new mode 100755 index 67fa44417473ed03e4c72bae6198fd3434738325..952085608fc657f1458067a7a9d13081b49d328e --- a/include/lapi/safe_rt_signal.h +++ b/include/lapi/safe_rt_signal.h @@ -15,10 +15,15 @@ static inline int safe_rt_sigaction(const char *file, const int lineno, int ret; ret = ltp_rt_sigaction(signum, act, oact, sigsetsize); - if (ret < 0) { - tst_brk(TBROK | TERRNO, - "%s:%d: ltp_rt_sigaction(%i, %p, %p, %zu) failed", - file, lineno, signum, act, oact, sigsetsize); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "ltp_rt_sigaction(%i, %p, %p, %zu) failed", + signum, act, oact, sigsetsize); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid ltp_rt_sigaction(%i, %p, %p, %zu) return value %d", + signum, act, oact, sigsetsize, ret); } return ret; @@ -35,10 +40,14 @@ static inline int safe_rt_sigprocmask(const char *file, const int lineno, int ret; ret = tst_syscall(__NR_rt_sigprocmask, how, set, oldset, sigsetsize); - if (ret < 0) { - tst_brk(TBROK | TERRNO, - "%s:%d: rt_sigprocmask(%i, %p, %p, %zu) failed", - file, lineno, how, set, oldset, sigsetsize); + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "rt_sigprocmask(%i, %p, %p, %zu) failed", + how, set, oldset, sigsetsize); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid rt_sigprocmask(%i, %p, %p, %zu) return value %d", + how, set, oldset, sigsetsize, ret); } return ret; diff --git a/include/lapi/sched.h b/include/lapi/sched.h old mode 100644 new mode 100755 index 26fe445e95250d2c832c5156712f4d5712ad3b83..036edd51d1b667e84352a991b1b6688e5a9e868d --- a/include/lapi/sched.h +++ b/include/lapi/sched.h @@ -3,8 +3,8 @@ * Copyright (c) 2015 Cui Bixuan */ -#ifndef __SCHED_H__ -#define __SCHED_H__ +#ifndef LAPI_SCHED_H__ +#define LAPI_SCHED_H__ #include "lapi/syscalls.h" #include @@ -28,17 +28,14 @@ struct sched_attr { uint64_t sched_period; }; -int sched_setattr(pid_t pid, - const struct sched_attr *attr, - unsigned int flags) +static inline int sched_setattr(pid_t pid, const struct sched_attr *attr, + unsigned int flags) { return syscall(__NR_sched_setattr, pid, attr, flags); } -int sched_getattr(pid_t pid, - struct sched_attr *attr, - unsigned int size, - unsigned int flags) +static inline int sched_getattr(pid_t pid, struct sched_attr *attr, + unsigned int size, unsigned int flags) { return syscall(__NR_sched_getattr, pid, attr, size, flags); } @@ -59,4 +56,4 @@ int sched_getattr(pid_t pid, #define CLONE_IO 0x80000000 #endif -#endif /* __SCHED_H__ */ +#endif /* LAPI_SCHED_H__ */ diff --git a/include/lapi/sctp.h b/include/lapi/sctp.h old mode 100644 new mode 100755 diff --git a/include/lapi/seccomp.h b/include/lapi/seccomp.h old mode 100644 new mode 100755 index fe95cab1b26aff12ff3787ecb0f583095feaba6b..29819ba6fde4ca8a9b0b1864b2e962b46f26762f --- a/include/lapi/seccomp.h +++ b/include/lapi/seccomp.h @@ -3,8 +3,8 @@ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. * Author: Yang Xu */ -#ifndef LAPI_SECCOMP_H -#define LAPI_SECCOMP_H +#ifndef LAPI_SECCOMP_H__ +#define LAPI_SECCOMP_H__ #include @@ -37,4 +37,4 @@ struct seccomp_data { }; #endif /* HAVE_LINUX_SECCOMP_H*/ -#endif /* LAPI_SECCOMP_H */ +#endif /* LAPI_SECCOMP_H__ */ diff --git a/include/lapi/securebits.h b/include/lapi/securebits.h old mode 100644 new mode 100755 index 2da137c3a6e928cc30c39e57dc4daa07e36d6947..1b4d003c2a4ada4c0e326b90ce2968a1a8c76b9e --- a/include/lapi/securebits.h +++ b/include/lapi/securebits.h @@ -3,8 +3,8 @@ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. * Author: Yang Xu */ -#ifndef LAPI_SECUREBITS_H -#define LAPI_SECUREBITS_H +#ifndef LAPI_SECUREBITS_H__ +#define LAPI_SECUREBITS_H__ # ifdef HAVE_LINUX_SECUREBITS_H # include @@ -14,4 +14,4 @@ # define SECBIT_NO_CAP_AMBIENT_RAISE 6 # endif -#endif /* LAPI_SECUREBITS_H */ +#endif /* LAPI_SECUREBITS_H__ */ diff --git a/include/lapi/seek.h b/include/lapi/seek.h old mode 100644 new mode 100755 index 1a29ba45dcacb1b31ad5def50aed1b0770bc29af..7062ee8d47c3a9a695bac46a58686831fbe0b5b9 --- a/include/lapi/seek.h +++ b/include/lapi/seek.h @@ -3,8 +3,8 @@ * Copyright (c) 2017 Cyril Hrubis */ -#ifndef SEEK_H__ -#define SEEK_H__ +#ifndef LAPI_SEEK_H__ +#define LAPI_SEEK_H__ #include @@ -16,4 +16,4 @@ # define SEEK_HOLE 4 #endif -#endif /* SEEK_H__ */ +#endif /* LAPI_SEEK_H__ */ diff --git a/include/lapi/semun.h b/include/lapi/sem.h old mode 100644 new mode 100755 similarity index 79% rename from include/lapi/semun.h rename to include/lapi/sem.h index 1a9dc9803bee5e87d5a3fd02d77850f8d7bbf400..495afe9374f253c71900fdaaaf2a26b4909503bd --- a/include/lapi/semun.h +++ b/include/lapi/sem.h @@ -2,9 +2,10 @@ /* * Copyright (c) 2015 Linux Test Project */ +#ifndef LAPI_SEM_H__ +#define LAPI_SEM_H__ -#ifndef SEMUN_H__ -#define SEMUN_H__ +#include #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including */ @@ -19,4 +20,8 @@ union semun { }; #endif -#endif /* SEMUN_H__ */ +#ifndef SEM_STAT_ANY +# define SEM_STAT_ANY 20 +#endif + +#endif /* LAPI_SEM_H__ */ diff --git a/include/lapi/sembuf.h b/include/lapi/sembuf.h new file mode 100755 index 0000000000000000000000000000000000000000..94a43a291e4ffdd1965cf8392ff8a670b104576d --- /dev/null +++ b/include/lapi/sembuf.h @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_SEMBUF_H__ +#define LAPI_SEMBUF_H__ + +#include "lapi/posix_types.h" +#include +#include "tst_timer.h" +#include "ipcbuf.h" + +#ifndef HAVE_SEMID64_DS + +#if defined(__mips__) +#define HAVE_SEMID64_DS +/* + * The semid64_ds structure for the MIPS architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for 2 miscellaneous 64-bit values on mips64, + * but used for the upper 32 bit of the time values on mips32. + */ +#if __BITS_PER_LONG == 64 +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + long sem_otime; /* last semop time */ + long sem_ctime; /* last change time */ + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused1; + unsigned long __unused2; +}; +#else +#define HAVE_SEMID64_DS_TIME_HIGH +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + unsigned long sem_otime; /* last semop time */ + unsigned long sem_ctime; /* last change time */ + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long sem_otime_high; + unsigned long sem_ctime_high; +}; +#endif +#endif /* __mips__ */ + +#if defined(__hppa__) +#define HAVE_SEMID64_DS +/* + * The semid64_ds structure for parisc architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ +#if __BITS_PER_LONG == 64 + long sem_otime; /* last semop time */ + long sem_ctime; /* last change time */ +#else +#define HAVE_SEMID64_DS_TIME_HIGH + unsigned long sem_otime_high; + unsigned long sem_otime; /* last semop time */ + unsigned long sem_ctime_high; + unsigned long sem_ctime; /* last change time */ +#endif + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused1; + unsigned long __unused2; +}; +#endif /* __hppa__ */ + +#if defined(__powerpc__) || defined(__powerpc64__) +#define HAVE_SEMID64_DS +/* + * The semid64_ds structure for PPC architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32/64-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ +#ifndef __powerpc64__ +#define HAVE_SEMID64_DS_TIME_HIGH + unsigned long sem_otime_high; + unsigned long sem_otime; /* last semop time */ + unsigned long sem_ctime_high; + unsigned long sem_ctime; /* last change time */ +#else + long sem_otime; /* last semop time */ + long sem_ctime; /* last change time */ +#endif + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; +#endif /* defined(__powerpc__) || defined(__powerpc64__) */ + +#if defined(__sparc__) +#define HAVE_SEMID64_DS +/* + * The semid64_ds structure for sparc architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ +#if defined(__arch64__) + long sem_otime; /* last semop time */ + long sem_ctime; /* last change time */ +#else +#define HAVE_SEMID64_DS_TIME_HIGH + unsigned long sem_otime_high; + unsigned long sem_otime; /* last semop time */ + unsigned long sem_ctime_high; + unsigned long sem_ctime; /* last change time */ +#endif + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused1; + unsigned long __unused2; +}; +#endif /* __sparc__ */ + +#if defined(__x86_64__) +#define HAVE_SEMID64_DS +/* + * The semid64_ds structure for x86 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + * + * x86_64 and x32 incorrectly added padding here, so the structures + * are still incompatible with the padding on x86. + */ +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ +#ifdef __i386__ +#define HAVE_SEMID64_DS_TIME_HIGH + unsigned long sem_otime; /* last semop time */ + unsigned long sem_otime_high; + unsigned long sem_ctime; /* last change time */ + unsigned long sem_ctime_high; +#else + __kernel_long_t sem_otime; /* last semop time */ + __kernel_ulong_t __unused1; + __kernel_long_t sem_ctime; /* last change time */ + __kernel_ulong_t __unused2; +#endif + __kernel_ulong_t sem_nsems; /* no. of semaphores in array */ + __kernel_ulong_t __unused3; + __kernel_ulong_t __unused4; +}; +#endif /* defined(__x86_64__) */ + +#if defined(__xtensa__) +#define HAVE_SEMID64_DS +#define HAVE_SEMID64_DS_TIME_HIGH + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ +#ifdef __XTENSA_EL__ + unsigned long sem_otime; /* last semop time */ + unsigned long sem_otime_high; + unsigned long sem_ctime; /* last change time */ + unsigned long sem_ctime_high; +#else + unsigned long sem_otime_high; + unsigned long sem_otime; /* last semop time */ + unsigned long sem_ctime_high; + unsigned long sem_ctime; /* last change time */ +#endif + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* __xtensa__ */ + +#ifndef HAVE_SEMID64_DS +/* + * The semid64_ds structure for most architectures (though it came + * from x86_32 originally). Note extra padding because this structure + * is passed back and forth between kernel and user space. + * + * semid64_ds was originally meant to be architecture specific, but + * everyone just ended up making identical copies without specific + * optimizations, so we may just as well all use the same one. + * + * 64 bit architectures use a 64-bit long time field here, while + * 32 bit architectures have a pair of unsigned long values. + * + * On big-endian systems, the padding is in the wrong place for + * historic reasons, so user space has to reconstruct a time_t + * value using + * + * user_semid_ds.sem_otime = kernel_semid64_ds.sem_otime + + * ((long long)kernel_semid64_ds.sem_otime_high << 32) + * + * Pad space is left for 2 miscellaneous 32-bit values + */ +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ +#if __BITS_PER_LONG == 64 + long sem_otime; /* last semop time */ + long sem_ctime; /* last change time */ +#else +#define HAVE_SEMID64_DS_TIME_HIGH + unsigned long sem_otime; /* last semop time */ + unsigned long sem_otime_high; + unsigned long sem_ctime; /* last change time */ + unsigned long sem_ctime_high; +#endif + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; +#endif /* semid64_ds */ + +#endif /* HAVE_SEMID64_DS */ + +#endif /* LAPI_SEMBUF_H__ */ diff --git a/include/lapi/setns.h b/include/lapi/setns.h old mode 100644 new mode 100755 index 7b0a7afc479373c890a031b25bfb5294714bda1e..2d0be88467a6f5e76a59ab0191e30d2e41b0080f --- a/include/lapi/setns.h +++ b/include/lapi/setns.h @@ -11,7 +11,7 @@ #include #ifndef HAVE_SETNS -int setns(int fd, int nstype) +static inline int setns(int fd, int nstype) { return tst_syscall(__NR_setns, fd, nstype); } diff --git a/include/lapi/shm.h b/include/lapi/shm.h new file mode 100755 index 0000000000000000000000000000000000000000..bb280fc44ef9005a107f15a39790be05275e339f --- /dev/null +++ b/include/lapi/shm.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + */ + +#ifndef LAPI_SHM_H__ +#define LAPI_SHM_H__ + +#include + +#ifndef SHM_STAT_ANY +# define SHM_STAT_ANY 15 +#endif + +#ifndef SHMMIN +# define SHMMIN 1 +#endif + +#ifndef SHMMAX +# define SHMMAX (ULONG_MAX - (1UL << 24)) +#endif + +#ifndef SHMMNI +# define SHMMNI 4096 +#endif + +#endif /* LAPI_SHM_H__ */ diff --git a/include/lapi/shmbuf.h b/include/lapi/shmbuf.h new file mode 100755 index 0000000000000000000000000000000000000000..b0a0fa3d96553f864c93ea533f1d7e58e73dfb58 --- /dev/null +++ b/include/lapi/shmbuf.h @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_SHMBUF_H__ +#define LAPI_SHMBUF_H__ + +#include "lapi/posix_types.h" +#include +#include "tst_timer.h" +#include "ipcbuf.h" + +#ifndef HAVE_SHMID64_DS + +#if defined(__mips__) +#define HAVE_SHMID64_DS +/* + * The shmid64_ds structure for the MIPS architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * As MIPS was lacking proper padding after shm_?time, we use 48 bits + * of the padding at the end to store a few additional bits of the time. + * libc implementations need to take care to convert this into a proper + * data structure when moving to 64-bit time_t. + */ + +#if __BITS_PER_LONG == 64 +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + long shm_atime; /* last attach time */ + long shm_dtime; /* last detach time */ + long shm_ctime; /* last change time */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused1; + unsigned long __unused2; +}; +#else +#define HAVE_SHMID64_DS_TIME_HIGH +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + unsigned long shm_atime; /* last attach time */ + unsigned long shm_dtime; /* last detach time */ + unsigned long shm_ctime; /* last change time */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned short shm_atime_high; + unsigned short shm_dtime_high; + unsigned short shm_ctime_high; + unsigned short __unused1; +}; +#endif + +#endif /* __mips__ */ + +#if defined(__hppa__) +#define HAVE_SHMID64_DS +/* + * The shmid64_ds structure for parisc architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ +#if __BITS_PER_LONG == 64 + long shm_atime; /* last attach time */ + long shm_dtime; /* last detach time */ + long shm_ctime; /* last change time */ +#else +#define HAVE_SHMID64_DS_TIME_HIGH + unsigned long shm_atime_high; + unsigned long shm_atime; /* last attach time */ + unsigned long shm_dtime_high; + unsigned long shm_dtime; /* last detach time */ + unsigned long shm_ctime_high; + unsigned long shm_ctime; /* last change time */ + unsigned int __pad4; +#endif + __kernel_size_t shm_segsz; /* size of segment (bytes) */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused1; + unsigned long __unused2; +}; +#endif /* __hppa__ */ + +#if defined(__powerpc__) || defined(__powerpc64__) +#define HAVE_SHMID64_DS +/* + * The shmid64_ds structure for PPC architecture. + * + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ +#ifdef __powerpc64__ + long shm_atime; /* last attach time */ + long shm_dtime; /* last detach time */ + long shm_ctime; /* last change time */ +#else +#define HAVE_SHMID64_DS_TIME_HIGH + unsigned long shm_atime_high; + unsigned long shm_atime; /* last attach time */ + unsigned long shm_dtime_high; + unsigned long shm_dtime; /* last detach time */ + unsigned long shm_ctime_high; + unsigned long shm_ctime; /* last change time */ + unsigned long __unused4; +#endif + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused5; + unsigned long __unused6; +}; + +#endif /* defined(__powerpc__) || defined(__powerpc64__) */ + +#if defined(__sparc__) +#define HAVE_SHMID64_DS +/* + * The shmid64_ds structure for sparc architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ +#if defined(__arch64__) + long shm_atime; /* last attach time */ + long shm_dtime; /* last detach time */ + long shm_ctime; /* last change time */ +#else +#define HAVE_SHMID64_DS_TIME_HIGH + unsigned long shm_atime_high; + unsigned long shm_atime; /* last attach time */ + unsigned long shm_dtime_high; + unsigned long shm_dtime; /* last detach time */ + unsigned long shm_ctime_high; + unsigned long shm_ctime; /* last change time */ +#endif + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __sparc__ */ + +#if defined(__x86_64__) && defined(__ILP32__) +#define HAVE_SHMID64_DS +/* + * The shmid64_ds structure for x86 architecture with x32 ABI. + * + * On x86-32 and x86-64 we can just use the generic definition, but + * x32 uses the same binary layout as x86_64, which is differnet + * from other 32-bit architectures. + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_long_t shm_atime; /* last attach time */ + __kernel_long_t shm_dtime; /* last detach time */ + __kernel_long_t shm_ctime; /* last change time */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + __kernel_ulong_t shm_nattch; /* no. of current attaches */ + __kernel_ulong_t __unused4; + __kernel_ulong_t __unused5; +}; +#endif /* defined(__x86_64__) && defined(__ILP32__) */ + +#if defined(__xtensa__) +#define HAVE_SHMID64_DS +#define HAVE_SHMID64_DS_TIME_HIGH +/* + * The shmid64_ds structure for Xtensa architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space, but the padding is on the wrong + * side for big-endian xtensa, for historic reasons. + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + unsigned long shm_atime; /* last attach time */ + unsigned long shm_atime_high; + unsigned long shm_dtime; /* last detach time */ + unsigned long shm_dtime_high; + unsigned long shm_ctime; /* last change time */ + unsigned long shm_ctime_high; + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* __xtensa__ */ + +#ifndef HAVE_SHMID64_DS +/* + * The shmid64_ds structure for most architectures (though it came + * from x86_32 originally). Note extra padding because this structure + * is passed back and forth between kernel and user space. + * + * shmid64_ds was originally meant to be architecture specific, but + * everyone just ended up making identical copies without specific + * optimizations, so we may just as well all use the same one. + * + * 64 bit architectures use a 64-bit long time field here, while + * 32 bit architectures have a pair of unsigned long values. + * On big-endian systems, the lower half is in the wrong place. + * + * + * Pad space is left for: + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ +#if __BITS_PER_LONG == 64 + long shm_atime; /* last attach time */ + long shm_dtime; /* last detach time */ + long shm_ctime; /* last change time */ +#else +#define HAVE_SHMID64_DS_TIME_HIGH + unsigned long shm_atime; /* last attach time */ + unsigned long shm_atime_high; + unsigned long shm_dtime; /* last detach time */ + unsigned long shm_dtime_high; + unsigned long shm_ctime; /* last change time */ + unsigned long shm_ctime_high; +#endif + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; +#endif /* shmid64_ds */ + +#endif /* HAVE_SHMID64_DS */ + +#endif /* LAPI_SHMBUF_H__ */ diff --git a/include/lapi/signal.h b/include/lapi/signal.h old mode 100644 new mode 100755 index d22965a94355f90c5af0c38c182536445dcd552f..6f4a7688139682b13f2bdb242635aa9bf16b8d7f --- a/include/lapi/signal.h +++ b/include/lapi/signal.h @@ -4,8 +4,8 @@ * Author: Daniel Díaz */ -#ifndef LAPI_SIGNAL_H -#define LAPI_SIGNAL_H +#ifndef LAPI_SIGNAL_H__ +#define LAPI_SIGNAL_H__ #include @@ -21,4 +21,4 @@ # define __SIGRTMAX (_NSIG - 1) #endif -#endif +#endif /* LAPI_SIGNAL_H__ */ diff --git a/include/lapi/socket.h b/include/lapi/socket.h old mode 100644 new mode 100755 index d6389e504146d8fa09434c7b52e7e0f7462a9faf..794dee49f83c41f4b913dae70cea70908448b97d --- a/include/lapi/socket.h +++ b/include/lapi/socket.h @@ -4,8 +4,8 @@ * Author: Xiao Yang */ -#ifndef __LAPI_SOCKET_H__ -#define __LAPI_SOCKET_H__ +#ifndef LAPI_SOCKET_H__ +#define LAPI_SOCKET_H__ #include "config.h" #include @@ -69,4 +69,4 @@ struct mmsghdr { }; #endif -#endif /* __LAPI_SOCKET_H__ */ +#endif /* LAPI_SOCKET_H__ */ diff --git a/include/lapi/splice.h b/include/lapi/splice.h old mode 100644 new mode 100755 index 0cd6f55d2772c9d1f6807c611cc543e93dcc0a7a..191b22d2d6397d1efad5e2025be5a2c4370724dc --- a/include/lapi/splice.h +++ b/include/lapi/splice.h @@ -4,19 +4,19 @@ * Copyright (c) 2014 Fujitsu Ltd. */ -#ifndef SPLICE_H -#define SPLICE_H +#ifndef LAPI_SPLICE_H__ +#define LAPI_SPLICE_H__ #include "config.h" #include "lapi/syscalls.h" #if !defined(HAVE_SPLICE) -ssize_t splice(int fd_in, loff_t *off_in, int fd_out, - loff_t *off_out, size_t len, unsigned int flags) +static inline ssize_t splice(int fd_in, loff_t *off_in, int fd_out, + loff_t *off_out, size_t len, unsigned int flags) { return tst_syscall(__NR_splice, fd_in, off_in, fd_out, off_out, len, flags); } #endif -#endif /* SPLICE_H */ +#endif /* LAPI_SPLICE_H__ */ diff --git a/include/lapi/stat.h b/include/lapi/stat.h old mode 100644 new mode 100755 index 979e42d37412f0638f8926a0d9910c27d6cec6ed..d596058877c4fb32657fcd0c0e90aba0875ed8b0 --- a/include/lapi/stat.h +++ b/include/lapi/stat.h @@ -4,8 +4,9 @@ * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 * Email: code@zilogic.com */ -#ifndef LAPI_STAT_H -#define LAPI_STAT_H + +#ifndef LAPI_STAT_H__ +#define LAPI_STAT_H__ #include #include @@ -175,6 +176,10 @@ static inline int statx(int dirfd, const char *pathname, unsigned int flags, # define STATX_BTIME 0x00000800U #endif +#ifndef STATX_MNT_ID +# define STATX_MNT_ID 0x00001000U +#endif + #ifndef STATX_ALL # define STATX_ALL 0x00000fffU #endif @@ -254,4 +259,4 @@ static inline int statx(int dirfd, const char *pathname, unsigned int flags, # define AT_STATX_DONT_SYNC 0x4000 #endif -#endif +#endif /* LAPI_STAT_H__ */ diff --git a/include/lapi/sync_file_range.h b/include/lapi/sync_file_range.h old mode 100644 new mode 100755 index 86bfe5d6ece10166f0146361fe0b2196ed40b102..2f81e446cf9a6362a95ef97ee7344dd298a0c15f --- a/include/lapi/sync_file_range.h +++ b/include/lapi/sync_file_range.h @@ -3,8 +3,8 @@ * Copyright (c) International Business Machines Corp., 2008 */ -#ifndef SYNC_FILE_RANGE_H -#define SYNC_FILE_RANGE_H +#ifndef LAPI_SYNC_FILE_RANGE_H__ +#define LAPI_SYNC_FILE_RANGE_H__ #include #include "config.h" @@ -55,4 +55,4 @@ static inline long sync_file_range(int fd, off64_t offset, off64_t nbytes, } #endif -#endif /* SYNC_FILE_RANGE_H */ +#endif /* LAPI_SYNC_FILE_RANGE_H__ */ diff --git a/include/lapi/syncfs.h b/include/lapi/syncfs.h old mode 100644 new mode 100755 index e5d29fa96a6b98f651686bb43a3c74d8e5ed7d02..5624832c1453048e25e8760265c4d149e9f6890f --- a/include/lapi/syncfs.h +++ b/include/lapi/syncfs.h @@ -4,18 +4,18 @@ * Author: Sumit Garg */ -#ifndef SYNCFS_H -#define SYNCFS_H +#ifndef LAPI_SYNCFS_H__ +#define LAPI_SYNCFS_H__ #include "config.h" #include #include "lapi/syscalls.h" #if !defined(HAVE_SYNCFS) -int syncfs(int fd) +static inline int syncfs(int fd) { return tst_syscall(__NR_syncfs, fd); } #endif -#endif /* SYNCFS_H */ +#endif /* LAPI_SYNCFS_H__ */ diff --git a/include/lapi/syscalls/aarch64.in b/include/lapi/syscalls/aarch64.in old mode 100644 new mode 100755 index 07556933f037ecba48d8810e1e21b9be82e933bd..89b63ee4b50cec005ee560fca026269247a7f911 --- a/include/lapi/syscalls/aarch64.in +++ b/include/lapi/syscalls/aarch64.in @@ -278,26 +278,6 @@ statx 291 io_pgetevents 292 rseq 293 kexec_file_load 294 -clock_gettime64 403 -clock_settime64 404 -clock_adjtime64 405 -clock_getres_time64 406 -clock_nanosleep_time64 407 -timer_gettime64 408 -timer_settime64 409 -timerfd_gettime64 410 -timerfd_settime64 411 -utimensat_time64 412 -pselect6_time64 413 -ppoll_time64 414 -io_pgetevents_time64 416 -recvmmsg_time64 417 -mq_timedsend_time64 418 -mq_timedreceive_time64 419 -semtimedop_time64 420 -rt_sigtimedwait_time64 421 -futex_time64 422 -sched_rr_get_interval_time64 423 pidfd_send_signal 424 io_uring_setup 425 io_uring_enter 426 @@ -310,6 +290,9 @@ fsmount 432 fspick 433 pidfd_open 434 clone3 435 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 _sysctl 1078 diff --git a/include/lapi/syscalls/arc.in b/include/lapi/syscalls/arc.in old mode 100644 new mode 100755 index 0cadb150c7fe08082d0b45e0f512e1ada5d0870b..72420754a77563f932ce4b8307e58a1c9ebfc1de --- a/include/lapi/syscalls/arc.in +++ b/include/lapi/syscalls/arc.in @@ -310,5 +310,8 @@ fsmount 432 fspick 433 pidfd_open 434 clone3 435 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in old mode 100644 new mode 100755 index 395d53a68f5c0b775f46a55f0b42b2c14cf6cf15..2a78d7c3c174bfe70e3b3c3bfa7ed906ca253342 --- a/include/lapi/syscalls/arm.in +++ b/include/lapi/syscalls/arm.in @@ -388,5 +388,8 @@ fsmount (__NR_SYSCALL_BASE+432) fspick (__NR_SYSCALL_BASE+433) pidfd_open (__NR_SYSCALL_BASE+434) clone3 (__NR_SYSCALL_BASE+435) +close_range (__NR_SYSCALL_BASE+436) openat2 (__NR_SYSCALL_BASE+437) pidfd_getfd (__NR_SYSCALL_BASE+438) +epoll_pwait2 (__NR_SYSCALL_BASE+441) +quotactl_fd (__NR_SYSCALL_BASE+443) diff --git a/include/lapi/syscalls/hppa.in b/include/lapi/syscalls/hppa.in old mode 100644 new mode 100755 index e00d2dc6d37d24e21c76a85c031017cecee9320e..2f0fc8153af999e44077be6e1d94f611d145ecd7 --- a/include/lapi/syscalls/hppa.in +++ b/include/lapi/syscalls/hppa.in @@ -17,6 +17,7 @@ splice 291 tee 293 vmsplice 294 syncfs 327 +setns 328 process_vm_readv 330 process_vm_writev 331 memfd_create 340 @@ -38,3 +39,6 @@ fsconfig 431 fsmount 432 fspick 433 pidfd_open 434 +close_range 436 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in old mode 100644 new mode 100755 index d6773abcb061c37e4ae261ba476b4a8468075612..34a8a621f0f6c0211ecb86e8cb980cfb8b888af3 --- a/include/lapi/syscalls/i386.in +++ b/include/lapi/syscalls/i386.in @@ -424,5 +424,8 @@ fsmount 432 fspick 433 pidfd_open 434 clone3 435 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/ia64.in b/include/lapi/syscalls/ia64.in old mode 100644 new mode 100755 index 427b711b1cc9fa3831078181dc6fa4003deabdb6..b729cd3f051fd8b6c53688454fe490e6803b0560 --- a/include/lapi/syscalls/ia64.in +++ b/include/lapi/syscalls/ia64.in @@ -337,5 +337,8 @@ fsconfig 1455 fsmount 1456 fspick 1457 pidfd_open 1458 +close_range 1460 openat2 1461 pidfd_getfd 1462 +epoll_pwait2 1465 +quotactl_fd 1467 diff --git a/include/lapi/syscalls/mips_n32.in b/include/lapi/syscalls/mips_n32.in old mode 100644 new mode 100755 index eb6140ebc480b4f15f9a8c15cd680cf3d271c7ee..46098a6164311f8a8042a9e5ef0fef849365d538 --- a/include/lapi/syscalls/mips_n32.in +++ b/include/lapi/syscalls/mips_n32.in @@ -1,366 +1,372 @@ -read 0 -write 1 -open 2 -close 3 -stat 4 -fstat 5 -lstat 6 -poll 7 -lseek 8 -mmap 9 -mprotect 10 -munmap 11 -brk 12 -rt_sigaction 13 -rt_sigprocmask 14 -ioctl 15 -pread64 16 -pwrite64 17 -readv 18 -writev 19 -access 20 -pipe 21 -_newselect 22 -sched_yield 23 -mremap 24 -msync 25 -mincore 26 -madvise 27 -shmget 28 -shmat 29 -shmctl 30 -dup 31 -dup2 32 -pause 33 -nanosleep 34 -getitimer 35 -setitimer 36 -alarm 37 -getpid 38 -sendfile 39 -socket 40 -connect 41 -accept 42 -sendto 43 -recvfrom 44 -sendmsg 45 -recvmsg 46 -shutdown 47 -bind 48 -listen 49 -getsockname 50 -getpeername 51 -socketpair 52 -setsockopt 53 -getsockopt 54 -clone 55 -fork 56 -execve 57 -exit 58 -wait4 59 -kill 60 -uname 61 -semget 62 -semop 63 -semctl 64 -shmdt 65 -msgget 66 -msgsnd 67 -msgrcv 68 -msgctl 69 -fcntl 70 -flock 71 -fsync 72 -fdatasync 73 -truncate 74 -ftruncate 75 -getdents 76 -getcwd 77 -chdir 78 -fchdir 79 -rename 80 -mkdir 81 -rmdir 82 -creat 83 -link 84 -unlink 85 -symlink 86 -readlink 87 -chmod 88 -fchmod 89 -chown 90 -fchown 91 -lchown 92 -umask 93 -gettimeofday 94 -getrlimit 95 -getrusage 96 -sysinfo 97 -times 98 -ptrace 99 -getuid 100 -syslog 101 -getgid 102 -setuid 103 -setgid 104 -geteuid 105 -getegid 106 -setpgid 107 -getppid 108 -getpgrp 109 -setsid 110 -setreuid 111 -setregid 112 -getgroups 113 -setgroups 114 -setresuid 115 -getresuid 116 -setresgid 117 -getresgid 118 -getpgid 119 -setfsuid 120 -setfsgid 121 -getsid 122 -capget 123 -capset 124 -rt_sigpending 125 -rt_sigtimedwait 126 -rt_sigqueueinfo 127 -rt_sigsuspend 128 -sigaltstack 129 -utime 130 -mknod 131 -personality 132 -ustat 133 -statfs 134 -fstatfs 135 -sysfs 136 -getpriority 137 -setpriority 138 -sched_setparam 139 -sched_getparam 140 -sched_setscheduler 141 -sched_getscheduler 142 -sched_get_priority_max 143 -sched_get_priority_min 144 -sched_rr_get_interval 145 -mlock 146 -munlock 147 -mlockall 148 -munlockall 149 -vhangup 150 -pivot_root 151 -_sysctl 152 -prctl 153 -adjtimex 154 -setrlimit 155 -chroot 156 -sync 157 -acct 158 -settimeofday 159 -mount 160 -umount2 161 -swapon 162 -swapoff 163 -reboot 164 -sethostname 165 -setdomainname 166 -create_module 167 -init_module 168 -delete_module 169 -get_kernel_syms 170 -query_module 171 -quotactl 172 -nfsservctl 173 -getpmsg 174 -putpmsg 175 -afs_syscall 176 -reserved177 177 -gettid 178 -readahead 179 -setxattr 180 -lsetxattr 181 -fsetxattr 182 -getxattr 183 -lgetxattr 184 -fgetxattr 185 -listxattr 186 -llistxattr 187 -flistxattr 188 -removexattr 189 -lremovexattr 190 -fremovexattr 191 -tkill 192 -reserved193 193 -futex 194 -sched_setaffinity 195 -sched_getaffinity 196 -cacheflush 197 -cachectl 198 -sysmips 199 -io_setup 200 -io_destroy 201 -io_getevents 202 -io_submit 203 -io_cancel 204 -exit_group 205 -lookup_dcookie 206 -epoll_create 207 -epoll_ctl 208 -epoll_wait 209 -remap_file_pages 210 -rt_sigreturn 211 -fcntl64 212 -set_tid_address 213 -restart_syscall 214 -semtimedop 215 -fadvise64 216 -statfs64 217 -fstatfs64 218 -sendfile64 219 -timer_create 220 -timer_settime 221 -timer_gettime 222 -timer_getoverrun 223 -timer_delete 224 -clock_settime 225 -clock_gettime 226 -clock_getres 227 -clock_nanosleep 228 -tgkill 229 -utimes 230 -mbind 231 -get_mempolicy 232 -set_mempolicy 233 -mq_open 234 -mq_unlink 235 -mq_timedsend 236 -mq_timedreceive 237 -mq_notify 238 -mq_getsetattr 239 -vserver 240 -waitid 241 -add_key 243 -request_key 244 -keyctl 245 -set_thread_area 246 -inotify_init 247 -inotify_add_watch 248 -inotify_rm_watch 249 -migrate_pages 250 -openat 251 -mkdirat 252 -mknodat 253 -fchownat 254 -futimesat 255 -newfstatat 256 -unlinkat 257 -renameat 258 -linkat 259 -symlinkat 260 -readlinkat 261 -fchmodat 262 -faccessat 263 -pselect6 264 -ppoll 265 -unshare 266 -splice 267 -sync_file_range 268 -tee 269 -vmsplice 270 -move_pages 271 -set_robust_list 272 -get_robust_list 273 -kexec_load 274 -getcpu 275 -epoll_pwait 276 -ioprio_set 277 -ioprio_get 278 -utimensat 279 -signalfd 280 -timerfd 281 -eventfd 282 -fallocate 283 -timerfd_create 284 -timerfd_gettime 285 -timerfd_settime 286 -signalfd4 287 -eventfd2 288 -epoll_create1 289 -dup3 290 -pipe2 291 -inotify_init1 292 -preadv 293 -pwritev 294 -rt_tgsigqueueinfo 295 -perf_event_open 296 -accept4 297 -recvmmsg 298 -getdents64 299 -fanotify_init 300 -fanotify_mark 301 -prlimit64 302 -name_to_handle_at 303 -open_by_handle_at 304 -clock_adjtime 305 -syncfs 306 -sendmmsg 307 -setns 308 -process_vm_readv 309 -process_vm_writev 310 -kcmp 311 -finit_module 312 -sched_setattr 313 -sched_getattr 314 -renameat2 315 -seccomp 316 -getrandom 317 -memfd_create 318 -bpf 319 -execveat 320 -userfaultfd 321 -membarrier 322 -mlock2 323 -copy_file_range 324 -preadv2 325 -pwritev2 326 -pkey_mprotect 327 -pkey_alloc 328 -pkey_free 329 -statx 330 -rseq 331 -io_pgetevents 332 -clock_gettime64 403 -clock_settime64 404 -clock_adjtime64 405 -clock_getres_time64 406 -clock_nanosleep_time64 407 -timer_gettime64 408 -timer_settime64 409 -timerfd_gettime64 410 -timerfd_settime64 411 -utimensat_time64 412 -pselect6_time64 413 -ppoll_time64 414 -io_pgetevents_time64 416 -recvmmsg_time64 417 -mq_timedsend_time64 418 -mq_timedreceive_time64 419 -semtimedop_time64 420 -rt_sigtimedwait_time64 421 -futex_time64 422 -sched_rr_get_interval_time64 423 -pidfd_send_signal 424 -io_uring_setup 425 -io_uring_enter 426 -io_uring_register 427 -open_tree 428 -move_mount 429 -fsopen 430 -fsconfig 431 -fsmount 432 -fspick 433 -pidfd_open 434 -clone3 435 -openat2 437 -pidfd_getfd 438 +read 6000 +write 6001 +open 6002 +close 6003 +stat 6004 +fstat 6005 +lstat 6006 +poll 6007 +lseek 6008 +mmap 6009 +mprotect 6010 +munmap 6011 +brk 6012 +rt_sigaction 6013 +rt_sigprocmask 6014 +ioctl 6015 +pread64 6016 +pwrite64 6017 +readv 6018 +writev 6019 +access 6020 +pipe 6021 +_newselect 6022 +sched_yield 6023 +mremap 6024 +msync 6025 +mincore 6026 +madvise 6027 +shmget 6028 +shmat 6029 +shmctl 6030 +dup 6031 +dup2 6032 +pause 6033 +nanosleep 6034 +getitimer 6035 +setitimer 6036 +alarm 6037 +getpid 6038 +sendfile 6039 +socket 6040 +connect 6041 +accept 6042 +sendto 6043 +recvfrom 6044 +sendmsg 6045 +recvmsg 6046 +shutdown 6047 +bind 6048 +listen 6049 +getsockname 6050 +getpeername 6051 +socketpair 6052 +setsockopt 6053 +getsockopt 6054 +clone 6055 +fork 6056 +execve 6057 +exit 6058 +wait4 6059 +kill 6060 +uname 6061 +semget 6062 +semop 6063 +semctl 6064 +shmdt 6065 +msgget 6066 +msgsnd 6067 +msgrcv 6068 +msgctl 6069 +fcntl 6070 +flock 6071 +fsync 6072 +fdatasync 6073 +truncate 6074 +ftruncate 6075 +getdents 6076 +getcwd 6077 +chdir 6078 +fchdir 6079 +rename 6080 +mkdir 6081 +rmdir 6082 +creat 6083 +link 6084 +unlink 6085 +symlink 6086 +readlink 6087 +chmod 6088 +fchmod 6089 +chown 6090 +fchown 6091 +lchown 6092 +umask 6093 +gettimeofday 6094 +getrlimit 6095 +getrusage 6096 +sysinfo 6097 +times 6098 +ptrace 6099 +getuid 6100 +syslog 6101 +getgid 6102 +setuid 6103 +setgid 6104 +geteuid 6105 +getegid 6106 +setpgid 6107 +getppid 6108 +getpgrp 6109 +setsid 6110 +setreuid 6111 +setregid 6112 +getgroups 6113 +setgroups 6114 +setresuid 6115 +getresuid 6116 +setresgid 6117 +getresgid 6118 +getpgid 6119 +setfsuid 6120 +setfsgid 6121 +getsid 6122 +capget 6123 +capset 6124 +rt_sigpending 6125 +rt_sigtimedwait 6126 +rt_sigqueueinfo 6127 +rt_sigsuspend 6128 +sigaltstack 6129 +utime 6130 +mknod 6131 +personality 6132 +ustat 6133 +statfs 6134 +fstatfs 6135 +sysfs 6136 +getpriority 6137 +setpriority 6138 +sched_setparam 6139 +sched_getparam 6140 +sched_setscheduler 6141 +sched_getscheduler 6142 +sched_get_priority_max 6143 +sched_get_priority_min 6144 +sched_rr_get_interval 6145 +mlock 6146 +munlock 6147 +mlockall 6148 +munlockall 6149 +vhangup 6150 +pivot_root 6151 +_sysctl 6152 +prctl 6153 +adjtimex 6154 +setrlimit 6155 +chroot 6156 +sync 6157 +acct 6158 +settimeofday 6159 +mount 6160 +umount2 6161 +swapon 6162 +swapoff 6163 +reboot 6164 +sethostname 6165 +setdomainname 6166 +create_module 6167 +init_module 6168 +delete_module 6169 +get_kernel_syms 6170 +query_module 6171 +quotactl 6172 +nfsservctl 6173 +getpmsg 6174 +putpmsg 6175 +afs_syscall 6176 +reserved177 6177 +gettid 6178 +readahead 6179 +setxattr 6180 +lsetxattr 6181 +fsetxattr 6182 +getxattr 6183 +lgetxattr 6184 +fgetxattr 6185 +listxattr 6186 +llistxattr 6187 +flistxattr 6188 +removexattr 6189 +lremovexattr 6190 +fremovexattr 6191 +tkill 6192 +reserved193 6193 +futex 6194 +sched_setaffinity 6195 +sched_getaffinity 6196 +cacheflush 6197 +cachectl 6198 +sysmips 6199 +io_setup 6200 +io_destroy 6201 +io_getevents 6202 +io_submit 6203 +io_cancel 6204 +exit_group 6205 +lookup_dcookie 6206 +epoll_create 6207 +epoll_ctl 6208 +epoll_wait 6209 +remap_file_pages 6210 +rt_sigreturn 6211 +fcntl64 6212 +set_tid_address 6213 +restart_syscall 6214 +semtimedop 6215 +fadvise64 6216 +statfs64 6217 +fstatfs64 6218 +sendfile64 6219 +timer_create 6220 +timer_settime 6221 +timer_gettime 6222 +timer_getoverrun 6223 +timer_delete 6224 +clock_settime 6225 +clock_gettime 6226 +clock_getres 6227 +clock_nanosleep 6228 +tgkill 6229 +utimes 6230 +mbind 6231 +get_mempolicy 6232 +set_mempolicy 6233 +mq_open 6234 +mq_unlink 6235 +mq_timedsend 6236 +mq_timedreceive 6237 +mq_notify 6238 +mq_getsetattr 6239 +vserver 6240 +waitid 6241 +add_key 6243 +request_key 6244 +keyctl 6245 +set_thread_area 6246 +inotify_init 6247 +inotify_add_watch 6248 +inotify_rm_watch 6249 +migrate_pages 6250 +openat 6251 +mkdirat 6252 +mknodat 6253 +fchownat 6254 +futimesat 6255 +newfstatat 6256 +unlinkat 6257 +renameat 6258 +linkat 6259 +symlinkat 6260 +readlinkat 6261 +fchmodat 6262 +faccessat 6263 +pselect6 6264 +ppoll 6265 +unshare 6266 +splice 6267 +sync_file_range 6268 +tee 6269 +vmsplice 6270 +move_pages 6271 +set_robust_list 6272 +get_robust_list 6273 +kexec_load 6274 +getcpu 6275 +epoll_pwait 6276 +ioprio_set 6277 +ioprio_get 6278 +utimensat 6279 +signalfd 6280 +timerfd 6281 +eventfd 6282 +fallocate 6283 +timerfd_create 6284 +timerfd_gettime 6285 +timerfd_settime 6286 +signalfd4 6287 +eventfd2 6288 +epoll_create1 6289 +dup3 6290 +pipe2 6291 +inotify_init1 6292 +preadv 6293 +pwritev 6294 +rt_tgsigqueueinfo 6295 +perf_event_open 6296 +accept4 6297 +recvmmsg 6298 +getdents64 6299 +fanotify_init 6300 +fanotify_mark 6301 +prlimit64 6302 +name_to_handle_at 6303 +open_by_handle_at 6304 +clock_adjtime 6305 +syncfs 6306 +sendmmsg 6307 +setns 6308 +process_vm_readv 6309 +process_vm_writev 6310 +kcmp 6311 +finit_module 6312 +sched_setattr 6313 +sched_getattr 6314 +renameat2 6315 +seccomp 6316 +getrandom 6317 +memfd_create 6318 +bpf 6319 +execveat 6320 +userfaultfd 6321 +membarrier 6322 +mlock2 6323 +copy_file_range 6324 +preadv2 6325 +pwritev2 6326 +pkey_mprotect 6327 +pkey_alloc 6328 +pkey_free 6329 +statx 6330 +rseq 6331 +io_pgetevents 6332 +clock_gettime64 6403 +clock_settime64 6404 +clock_adjtime64 6405 +clock_getres_time64 6406 +clock_nanosleep_time64 6407 +timer_gettime64 6408 +timer_settime64 6409 +timerfd_gettime64 6410 +timerfd_settime64 6411 +utimensat_time64 6412 +pselect6_time64 6413 +ppoll_time64 6414 +io_pgetevents_time64 6416 +recvmmsg_time64 6417 +mq_timedsend_time64 6418 +mq_timedreceive_time64 6419 +semtimedop_time64 6420 +rt_sigtimedwait_time64 6421 +futex_time64 6422 +sched_rr_get_interval_time64 6423 +pidfd_send_signal 6424 +io_uring_setup 6425 +io_uring_enter 6426 +io_uring_register 6427 +open_tree 6428 +move_mount 6429 +fsopen 6430 +fsconfig 6431 +fsmount 6432 +fspick 6433 +pidfd_open 6434 +clone3 6435 +close_range 6436 +openat2 6437 +pidfd_getfd 6438 +faccessat2 6439 +process_madvise 6440 +epoll_pwait2 6441 +mount_setattr 6442 +quotactl_fd 6443 diff --git a/include/lapi/syscalls/mips_n64.in b/include/lapi/syscalls/mips_n64.in old mode 100644 new mode 100755 index 5480aa3c9c66bbcabed6420bb50cecd1c581f80d..07f96ac5d32f7d57f51b18936de81cf13b1223db --- a/include/lapi/syscalls/mips_n64.in +++ b/include/lapi/syscalls/mips_n64.in @@ -1,342 +1,348 @@ -read 0 -write 1 -open 2 -close 3 -stat 4 -fstat 5 -lstat 6 -poll 7 -lseek 8 -mmap 9 -mprotect 10 -munmap 11 -brk 12 -rt_sigaction 13 -rt_sigprocmask 14 -ioctl 15 -pread64 16 -pwrite64 17 -readv 18 -writev 19 -access 20 -pipe 21 -_newselect 22 -sched_yield 23 -mremap 24 -msync 25 -mincore 26 -madvise 27 -shmget 28 -shmat 29 -shmctl 30 -dup 31 -dup2 32 -pause 33 -nanosleep 34 -getitimer 35 -setitimer 36 -alarm 37 -getpid 38 -sendfile 39 -socket 40 -connect 41 -accept 42 -sendto 43 -recvfrom 44 -sendmsg 45 -recvmsg 46 -shutdown 47 -bind 48 -listen 49 -getsockname 50 -getpeername 51 -socketpair 52 -setsockopt 53 -getsockopt 54 -clone 55 -fork 56 -execve 57 -exit 58 -wait4 59 -kill 60 -uname 61 -semget 62 -semop 63 -semctl 64 -shmdt 65 -msgget 66 -msgsnd 67 -msgrcv 68 -msgctl 69 -fcntl 70 -flock 71 -fsync 72 -fdatasync 73 -truncate 74 -ftruncate 75 -getdents 76 -getcwd 77 -chdir 78 -fchdir 79 -rename 80 -mkdir 81 -rmdir 82 -creat 83 -link 84 -unlink 85 -symlink 86 -readlink 87 -chmod 88 -fchmod 89 -chown 90 -fchown 91 -lchown 92 -umask 93 -gettimeofday 94 -getrlimit 95 -getrusage 96 -sysinfo 97 -times 98 -ptrace 99 -getuid 100 -syslog 101 -getgid 102 -setuid 103 -setgid 104 -geteuid 105 -getegid 106 -setpgid 107 -getppid 108 -getpgrp 109 -setsid 110 -setreuid 111 -setregid 112 -getgroups 113 -setgroups 114 -setresuid 115 -getresuid 116 -setresgid 117 -getresgid 118 -getpgid 119 -setfsuid 120 -setfsgid 121 -getsid 122 -capget 123 -capset 124 -rt_sigpending 125 -rt_sigtimedwait 126 -rt_sigqueueinfo 127 -rt_sigsuspend 128 -sigaltstack 129 -utime 130 -mknod 131 -personality 132 -ustat 133 -statfs 134 -fstatfs 135 -sysfs 136 -getpriority 137 -setpriority 138 -sched_setparam 139 -sched_getparam 140 -sched_setscheduler 141 -sched_getscheduler 142 -sched_get_priority_max 143 -sched_get_priority_min 144 -sched_rr_get_interval 145 -mlock 146 -munlock 147 -mlockall 148 -munlockall 149 -vhangup 150 -pivot_root 151 -_sysctl 152 -prctl 153 -adjtimex 154 -setrlimit 155 -chroot 156 -sync 157 -acct 158 -settimeofday 159 -mount 160 -umount2 161 -swapon 162 -swapoff 163 -reboot 164 -sethostname 165 -setdomainname 166 -create_module 167 -init_module 168 -delete_module 169 -get_kernel_syms 170 -query_module 171 -quotactl 172 -nfsservctl 173 -getpmsg 174 -putpmsg 175 -afs_syscall 176 -reserved177 177 -gettid 178 -readahead 179 -setxattr 180 -lsetxattr 181 -fsetxattr 182 -getxattr 183 -lgetxattr 184 -fgetxattr 185 -listxattr 186 -llistxattr 187 -flistxattr 188 -removexattr 189 -lremovexattr 190 -fremovexattr 191 -tkill 192 -reserved193 193 -futex 194 -sched_setaffinity 195 -sched_getaffinity 196 -cacheflush 197 -cachectl 198 -sysmips 199 -io_setup 200 -io_destroy 201 -io_getevents 202 -io_submit 203 -io_cancel 204 -exit_group 205 -lookup_dcookie 206 -epoll_create 207 -epoll_ctl 208 -epoll_wait 209 -remap_file_pages 210 -rt_sigreturn 211 -set_tid_address 212 -restart_syscall 213 -semtimedop 214 -fadvise64 215 -timer_create 216 -timer_settime 217 -timer_gettime 218 -timer_getoverrun 219 -timer_delete 220 -clock_settime 221 -clock_gettime 222 -clock_getres 223 -clock_nanosleep 224 -tgkill 225 -utimes 226 -mbind 227 -get_mempolicy 228 -set_mempolicy 229 -mq_open 230 -mq_unlink 231 -mq_timedsend 232 -mq_timedreceive 233 -mq_notify 234 -mq_getsetattr 235 -vserver 236 -waitid 237 -add_key 239 -request_key 240 -keyctl 241 -set_thread_area 242 -inotify_init 243 -inotify_add_watch 244 -inotify_rm_watch 245 -migrate_pages 246 -openat 247 -mkdirat 248 -mknodat 249 -fchownat 250 -futimesat 251 -newfstatat 252 -unlinkat 253 -renameat 254 -linkat 255 -symlinkat 256 -readlinkat 257 -fchmodat 258 -faccessat 259 -pselect6 260 -ppoll 261 -unshare 262 -splice 263 -sync_file_range 264 -tee 265 -vmsplice 266 -move_pages 267 -set_robust_list 268 -get_robust_list 269 -kexec_load 270 -getcpu 271 -epoll_pwait 272 -ioprio_set 273 -ioprio_get 274 -utimensat 275 -signalfd 276 -timerfd 277 -eventfd 278 -fallocate 279 -timerfd_create 280 -timerfd_gettime 281 -timerfd_settime 282 -signalfd4 283 -eventfd2 284 -epoll_create1 285 -dup3 286 -pipe2 287 -inotify_init1 288 -preadv 289 -pwritev 290 -rt_tgsigqueueinfo 291 -perf_event_open 292 -accept4 293 -recvmmsg 294 -fanotify_init 295 -fanotify_mark 296 -prlimit64 297 -name_to_handle_at 298 -open_by_handle_at 299 -clock_adjtime 300 -syncfs 301 -sendmmsg 302 -setns 303 -process_vm_readv 304 -process_vm_writev 305 -kcmp 306 -finit_module 307 -getdents64 308 -sched_setattr 309 -sched_getattr 310 -renameat2 311 -seccomp 312 -getrandom 313 -memfd_create 314 -bpf 315 -execveat 316 -userfaultfd 317 -membarrier 318 -mlock2 319 -copy_file_range 320 -preadv2 321 -pwritev2 322 -pkey_mprotect 323 -pkey_alloc 324 -pkey_free 325 -statx 326 -rseq 327 -io_pgetevents 328 -pidfd_send_signal 424 -io_uring_setup 425 -io_uring_enter 426 -io_uring_register 427 -open_tree 428 -move_mount 429 -fsopen 430 -fsconfig 431 -fsmount 432 -fspick 433 -pidfd_open 434 -clone3 435 -openat2 437 -pidfd_getfd 438 +read 5000 +write 5001 +open 5002 +close 5003 +stat 5004 +fstat 5005 +lstat 5006 +poll 5007 +lseek 5008 +mmap 5009 +mprotect 5010 +munmap 5011 +brk 5012 +rt_sigaction 5013 +rt_sigprocmask 5014 +ioctl 5015 +pread64 5016 +pwrite64 5017 +readv 5018 +writev 5019 +access 5020 +pipe 5021 +_newselect 5022 +sched_yield 5023 +mremap 5024 +msync 5025 +mincore 5026 +madvise 5027 +shmget 5028 +shmat 5029 +shmctl 5030 +dup 5031 +dup2 5032 +pause 5033 +nanosleep 5034 +getitimer 5035 +setitimer 5036 +alarm 5037 +getpid 5038 +sendfile 5039 +socket 5040 +connect 5041 +accept 5042 +sendto 5043 +recvfrom 5044 +sendmsg 5045 +recvmsg 5046 +shutdown 5047 +bind 5048 +listen 5049 +getsockname 5050 +getpeername 5051 +socketpair 5052 +setsockopt 5053 +getsockopt 5054 +clone 5055 +fork 5056 +execve 5057 +exit 5058 +wait4 5059 +kill 5060 +uname 5061 +semget 5062 +semop 5063 +semctl 5064 +shmdt 5065 +msgget 5066 +msgsnd 5067 +msgrcv 5068 +msgctl 5069 +fcntl 5070 +flock 5071 +fsync 5072 +fdatasync 5073 +truncate 5074 +ftruncate 5075 +getdents 5076 +getcwd 5077 +chdir 5078 +fchdir 5079 +rename 5080 +mkdir 5081 +rmdir 5082 +creat 5083 +link 5084 +unlink 5085 +symlink 5086 +readlink 5087 +chmod 5088 +fchmod 5089 +chown 5090 +fchown 5091 +lchown 5092 +umask 5093 +gettimeofday 5094 +getrlimit 5095 +getrusage 5096 +sysinfo 5097 +times 5098 +ptrace 5099 +getuid 5100 +syslog 5101 +getgid 5102 +setuid 5103 +setgid 5104 +geteuid 5105 +getegid 5106 +setpgid 5107 +getppid 5108 +getpgrp 5109 +setsid 5110 +setreuid 5111 +setregid 5112 +getgroups 5113 +setgroups 5114 +setresuid 5115 +getresuid 5116 +setresgid 5117 +getresgid 5118 +getpgid 5119 +setfsuid 5120 +setfsgid 5121 +getsid 5122 +capget 5123 +capset 5124 +rt_sigpending 5125 +rt_sigtimedwait 5126 +rt_sigqueueinfo 5127 +rt_sigsuspend 5128 +sigaltstack 5129 +utime 5130 +mknod 5131 +personality 5132 +ustat 5133 +statfs 5134 +fstatfs 5135 +sysfs 5136 +getpriority 5137 +setpriority 5138 +sched_setparam 5139 +sched_getparam 5140 +sched_setscheduler 5141 +sched_getscheduler 5142 +sched_get_priority_max 5143 +sched_get_priority_min 5144 +sched_rr_get_interval 5145 +mlock 5146 +munlock 5147 +mlockall 5148 +munlockall 5149 +vhangup 5150 +pivot_root 5151 +_sysctl 5152 +prctl 5153 +adjtimex 5154 +setrlimit 5155 +chroot 5156 +sync 5157 +acct 5158 +settimeofday 5159 +mount 5160 +umount2 5161 +swapon 5162 +swapoff 5163 +reboot 5164 +sethostname 5165 +setdomainname 5166 +create_module 5167 +init_module 5168 +delete_module 5169 +get_kernel_syms 5170 +query_module 5171 +quotactl 5172 +nfsservctl 5173 +getpmsg 5174 +putpmsg 5175 +afs_syscall 5176 +reserved177 5177 +gettid 5178 +readahead 5179 +setxattr 5180 +lsetxattr 5181 +fsetxattr 5182 +getxattr 5183 +lgetxattr 5184 +fgetxattr 5185 +listxattr 5186 +llistxattr 5187 +flistxattr 5188 +removexattr 5189 +lremovexattr 5190 +fremovexattr 5191 +tkill 5192 +reserved193 5193 +futex 5194 +sched_setaffinity 5195 +sched_getaffinity 5196 +cacheflush 5197 +cachectl 5198 +sysmips 5199 +io_setup 5200 +io_destroy 5201 +io_getevents 5202 +io_submit 5203 +io_cancel 5204 +exit_group 5205 +lookup_dcookie 5206 +epoll_create 5207 +epoll_ctl 5208 +epoll_wait 5209 +remap_file_pages 5210 +rt_sigreturn 5211 +set_tid_address 5212 +restart_syscall 5213 +semtimedop 5214 +fadvise64 5215 +timer_create 5216 +timer_settime 5217 +timer_gettime 5218 +timer_getoverrun 5219 +timer_delete 5220 +clock_settime 5221 +clock_gettime 5222 +clock_getres 5223 +clock_nanosleep 5224 +tgkill 5225 +utimes 5226 +mbind 5227 +get_mempolicy 5228 +set_mempolicy 5229 +mq_open 5230 +mq_unlink 5231 +mq_timedsend 5232 +mq_timedreceive 5233 +mq_notify 5234 +mq_getsetattr 5235 +vserver 5236 +waitid 5237 +add_key 5239 +request_key 5240 +keyctl 5241 +set_thread_area 5242 +inotify_init 5243 +inotify_add_watch 5244 +inotify_rm_watch 5245 +migrate_pages 5246 +openat 5247 +mkdirat 5248 +mknodat 5249 +fchownat 5250 +futimesat 5251 +newfstatat 5252 +unlinkat 5253 +renameat 5254 +linkat 5255 +symlinkat 5256 +readlinkat 5257 +fchmodat 5258 +faccessat 5259 +pselect6 5260 +ppoll 5261 +unshare 5262 +splice 5263 +sync_file_range 5264 +tee 5265 +vmsplice 5266 +move_pages 5267 +set_robust_list 5268 +get_robust_list 5269 +kexec_load 5270 +getcpu 5271 +epoll_pwait 5272 +ioprio_set 5273 +ioprio_get 5274 +utimensat 5275 +signalfd 5276 +timerfd 5277 +eventfd 5278 +fallocate 5279 +timerfd_create 5280 +timerfd_gettime 5281 +timerfd_settime 5282 +signalfd4 5283 +eventfd2 5284 +epoll_create1 5285 +dup3 5286 +pipe2 5287 +inotify_init1 5288 +preadv 5289 +pwritev 5290 +rt_tgsigqueueinfo 5291 +perf_event_open 5292 +accept4 5293 +recvmmsg 5294 +fanotify_init 5295 +fanotify_mark 5296 +prlimit64 5297 +name_to_handle_at 5298 +open_by_handle_at 5299 +clock_adjtime 5300 +syncfs 5301 +sendmmsg 5302 +setns 5303 +process_vm_readv 5304 +process_vm_writev 5305 +kcmp 5306 +finit_module 5307 +getdents64 5308 +sched_setattr 5309 +sched_getattr 5310 +renameat2 5311 +seccomp 5312 +getrandom 5313 +memfd_create 5314 +bpf 5315 +execveat 5316 +userfaultfd 5317 +membarrier 5318 +mlock2 5319 +copy_file_range 5320 +preadv2 5321 +pwritev2 5322 +pkey_mprotect 5323 +pkey_alloc 5324 +pkey_free 5325 +statx 5326 +rseq 5327 +io_pgetevents 5328 +pidfd_send_signal 5424 +io_uring_setup 5425 +io_uring_enter 5426 +io_uring_register 5427 +open_tree 5428 +move_mount 5429 +fsopen 5430 +fsconfig 5431 +fsmount 5432 +fspick 5433 +pidfd_open 5434 +clone3 5435 +close_range 5436 +openat2 5437 +pidfd_getfd 5438 +faccessat2 5439 +process_madvise 5440 +epoll_pwait2 5441 +mount_setattr 5442 +quotactl_fd 5443 diff --git a/include/lapi/syscalls/mips_o32.in b/include/lapi/syscalls/mips_o32.in old mode 100644 new mode 100755 index feee8fbf359dee87f5cb551751da92012d6f9f14..5e64a4a1cdaf99eed8cbe05e7467c28dc87fd1e9 --- a/include/lapi/syscalls/mips_o32.in +++ b/include/lapi/syscalls/mips_o32.in @@ -1,412 +1,418 @@ -syscall 0 -exit 1 -fork 2 -read 3 -write 4 -open 5 -close 6 -waitpid 7 -creat 8 -link 9 -unlink 10 -execve 11 -chdir 12 -time 13 -mknod 14 -chmod 15 -lchown 16 -break 17 -unused18 18 -lseek 19 -getpid 20 -mount 21 -umount 22 -setuid 23 -getuid 24 -stime 25 -ptrace 26 -alarm 27 -unused28 28 -pause 29 -utime 30 -stty 31 -gtty 32 -access 33 -nice 34 -ftime 35 -sync 36 -kill 37 -rename 38 -mkdir 39 -rmdir 40 -dup 41 -pipe 42 -times 43 -prof 44 -brk 45 -setgid 46 -getgid 47 -signal 48 -geteuid 49 -getegid 50 -acct 51 -umount2 52 -lock 53 -ioctl 54 -fcntl 55 -mpx 56 -setpgid 57 -ulimit 58 -unused59 59 -umask 60 -chroot 61 -ustat 62 -dup2 63 -getppid 64 -getpgrp 65 -setsid 66 -sigaction 67 -sgetmask 68 -ssetmask 69 -setreuid 70 -setregid 71 -sigsuspend 72 -sigpending 73 -sethostname 74 -setrlimit 75 -getrlimit 76 -getrusage 77 -gettimeofday 78 -settimeofday 79 -getgroups 80 -setgroups 81 -reserved82 82 -symlink 83 -unused84 84 -readlink 85 -uselib 86 -swapon 87 -reboot 88 -readdir 89 -mmap 90 -munmap 91 -truncate 92 -ftruncate 93 -fchmod 94 -fchown 95 -getpriority 96 -setpriority 97 -profil 98 -statfs 99 -fstatfs 100 -ioperm 101 -socketcall 102 -syslog 103 -setitimer 104 -getitimer 105 -stat 106 -lstat 107 -fstat 108 -unused109 109 -iopl 110 -vhangup 111 -idle 112 -vm86 113 -wait4 114 -swapoff 115 -sysinfo 116 -ipc 117 -fsync 118 -sigreturn 119 -clone 120 -setdomainname 121 -uname 122 -modify_ldt 123 -adjtimex 124 -mprotect 125 -sigprocmask 126 -create_module 127 -init_module 128 -delete_module 129 -get_kernel_syms 130 -quotactl 131 -getpgid 132 -fchdir 133 -bdflush 134 -sysfs 135 -personality 136 -afs_syscall 137 -setfsuid 138 -setfsgid 139 -_llseek 140 -getdents 141 -_newselect 142 -flock 143 -msync 144 -readv 145 -writev 146 -cacheflush 147 -cachectl 148 -sysmips 149 -unused150 150 -getsid 151 -fdatasync 152 -_sysctl 153 -mlock 154 -munlock 155 -mlockall 156 -munlockall 157 -sched_setparam 158 -sched_getparam 159 -sched_setscheduler 160 -sched_getscheduler 161 -sched_yield 162 -sched_get_priority_max 163 -sched_get_priority_min 164 -sched_rr_get_interval 165 -nanosleep 166 -mremap 167 -accept 168 -bind 169 -connect 170 -getpeername 171 -getsockname 172 -getsockopt 173 -listen 174 -recv 175 -recvfrom 176 -recvmsg 177 -send 178 -sendmsg 179 -sendto 180 -setsockopt 181 -shutdown 182 -socket 183 -socketpair 184 -setresuid 185 -getresuid 186 -query_module 187 -poll 188 -nfsservctl 189 -setresgid 190 -getresgid 191 -prctl 192 -rt_sigreturn 193 -rt_sigaction 194 -rt_sigprocmask 195 -rt_sigpending 196 -rt_sigtimedwait 197 -rt_sigqueueinfo 198 -rt_sigsuspend 199 -pread64 200 -pwrite64 201 -chown 202 -getcwd 203 -capget 204 -capset 205 -sigaltstack 206 -sendfile 207 -getpmsg 208 -putpmsg 209 -mmap2 210 -truncate64 211 -ftruncate64 212 -stat64 213 -lstat64 214 -fstat64 215 -pivot_root 216 -mincore 217 -madvise 218 -getdents64 219 -fcntl64 220 -reserved221 221 -gettid 222 -readahead 223 -setxattr 224 -lsetxattr 225 -fsetxattr 226 -getxattr 227 -lgetxattr 228 -fgetxattr 229 -listxattr 230 -llistxattr 231 -flistxattr 232 -removexattr 233 -lremovexattr 234 -fremovexattr 235 -tkill 236 -sendfile64 237 -futex 238 -sched_setaffinity 239 -sched_getaffinity 240 -io_setup 241 -io_destroy 242 -io_getevents 243 -io_submit 244 -io_cancel 245 -exit_group 246 -lookup_dcookie 247 -epoll_create 248 -epoll_ctl 249 -epoll_wait 250 -remap_file_pages 251 -set_tid_address 252 -restart_syscall 253 -fadvise64 254 -statfs64 255 -fstatfs64 256 -timer_create 257 -timer_settime 258 -timer_gettime 259 -timer_getoverrun 260 -timer_delete 261 -clock_settime 262 -clock_gettime 263 -clock_getres 264 -clock_nanosleep 265 -tgkill 266 -utimes 267 -mbind 268 -get_mempolicy 269 -set_mempolicy 270 -mq_open 271 -mq_unlink 272 -mq_timedsend 273 -mq_timedreceive 274 -mq_notify 275 -mq_getsetattr 276 -vserver 277 -waitid 278 -add_key 280 -request_key 281 -keyctl 282 -set_thread_area 283 -inotify_init 284 -inotify_add_watch 285 -inotify_rm_watch 286 -migrate_pages 287 -openat 288 -mkdirat 289 -mknodat 290 -fchownat 291 -futimesat 292 -fstatat64 293 -unlinkat 294 -renameat 295 -linkat 296 -symlinkat 297 -readlinkat 298 -fchmodat 299 -faccessat 300 -pselect6 301 -ppoll 302 -unshare 303 -splice 304 -sync_file_range 305 -tee 306 -vmsplice 307 -move_pages 308 -set_robust_list 309 -get_robust_list 310 -kexec_load 311 -getcpu 312 -epoll_pwait 313 -ioprio_set 314 -ioprio_get 315 -utimensat 316 -signalfd 317 -timerfd 318 -eventfd 319 -fallocate 320 -timerfd_create 321 -timerfd_gettime 322 -timerfd_settime 323 -signalfd4 324 -eventfd2 325 -epoll_create1 326 -dup3 327 -pipe2 328 -inotify_init1 329 -preadv 330 -pwritev 331 -rt_tgsigqueueinfo 332 -perf_event_open 333 -accept4 334 -recvmmsg 335 -fanotify_init 336 -fanotify_mark 337 -prlimit64 338 -name_to_handle_at 339 -open_by_handle_at 340 -clock_adjtime 341 -syncfs 342 -sendmmsg 343 -setns 344 -process_vm_readv 345 -process_vm_writev 346 -kcmp 347 -finit_module 348 -sched_setattr 349 -sched_getattr 350 -renameat2 351 -seccomp 352 -getrandom 353 -memfd_create 354 -bpf 355 -execveat 356 -userfaultfd 357 -membarrier 358 -mlock2 359 -copy_file_range 360 -preadv2 361 -pwritev2 362 -pkey_mprotect 363 -pkey_alloc 364 -pkey_free 365 -statx 366 -rseq 367 -io_pgetevents 368 -semget 393 -semctl 394 -shmget 395 -shmctl 396 -shmat 397 -shmdt 398 -msgget 399 -msgsnd 400 -msgrcv 401 -msgctl 402 -clock_gettime64 403 -clock_settime64 404 -clock_adjtime64 405 -clock_getres_time64 406 -clock_nanosleep_time64 407 -timer_gettime64 408 -timer_settime64 409 -timerfd_gettime64 410 -timerfd_settime64 411 -utimensat_time64 412 -pselect6_time64 413 -ppoll_time64 414 -io_pgetevents_time64 416 -recvmmsg_time64 417 -mq_timedsend_time64 418 -mq_timedreceive_time64 419 -semtimedop_time64 420 -rt_sigtimedwait_time64 421 -futex_time64 422 -sched_rr_get_interval_time64 423 -pidfd_send_signal 424 -io_uring_setup 425 -io_uring_enter 426 -io_uring_register 427 -open_tree 428 -move_mount 429 -fsopen 430 -fsconfig 431 -fsmount 432 -fspick 433 -pidfd_open 434 -clone3 435 -openat2 437 -pidfd_getfd 438 +syscall 4000 +exit 4001 +fork 4002 +read 4003 +write 4004 +open 4005 +close 4006 +waitpid 4007 +creat 4008 +link 4009 +unlink 4010 +execve 4011 +chdir 4012 +time 4013 +mknod 4014 +chmod 4015 +lchown 4016 +break 4017 +unused18 4018 +lseek 4019 +getpid 4020 +mount 4021 +umount 4022 +setuid 4023 +getuid 4024 +stime 4025 +ptrace 4026 +alarm 4027 +unused28 4028 +pause 4029 +utime 4030 +stty 4031 +gtty 4032 +access 4033 +nice 4034 +ftime 4035 +sync 4036 +kill 4037 +rename 4038 +mkdir 4039 +rmdir 4040 +dup 4041 +pipe 4042 +times 4043 +prof 4044 +brk 4045 +setgid 4046 +getgid 4047 +signal 4048 +geteuid 4049 +getegid 4050 +acct 4051 +umount2 4052 +lock 4053 +ioctl 4054 +fcntl 4055 +mpx 4056 +setpgid 4057 +ulimit 4058 +unused59 4059 +umask 4060 +chroot 4061 +ustat 4062 +dup2 4063 +getppid 4064 +getpgrp 4065 +setsid 4066 +sigaction 4067 +sgetmask 4068 +ssetmask 4069 +setreuid 4070 +setregid 4071 +sigsuspend 4072 +sigpending 4073 +sethostname 4074 +setrlimit 4075 +getrlimit 4076 +getrusage 4077 +gettimeofday 4078 +settimeofday 4079 +getgroups 4080 +setgroups 4081 +reserved82 4082 +symlink 4083 +unused84 4084 +readlink 4085 +uselib 4086 +swapon 4087 +reboot 4088 +readdir 4089 +mmap 4090 +munmap 4091 +truncate 4092 +ftruncate 4093 +fchmod 4094 +fchown 4095 +getpriority 4096 +setpriority 4097 +profil 4098 +statfs 4099 +fstatfs 4100 +ioperm 4101 +socketcall 4102 +syslog 4103 +setitimer 4104 +getitimer 4105 +stat 4106 +lstat 4107 +fstat 4108 +unused109 4109 +iopl 4110 +vhangup 4111 +idle 4112 +vm86 4113 +wait4 4114 +swapoff 4115 +sysinfo 4116 +ipc 4117 +fsync 4118 +sigreturn 4119 +clone 4120 +setdomainname 4121 +uname 4122 +modify_ldt 4123 +adjtimex 4124 +mprotect 4125 +sigprocmask 4126 +create_module 4127 +init_module 4128 +delete_module 4129 +get_kernel_syms 4130 +quotactl 4131 +getpgid 4132 +fchdir 4133 +bdflush 4134 +sysfs 4135 +personality 4136 +afs_syscall 4137 +setfsuid 4138 +setfsgid 4139 +_llseek 4140 +getdents 4141 +_newselect 4142 +flock 4143 +msync 4144 +readv 4145 +writev 4146 +cacheflush 4147 +cachectl 4148 +sysmips 4149 +unused150 4150 +getsid 4151 +fdatasync 4152 +_sysctl 4153 +mlock 4154 +munlock 4155 +mlockall 4156 +munlockall 4157 +sched_setparam 4158 +sched_getparam 4159 +sched_setscheduler 4160 +sched_getscheduler 4161 +sched_yield 4162 +sched_get_priority_max 4163 +sched_get_priority_min 4164 +sched_rr_get_interval 4165 +nanosleep 4166 +mremap 4167 +accept 4168 +bind 4169 +connect 4170 +getpeername 4171 +getsockname 4172 +getsockopt 4173 +listen 4174 +recv 4175 +recvfrom 4176 +recvmsg 4177 +send 4178 +sendmsg 4179 +sendto 4180 +setsockopt 4181 +shutdown 4182 +socket 4183 +socketpair 4184 +setresuid 4185 +getresuid 4186 +query_module 4187 +poll 4188 +nfsservctl 4189 +setresgid 4190 +getresgid 4191 +prctl 4192 +rt_sigreturn 4193 +rt_sigaction 4194 +rt_sigprocmask 4195 +rt_sigpending 4196 +rt_sigtimedwait 4197 +rt_sigqueueinfo 4198 +rt_sigsuspend 4199 +pread64 4200 +pwrite64 4201 +chown 4202 +getcwd 4203 +capget 4204 +capset 4205 +sigaltstack 4206 +sendfile 4207 +getpmsg 4208 +putpmsg 4209 +mmap2 4210 +truncate64 4211 +ftruncate64 4212 +stat64 4213 +lstat64 4214 +fstat64 4215 +pivot_root 4216 +mincore 4217 +madvise 4218 +getdents64 4219 +fcntl64 4220 +reserved221 4221 +gettid 4222 +readahead 4223 +setxattr 4224 +lsetxattr 4225 +fsetxattr 4226 +getxattr 4227 +lgetxattr 4228 +fgetxattr 4229 +listxattr 4230 +llistxattr 4231 +flistxattr 4232 +removexattr 4233 +lremovexattr 4234 +fremovexattr 4235 +tkill 4236 +sendfile64 4237 +futex 4238 +sched_setaffinity 4239 +sched_getaffinity 4240 +io_setup 4241 +io_destroy 4242 +io_getevents 4243 +io_submit 4244 +io_cancel 4245 +exit_group 4246 +lookup_dcookie 4247 +epoll_create 4248 +epoll_ctl 4249 +epoll_wait 4250 +remap_file_pages 4251 +set_tid_address 4252 +restart_syscall 4253 +fadvise64 4254 +statfs64 4255 +fstatfs64 4256 +timer_create 4257 +timer_settime 4258 +timer_gettime 4259 +timer_getoverrun 4260 +timer_delete 4261 +clock_settime 4262 +clock_gettime 4263 +clock_getres 4264 +clock_nanosleep 4265 +tgkill 4266 +utimes 4267 +mbind 4268 +get_mempolicy 4269 +set_mempolicy 4270 +mq_open 4271 +mq_unlink 4272 +mq_timedsend 4273 +mq_timedreceive 4274 +mq_notify 4275 +mq_getsetattr 4276 +vserver 4277 +waitid 4278 +add_key 4280 +request_key 4281 +keyctl 4282 +set_thread_area 4283 +inotify_init 4284 +inotify_add_watch 4285 +inotify_rm_watch 4286 +migrate_pages 4287 +openat 4288 +mkdirat 4289 +mknodat 4290 +fchownat 4291 +futimesat 4292 +fstatat64 4293 +unlinkat 4294 +renameat 4295 +linkat 4296 +symlinkat 4297 +readlinkat 4298 +fchmodat 4299 +faccessat 4300 +pselect6 4301 +ppoll 4302 +unshare 4303 +splice 4304 +sync_file_range 4305 +tee 4306 +vmsplice 4307 +move_pages 4308 +set_robust_list 4309 +get_robust_list 4310 +kexec_load 4311 +getcpu 4312 +epoll_pwait 4313 +ioprio_set 4314 +ioprio_get 4315 +utimensat 4316 +signalfd 4317 +timerfd 4318 +eventfd 4319 +fallocate 4320 +timerfd_create 4321 +timerfd_gettime 4322 +timerfd_settime 4323 +signalfd4 4324 +eventfd2 4325 +epoll_create1 4326 +dup3 4327 +pipe2 4328 +inotify_init1 4329 +preadv 4330 +pwritev 4331 +rt_tgsigqueueinfo 4332 +perf_event_open 4333 +accept4 4334 +recvmmsg 4335 +fanotify_init 4336 +fanotify_mark 4337 +prlimit64 4338 +name_to_handle_at 4339 +open_by_handle_at 4340 +clock_adjtime 4341 +syncfs 4342 +sendmmsg 4343 +setns 4344 +process_vm_readv 4345 +process_vm_writev 4346 +kcmp 4347 +finit_module 4348 +sched_setattr 4349 +sched_getattr 4350 +renameat2 4351 +seccomp 4352 +getrandom 4353 +memfd_create 4354 +bpf 4355 +execveat 4356 +userfaultfd 4357 +membarrier 4358 +mlock2 4359 +copy_file_range 4360 +preadv2 4361 +pwritev2 4362 +pkey_mprotect 4363 +pkey_alloc 4364 +pkey_free 4365 +statx 4366 +rseq 4367 +io_pgetevents 4368 +semget 4393 +semctl 4394 +shmget 4395 +shmctl 4396 +shmat 4397 +shmdt 4398 +msgget 4399 +msgsnd 4400 +msgrcv 4401 +msgctl 4402 +clock_gettime64 4403 +clock_settime64 4404 +clock_adjtime64 4405 +clock_getres_time64 4406 +clock_nanosleep_time64 4407 +timer_gettime64 4408 +timer_settime64 4409 +timerfd_gettime64 4410 +timerfd_settime64 4411 +utimensat_time64 4412 +pselect6_time64 4413 +ppoll_time64 4414 +io_pgetevents_time64 4416 +recvmmsg_time64 4417 +mq_timedsend_time64 4418 +mq_timedreceive_time64 4419 +semtimedop_time64 4420 +rt_sigtimedwait_time64 4421 +futex_time64 4422 +sched_rr_get_interval_time64 4423 +pidfd_send_signal 4424 +io_uring_setup 4425 +io_uring_enter 4426 +io_uring_register 4427 +open_tree 4428 +move_mount 4429 +fsopen 4430 +fsconfig 4431 +fsmount 4432 +fspick 4433 +pidfd_open 4434 +clone3 4435 +close_range 4436 +openat2 4437 +pidfd_getfd 4438 +faccessat2 4439 +process_madvise 4440 +epoll_pwait2 4441 +mount_setattr 4442 +quotactl_fd 4443 diff --git a/include/lapi/syscalls/order b/include/lapi/syscalls/order old mode 100644 new mode 100755 diff --git a/include/lapi/syscalls/powerpc.in b/include/lapi/syscalls/powerpc.in old mode 100644 new mode 100755 index cdbebc62d9c1c7cc9953fb98589c95c98a247917..f4e85940c2c7326c6cabdf5814c45b64be9bc7dc --- a/include/lapi/syscalls/powerpc.in +++ b/include/lapi/syscalls/powerpc.in @@ -417,5 +417,8 @@ fsmount 432 fspick 433 pidfd_open 434 clone3 435 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in old mode 100644 new mode 100755 index cdbebc62d9c1c7cc9953fb98589c95c98a247917..f4e85940c2c7326c6cabdf5814c45b64be9bc7dc --- a/include/lapi/syscalls/powerpc64.in +++ b/include/lapi/syscalls/powerpc64.in @@ -417,5 +417,8 @@ fsmount 432 fspick 433 pidfd_open 434 clone3 435 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/regen.sh b/include/lapi/syscalls/regen.sh index 7a4f0cf443765888f92f7987ee74192afec6d2ac..d7daf8ad0f3d3c434ea30520212db3ed071d25bc 100755 --- a/include/lapi/syscalls/regen.sh +++ b/include/lapi/syscalls/regen.sh @@ -27,8 +27,8 @@ cat << EOF > "${output_pid}" * Licensed under the GPLv2 or later, see the COPYING file. */ -#ifndef __LAPI_SYSCALLS_H__ -#define __LAPI_SYSCALLS_H__ +#ifndef LAPI_SYSCALLS_H__ +#define LAPI_SYSCALLS_H__ #include #include @@ -80,7 +80,7 @@ for arch in $(cat "${srcdir}/order") ; do s390) echo "#if defined(__s390__) && !defined(__s390x__)" ;; mips_n32) echo "#if defined(__mips__) && defined(_ABIN32)" ;; mips_n64) echo "#if defined(__mips__) && defined(_ABI64)" ;; - mips_o32) echo "#if defined(__mips__) && defined(_ABIO32)" ;; + mips_o32) echo "#if defined(__mips__) && defined(_ABIO32) && _MIPS_SZLONG == 32" ;; *) echo "#ifdef __${arch}__" ;; esac while read line ; do diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in old mode 100644 new mode 100755 index c3f249aedf7bd5881d2571e18870070b5fd31376..3e16d84750a5004c64da4bcc2db8f456f97fd1b9 --- a/include/lapi/syscalls/s390.in +++ b/include/lapi/syscalls/s390.in @@ -404,5 +404,8 @@ fsmount 432 fspick 433 pidfd_open 434 clone3 435 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/s390x.in b/include/lapi/syscalls/s390x.in old mode 100644 new mode 100755 index 88cc9b86bd9876cc99d6e636ee08e54f546fbe7a..beb0819aff1da1a35bb09df639e3d9113b6ae092 --- a/include/lapi/syscalls/s390x.in +++ b/include/lapi/syscalls/s390x.in @@ -352,5 +352,8 @@ fsmount 432 fspick 433 pidfd_open 434 clone3 435 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/sh.in b/include/lapi/syscalls/sh.in old mode 100644 new mode 100755 index 06055ed106d5dcc769d69ad6bbbe636bbb788fd8..a81cf8297a8eaf964906a59f5cb1fe482d29232f --- a/include/lapi/syscalls/sh.in +++ b/include/lapi/syscalls/sh.in @@ -398,5 +398,8 @@ fsconfig 431 fsmount 432 fspick 433 pidfd_open 434 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in old mode 100644 new mode 100755 index 522e3c99746ba2910f96fe7c2ad0a2aa600a41bf..6a7817ae5b3214fe994c85c6e0f63c581afdb6e2 --- a/include/lapi/syscalls/sparc.in +++ b/include/lapi/syscalls/sparc.in @@ -403,5 +403,8 @@ fsconfig 431 fsmount 432 fspick 433 pidfd_open 434 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/sparc64.in b/include/lapi/syscalls/sparc64.in old mode 100644 new mode 100755 index 6f884a7bf70dd97336071d5cf0e33b59d07ea652..d3995181c83713b88d85637c614a396d38c75e58 --- a/include/lapi/syscalls/sparc64.in +++ b/include/lapi/syscalls/sparc64.in @@ -368,5 +368,8 @@ fsconfig 431 fsmount 432 fspick 433 pidfd_open 434 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in old mode 100644 new mode 100755 index c76328c93abd45a27f0f0b29dc901bf4b7f292c5..a5b2a24fedb4bfa2de3e2877c0a2a39c86085a8d --- a/include/lapi/syscalls/x86_64.in +++ b/include/lapi/syscalls/x86_64.in @@ -345,8 +345,11 @@ fsmount 432 fspick 433 pidfd_open 434 clone3 435 +close_range 436 openat2 437 pidfd_getfd 438 +epoll_pwait2 441 +quotactl_fd 443 rt_sigaction 512 rt_sigreturn 513 ioctl 514 diff --git a/include/lapi/tcp.h b/include/lapi/tcp.h old mode 100644 new mode 100755 diff --git a/include/lapi/tee.h b/include/lapi/tee.h old mode 100644 new mode 100755 index 422e81177341c45f1790b2269d29dc5f8bce07fd..8ba3c9be36f744e4e935d3711412104f96d29b19 --- a/include/lapi/tee.h +++ b/include/lapi/tee.h @@ -4,17 +4,18 @@ * Copyright (c) 2014 Fujitsu Ltd. */ -#ifndef TEE_H -#define TEE_H +#ifndef LAPI_TEE_H__ +#define LAPI_TEE_H__ #include "config.h" #include "lapi/syscalls.h" #if !defined(HAVE_TEE) -ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags) +static inline ssize_t tee(int fd_in, int fd_out, + size_t len, unsigned int flags) { return tst_syscall(__NR_tee, fd_in, fd_out, len, flags); } #endif -#endif /* TEE_H */ +#endif /* LAPI_TEE_H__ */ diff --git a/include/lapi/termbits.h b/include/lapi/termbits.h old mode 100644 new mode 100755 index d79da085b15693b9d6d0796fa831e3ca16dcb0dd..04f5148181ae00e1d54ed76796d9e56e7b656b6f --- a/include/lapi/termbits.h +++ b/include/lapi/termbits.h @@ -10,4 +10,4 @@ # define EXTPROC 0200000 #endif -#endif +#endif /* LAPI_TERMBITS_H__ */ diff --git a/include/lapi/timerfd.h b/include/lapi/timerfd.h old mode 100644 new mode 100755 index 50e09726be4b190a93701e30cefb2b21fbd4750b..14f8405abf12606d8c29cbc14a5b881fbb854cf5 --- a/include/lapi/timerfd.h +++ b/include/lapi/timerfd.h @@ -4,8 +4,8 @@ * Copyright (c) 2014 Fujitsu Ltd. */ -#ifndef TIMERFD_H -#define TIMERFD_H +#ifndef LAPI_TIMERFD_H__ +#define LAPI_TIMERFD_H__ #include #include "config.h" @@ -16,15 +16,16 @@ #endif #if !defined(HAVE_TIMERFD_CREATE) -int timerfd_create(int clockid, int flags) +static inline int timerfd_create(int clockid, int flags) { return ltp_syscall(__NR_timerfd_create, clockid, flags); } #endif #if !defined(HAVE_TIMERFD_GETTIME) -int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, - struct itimerspec *old_value) +static inline int timerfd_settime(int fd, int flags, + const struct itimerspec *new_value, + struct itimerspec *old_value) { return ltp_syscall(__NR_timerfd_settime, fd, flags, new_value, old_value); @@ -32,10 +33,10 @@ int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, #endif #if !defined(HAVE_TIMERFD_SETTIME) -int timerfd_gettime(int fd, struct itimerspec *curr_value) +static inline int timerfd_gettime(int fd, struct itimerspec *curr_value) { return ltp_syscall(__NR_timerfd_gettime, fd, curr_value); } #endif -#endif /* TIMERFD_H */ +#endif /* LAPI_TIMERFD_H__ */ diff --git a/include/lapi/timex.h b/include/lapi/timex.h old mode 100644 new mode 100755 diff --git a/include/lapi/tty.h b/include/lapi/tty.h old mode 100644 new mode 100755 index 353a103f12711613d53f0b6293d019ead115a5c2..93a6254347c305341ed29b59119a4ae8864e9b48 --- a/include/lapi/tty.h +++ b/include/lapi/tty.h @@ -3,15 +3,19 @@ * Copyright (c) 2020 Petr Vorel */ -#ifndef LAPI_TTY_H -#define LAPI_TTY_H +#ifndef LAPI_TTY_H__ +#define LAPI_TTY_H__ #ifdef HAVE_LINUX_TTY_H # include #endif +#ifndef N_HDLC +# define N_HDLC 13 +#endif + #ifndef N_SLCAN # define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ #endif -#endif /* LAPI_TTY_H */ +#endif /* LAPI_TTY_H__ */ diff --git a/include/lapi/udp.h b/include/lapi/udp.h old mode 100644 new mode 100755 diff --git a/include/lapi/ustat.h b/include/lapi/ustat.h old mode 100644 new mode 100755 index 98633e7494e2ac557ec0e720e65745fc006badd2..218a53b14b000d6fdd09ba78f6d16ae5a102750b --- a/include/lapi/ustat.h +++ b/include/lapi/ustat.h @@ -1,7 +1,7 @@ //SPDX-License-Identifier: GPL-2.0-or-later -#ifndef LAPI_USTAT_H -#define LAPI_USTAT_H +#ifndef LAPI_USTAT_H__ +#define LAPI_USTAT_H__ #include "config.h" @@ -19,4 +19,4 @@ struct ustat { }; #endif -#endif /* LAPI_USTAT_H */ +#endif /* LAPI_USTAT_H__ */ diff --git a/include/lapi/utime.h b/include/lapi/utime.h old mode 100644 new mode 100755 index dbfaa55be35dde8c05c1950ffc7512646624c193..a8085ae0a910831b83a9360274bbb99395ed29a6 --- a/include/lapi/utime.h +++ b/include/lapi/utime.h @@ -3,7 +3,8 @@ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. */ -#ifndef __UTIME_H__ +#ifndef LAPI_UTIME_H__ +#define LAPI_UTIME_H__ #ifndef UTIME_NOW # define UTIME_NOW ((1l << 30) - 1l) @@ -13,4 +14,4 @@ # define UTIME_OMIT ((1l << 30) - 2l) #endif -#endif /* __UTIME_H__ */ +#endif /* LAPI_UTIME_H__ */ diff --git a/include/lapi/utsname.h b/include/lapi/utsname.h old mode 100644 new mode 100755 index 6209eac47b631ff558061a83b8c8dce329ea5ca2..f94d3e1e3298be748fe83a7093e7ec9d974ae48c --- a/include/lapi/utsname.h +++ b/include/lapi/utsname.h @@ -3,6 +3,9 @@ * Copyright (c) 2019 Petr Vorel */ +#ifndef LAPI_UTSNAME_H__ +#define LAPI_UTSNAME_H__ + #ifdef HAVE_SYS_UTSNAME_H # include #endif @@ -14,3 +17,5 @@ #ifndef _UTSNAME_DOMAIN_LENGTH # define _UTSNAME_DOMAIN_LENGTH _UTSNAME_LENGTH #endif + +#endif /* LAPI_UTSNAME_H__ */ diff --git a/include/lapi/vm_sockets.h b/include/lapi/vm_sockets.h new file mode 100755 index 0000000000000000000000000000000000000000..07884e538688569b5325b251fd629f20e44c1cdb --- /dev/null +++ b/include/lapi/vm_sockets.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC + */ + +#ifndef LAPI_VM_SOCKETS_H__ +#define LAPI_VM_SOCKETS_H__ + +#include + +#if HAVE_LINUX_VM_SOCKETS_H +# include +#endif + +#ifndef VMADDR_CID_LOCAL +# define VMADDR_CID_LOCAL 1 +#endif + +#endif /* LAPI_VM_SOCKETS_H__ */ diff --git a/include/lapi/vmsplice.h b/include/lapi/vmsplice.h old mode 100644 new mode 100755 index ba0fcca2777f6dda18642bf4751a8c541478abc5..b6db77cb9e9bcad6960b572958fb73e3d4c6a24a --- a/include/lapi/vmsplice.h +++ b/include/lapi/vmsplice.h @@ -4,8 +4,8 @@ * Copyright (c) 2014 Cyril Hrubis */ -#ifndef VMSPLICE_H -#define VMSPLICE_H +#ifndef LAPI_VMSPLICE_H__ +#define LAPI_VMSPLICE_H__ #include "config.h" #include "lapi/syscalls.h" @@ -13,11 +13,11 @@ #include "lapi/iovec.h" #if !defined(HAVE_VMSPLICE) -ssize_t vmsplice(int fd, const struct iovec *iov, - unsigned long nr_segs, unsigned int flags) +static inline ssize_t vmsplice(int fd, const struct iovec *iov, + unsigned long nr_segs, unsigned int flags) { return tst_syscall(__NR_vmsplice, fd, iov, nr_segs, flags); } #endif -#endif /* VMSPLICE_H */ +#endif /* LAPI_VMSPLICE_H__ */ diff --git a/include/lapi/xfrm.h b/include/lapi/xfrm.h old mode 100644 new mode 100755 index d9051202c160905d4178911fcef86f110ff99c2f..48503b7ef1bac5040b3c2861ad4b5620a9ed6e07 --- a/include/lapi/xfrm.h +++ b/include/lapi/xfrm.h @@ -14,4 +14,4 @@ # define XFRM_MSG_GETPOLICY 21 #endif -#endif +#endif /* LAPI_XFRM_H__ */ diff --git a/testcases/kernel/syscalls/ipc/lib/libmsgctl.h b/include/libmsgctl.h old mode 100644 new mode 100755 similarity index 100% rename from testcases/kernel/syscalls/ipc/lib/libmsgctl.h rename to include/libmsgctl.h diff --git a/testcases/kernel/syscalls/ipc/libnewipc/libnewipc.h b/include/libnewipc.h old mode 100644 new mode 100755 similarity index 84% rename from testcases/kernel/syscalls/ipc/libnewipc/libnewipc.h rename to include/libnewipc.h index 660be8088053d9192733d7064662281c648ae4ee..9eec317638a554b688748a0322145368b0d83096 --- a/testcases/kernel/syscalls/ipc/libnewipc/libnewipc.h +++ b/include/libnewipc.h @@ -22,6 +22,9 @@ #ifndef __LIBNEWIPC_H #define __LIBNEWIPC_H 1 +#include +#include + #define MSG_RD 0400 #define MSG_WR 0200 #define MSG_RW (MSG_RD | MSG_WR) @@ -46,9 +49,11 @@ key_t getipckey(const char *file, const int lineno); #define GETIPCKEY() \ getipckey(__FILE__, __LINE__) -int get_used_queues(const char *file, const int lineno); +int get_used_sysvipc(const char *file, const int lineno, const char *sysvipc_file); #define GET_USED_QUEUES() \ - get_used_queues(__FILE__, __LINE__) + get_used_sysvipc(__FILE__, __LINE__, "/proc/sysvipc/msg") +#define GET_USED_SEGMENTS() \ + get_used_sysvipc(__FILE__, __LINE__, "/proc/sysvipc/shm") void *probe_free_addr(const char *file, const int lineno); #define PROBE_FREE_ADDR() \ diff --git a/include/libsigwait.h b/include/libsigwait.h new file mode 100755 index 0000000000000000000000000000000000000000..2fca578b19aca8218cf915672bbb7e4053a71959 --- /dev/null +++ b/include/libsigwait.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef SIGWAIT_H__ +#define SIGWAIT_H__ + +#include "tst_test.h" +#include "tst_timer.h" +#include + +/* swi: sigwaitinfo() */ +typedef int (*swi_func) (const sigset_t * set, siginfo_t * info, + void * timeout); +typedef void (*test_func) (swi_func, int, enum tst_ts_type type); + +struct sigwait_test_desc { + test_func tf; + int signo; +}; + +void test_empty_set(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void test_timeout(swi_func sigwaitinfo, int signo, enum tst_ts_type type); +void test_unmasked_matching(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void test_unmasked_matching_noinfo(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void test_masked_matching(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void test_masked_matching_rt(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void test_masked_matching_noinfo(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void test_bad_address(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void test_bad_address2(swi_func sigwaitinfo, int signo LTP_ATTRIBUTE_UNUSED, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void test_bad_address3(swi_func sigwaitinfo, int signo LTP_ATTRIBUTE_UNUSED, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED); +void sigwait_setup(void); +#endif /* SIGWAIT_H__ */ diff --git a/include/libswap.h b/include/libswap.h new file mode 100755 index 0000000000000000000000000000000000000000..d4b5301a54a58ecb3e90a63df49b6c1275496ffc --- /dev/null +++ b/include/libswap.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Author: Stanislav Kholmanskikh + */ + +/* + * Contains common content for all swapon/swapoff tests + */ + +#ifndef __LIBSWAP_H__ +#define __LIBSWAP_H__ + +/* + * Make a swap file + */ +int make_swapfile(const char *swapfile, int safe); + +/* + * Check swapon/swapoff support status of filesystems or files + * we are testing on. + */ +void is_swap_supported(const char *filename); +#endif /* __LIBSWAP_H__ */ diff --git a/include/mk/automake.mk b/include/mk/automake.mk old mode 100644 new mode 100755 diff --git a/include/mk/config-openposix.mk.in b/include/mk/config-openposix.mk.in old mode 100644 new mode 100755 diff --git a/include/mk/config.mk.in b/include/mk/config.mk.in old mode 100644 new mode 100755 index 427608a17b61fb033d33d7b1189eeb852c3df4dc..218447ef38b3fb413d3576a0c9292dd4a5696f0c --- a/include/mk/config.mk.in +++ b/include/mk/config.mk.in @@ -31,6 +31,19 @@ RANLIB := @RANLIB@ STRIP := @STRIP@ YACC := @YACC@ +HOSTCC = @HOSTCC@ +build := @build@ +host := @host@ +ifeq ($(strip $(HOSTCC)),) +# native build, respect CC +ifeq ($(build),$(host)) +HOSTCC := $(CC) +else +# cross compilation +HOSTCC := cc +endif +endif + AIO_LIBS := @AIO_LIBS@ CAP_LIBS := @CAP_LIBS@ ACL_LIBS := @ACL_LIBS@ @@ -39,8 +52,8 @@ LEXLIB := @LEXLIB@ NUMA_LIBS := @NUMA_LIBS@ SELINUX_LIBS := @SELINUX_LIBS@ HAVE_RPC := @HAVE_RPC@ -TIRPC_CFLAGS := @TIRPC_CFLAGS@ -TIRPC_LIBS := @TIRPC_LIBS@ +LIBTIRPC_CFLAGS := @LIBTIRPC_CFLAGS@ +LIBTIRPC_LIBS := @LIBTIRPC_LIBS@ KEYUTILS_LIBS := @KEYUTILS_LIBS@ HAVE_FTS_H := @HAVE_FTS_H@ LIBMNL_LIBS := @LIBMNL_LIBS@ @@ -70,6 +83,14 @@ WCFLAGS ?= -Wall -W @GCC_WARN_OLDSTYLE@ LDFLAGS += $(WLDFLAGS) CFLAGS += $(DEBUG_CFLAGS) $(OPT_CFLAGS) $(WCFLAGS) +ifeq ($(strip $(HOST_CFLAGS)),) +HOST_CFLAGS := $(CFLAGS) +endif + +ifeq ($(strip $(HOST_LDFLAGS)),) +HOST_LDFLAGS := $(LDFLAGS) +endif + LINUX_VERSION := @LINUX_VERSION@ LINUX_DIR := @LINUX_DIR@ LINUX_VERSION_MAJOR := @LINUX_VERSION_MAJOR@ diff --git a/include/mk/env_post.mk b/include/mk/env_post.mk old mode 100644 new mode 100755 index f4169ad666327a330849fb0be4571fbc9b3aaef8..ec045c40dd5e3a5c784c42e2cb24aca6287ebfd0 --- a/include/mk/env_post.mk +++ b/include/mk/env_post.mk @@ -1,7 +1,8 @@ # # Environment post-setup Makefile. # -# Copyright (C) 2009, Cisco Systems Inc. +# Copyright (c) Linux Test Project, 2009-2020 +# Copyright (c) Cisco Systems Inc., 2009 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -46,12 +47,11 @@ LDFLAGS += -L$(top_builddir)/lib/android_libpthread LDFLAGS += -L$(top_builddir)/lib/android_librt endif -MAKE_TARGETS ?= $(notdir $(patsubst %.c,%,$(wildcard $(abs_srcdir)/*.c))) - +MAKE_TARGETS ?= $(notdir $(patsubst %.c,%,$(sort $(wildcard $(abs_srcdir)/*.c)))) MAKE_TARGETS := $(filter-out $(FILTER_OUT_MAKE_TARGETS),$(MAKE_TARGETS)) # with only *.dwo, .[0-9]+.dwo can not be cleaned -CLEAN_TARGETS += $(MAKE_TARGETS) *.o *.pyc .cache.mk *.dwo .*.dwo +CLEAN_TARGETS += $(MAKE_TARGETS) $(HOST_MAKE_TARGETS) *.o *.pyc .cache.mk *.dwo .*.dwo # Majority of the files end up in testcases/bin... INSTALL_DIR ?= testcases/bin @@ -79,32 +79,27 @@ INSTALL_TARGETS := $(patsubst $(abs_srcdir)/%,%,$(INSTALL_TARGETS)) # scripts, so let's chmod them like that. INSTALL_MODE ?= 00775 -ifdef MAKE_3_80_COMPAT - -INSTALL_PATH := $(call MAKE_3_80_abspath,$(DESTDIR)/$(INSTALL_DIR)) - -INSTALL_TARGETS_ABS := $(call MAKE_3_80_abspath,$(addprefix $(INSTALL_PATH)/,$(INSTALL_TARGETS))) -MAKE_TARGETS_ABS := $(call MAKE_3_80_abspath,$(addprefix $(INSTALL_PATH)/,$(MAKE_TARGETS))) - -INSTALL_FILES := $(INSTALL_TARGETS_ABS) $(MAKE_TARGETS_ABS) - -$(INSTALL_TARGETS_ABS): - test -d "$(@D)" || mkdir -p "$(@D)" - install -m $(INSTALL_MODE) "$(abs_srcdir)/$(subst $(INSTALL_PATH)/,,$@)" "$@" - -$(MAKE_TARGETS_ABS): - test -d "$(@D)" || mkdir -p "$(@D)" - install -m $(INSTALL_MODE) "$(abs_builddir)/$(subst $(INSTALL_PATH)/,,$@)" "$@" -else $(abspath $(addprefix $(DESTDIR)/$(INSTALL_DIR)/,$(sort $(dir $(INSTALL_TARGETS) $(MAKE_TARGETS))))): mkdir -p "$@" $(foreach install_target,$(INSTALL_TARGETS),$(eval $(call generate_install_rule,$(install_target),$(abs_srcdir),$(INSTALL_DIR)))) $(foreach make_target,$(MAKE_TARGETS),$(eval $(call generate_install_rule,$(make_target),$(abs_builddir),$(INSTALL_DIR)))) -endif else # else ! $(filter-out install,$(MAKECMDGOALS)),$(MAKECMDGOALS) $(error You must define $$(prefix) before executing install) endif # END $(filter-out install,$(MAKECMDGOALS)),$(MAKECMDGOALS) endif +CHECK_TARGETS ?= $(addprefix check-,$(notdir $(patsubst %.c,%,$(sort $(wildcard $(abs_srcdir)/*.c))))) +CHECK_TARGETS := $(filter-out $(addprefix check-, $(FILTER_OUT_MAKE_TARGETS)), $(CHECK_TARGETS)) +CHECK ?= $(abs_top_srcdir)/tools/sparse/sparse-ltp +CHECK_NOFLAGS ?= $(abs_top_srcdir)/scripts/checkpatch.pl -f --no-tree --terse --no-summary --ignore CONST_STRUCT,VOLATILE,SPLIT_STRING +SHELL_CHECK ?= $(abs_top_srcdir)/scripts/checkbashisms.pl --force --extra +SHELL_CHECK_TARGETS ?= $(addprefix check-,$(notdir $(sort $(wildcard $(abs_srcdir)/*.sh)))) + +ifeq ($(CHECK),$(abs_top_srcdir)/tools/sparse/sparse-ltp) +CHECK_DEPS += $(CHECK) +endif + +include $(top_srcdir)/include/mk/rules.mk + endif diff --git a/include/mk/env_pre.mk b/include/mk/env_pre.mk old mode 100644 new mode 100755 index c4a1f470810e4759e533e1b25c066a7d32c39cf0..f362151675d0055e3c643cb2c94d84654d47638a --- a/include/mk/env_pre.mk +++ b/include/mk/env_pre.mk @@ -1,7 +1,8 @@ # # Make pre-include environment Makefile. # -# Copyright (C) 2009, Cisco Systems Inc. +# Copyright (c) Linux Test Project, 2009-2020 +# Copyright (c) Cisco Systems Inc., 2009 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -36,28 +37,13 @@ BUILD_TREE_NONSRCDIR_INSTALL := 3 # configure not run. BUILD_TREE_UNCONFIGURED := 4 -ifndef MAKE_VERSION_CHECK -export MAKE_VERSION_CHECK = 1 -ifneq ($(firstword $(sort 3.80 $(MAKE_VERSION))),3.80) -$(error Your version of make $(MAKE_VERSION) is too old. Upgrade to at least 3.80; 3.81+ is preferred) -else -ifneq ($(filter 3.80%,$(MAKE_VERSION)),) -export MAKE_3_80_COMPAT := 1 -endif # make 3.80? -endif # At least make 3.80? -endif # MAKE_VERSION_CHECK - # Get the absolute path for the source directory. top_srcdir ?= $(error You must define top_srcdir before including this file) include $(top_srcdir)/include/mk/functions.mk # Where's the root source directory? -ifdef MAKE_3_80_COMPAT -abs_top_srcdir := $(call MAKE_3_80_abspath,$(top_srcdir)) -else abs_top_srcdir := $(abspath $(top_srcdir)) -endif # # Where's the root object directory? @@ -67,26 +53,20 @@ endif # top_builddir ?= $(top_srcdir) -# We need the absolute path... -ifdef MAKE_3_80_COMPAT -abs_top_builddir := $(call MAKE_3_80_abspath,$(top_builddir)) -else +# We need the absolute path abs_top_builddir := $(abspath $(top_builddir)) -endif # Where's the root object directory? builddir := . abs_builddir := $(CURDIR) -cwd_rel_from_top := $(subst $(abs_top_builddir),,$(abs_builddir)) +cwd_rel1 := $(subst $(abs_top_builddir),,$(abs_builddir)) +cwd_rel2 := $(subst $(abs_top_builddir)/,,$(abs_builddir)) +cwd_rel_from_top := $(if $(cwd_rel1),$(cwd_rel2),$(cwd_rel1)) -# Where's the source located at? Squish all of the / away by using abspath... -ifdef MAKE_3_80_COMPAT -abs_srcdir := $(call MAKE_3_80_abspath,$(abs_top_srcdir)/$(cwd_rel_from_top)) -else +# Where's the source located at? Squish all of the / away by using abspath abs_srcdir := $(abspath $(abs_top_srcdir)/$(cwd_rel_from_top)) -endif srcdir := $(strip $(subst $(abs_top_srcdir)/,,$(abs_srcdir))) @@ -136,13 +116,7 @@ BUILD_TREE_STATE := $(BUILD_TREE_NONSRCDIR_INSTALL) endif endif -ifeq ($(MAKE_3_80_COMPAT),1) -# Trick make 3.80 into thinking that the default goal is all. -.PHONY: default -default: all -else .DEFAULT_GOAL := all -endif endif # END autotools, *clean... @@ -152,4 +126,8 @@ BUILD_TREE_STATE ?= $(BUILD_TREE_UNCONFIGURED) # just these two vars and $(CURDIR). export abs_top_srcdir abs_top_builddir BUILD_TREE_STATE +ifeq ($V,1) +VERBOSE=1 +endif + endif diff --git a/include/mk/features.mk.in b/include/mk/features.mk.in old mode 100644 new mode 100755 index 8e561b73841a36a6231d1429246f1a3528be5027..ecb15a0f79dfb96531cdd22cb5fa30f695b5a886 --- a/include/mk/features.mk.in +++ b/include/mk/features.mk.in @@ -27,6 +27,11 @@ WITH_PERL := @WITH_PERL@ WITH_PYTHON := @WITH_PYTHON@ +METADATA_GENERATOR := @METADATA_GENERATOR@ +WITH_METADATA := @WITH_METADATA@ +WITH_METADATA_HTML := @WITH_METADATA_HTML@ +WITH_METADATA_PDF := @WITH_METADATA_PDF@ + # Features knobs # Test suite knobs diff --git a/include/mk/functions.mk b/include/mk/functions.mk old mode 100644 new mode 100755 index 6f67b5af8c3bfc782884030ae8e40f6b0a87db54..e86dbccdc0bbf7d0d5ba753cb10b484f4ea916a9 --- a/include/mk/functions.mk +++ b/include/mk/functions.mk @@ -1,7 +1,8 @@ # # A Makefile with a collection of reusable functions. # -# Copyright (C) 2009, Cisco Systems Inc. +# Copyright (c) Linux Test Project, 2009-2020 +# Copyright (c) Cisco Systems Inc., 2009 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -20,25 +21,6 @@ # Ngie Cooper, July 2009 # -SQUOTE := ' - -# ' # to keep colorized editors from going nuts - -MAKE_3_80_realpath = $(shell $(top_srcdir)/scripts/realpath.sh '$(subst $(SQUOTE),\\$(SQUOTE),$(1))') - -MAKE_3_80_abspath = $(shell $(top_srcdir)/scripts/abspath.sh '$(subst $(SQUOTE),\\$(SQUOTE),$(1))') - -# -# NOTE (garrcoop): -# -# The following functions are (sometimes) split into 3.80 and 3.81+ -# counterparts, and not conditionalized inside of the define(s) to work around -# an issue with how make 3.80 evaluates defines. -# -# SO DO NOT INTERNALIZE CONDITIONALS IN DEFINES OR YOU WILL BREAK MAKE 3.80! -# - -# # Generate an install rule which also creates the install directory if needed # to avoid unnecessary bourne shell based for-loops and install errors, as well # as adhoc install rules. @@ -46,26 +28,16 @@ MAKE_3_80_abspath = $(shell $(top_srcdir)/scripts/abspath.sh '$(subst $(SQUOTE), # 1 -> Target basename. # 2 -> Source directory. # 3 -> Destination directory. -# -ifdef MAKE_3_80_COMPAT -define generate_install_rule - -INSTALL_FILES += $$(call MAKE_3_80_abspath,$$(DESTDIR)/$(3)/$(1)) -$$(call MAKE_3_80_abspath,$$(DESTDIR)/$(3)/$(1)): \ - $$(call MAKE_3_80_abspath,$$(dir $$(DESTDIR)/$(3)/$(1))) - install -m $$(INSTALL_MODE) "$(2)/$(1)" "$$@" -endef -else # not MAKE_3_80_COMPAT define generate_install_rule INSTALL_FILES += $$(abspath $$(DESTDIR)/$(3)/$(1)) $$(abspath $$(DESTDIR)/$(3)/$(1)): \ $$(abspath $$(dir $$(DESTDIR)/$(3)/$(1))) - install -m $$(INSTALL_MODE) "$(2)/$(1)" "$$@" + install -m $$(INSTALL_MODE) $(shell test -d "$(2)/$(1)" && echo "-d") $(PARAM) "$(2)/$(1)" $$@ + $(shell test -d "$(2)/$(1)" && echo "install -m "'$$(INSTALL_MODE) $(PARAM)' "$(2)/$(1)/*" -t '$$@') endef -endif # END MAKE_3_80_COMPAT # # Set SUBDIRS to the subdirectories where Makefiles were found. diff --git a/include/mk/generic_leaf_target.inc b/include/mk/generic_leaf_target.inc old mode 100644 new mode 100755 index dd54d05e9664929a90e1721bfe20a9ed20075b86..33e9c9ea02ada1076f599728ae5b6ad7f1c0ab70 --- a/include/mk/generic_leaf_target.inc +++ b/include/mk/generic_leaf_target.inc @@ -57,11 +57,13 @@ # rope to hang one's self in the event of # unwanted behavior. # +# $(HOST_MAKE_TARGETS) : Host tools which use $HOSTCC. +# # $(CLEAN_TARGETS) : What targets should be cleaned (must be -# real files). This will automatically append -# adds the .o suffix to all files referenced -# by $(MAKE_TARGETS)) to CLEAN_TARGETS, if -# MAKE_TARGETS wasn't defined (see +# real files or directories). This will automatically append +# adds the .o suffix to all files referenced by +# $(MAKE_TARGETS)) to CLEAN_TARGETS, if MAKE_TARGETS wasn't +# defined (see # $(MAKE_TARGETS)). # $(INSTALL_MODE) : What mode should we using when calling # install(1)? @@ -90,17 +92,24 @@ # INSTALL_DIR := $(libdir) # -.PHONY: all clean install +.PHONY: all clean install check + +ifneq ($(strip $(MAKE_TARGETS)),) +$(MAKE_TARGETS) += $(HOST_MAKE_TARGETS) +endif $(MAKE_TARGETS): | $(MAKE_DEPS) all: $(MAKE_TARGETS) clean:: $(CLEAN_DEPS) - -$(RM) -f $(CLEAN_TARGETS) + -$(RM) -f -r $(CLEAN_TARGETS) $(INSTALL_FILES): | $(INSTALL_DEPS) install: $(INSTALL_FILES) +$(CHECK_TARGETS): | $(CHECK_DEPS) +check: $(CHECK_TARGETS) $(SHELL_CHECK_TARGETS) + # vim: syntax=make diff --git a/include/mk/generic_leaf_target.mk b/include/mk/generic_leaf_target.mk old mode 100644 new mode 100755 diff --git a/include/mk/generic_trunk_target.inc b/include/mk/generic_trunk_target.inc old mode 100644 new mode 100755 index cc255c62a8c491d830c7a7dedc5624889cda4e59..82aece7c02680c3faf76add58d08d68762908637 --- a/include/mk/generic_trunk_target.inc +++ b/include/mk/generic_trunk_target.inc @@ -48,7 +48,7 @@ include $(top_srcdir)/include/mk/functions.mk -RECURSIVE_TARGETS ?= all install +RECURSIVE_TARGETS ?= all install check $(eval $(get_make_dirs)) @@ -68,6 +68,9 @@ $(INSTALL_FILES): | $(INSTALL_DEPS) trunk-install: $(INSTALL_FILES) +$(CHECK_TARGETS): | $(CHECK_DEPS) +trunk-check: $(CHECK_TARGETS) $(SHELL_CHECK_TARGETS) + # Avoid creating duplicate .PHONY references to all, clean, and install. IIRC, # I've seen some indeterministic behavior when one does this in the past with # GNU Make... @@ -75,9 +78,16 @@ trunk-install: $(INSTALL_FILES) all: trunk-all clean:: trunk-clean +ifdef VERBOSE @set -e; for dir in $(SUBDIRS); do \ $(MAKE) -C "$$dir" -f "$(abs_srcdir)/$$dir/Makefile" $@; \ done +else + @set -e; for dir in $(SUBDIRS); do \ + echo "DIR $$dir"; \ + $(MAKE) --no-print-directory -C "$$dir" -f "$(abs_srcdir)/$$dir/Makefile" $@; \ + done +endif ifneq ($(abs_builddir),$(abs_srcdir)) $(RM) -Rf $(SUBDIRS) endif @@ -90,9 +100,17 @@ ifeq ($(strip $(SUBDIRS)),) $(error SUBDIRS empty -- did you want generic_leaf_target instead?) else $(RECURSIVE_TARGETS): %: | $(SUBDIRS) +ifdef VERBOSE @set -e; for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir -f "$(abs_srcdir)/$$dir/Makefile" $@; \ done +else + @set -e; for dir in $(SUBDIRS); do \ + $(MAKE) --no-print-directory -C $$dir -f "$(abs_srcdir)/$$dir/Makefile" $@; \ + done endif +endif + +check: trunk-check # vim: syntax=make diff --git a/include/mk/generic_trunk_target.mk b/include/mk/generic_trunk_target.mk old mode 100644 new mode 100755 diff --git a/include/mk/gitignore.mk b/include/mk/gitignore.mk old mode 100644 new mode 100755 diff --git a/include/mk/lib.mk b/include/mk/lib.mk old mode 100644 new mode 100755 index 36e1ba17b1b9a3cc636263bea1c3b35c597dc143..3bf63bf9e86d788d2206d2669c580060ef40b319 --- a/include/mk/lib.mk +++ b/include/mk/lib.mk @@ -1,7 +1,8 @@ # # library include Makefile. # -# Copyright (C) 2009, Cisco Systems Inc. +# Copyright (c) Linux Test Project, 2009-2020 +# Copyright (c) Cisco Systems Inc., 2009 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,6 +26,7 @@ # Makefile to include for libraries. include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/sparse.mk INSTALL_DIR := $(libdir) @@ -49,25 +51,28 @@ endif MAKE_TARGETS += $(LIB) LIBSRCS ?= $(wildcard $(abs_srcdir)/*.c) - -ifdef MAKE_3_80_COMPAT -LIBSRCS := $(call MAKE_3_80_abspath,$(LIBSRCS)) -else +LIBSRCS := $(sort $(LIBSRCS)) LIBSRCS := $(abspath $(LIBSRCS)) -endif - LIBSRCS := $(subst $(abs_srcdir)/,,$(wildcard $(LIBSRCS))) - LIBSRCS := $(filter-out $(FILTER_OUT_LIBSRCS),$(LIBSRCS)) LIBOBJS := $(LIBSRCS:.c=.o) +CHECK_TARGETS := $(addprefix check-,$(notdir $(LIBSRCS:.c=))) + $(LIB): $(notdir $(LIBOBJS)) - if [ -z "$(strip $^)" ] ; then \ + @if [ -z "$(strip $^)" ] ; then \ echo "Cowardly refusing to create empty archive"; \ exit 1; \ fi +ifdef VERBOSE $(if $(AR),$(AR),ar) -rc "$@" $^ $(if $(RANLIB),$(RANLIB),ranlib) "$@" +else + @echo "AR $@" + @$(if $(AR),$(AR),ar) -rc "$@" $^ + @echo "RANLIB $@" + @$(if $(RANLIB),$(RANLIB),ranlib) "$@" +endif include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/include/mk/man.mk b/include/mk/man.mk old mode 100644 new mode 100755 diff --git a/include/mk/module.mk b/include/mk/module.mk old mode 100644 new mode 100755 index 07d8fa89efa67a44d1db08491d294e2af68fe8d2..3bb7350f1ea393fcb86b2b3c623c705771939ac5 --- a/include/mk/module.mk +++ b/include/mk/module.mk @@ -42,10 +42,12 @@ endif ifneq ($(filter install clean,$(MAKECMDGOALS)),) MAKE_TARGETS := $(filter-out %.ko, $(MAKE_TARGETS)) -MAKE_TARGETS += $(wildcard *.ko) +MAKE_TARGETS += $(sort $(wildcard *.ko)) endif -CLEAN_TARGETS += .dep_modules +CLEAN_TARGETS += .dep_modules *.mod built-in.a + +CHECK_TARGETS := $(filter-out %.ko, $(CHECK_TARGETS)) MODULE_SOURCES := $(patsubst %.ko,%.c,$(filter %.ko, $(MAKE_TARGETS))) diff --git a/include/mk/rules.mk b/include/mk/rules.mk new file mode 100755 index 0000000000000000000000000000000000000000..a60e6705a5ffaab84a3bc4ed88627a4019f7c466 --- /dev/null +++ b/include/mk/rules.mk @@ -0,0 +1,59 @@ +target_rel_dir := $(if $(cwd_rel_from_top),$(cwd_rel_from_top)/,) + +%.o: %.c +ifdef VERBOSE + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< +else + @$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + @echo CC $(target_rel_dir)$@ +endif + +ifdef VERBOSE +COMPILE.c=$(CC) $(CPPFLAGS) $(CFLAGS) -c +else +COMPILE.c=@echo CC $(target_rel_dir)$@; $(CC) $(CPPFLAGS) $(CFLAGS) -c +endif + +%: %.o +ifdef VERBOSE + $(CC) $(LDFLAGS) $^ $(LTPLDLIBS) $(LDLIBS) -o $@ +else + @$(CC) $(LDFLAGS) $^ $(LTPLDLIBS) $(LDLIBS) -o $@ + @echo LD $(target_rel_dir)$@ +endif + +$(HOST_MAKE_TARGETS): %: %.c +ifdef VERBOSE + $(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $< $(HOST_LDLIBS) -o $@ +else + @$(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $< $(HOST_LDLIBS) -o $@ + @echo HOSTCC $(target_rel_dir)$@ +endif + +%: %.c +ifdef VERBOSE + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ $(LTPLDLIBS) $(LDLIBS) -o $@ +else + @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ $(LTPLDLIBS) $(LDLIBS) -o $@ + @echo CC $(target_rel_dir)$@ +endif + +.PHONY: $(CHECK_TARGETS) +$(CHECK_TARGETS): check-%: %.c +ifdef VERBOSE + -$(CHECK_NOFLAGS) $< + -$(CHECK) $(CHECK_FLAGS) $(CPPFLAGS) $(CFLAGS) $< +else + @echo CHECK $(target_rel_dir)$< + @-$(CHECK_NOFLAGS) $< + @-$(CHECK) $(CHECK_FLAGS) $(CPPFLAGS) $(CFLAGS) $< +endif + +.PHONY: $(SHELL_CHECK_TARGETS) +$(SHELL_CHECK_TARGETS): check-%.sh: %.sh +ifdef VERBOSE + -$(SHELL_CHECK) $< +else + @echo CHECK $(target_rel_dir)$< + @-$(SHELL_CHECK) $< +endif diff --git a/include/mk/sparse.mk b/include/mk/sparse.mk new file mode 100755 index 0000000000000000000000000000000000000000..a86928393afffb02c108872f87596c42fac9a7a5 --- /dev/null +++ b/include/mk/sparse.mk @@ -0,0 +1,9 @@ +# Rules to make sparse tool(s) for inclusion in lib and testcases Makefiles + +SPARSE_DIR:= $(abs_top_builddir)/tools/sparse + +$(SPARSE_DIR)/sparse-ltp: $(SPARSE_DIR) + $(MAKE) -C "$^" all + +$(SPARSE_DIR): %: + mkdir -p "$@" diff --git a/include/mk/testcases.mk b/include/mk/testcases.mk old mode 100644 new mode 100755 index 684655fbf0535f83aa12b5101dfbf5b5e498b06e..444020f16465d22682c10ea244fe4c453b07459e --- a/include/mk/testcases.mk +++ b/include/mk/testcases.mk @@ -22,6 +22,7 @@ include $(top_srcdir)/include/mk/env_pre.mk include $(top_srcdir)/include/mk/functions.mk +include $(top_srcdir)/include/mk/sparse.mk APICMDS_DIR := $(abs_top_builddir)/tools/apicmds @@ -48,8 +49,17 @@ LTPLIBS_FILES = $(addsuffix .a, $(addprefix $(abs_top_builddir)/libs/, $(foreach MAKE_DEPS += $(LTPLIBS_FILES) +.PHONY: $(LTPLIBS_FILES) + $(LTPLIBS_FILES): $(LTPLIBS_DIRS) - $(MAKE) -C "$^" -f "$(subst $(abs_top_builddir),$(abs_top_srcdir),$^)/Makefile" all + +$(LTPLIBS_FILES): %: +ifdef VERBOSE + $(MAKE) -C "$(dir $@)" -f "$(subst $(abs_top_builddir),$(abs_top_srcdir),$(dir $@))/Makefile" all +else + @echo "BUILD $(notdir $@)" + @$(MAKE) --no-print-directory -C "$(dir $@)" -f "$(subst $(abs_top_builddir),$(abs_top_srcdir),$(dir $@))/Makefile" all +endif LDFLAGS += $(addprefix -L$(top_builddir)/libs/lib, $(LTPLIBS)) diff --git a/include/old/cleanup.c b/include/old/cleanup.c old mode 100644 new mode 100755 diff --git a/include/old/ltp_cpuid.h b/include/old/ltp_cpuid.h old mode 100644 new mode 100755 diff --git a/include/old/ltp_priv.h b/include/old/ltp_priv.h old mode 100644 new mode 100755 index 0552457e591f2eba5b4809f939f21782aa471a20..0a0ef70f334775a056b6b63335fb86189296b08e --- a/include/old/ltp_priv.h +++ b/include/old/ltp_priv.h @@ -23,18 +23,7 @@ #define __LTP_PRIV_H__ #include - -/* - * This is the default temporary directory used by tst_tmpdir(). - * - * This is used when TMPDIR env variable is not set. - */ -#define TEMPDIR "/tmp" - -/* - * Default filesystem to be used for tests. - */ -#define DEFAULT_FS_TYPE "ext2" +#include "tst_defaults.h" /* environment variables for controlling tst_res verbosity */ #define TOUT_VERBOSE_S "VERBOSE" /* All test cases reported */ diff --git a/include/old/ltp_signal.h b/include/old/ltp_signal.h old mode 100644 new mode 100755 diff --git a/include/old/old_checkpoint.h b/include/old/old_checkpoint.h old mode 100644 new mode 100755 diff --git a/include/old/old_device.h b/include/old/old_device.h old mode 100644 new mode 100755 diff --git a/include/old/old_module.h b/include/old/old_module.h old mode 100644 new mode 100755 index c50efec76244f1674de02124b9e99eda876e380f..496520d64d1750d497543c67524e6eb1dde15ece --- a/include/old/old_module.h +++ b/include/old/old_module.h @@ -34,6 +34,14 @@ #ifndef TST_MODULE #define TST_MODULE +void tst_module_exists_(void (cleanup_fn)(void), const char *mod_name, + char **mod_path); + +void tst_module_load_(void (cleanup_fn)(void), const char *mod_name, + char *const argv[]); + +void tst_module_unload_(void (cleanup_fn)(void), const char *mod_name); + /* * Check module existence. * @@ -44,8 +52,11 @@ * * In case of failure, test'll call cleanup_fn and exit with TCONF return value. */ -void tst_module_exist(void (cleanup_fn)(void), const char *mod_name, - char **mod_path); +static inline void tst_module_exists(void (cleanup_fn)(void), + const char *mod_name, char **mod_path) +{ + tst_module_exists_(cleanup_fn, mod_name, mod_path); +} /* * Load a module using insmod program. @@ -58,8 +69,11 @@ void tst_module_exist(void (cleanup_fn)(void), const char *mod_name, * In case of insmod failure, test will call cleanup_fn and exit with TBROK * return value. */ -void tst_module_load(void (cleanup_fn)(void), - const char *mod_name, char *const argv[]); +static inline void tst_module_load(void (cleanup_fn)(void), + const char *mod_name, char *const argv[]) +{ + tst_module_load_(cleanup_fn, mod_name, argv); +} /* * Unload a module using rmmod program. In case of failure, test will call @@ -67,6 +81,9 @@ void tst_module_load(void (cleanup_fn)(void), * * @mod_name: can be module name or module's file name. */ -void tst_module_unload(void (cleanup_fn)(void), const char *mod_name); +static inline void tst_module_unload(void (cleanup_fn)(void), const char *mod_name) +{ + tst_module_unload_(cleanup_fn, mod_name); +} #endif /* TST_MODULE */ diff --git a/include/old/old_resource.h b/include/old/old_resource.h old mode 100644 new mode 100755 diff --git a/include/old/old_safe_file_ops.h b/include/old/old_safe_file_ops.h old mode 100644 new mode 100755 diff --git a/include/old/old_safe_net.h b/include/old/old_safe_net.h old mode 100644 new mode 100755 diff --git a/include/old/old_safe_stdio.h b/include/old/old_safe_stdio.h old mode 100644 new mode 100755 diff --git a/include/old/old_tmpdir.h b/include/old/old_tmpdir.h old mode 100644 new mode 100755 diff --git a/include/old/random_range.h b/include/old/random_range.h old mode 100644 new mode 100755 diff --git a/include/old/safe_macros.h b/include/old/safe_macros.h old mode 100644 new mode 100755 index e778d3077e86637a81e14d7e124ca872dc0fb76c..fb1d7a110b57550f640ff36e24561978202d3453 --- a/include/old/safe_macros.h +++ b/include/old/safe_macros.h @@ -157,7 +157,7 @@ /* * following functions are inline because the behaviour may depend on - * -D_FILE_OFFSET_BITS=64 -DOFF_T=__off64_t compile flags + * -D_FILE_OFFSET_BITS=64 compile flag */ static inline void *safe_mmap(const char *file, const int lineno, diff --git a/include/old/test.h b/include/old/test.h old mode 100644 new mode 100755 index 604254eea61b7202a4503d02a63fef19c3be148c..2ae7dba71fc2a4f4c6e04c019335c7b6520ac6a4 --- a/include/old/test.h +++ b/include/old/test.h @@ -129,7 +129,7 @@ void tst_resm_hexd_(const char *file, const int lineno, int ttype, tst_resm_hexd_(__FILE__, __LINE__, (ttype), (buf), (size), \ (arg_fmt), ##__VA_ARGS__) -void tst_brkm_(const char *file, const int lineno, int ttype, +void tst_brkm__(const char *file, const int lineno, int ttype, void (*func)(void), const char *arg_fmt, ...) __attribute__ ((format (printf, 5, 6))) LTP_ATTRIBUTE_NORETURN; @@ -139,11 +139,18 @@ void tst_brkm_(const char *file, const int lineno, int ttype, if (tst_test) \ tst_brk_(__FILE__, __LINE__, flags, fmt, ##__VA_ARGS__); \ else \ - tst_brkm_(__FILE__, __LINE__, flags, cleanup, fmt, ##__VA_ARGS__); \ + tst_brkm__(__FILE__, __LINE__, flags, cleanup, fmt, ##__VA_ARGS__); \ + } while (0) + +#define tst_brkm_(file, lineno, flags, cleanup, fmt, ...) do { \ + if (tst_test) \ + tst_brk_(file, lineno, flags, fmt, ##__VA_ARGS__); \ + else \ + tst_brkm__(file, lineno, flags, cleanup, fmt, ##__VA_ARGS__); \ } while (0) #else # define tst_brkm(flags, cleanup, fmt, ...) do { \ - tst_brkm_(__FILE__, __LINE__, flags, cleanup, fmt, ##__VA_ARGS__); \ + tst_brkm__(__FILE__, __LINE__, flags, cleanup, fmt, ##__VA_ARGS__); \ } while (0) #endif diff --git a/include/old/tlibio.h b/include/old/tlibio.h old mode 100644 new mode 100755 diff --git a/include/old/usctest.h b/include/old/usctest.h old mode 100644 new mode 100755 diff --git a/include/parse_vdso.h b/include/parse_vdso.h new file mode 100755 index 0000000000000000000000000000000000000000..5212fc659e34268f918b4efd9900e55331dad5d3 --- /dev/null +++ b/include/parse_vdso.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef PARSE_VDSO_H__ +#define PARSE_VDSO_H__ + +#include + +/* + * To use this vDSO parser, first call one of the vdso_init_* functions. + * If you've already parsed auxv, then pass the value of AT_SYSINFO_EHDR + * to vdso_init_from_sysinfo_ehdr. Otherwise pass auxv to vdso_init_from_auxv. + * Then call vdso_sym for each symbol you want. For example, to look up + * gettimeofday on x86_64, use: + * + * = vdso_sym("LINUX_2.6", "gettimeofday"); + * or + * = vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); + * + * vdso_sym will return 0 if the symbol doesn't exist or if the init function + * failed or was not called. vdso_sym is a little slow, so its return value + * should be cached. + * + * vdso_sym is threadsafe; the init functions are not. + * + * These are the prototypes: + */ + +#include + +extern void vdso_init_from_auxv(void *auxv); +extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); +extern void *vdso_sym(const char *version, const char *name); + +typedef int (*gettime_t)(clockid_t clk_id, void *ts); +void find_clock_gettime_vdso(gettime_t *ptr_vdso_gettime, + gettime_t *ptr_vdso_gettime64); +#endif /* PARSE_VDSO_H__ */ diff --git a/include/safe_file_ops_fn.h b/include/safe_file_ops_fn.h old mode 100644 new mode 100755 index 052fb1b9a474526c5575af4538054d1875e750d7..e8ed853829d343afb3e05300fe7dc678e428f186 --- a/include/safe_file_ops_fn.h +++ b/include/safe_file_ops_fn.h @@ -23,6 +23,16 @@ #include "lapi/utime.h" +/* + * Count number of expected assigned conversions. Any conversion starts with '%'. + * The '%%' matches % and no assignment is done. The %*x matches as x would do but + * the assignment is suppressed. + * + * NOTE: This is not 100% correct for complex scanf strings, but will do for + * all of our intended usage. + */ +int tst_count_scanf_conversions(const char *fmt); + /* * All-in-one function to scanf value(s) from a file. */ @@ -52,10 +62,14 @@ void safe_file_printf(const char *file, const int lineno, const char *path, const char *fmt, ...) __attribute__ ((format (printf, 5, 6))); +void safe_try_file_printf(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *path, const char *fmt, ...) + __attribute__ ((format (printf, 5, 6))); + /* * Safe function to copy files, no more system("cp ...") please. */ -void safe_cp(const char *file, const int lineno, +int safe_cp(const char *file, const int lineno, void (*cleanup_fn)(void), const char *src, const char *dst); @@ -71,7 +85,7 @@ void safe_cp(const char *file, const int lineno, * times is a timespec[2] (as for utimensat(2)). If times is NULL then * the access/modification times of the file is set to the current time. */ -void safe_touch(const char *file, const int lineno, +int safe_touch(const char *file, const int lineno, void (*cleanup_fn)(void), const char *pathname, mode_t mode, const struct timespec times[2]); diff --git a/include/safe_macros_fn.h b/include/safe_macros_fn.h old mode 100644 new mode 100755 diff --git a/include/safe_net_fn.h b/include/safe_net_fn.h old mode 100644 new mode 100755 index 2fda11fab7157511bc7c49924fd720717f9b2ece..ff81b13372b52efb71d52a91bf7ac95f0537dada --- a/include/safe_net_fn.h +++ b/include/safe_net_fn.h @@ -47,6 +47,9 @@ ssize_t safe_sendto(const char *file, const int lineno, char len_strict, ssize_t safe_sendmsg(const char *file, const int lineno, size_t msg_len, int sockfd, const struct msghdr *msg, int flags); +ssize_t safe_recv(const char *file, const int lineno, size_t len, + int sockfd, void *buf, size_t size, int flags); + ssize_t safe_recvmsg(const char *file, const int lineno, size_t msg_len, int sockfd, struct msghdr *msg, int flags); diff --git a/include/safe_stdio_fn.h b/include/safe_stdio_fn.h old mode 100644 new mode 100755 diff --git a/include/time64_variants.h b/include/time64_variants.h new file mode 100755 index 0000000000000000000000000000000000000000..fc52623c868a82f34945bb18aed20192df95a063 --- /dev/null +++ b/include/time64_variants.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef TIME64_VARIANTS_H +#define TIME64_VARIANTS_H + +#include "config.h" + +#ifdef HAVE_LIBAIO +#include +#endif + +#include +#include +#include +#include +#include "tst_timer.h" + +struct tst_ts; +struct pollfd; +struct io_event; +struct sembuf; +struct mmsghdr; + +struct time64_variants { + char *desc; + + enum tst_ts_type ts_type; + int (*clock_gettime)(clockid_t clk_id, void *ts); + int (*clock_settime)(clockid_t clk_id, void *ts); + int (*clock_nanosleep)(clockid_t clock_id, int flags, void *request, void *remain); + + int (*timer_gettime)(kernel_timer_t timer, void *its); + int (*timer_settime)(kernel_timer_t timerid, int flags, void *its, void *old_its); + int (*tfd_gettime)(int fd, void *its); + int (*tfd_settime)(int fd, int flags, void *new_value, void *old_value); + +#ifdef HAVE_LIBAIO + int (*io_pgetevents)(io_context_t ctx, long min_nr, long max_nr, + struct io_event *events, void *timeout, sigset_t *sigmask); +#endif + + int (*mqt_send)(mqd_t mqdes, const char *msg_ptr, size_t msg_len, + unsigned int msg_prio, void *abs_timeout); + ssize_t (*mqt_receive)(mqd_t mqdes, char *msg_ptr, size_t msg_len, + unsigned int *msg_prio, void *abs_timeout); + int (*ppoll)(struct pollfd *fds, nfds_t nfds, void *tmo_p, + const sigset_t *sigmask, size_t sigsetsize); + int (*sched_rr_get_interval)(pid_t pid, void *ts); + int (*semop)(int semid, struct sembuf *sops, size_t nsops); + int (*semtimedop)(int semid, struct sembuf *sops, size_t nsops, void *timeout); + int (*sigwait) (const sigset_t * set, siginfo_t * info, + void * timeout); + int (*recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, + unsigned int flags, void *timeout); + int (*sendmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, + unsigned int flags); + int (*utimensat)(int dirfd, const char *pathname, void *times, + int flags); +}; + +#endif /* TIME64_VARIANTS_H */ diff --git a/include/tst_af_alg.h b/include/tst_af_alg.h old mode 100644 new mode 100755 index fc4b1989a2874db4014d14c2469aeab7ebd5c3d2..86df18eb81bb1413ba01439ddc8ad0094d90d0bf --- a/include/tst_af_alg.h +++ b/include/tst_af_alg.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright 2019 Google LLC + * Copyright (c) Linux Test Project, 2021 */ /** * @file tst_af_alg.h @@ -60,8 +61,19 @@ void tst_alg_bind(int algfd, const char *algtype, const char *algname); * @param algtype The type of algorithm, such as "hash" or "skcipher" * @param algname The name of the algorithm, such as "sha256" or "xts(aes)" * - * Return true if the algorithm is available, or false if unavailable. - * If another error occurs, tst_brk() is called with TBROK. + * Return 0 if the algorithm is available, or errno if unavailable. + */ +int tst_try_alg(const char *algtype, const char *algname); + +/** + * Check for the availability of an algorithm. + * + * @param algtype The type of algorithm, such as "hash" or "skcipher" + * @param algname The name of the algorithm, such as "sha256" or "xts(aes)" + * + * Return true if the algorithm is available, or false if unavailable + * and call tst_res() with TCONF. If another error occurs, tst_brk() is called + * with TBROK unless algorithm is disabled due FIPS mode (errno ELIBBAD). */ bool tst_have_alg(const char *algtype, const char *algname); @@ -133,4 +145,36 @@ int tst_alg_setup(const char *algtype, const char *algname, int tst_alg_setup_reqfd(const char *algtype, const char *algname, const uint8_t *key, unsigned int keylen); +/** Specification of control data to send to an AF_ALG request socket */ +struct tst_alg_sendmsg_params { + + /** If true, send ALG_SET_OP with ALG_OP_ENCRYPT */ + bool encrypt; + + /** If true, send ALG_SET_OP with ALG_OP_DECRYPT */ + bool decrypt; + + /** If ivlen != 0, send ALG_SET_IV */ + const uint8_t *iv; + unsigned int ivlen; + + /** If assoclen != 0, send ALG_SET_AEAD_ASSOCLEN */ + unsigned int assoclen; + + /* Value to use as msghdr::msg_flags */ + uint32_t msg_flags; +}; + +/** + * Send some data to an AF_ALG request socket, including control data. + * @param reqfd An AF_ALG request socket + * @param data The data to send + * @param datalen The length of data in bytes + * @param params Specification of the control data to send + * + * On failure, tst_brk() is called with TBROK. + */ +void tst_alg_sendmsg(int reqfd, const void *data, size_t datalen, + const struct tst_alg_sendmsg_params *params); + #endif /* TST_AF_ALG_H */ diff --git a/include/tst_ansi_color.h b/include/tst_ansi_color.h old mode 100644 new mode 100755 diff --git a/include/tst_arch.h b/include/tst_arch.h new file mode 100755 index 0000000000000000000000000000000000000000..4a9473c6f1db39c0f63187e265bfc3baf4637d72 --- /dev/null +++ b/include/tst_arch.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2021 Li Wang + */ + +#ifndef TST_ARCH_H__ +#define TST_ARCH_H__ + +enum tst_arch_type { + TST_UNKNOWN, + TST_X86, + TST_X86_64, + TST_IA64, + TST_PPC, + TST_PPC64, + TST_S390, + TST_S390X, + TST_ARM, + TST_AARCH64, + TST_SPARC, +}; + +/* + * This tst_arch is to save the system architecture for + * using in the whole testcase. + */ +extern const struct tst_arch { + char name[16]; + enum tst_arch_type type; +} tst_arch; + +/* + * Check if test platform is in the given arch list. If yes return 1, + * otherwise return 0. + * + * @archlist A NULL terminated array of architectures to support. + */ +int tst_is_on_arch(const char *const *archlist); + +#endif /* TST_ARCH_H__ */ diff --git a/include/tst_assert.h b/include/tst_assert.h old mode 100644 new mode 100755 index 9969a81690189c4f45b80d53fedceec33115c878..dcb62dfeae9fa7fda405ed7b3d948c3b04a57553 --- a/include/tst_assert.h +++ b/include/tst_assert.h @@ -21,6 +21,15 @@ void tst_assert_int(const char *file, const int lineno, #define TST_ASSERT_FILE_INT(path, prefix, val) \ tst_assert_file_int(__FILE__, __LINE__, path, prefix, val) +/* + * Same as tst_assert_int() but for unsigned long. + */ +void tst_assert_ulong(const char *file, const int lineno, + const char *path, unsigned long val); + +#define TST_ASSERT_ULONG(path, val) \ + tst_assert_ulong(__FILE__, __LINE__, path, val) + /* * Asserts that integer value stored in the prefix field of file pointed by path * equals to the value passed to this function. This is mostly useful for diff --git a/include/tst_atomic.h b/include/tst_atomic.h old mode 100644 new mode 100755 diff --git a/include/tst_bitmap.h b/include/tst_bitmap.h new file mode 100755 index 0000000000000000000000000000000000000000..d294e3ec0a9da81ddeb35f5ddea8946de8c7f2a5 --- /dev/null +++ b/include/tst_bitmap.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2021 + * Author: Xie Ziyao + */ + +#ifndef TST_BITMAP_H__ +#define TST_BITMAP_H__ + +/* + * Check whether the n-th bit of val is set + * @return 0: the n-th bit of val is 0, 1: the n-th bit of val is 1 + */ +#define TST_IS_BIT_SET(val, n) (((val) & (1<<(n))) >> (n)) + +#endif /* TST_BITMAP_H__ */ diff --git a/include/tst_bool_expr.h b/include/tst_bool_expr.h new file mode 100755 index 0000000000000000000000000000000000000000..894d219548207ac31634739b63205e6606609bde --- /dev/null +++ b/include/tst_bool_expr.h @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + */ + +#ifndef TST_BOOL_EXPR_H__ +#define TST_BOOL_EXPR_H__ + +enum tst_op { + TST_OP_NOT, + TST_OP_AND, + TST_OP_OR, + TST_OP_VAR, + /* Used only internally */ + TST_OP_LPAR, + TST_OP_RPAR, +}; + +struct tst_expr_tok { + enum tst_op op; + const char *tok; + size_t tok_len; + struct tst_expr_tok *next; + const void *priv; +}; + +struct tst_expr { + struct tst_expr_tok *rpn; + struct tst_expr_tok buf[]; +}; + +/* + * Parses an boolean expression and returns a simplified RPN version. + * + * If expression is not valid the call prints error into stderr and returns + * NULL. On success pointer to an expression is returned which can be evaluated + * by the tst_bool_expr_eval() function and has to be later freed by the + * caller. + * + * The boolean expression can consists of: + * + * - unary negation opeartion ! + * - two binary operations & and | + * - correct sequence of parentheses () + * - strings that are treated as boolean variables + * + * e.g. '(A | B) & C' or 'Variable_1 & Variable_2' are both a valid boolean + * expressions. + * + * @expr String containing a boolean expression to be parsed. + * @return Pointer to an RPN expression. + */ +struct tst_expr *tst_bool_expr_parse(const char *expr); + +/* + * Prints an string representation of the expression into a FILE. + * + * @param A FILE to print to. + * @expr An expression to print. + */ +void tst_bool_expr_print(FILE *f, struct tst_expr *expr); + +/* + * Evaluates an expression given a map for variables. + * + * The call will fail if: + * - map function returns -1 which indicates undefined variable + * - the eval function runs out of stack + * + * @param expr Boolean expression in RPN. + * @param map Mapping function for boolean variables. + * + * @return Returns 0 or 1 if expression was evaluated correctly and -1 on error. + */ +int tst_bool_expr_eval(struct tst_expr *expr, + int (*map)(struct tst_expr_tok *var)); + +/* + * Frees the memory allocated by the tst_bool_expr_parse(). + * + * @param Boolean expression. + */ +void tst_bool_expr_free(struct tst_expr *expr); + +#endif /* TST_BOOL_EXPR_H__ */ diff --git a/include/tst_buffers.h b/include/tst_buffers.h old mode 100644 new mode 100755 diff --git a/include/tst_capability.h b/include/tst_capability.h old mode 100644 new mode 100755 diff --git a/include/tst_cgroup.h b/include/tst_cgroup.h new file mode 100755 index 0000000000000000000000000000000000000000..5190d8794719e5098faa360cf4c6bc2c659e9b09 --- /dev/null +++ b/include/tst_cgroup.h @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Red Hat, Inc. + * Copyright (c) 2020 Li Wang + * Copyright (c) 2020-2021 SUSE LLC + */ +/*\ + * [Description] + * + * The LTP CGroups API tries to present a consistent interface to the + * many possible CGroup configurations a system could have. + * + * You may ask; "Why don't you just mount a simple CGroup hierarchy, + * instead of scanning the current setup?". The short answer is that + * it is not possible unless no CGroups are currently active and + * almost all of our users will have CGroups active. Even if + * unmounting the current CGroup hierarchy is a reasonable thing to do + * to the sytem manager, it is highly unlikely the CGroup hierarchy + * will be destroyed. So users would be forced to remove their CGroup + * configuration and reboot the system. + * + * The core library tries to ensure an LTP CGroup exists on each + * hierarchy root. Inside the LTP group it ensures a 'drain' group + * exists and creats a test group for the current test. In the worst + * case we end up with a set of hierarchies like the follwoing. Where + * existing system-manager-created CGroups have been omitted. + * + * (V2 Root) (V1 Root 1) ... (V1 Root N) + * | | | + * (ltp) (ltp) ... (ltp) + * / \ / \ / \ + * (drain) (test-n) (drain) (test-n) ... (drain) (test-n) + * + * V2 CGroup controllers use a single unified hierarchy on a single + * root. Two or more V1 controllers may share a root or have their own + * root. However there may exist only one instance of a controller. + * So you can not have the same V1 controller on multiple roots. + * + * It is possible to have both a V2 hierarchy and V1 hierarchies + * active at the same time. Which is what is shown above. Any + * controllers attached to V1 hierarchies will not be available in the + * V2 hierarchy. The reverse is also true. + * + * Note that a single hierarchy may be mounted multiple + * times. Allowing it to be accessed at different locations. However + * subsequent mount operations will fail if the mount options are + * different from the first. + * + * The user may pre-create the CGroup hierarchies and the ltp CGroup, + * otherwise the library will try to create them. If the ltp group + * already exists and has appropriate permissions, then admin + * privileges will not be required to run the tests. + * + * Because the test may not have access to the CGroup root(s), the + * drain CGroup is created. This can be used to store processes which + * would otherwise block the destruction of the individual test CGroup + * or one of its descendants. + * + * The test author may create child CGroups within the test CGroup + * using the CGroup Item API. The library will create the new CGroup + * in all the relevant hierarchies. + * + * There are many differences between the V1 and V2 CGroup APIs. If a + * controller is on both V1 and V2, it may have different parameters + * and control files. Some of these control files have a different + * name, but similar functionality. In this case the Item API uses + * the V2 names and aliases them to the V1 name when appropriate. + * + * Some control files only exist on one of the versions or they can be + * missing due to other reasons. The Item API allows the user to check + * if the file exists before trying to use it. + * + * Often a control file has almost the same functionality between V1 + * and V2. Which means it can be used in the same way most of the + * time, but not all. For now this is handled by exposing the API + * version a controller is using to allow the test author to handle + * edge cases. (e.g. V2 memory.swap.max accepts "max", but V1 + * memory.memsw.limit_in_bytes does not). + */ + +#ifndef TST_CGROUP_H +#define TST_CGROUP_H + +#include + +/* CGroups Kernel API version */ +enum tst_cgroup_ver { + TST_CGROUP_V1 = 1, + TST_CGROUP_V2 = 2, +}; + +/* Used to specify CGroup hierarchy configuration options, allowing a + * test to request a particular CGroup structure. + */ +struct tst_cgroup_opts { + /* Only try to mount V1 CGroup controllers. This will not + * prevent V2 from being used if it is already mounted, it + * only indicates that we should mount V1 controllers if + * nothing is present. By default we try to mount V2 first. */ + int only_mount_v1:1; +}; + +/* A Control Group in LTP's aggregated hierarchy */ +struct tst_cgroup_group; + +/* Search the system for mounted cgroups and available + * controllers. Called automatically by tst_cgroup_require. + */ +void tst_cgroup_scan(void); +/* Print the config detected by tst_cgroup_scan */ +void tst_cgroup_print_config(void); + +/* Ensure the specified controller is available in the test's default + * CGroup, mounting/enabling it if necessary */ +void tst_cgroup_require(const char *const ctrl_name, + const struct tst_cgroup_opts *const options) + __attribute__ ((nonnull (1))); + +/* Tear down any CGroups created by calls to tst_cgroup_require */ +void tst_cgroup_cleanup(void); + +/* Get the default CGroup for the test. It allocates memory (in a + * guarded buffer) so should always be called from setup + */ +const struct tst_cgroup_group *tst_cgroup_get_test_group(void) + __attribute__ ((warn_unused_result)); +/* Get the shared drain group. Also should be called from setup */ +const struct tst_cgroup_group *tst_cgroup_get_drain_group(void) + __attribute__ ((warn_unused_result)); + +/* Create a descendant CGroup */ +struct tst_cgroup_group * +tst_cgroup_group_mk(const struct tst_cgroup_group *const parent, + const char *const group_name) + __attribute__ ((nonnull, warn_unused_result)); +const char * +tst_cgroup_group_name(const struct tst_cgroup_group *const cg) + __attribute__ ((nonnull, warn_unused_result)); + +/* Remove a descendant CGroup */ +struct tst_cgroup_group * +tst_cgroup_group_rm(struct tst_cgroup_group *const cg) + __attribute__ ((nonnull, warn_unused_result)); + +#define TST_CGROUP_VER(cg, ctrl_name) \ + tst_cgroup_ver(__FILE__, __LINE__, (cg), (ctrl_name)) + +enum tst_cgroup_ver tst_cgroup_ver(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const ctrl_name) + __attribute__ ((nonnull, warn_unused_result)); + +#define TST_CGROUP_VER_IS_V1(cg, ctrl_name) \ + (TST_CGROUP_VER((cg), (ctrl_name)) == TST_CGROUP_V1) + +#define SAFE_CGROUP_HAS(cg, file_name) \ + safe_cgroup_has(__FILE__, __LINE__, (cg), (file_name)) + +int safe_cgroup_has(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name) + __attribute__ ((nonnull, warn_unused_result)); + +#define SAFE_CGROUP_READ(cg, file_name, out, len) \ + safe_cgroup_read(__FILE__, __LINE__, \ + (cg), (file_name), (out), (len)) + +ssize_t safe_cgroup_read(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + char *const out, const size_t len) + __attribute__ ((nonnull)); + +#define SAFE_CGROUP_PRINTF(cg, file_name, fmt, ...) \ + safe_cgroup_printf(__FILE__, __LINE__, \ + (cg), (file_name), (fmt), __VA_ARGS__) + +#define SAFE_CGROUP_PRINT(cg, file_name, str) \ + safe_cgroup_printf(__FILE__, __LINE__, (cg), (file_name), "%s", (str)) + +void safe_cgroup_printf(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + const char *const fmt, ...) + __attribute__ ((format (printf, 5, 6), nonnull)); + +#define SAFE_CGROUP_SCANF(cg, file_name, fmt, ...) \ + safe_cgroup_scanf(__FILE__, __LINE__, \ + (cg), (file_name), (fmt), __VA_ARGS__) + +void safe_cgroup_scanf(const char *file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + const char *const fmt, ...) + __attribute__ ((format (scanf, 5, 6), nonnull)); + +#define SAFE_CGROUP_LINES_SCANF(cg, file_name, fmt, ...) \ + safe_cgroup_lines_scanf(__FILE__, __LINE__, \ + (cg), (file_name), (fmt), __VA_ARGS__) + +void safe_cgroup_lines_scanf(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + const char *const fmt, ...) + __attribute__ ((format (scanf, 5, 6), nonnull)); + +#define SAFE_CGROUP_OCCURSIN(cg, file_name, needle) \ + safe_cgroup_occursin(__FILE__, __LINE__, \ + (cg), (file_name), (needle)) + +int safe_cgroup_occursin(const char *file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + const char *const needle); + +#endif /* TST_CGROUP_H */ diff --git a/include/tst_checkpoint.h b/include/tst_checkpoint.h old mode 100644 new mode 100755 index 5c8067d0dc0000a28784f8608bcbbdb31e42fa06..1b6911d73a2cf0692785593ba068530d62361b78 --- a/include/tst_checkpoint.h +++ b/include/tst_checkpoint.h @@ -8,20 +8,21 @@ #include "tst_checkpoint_fn.h" #define TST_CHECKPOINT_WAIT(id) \ - tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, 0); + tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, 0) #define TST_CHECKPOINT_WAIT2(id, msec_timeout) \ - tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, msec_timeout); + tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, msec_timeout) #define TST_CHECKPOINT_WAKE(id) \ - tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, 1); + tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, 1) #define TST_CHECKPOINT_WAKE2(id, nr_wake) \ - tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, nr_wake); + tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, nr_wake) -#define TST_CHECKPOINT_WAKE_AND_WAIT(id) \ +#define TST_CHECKPOINT_WAKE_AND_WAIT(id) do { \ tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, 1); \ - tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, 0); + tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, 0); \ +} while (0) extern const char *tst_ipc_path; diff --git a/include/tst_checkpoint_fn.h b/include/tst_checkpoint_fn.h old mode 100644 new mode 100755 diff --git a/include/tst_checksum.h b/include/tst_checksum.h old mode 100644 new mode 100755 diff --git a/include/tst_clocks.h b/include/tst_clocks.h old mode 100644 new mode 100755 index 80030c6b0c689a14c5feb9edb6e6a09f8f8d365f..06d2d03bef330c8392d81af06b875255001228e0 --- a/include/tst_clocks.h +++ b/include/tst_clocks.h @@ -20,4 +20,15 @@ int tst_clock_settime(clockid_t clk_id, struct timespec *ts); */ const char *tst_clock_name(clockid_t clk_id); +/* + * Returns current system time for file/IPC operations, which may slightly lag + * behind time() return values. + * + * The reason for this is that the time() syscall reads the nanosecond timer at + * the time of the call and adds it to the kernel current time, because of that + * accumulation may cause it jump one second ahead compared to the kernel time + * stamp that is used for IPC and filesystems. + */ +time_t tst_get_fs_timestamp(void); + #endif /* TST_CLOCKS__ */ diff --git a/include/tst_clone.h b/include/tst_clone.h old mode 100644 new mode 100755 index 88188525d081789180e8fad3708371e026478ebf..9ffdc68d113586a0e918b74d89df80d403f100f0 --- a/include/tst_clone.h +++ b/include/tst_clone.h @@ -5,6 +5,34 @@ #ifndef TST_CLONE_H__ #define TST_CLONE_H__ +#ifdef TST_TEST_H__ + +/* The parts of clone3's clone_args we support */ +struct tst_clone_args { + uint64_t flags; + uint64_t exit_signal; +}; + +/* clone3 with fallbacks to clone when possible. Be aware that it + * returns -1 if clone3 fails (except ENOSYS), but -2 if clone fails. + * + * Without CLONE_VM this acts like fork so you may want to set + * tst_test.forks_child (safe_clone requires this). + * + * You should set exit_signal to SIGCHLD for + * tst_reap_children. Otherwise you must call wait with the + * appropriate parameters. + */ +pid_t tst_clone(const struct tst_clone_args *args); + +pid_t safe_clone(const char *file, const int lineno, + const struct tst_clone_args *args); + +/* "Safe" version of tst_clone */ +#define SAFE_CLONE(args) safe_clone(__FILE__, __LINE__, args) + +#endif /* TST_TEST_H__ */ + /* Functions from lib/cloner.c */ int ltp_clone(unsigned long flags, int (*fn)(void *arg), void *arg, size_t stack_size, void *stack); diff --git a/include/tst_cmd.h b/include/tst_cmd.h old mode 100644 new mode 100755 diff --git a/include/tst_common.h b/include/tst_common.h old mode 100644 new mode 100755 diff --git a/include/tst_coredump.h b/include/tst_coredump.h old mode 100644 new mode 100755 diff --git a/include/tst_cpu.h b/include/tst_cpu.h old mode 100644 new mode 100755 index c83a5826007a610521882cb57cef0ebd626ea441..0724975f039c32f2342f46a2be3389e12f3e460c --- a/include/tst_cpu.h +++ b/include/tst_cpu.h @@ -8,10 +8,15 @@ long tst_ncpus(void); long tst_ncpus_conf(void); long tst_ncpus_max(void); +long tst_ncpus_available(void); #define VIRT_ANY 0 /* catch-all argument for tst_is_virt() */ #define VIRT_XEN 1 /* xen dom0/domU */ #define VIRT_KVM 2 /* only default virtual CPU */ +#define VIRT_IBMZ 3 /* ibm system z */ +#define VIRT_IBMZ_LPAR 4 /* ibm system z lpar */ +#define VIRT_IBMZ_ZVM 5 /* ibm system z zvm */ +#define VIRT_HYPERV 6 /* Microsoft Hyper-V */ #define VIRT_OTHER 0xffff /* unrecognized hypervisor */ int tst_is_virt(int virt_type); diff --git a/include/tst_crypto.h b/include/tst_crypto.h old mode 100644 new mode 100755 diff --git a/include/tst_defaults.h b/include/tst_defaults.h new file mode 100755 index 0000000000000000000000000000000000000000..083427b7e2d67c2b940e598e6e893bdc4953a73d --- /dev/null +++ b/include/tst_defaults.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Cyril Hrubis + */ + +#ifndef TST_DEFAULTS_H_ +#define TST_DEFAULTS_H_ + +/* + * This is the default temporary directory used by tst_tmpdir(). + * + * This is used when TMPDIR env variable is not set. + */ +#define TEMPDIR "/tmp" + +/* + * Default filesystem to be used for tests. + */ +#define DEFAULT_FS_TYPE "ext2" + +#endif /* TST_DEFAULTS_H_ */ diff --git a/include/tst_device.h b/include/tst_device.h old mode 100644 new mode 100755 index 950cfe1edcbad758c1eed07b230285f3f155bfaa..72c560c021c39a848ed07a01c66dac42570902ce --- a/include/tst_device.h +++ b/include/tst_device.h @@ -7,10 +7,12 @@ #define TST_DEVICE_H__ #include +#include struct tst_device { const char *dev; const char *fs_type; + uint64_t size; }; /* @@ -57,11 +59,30 @@ int tst_find_free_loopdev(const char *path, size_t path_len); */ int tst_attach_device(const char *dev_path, const char *file_path); +/* + * Get size (in MB) of the given device + */ +uint64_t tst_get_device_size(const char *dev_path); + +/* + * Detaches a file from a loop device fd. + * + * @dev_path Path to the loop device e.g. /dev/loop0 + * @dev_fd a open fd for the loop device + * @return Zero on succes, non-zero otherwise. + */ +int tst_detach_device_by_fd(const char *dev_path, int dev_fd); + /* * Detaches a file from a loop device. * * @dev_path Path to the loop device e.g. /dev/loop0 * @return Zero on succes, non-zero otherwise. + * + * Internally this function opens the device and calls + * tst_detach_device_by_fd(). If you keep device file descriptor open you + * have to call the by_fd() variant since having the device open twice will + * prevent it from being detached. */ int tst_detach_device(const char *dev_path); @@ -84,4 +105,11 @@ unsigned long tst_dev_bytes_written(const char *dev); */ void tst_purge_dir(const char *path); +/* + * Find the file or path belongs to which block dev + * @path Path to find the backing dev + * @dev The block dev + */ +void tst_find_backing_dev(const char *path, char *dev); + #endif /* TST_DEVICE_H__ */ diff --git a/include/tst_fips.h b/include/tst_fips.h new file mode 100755 index 0000000000000000000000000000000000000000..881c32391c6e5fe04ac67202eb3d71a4d0a0a12e --- /dev/null +++ b/include/tst_fips.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Petr Vorel + */ + +#ifndef TST_FIPS_H__ +#define TST_FIPS_H__ + +/* + * Detect whether FIPS enabled + * @return 0: FIPS not enabled, 1: FIPS enabled + */ +int tst_fips_enabled(void); + +#endif /* TST_FIPS_H__ */ diff --git a/include/tst_fs.h b/include/tst_fs.h old mode 100644 new mode 100755 index bcef87a4030a22d2e0997664a06dbaa9ea0e9f9a..efcdff6084cc6f7fd1a9614a2b873fda58c1ef3a --- a/include/tst_fs.h +++ b/include/tst_fs.h @@ -29,6 +29,8 @@ #define TST_NILFS_MAGIC 0x3434 #define TST_EXOFS_MAGIC 0x5DF5 #define TST_OVERLAYFS_MAGIC 0x794c7630 +#define TST_FUSE_MAGIC 0x65735546 +#define TST_EXFAT_MAGIC 0x2011BAB0UL enum { TST_BYTES = 1, @@ -140,6 +142,15 @@ int tst_get_path(const char *prog_name, char *buf, size_t buf_len); */ int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount); +/* + * Preallocate space in open file. If fallocate() fails, falls back to + * using tst_fill_fd(). + * @fd: file descriptor + * @bs: block size + * @bcount: blocks count + */ +int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount); + /* * Creates/ovewrites a file with specified pattern * @path: path to file @@ -149,18 +160,56 @@ int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount); */ int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount); -#define TST_FS_SKIP_FUSE 0x01 +/* + * Creates file of specified size. Space will be only preallocated if possible. + * @path: path to file + * @bs: block size + * @bcount: blocks amount + */ +int tst_prealloc_file(const char *path, size_t bs, size_t bcount); + +enum tst_fs_impl { + TST_FS_UNSUPPORTED = 0, + TST_FS_KERNEL = 1, + TST_FS_FUSE = 2, +}; /* - * Return 1 if a specified fiilsystem is supported - * Return 0 if a specified fiilsystem isn't supported + * Returns if filesystem is suppored and if driver is in kernel or FUSE. + * + * @fs_type A filesystem name to check the support for. */ -int tst_fs_is_supported(const char *fs_type, int flags); +enum tst_fs_impl tst_fs_is_supported(const char *fs_type); /* * Returns NULL-terminated array of kernel-supported filesystems. + * + * @skiplist A NULL terminated array of filesystems to skip. +*/ +const char **tst_get_supported_fs_types(const char *const *skiplist); + +/* + * Returns 1 if filesystem is in skiplist 0 otherwise. + * + * @fs_type A filesystem type to lookup. + * @skiplist A NULL terminated array of fileystemsytems to skip. + */ +int tst_fs_in_skiplist(const char *fs_type, const char *const *skiplist); + +/* + * Check whether device supports FS quotas. Negative return value means that + * quotas appear to be broken. + */ +int tst_check_quota_support(const char *device, int format, char *quotafile); + +/* + * Check for quota support and terminate the test with appropriate exit status + * if quotas are not supported or broken. */ -const char **tst_get_supported_fs_types(int flags); +#define tst_require_quota_support(dev, fmt, qfile) \ + tst_require_quota_support_(__FILE__, __LINE__, (dev), (fmt), (qfile)) +void tst_require_quota_support_(const char *file, const int lineno, + const char *device, int format, char *quotafile); /* * Creates and writes to files on given path until write fails with ENOSPC diff --git a/include/tst_fuzzy_sync.h b/include/tst_fuzzy_sync.h old mode 100644 new mode 100755 index 9ff3a78aee388d54a1135625463c4ef99d7282b4..bc3450294aeeea7cacc053a5dc8372a23c84e056 --- a/include/tst_fuzzy_sync.h +++ b/include/tst_fuzzy_sync.h @@ -59,12 +59,14 @@ * @sa tst_fzsync_pair */ -#include -#include #include -#include #include +#include +#include +#include +#include #include "tst_atomic.h" +#include "tst_cpu.h" #include "tst_timer.h" #include "tst_safe_pthread.h" @@ -180,6 +182,15 @@ struct tst_fzsync_pair { int exec_loop; /** Internal; The second thread or 0 */ pthread_t thread_b; + /** + * The flag indicates single core machines or not + * + * If running on single core machines, it would take considerable + * amount of time to run fuzzy sync library. + * Thus call sched_yield to give up cpu to decrease the test time. + */ + bool yield_in_wait; + }; #define CHK(param, low, hi, def) do { \ @@ -199,13 +210,16 @@ struct tst_fzsync_pair { * * @sa tst_fzsync_pair_reset() */ -static void tst_fzsync_pair_init(struct tst_fzsync_pair *pair) +static inline void tst_fzsync_pair_init(struct tst_fzsync_pair *pair) { CHK(avg_alpha, 0, 1, 0.25); CHK(min_samples, 20, INT_MAX, 1024); CHK(max_dev_ratio, 0, 1, 0.1); CHK(exec_time_p, 0, 1, 0.5); CHK(exec_loops, 20, INT_MAX, 3000000); + + if (tst_ncpus_available() <= 1) + pair->yield_in_wait = 1; } #undef CHK @@ -216,7 +230,7 @@ static void tst_fzsync_pair_init(struct tst_fzsync_pair *pair) * * Call this from your cleanup function. */ -static void tst_fzsync_pair_cleanup(struct tst_fzsync_pair *pair) +static inline void tst_fzsync_pair_cleanup(struct tst_fzsync_pair *pair) { if (pair->thread_b) { /* Revoke thread B if parent hits accidental break */ @@ -240,7 +254,7 @@ struct tst_fzsync_run_thread { * Wrap run_b for tst_fzsync_pair_reset to enable pthread cancel * at the start of the thread B. */ -static void *tst_fzsync_thread_wrapper(void *run_thread) +static inline void *tst_fzsync_thread_wrapper(void *run_thread) { struct tst_fzsync_run_thread t = *(struct tst_fzsync_run_thread *)run_thread; @@ -254,7 +268,7 @@ static void *tst_fzsync_thread_wrapper(void *run_thread) * * @relates tst_fzsync_stat */ -static void tst_init_stat(struct tst_fzsync_stat *s) +static inline void tst_init_stat(struct tst_fzsync_stat *s) { s->avg = 0; s->avg_dev = 0; @@ -278,7 +292,7 @@ static void tst_init_stat(struct tst_fzsync_stat *s) * * @sa tst_fzsync_pair_init() */ -static void tst_fzsync_pair_reset(struct tst_fzsync_pair *pair, +static inline void tst_fzsync_pair_reset(struct tst_fzsync_pair *pair, void *(*run_b)(void *)) { tst_fzsync_pair_cleanup(pair); @@ -289,6 +303,7 @@ static void tst_fzsync_pair_reset(struct tst_fzsync_pair *pair, tst_init_stat(&pair->diff_ab); tst_init_stat(&pair->spins_avg); pair->delay = 0; + pair->delay_bias = 0; pair->sampling = pair->min_samples; pair->exec_loop = 0; @@ -325,7 +340,7 @@ static inline void tst_fzsync_stat_info(struct tst_fzsync_stat stat, * * @relates tst_fzsync_pair */ -static void tst_fzsync_pair_info(struct tst_fzsync_pair *pair) +static inline void tst_fzsync_pair_info(struct tst_fzsync_pair *pair) { tst_res(TINFO, "loop = %d, delay_bias = %d", pair->exec_loop, pair->delay_bias); @@ -478,7 +493,7 @@ static inline void tst_upd_diff_stat(struct tst_fzsync_stat *s, * * @relates tst_fzsync_pair */ -static void tst_fzsync_pair_update(struct tst_fzsync_pair *pair) +static inline void tst_fzsync_pair_update(struct tst_fzsync_pair *pair) { float alpha = pair->avg_alpha; float per_spin_time, time_delay; @@ -511,15 +526,15 @@ static void tst_fzsync_pair_update(struct tst_fzsync_pair *pair) per_spin_time = fabsf(pair->diff_ab.avg) / MAX(pair->spins_avg.avg, 1.0f); time_delay = drand48() * (pair->diff_sa.avg + pair->diff_sb.avg) - pair->diff_sb.avg; - pair->delay += (int)(time_delay / per_spin_time); + pair->delay += (int)(1.1 * time_delay / per_spin_time); if (!pair->sampling) { tst_res(TINFO, "Reached deviation ratios < %.2f, introducing randomness", pair->max_dev_ratio); - tst_res(TINFO, "Delay range is [-%d, %d]", - (int)(pair->diff_sb.avg / per_spin_time) + pair->delay_bias, - (int)(pair->diff_sa.avg / per_spin_time) - pair->delay_bias); + tst_res(TINFO, "Delay range is [%d, %d]", + -(int)(pair->diff_sb.avg / per_spin_time) + pair->delay_bias, + (int)(pair->diff_sa.avg / per_spin_time) + pair->delay_bias); tst_fzsync_pair_info(pair); pair->sampling = -1; } @@ -550,7 +565,8 @@ static void tst_fzsync_pair_update(struct tst_fzsync_pair *pair) */ static inline void tst_fzsync_pair_wait(int *our_cntr, int *other_cntr, - int *spins) + int *spins, + bool yield_in_wait) { if (tst_atomic_inc(other_cntr) == INT_MAX) { /* @@ -560,27 +576,53 @@ static inline void tst_fzsync_pair_wait(int *our_cntr, * line above before doing that. If we are in rear position * then our counter may already have been set to zero. */ - while (tst_atomic_load(our_cntr) > 0 - && tst_atomic_load(our_cntr) < INT_MAX) { - if (spins) - (*spins)++; + if (yield_in_wait) { + while (tst_atomic_load(our_cntr) > 0 + && tst_atomic_load(our_cntr) < INT_MAX) { + if (spins) + (*spins)++; + + sched_yield(); + } + } else { + while (tst_atomic_load(our_cntr) > 0 + && tst_atomic_load(our_cntr) < INT_MAX) { + if (spins) + (*spins)++; + } } + tst_atomic_store(0, other_cntr); /* * Once both counters have been set to zero the invariant * is restored and we can continue. */ - while (tst_atomic_load(our_cntr) > 1) - ; + if (yield_in_wait) { + while (tst_atomic_load(our_cntr) > 1) + sched_yield(); + } else { + while (tst_atomic_load(our_cntr) > 1) + ; + } } else { /* * If our counter is less than the other thread's we are ahead * of it and need to wait. */ - while (tst_atomic_load(our_cntr) < tst_atomic_load(other_cntr)) { - if (spins) - (*spins)++; + if (yield_in_wait) { + while (tst_atomic_load(our_cntr) < + tst_atomic_load(other_cntr)) { + if (spins) + (*spins)++; + sched_yield(); + } + } else { + while (tst_atomic_load(our_cntr) < + tst_atomic_load(other_cntr)) { + if (spins) + (*spins)++; + } } } } @@ -593,7 +635,7 @@ static inline void tst_fzsync_pair_wait(int *our_cntr, */ static inline void tst_fzsync_wait_a(struct tst_fzsync_pair *pair) { - tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, NULL); + tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, NULL, pair->yield_in_wait); } /** @@ -604,7 +646,7 @@ static inline void tst_fzsync_wait_a(struct tst_fzsync_pair *pair) */ static inline void tst_fzsync_wait_b(struct tst_fzsync_pair *pair) { - tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, NULL); + tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, NULL, pair->yield_in_wait); } /** @@ -694,8 +736,15 @@ static inline void tst_fzsync_start_race_a(struct tst_fzsync_pair *pair) tst_fzsync_wait_a(pair); delay = pair->delay; - while (delay < 0) - delay++; + if (pair->yield_in_wait) { + while (delay < 0) { + sched_yield(); + delay++; + } + } else { + while (delay < 0) + delay++; + } tst_fzsync_time(&pair->a_start); } @@ -709,7 +758,7 @@ static inline void tst_fzsync_start_race_a(struct tst_fzsync_pair *pair) static inline void tst_fzsync_end_race_a(struct tst_fzsync_pair *pair) { tst_fzsync_time(&pair->a_end); - tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, &pair->spins); + tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, &pair->spins, pair->yield_in_wait); } /** @@ -725,8 +774,15 @@ static inline void tst_fzsync_start_race_b(struct tst_fzsync_pair *pair) tst_fzsync_wait_b(pair); delay = pair->delay; - while (delay > 0) - delay--; + if (pair->yield_in_wait) { + while (delay > 0) { + sched_yield(); + delay--; + } + } else { + while (delay > 0) + delay--; + } tst_fzsync_time(&pair->b_start); } @@ -740,7 +796,7 @@ static inline void tst_fzsync_start_race_b(struct tst_fzsync_pair *pair) static inline void tst_fzsync_end_race_b(struct tst_fzsync_pair *pair) { tst_fzsync_time(&pair->b_end); - tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, &pair->spins); + tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, &pair->spins, pair->yield_in_wait); } /** diff --git a/include/tst_get_bad_addr.h b/include/tst_get_bad_addr.h old mode 100644 new mode 100755 diff --git a/include/tst_hugepage.h b/include/tst_hugepage.h old mode 100644 new mode 100755 index 60c03c5c50d2c9fc37f20b8d29151980079990e8..e08a2daa246ab6629761405cec8d502c6461d32e --- a/include/tst_hugepage.h +++ b/include/tst_hugepage.h @@ -12,6 +12,11 @@ extern char *nr_opt; /* -s num Set the number of the been allocated hugepages */ extern char *Hopt; /* -H /.. Location of hugetlbfs, i.e. -H /var/hugetlbfs */ +/* + * Get the default hugepage size. Returns 0 if hugepages are not supported. + */ +size_t tst_get_hugepage_size(void); + /* * Try the best to request a specified number of huge pages from system, * it will store the reserved hpage number in tst_hugepages. diff --git a/include/tst_kconfig.h b/include/tst_kconfig.h old mode 100644 new mode 100755 index 2d2cfd782f7f3f17a114725b80b42c0cb17b2e53..cc0908ea8a6e3a524c87a8c32b77225845645a67 --- a/include/tst_kconfig.h +++ b/include/tst_kconfig.h @@ -6,27 +6,27 @@ #ifndef TST_KCONFIG_H__ #define TST_KCONFIG_H__ -struct tst_kconfig_res { - char match; - char *value; +struct tst_kconfig_var { + char id[64]; + unsigned int id_len; + char choice; + char *val; }; /** - * Reads a kernel config and parses it for values defined in kconfigs array. + * + * Reads a kernel config, parses it and writes results into an array of + * tst_kconfig_var structures. * * The path to the kernel config should be autodetected in most of the cases as * the code looks for know locations. It can be explicitely set/overrided with * the KCONFIG_PATH environment variable as well. * - * The kcofings array is expected to contain strings in a format "CONFIG_FOO" - * or "CONFIG_FOO=bar". The result array has to be suitably sized to fit the - * results. - * - * @param kconfigs array of config strings to look for - * @param results array to store results to - * @param cnt size of the arrays + * The caller has to initialize the tst_kconfig_var structure. The id has to be + * filled with config variable name such as 'CONFIG_FOO', the id_len should + * hold the id string length and the choice and val has to be zeroed. * - * The match in the tst_kconfig_res structure is set as follows: + * After a call to this function each choice be set as follows: * * 'm' - config option set to m * 'y' - config option set to y @@ -34,15 +34,18 @@ struct tst_kconfig_res { * 'n' - config option is not set * 0 - config option not found * - * In the case that match is set to 'v' the value points to a newly allocated - * string that holds the value. + * In the case that match is set to 'v' the val pointer points to a newly + * allocated string that holds the value. + * + * @param vars An array of caller initalized tst_kconfig_var structures. + * @param vars_len Length of the vars array. */ -void tst_kconfig_read(const char *const kconfigs[], - struct tst_kconfig_res results[], size_t cnt); +void tst_kconfig_read(struct tst_kconfig_var vars[], size_t vars_len); /** * Checks if required kernel configuration options are set in the kernel - * config and exits the test with TCONF if at least one is missing. + * config. Return 0 if every config is satisfied and return 1 if at least + * one is missing. * * The config options can be passed in two different formats, either * "CONFIG_FOO" in which case the option has to be set in order to continue the @@ -51,6 +54,6 @@ void tst_kconfig_read(const char *const kconfigs[], * * @param kconfigs NULL-terminated array of config strings needed for the testrun. */ -void tst_kconfig_check(const char *const kconfigs[]); +int tst_kconfig_check(const char *const kconfigs[]); #endif /* TST_KCONFIG_H__ */ diff --git a/include/tst_kernel.h b/include/tst_kernel.h old mode 100644 new mode 100755 index 71ab9466b03fb600471e8d44ab38c22181db4c73..9e17bb71e59224faefa40e9c55a4682c91859950 --- a/include/tst_kernel.h +++ b/include/tst_kernel.h @@ -13,9 +13,11 @@ int tst_kernel_bits(void); /** * Checks support for the kernel driver. * - * @param name The name of the driver. - * @return Returns 0 if the kernel has the driver or modprobe is missing. + * @param driver The name of the driver. + * @return Returns 0 if the kernel has the driver, + * -1 when driver is missing or config file not available. + * On Android *always* 0 (always expect the driver is available). */ -int tst_check_driver(const char *name); +int tst_check_driver(const char *driver); #endif /* TST_KERNEL_H__ */ diff --git a/include/tst_kvercmp.h b/include/tst_kvercmp.h old mode 100644 new mode 100755 index 5bf1169f90ed2d3e3f1c83989addbdacab600cf7..495e8db1f204d678594ce1f427aeea32674823b2 --- a/include/tst_kvercmp.h +++ b/include/tst_kvercmp.h @@ -30,7 +30,7 @@ int tst_kvexcmp(const char *tst_exv, const char *cur_kver); /* * Compare given kernel version with currently running kernel. * - * Returns negative if older, 0 if the smame and possitive if newer. + * Returns negative if older, 0 if the same and possitive if newer. */ int tst_kvercmp(int r1, int r2, int r3); diff --git a/include/tst_lockdown.h b/include/tst_lockdown.h new file mode 100755 index 0000000000000000000000000000000000000000..2bd1aa251d70ed5aac62462f17b14eeb1c0ef8ec --- /dev/null +++ b/include/tst_lockdown.h @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef TST_LOCKDOWN_H +#define TST_LOCKDOWN_H + +int tst_secureboot_enabled(void); +int tst_lockdown_enabled(void); + +#endif /* TST_LOCKDOWN_H */ diff --git a/include/tst_memutils.h b/include/tst_memutils.h new file mode 100755 index 0000000000000000000000000000000000000000..45dec55bcc2226e8a5f6aea06684732f9f958178 --- /dev/null +++ b/include/tst_memutils.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2020 SUSE LLC + */ + +#ifndef TST_MEMUTILS_H__ +#define TST_MEMUTILS_H__ + +/* + * Fill up to maxsize physical memory with fillchar, then free it for reuse. + * If maxsize is zero, fill as much memory as possible. This function is + * intended for data disclosure vulnerability tests to reduce the probability + * that a vulnerable kernel will leak a block of memory that was full of + * zeroes by chance. + * + * The function keeps a safety margin to avoid invoking OOM killer and + * respects the limitations of available address space. (Less than 3GB can be + * polluted on a 32bit system regardless of available physical RAM.) + */ +void tst_pollute_memory(size_t maxsize, int fillchar); + +/* + * Read the value of MemAvailable from /proc/meminfo, if no support on + * older kernels, return 'MemFree + Cached' for instead. + */ +long long tst_available_mem(void); + +/* + * Enable OOM protection to prevent process($PID) being killed by OOM Killer. + * echo -1000 >/proc/$PID/oom_score_adj + * + * If the pid is 0 which means it will set on current(self) process. + * + * Unless the process has CAP_SYS_RESOURCE this call will be no-op because + * setting adj value < 0 requires it. + * + * CAP_SYS_RESOURCE: + * set /proc/[pid]/oom_score_adj to a value lower than the value last set + * by a process with CAP_SYS_RESOURCE. + * + * Note: + * This exported tst_enable_oom_protection function can be used at anywhere + * you want to protect, but please remember that if you do enable protection + * on a process($PID) that all the children will inherit its score and be + * ignored by OOM Killer as well. So that's why tst_disable_oom_protection() + * to be used in combination. + */ +void tst_enable_oom_protection(pid_t pid); + +/* + * Disable the OOM protection for the process($PID). + * echo 0 >/proc/$PID/oom_score_adj + */ +void tst_disable_oom_protection(pid_t pid); + +#endif /* TST_MEMUTILS_H__ */ diff --git a/include/tst_minmax.h b/include/tst_minmax.h old mode 100644 new mode 100755 diff --git a/include/tst_mkfs.h b/include/tst_mkfs.h old mode 100644 new mode 100755 diff --git a/include/tst_module.h b/include/tst_module.h new file mode 100755 index 0000000000000000000000000000000000000000..2654c5afb6c4a49f0044bcd8d3a484f43ef09f63 --- /dev/null +++ b/include/tst_module.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Alexey Kodanev + */ + +#ifndef TST_MODULE_H +#define TST_MODULE_H + +void tst_module_exists_(void (cleanup_fn)(void), const char *mod_name, + char **mod_path); + +static inline void tst_module_exists(const char *mod_name, char **mod_path) +{ + tst_module_exists_(NULL, mod_name, mod_path); +} + +void tst_module_load_(void (cleanup_fn)(void), const char *mod_name, + char *const argv[]); + +static inline void tst_module_load(const char *mod_name, char *const argv[]) +{ + tst_module_load_(NULL, mod_name, argv); +} + +void tst_module_unload_(void (cleanup_fn)(void), const char *mod_name); + +static inline void tst_module_unload(const char *mod_name) +{ + tst_module_unload_(NULL, mod_name); +} + +#endif /* TST_MODULE_H */ diff --git a/include/tst_net.h b/include/tst_net.h old mode 100644 new mode 100755 diff --git a/include/tst_netdevice.h b/include/tst_netdevice.h new file mode 100755 index 0000000000000000000000000000000000000000..f0266120822af082e7be6356ba60241b55e04116 --- /dev/null +++ b/include/tst_netdevice.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2021 Linux Test Project + */ + +#ifndef TST_NETDEVICE_H +#define TST_NETDEVICE_H + +/* Find device index for given network interface name. */ +int tst_netdev_index_by_name(const char *file, const int lineno, + const char *ifname); +#define NETDEV_INDEX_BY_NAME(ifname) \ + tst_netdev_index_by_name(__FILE__, __LINE__, (ifname)) + +/* Activate or deactivate network interface */ +int tst_netdev_set_state(const char *file, const int lineno, + const char *ifname, int up); +#define NETDEV_SET_STATE(ifname, up) \ + tst_netdev_set_state(__FILE__, __LINE__, (ifname), (up)) + +/* Create a connected pair of virtual network devices */ +int tst_create_veth_pair(const char *file, const int lineno, + const char *ifname1, const char *ifname2); +#define CREATE_VETH_PAIR(ifname1, ifname2) \ + tst_create_veth_pair(__FILE__, __LINE__, (ifname1), (ifname2)) + +int tst_netdev_add_device(const char *file, const int lineno, + const char *ifname, const char *devtype); +#define NETDEV_ADD_DEVICE(ifname, devtype) \ + tst_netdev_add_device(__FILE__, __LINE__, (ifname), (devtype)) + +int tst_netdev_remove_device(const char *file, const int lineno, + const char *ifname); +#define NETDEV_REMOVE_DEVICE(ifname) \ + tst_netdev_remove_device(__FILE__, __LINE__, (ifname)) + +int tst_netdev_add_address(const char *file, const int lineno, + const char *ifname, unsigned int family, const void *address, + unsigned int prefix, size_t addrlen, unsigned int flags); +#define NETDEV_ADD_ADDRESS(ifname, family, address, prefix, addrlen, flags) \ + tst_netdev_add_address(__FILE__, __LINE__, (ifname), (family), \ + (address), (prefix), (addrlen), (flags)) + +int tst_netdev_add_address_inet(const char *file, const int lineno, + const char *ifname, in_addr_t address, unsigned int prefix, + unsigned int flags); +#define NETDEV_ADD_ADDRESS_INET(ifname, address, prefix, flags) \ + tst_netdev_add_address_inet(__FILE__, __LINE__, (ifname), (address), \ + (prefix), (flags)) + +int tst_netdev_remove_address(const char *file, const int lineno, + const char *ifname, unsigned int family, const void *address, + size_t addrlen); +#define NETDEV_REMOVE_ADDRESS(ifname, family, address, addrlen) \ + tst_netdev_remove_address(__FILE__, __LINE__, (ifname), (family), \ + (address), (addrlen)) + +int tst_netdev_remove_address_inet(const char *file, const int lineno, + const char *ifname, in_addr_t address); +#define NETDEV_REMOVE_ADDRESS_INET(ifname, address) \ + tst_netdev_remove_address_inet(__FILE__, __LINE__, (ifname), (address)) + +int tst_netdev_change_ns_fd(const char *file, const int lineno, + const char *ifname, int nsfd); +#define NETDEV_CHANGE_NS_FD(ifname, nsfd) \ + tst_netdev_change_ns_fd(__FILE__, __LINE__, (ifname), (nsfd)) + +int tst_netdev_change_ns_pid(const char *file, const int lineno, + const char *ifname, pid_t nspid); +#define NETDEV_CHANGE_NS_PID(ifname, nspid) \ + tst_netdev_change_ns_pid(__FILE__, __LINE__, (ifname), (nspid)) + +/* + * Add new static entry to main routing table. If you specify gateway address, + * the interface name is optional. + */ +int tst_netdev_add_route(const char *file, const int lineno, + const char *ifname, unsigned int family, const void *srcaddr, + unsigned int srcprefix, size_t srclen, const void *dstaddr, + unsigned int dstprefix, size_t dstlen, const void *gateway, + size_t gatewaylen); +#define NETDEV_ADD_ROUTE(ifname, family, srcaddr, srcprefix, srclen, dstaddr, \ + dstprefix, dstlen, gateway, gatewaylen) \ + tst_netdev_add_route(__FILE__, __LINE__, (ifname), (family), \ + (srcaddr), (srcprefix), (srclen), (dstaddr), (dstprefix), \ + (dstlen), (gateway), (gatewaylen)) + +/* + * Simplified function for adding IPv4 static route. If you set srcprefix + * or dstprefix to 0, the corresponding address will be ignored. Interface + * name is optional if gateway address is non-zero. + */ +int tst_netdev_add_route_inet(const char *file, const int lineno, + const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, + in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway); +#define NETDEV_ADD_ROUTE_INET(ifname, srcaddr, srcprefix, dstaddr, dstprefix, \ + gateway) \ + tst_netdev_add_route_inet(__FILE__, __LINE__, (ifname), (srcaddr), \ + (srcprefix), (dstaddr), (dstprefix), (gateway)) + +/* + * Remove static entry from main routing table. + */ +int tst_netdev_remove_route(const char *file, const int lineno, + const char *ifname, unsigned int family, const void *srcaddr, + unsigned int srcprefix, size_t srclen, const void *dstaddr, + unsigned int dstprefix, size_t dstlen, const void *gateway, + size_t gatewaylen); +#define NETDEV_REMOVE_ROUTE(ifname, family, srcaddr, srcprefix, srclen, \ + dstaddr, dstprefix, dstlen, gateway, gatewaylen) \ + tst_netdev_remove_route(__FILE__, __LINE__, (ifname), (family), \ + (srcaddr), (srcprefix), (srclen), (dstaddr), (dstprefix), \ + (dstlen), (gateway), (gatewaylen)) + +/* + * Simplified function for removing IPv4 static route. + */ +int tst_netdev_remove_route_inet(const char *file, const int lineno, + const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, + in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway); +#define NETDEV_REMOVE_ROUTE_INET(ifname, srcaddr, srcprefix, dstaddr, \ + dstprefix, gateway) \ + tst_netdev_remove_route_inet(__FILE__, __LINE__, (ifname), (srcaddr), \ + (srcprefix), (dstaddr), (dstprefix), (gateway)) + +#endif /* TST_NETDEVICE_H */ diff --git a/include/tst_netlink.h b/include/tst_netlink.h old mode 100644 new mode 100755 diff --git a/include/tst_numa.h b/include/tst_numa.h old mode 100644 new mode 100755 index 846e093a916743f75a9f88373ab65dd6640478a7..3af311e5e97260a6af2a4e87f900bcce7b54505d --- a/include/tst_numa.h +++ b/include/tst_numa.h @@ -38,7 +38,7 @@ void tst_nodemap_print_counters(struct tst_nodemap *nodes); * * @mode Numa mempolicy mode. */ -const char *tst_numa_mode_name(int mode); +const char *tst_mempolicy_mode_name(int mode); /** * Maps pages into memory, if path is NULL the mapping is anonymous otherwise is backed by the file. diff --git a/include/tst_path_has_mnt_flags.h b/include/tst_path_has_mnt_flags.h old mode 100644 new mode 100755 diff --git a/include/tst_pid.h b/include/tst_pid.h old mode 100644 new mode 100755 index 9ba1abb27b7c27623c2a4198274953d94e42e44e..8d999a655f1a54763aed8062a9a927baef6a0d9b --- a/include/tst_pid.h +++ b/include/tst_pid.h @@ -13,8 +13,10 @@ pid_t tst_get_unused_pid_(void (*cleanup_fn)(void)); /* - * Returns number of free pids by substarction of the number of pids - * currently used ('ps -eT') from max_pids + * Returns number of free pids by subtraction of the number of pids + * currently used ('ps -eT') from maximum number of processes. + * The limit of processes come from kernel pid_max and cgroup session limits + * (e.g. configured by systemd user.slice). */ int tst_get_free_pids_(void (*cleanup_fn)(void)); diff --git a/include/tst_private.h b/include/tst_private.h old mode 100644 new mode 100755 index e30d34740141acd0abc83e17ad040d68dc7eebfa..6f4f39b151193356d21b158b69c3e729b7d04af9 --- a/include/tst_private.h +++ b/include/tst_private.h @@ -11,6 +11,7 @@ #include #include +#include "tst_defaults.h" #define MAX_IPV4_PREFIX 32 #define MAX_IPV6_PREFIX 128 @@ -29,4 +30,21 @@ void tst_print_svar_change(const char *name, const char *val); int tst_get_prefix(const char *ip_str, int is_ipv6); +/* + * Checks kernel config for a single configuration option and returns its + * state if found. The possible return values are the same as for + * tst_kconfig_var.choice, with the same meaning. See tst_kconfig_read() + * description in tst_kconfig.h. + */ +char tst_kconfig_get(const char *confname); + +/* + * If cmd argument is a single command, this function just checks command + * whether exists. If not, case skips. + * If cmd argument is a complex string ie 'mkfs.ext4 >= 1.43.0', this + * function checks command version whether meets this requirement. + * If not, case skips. + */ +void tst_check_cmd(const char *cmd); + #endif diff --git a/include/tst_process_state.h b/include/tst_process_state.h old mode 100644 new mode 100755 index c32aa58e6866a6512115f00b0126438183c5402a..81532524abd22897cf2f2596f1acffde4cb1ad94 --- a/include/tst_process_state.h +++ b/include/tst_process_state.h @@ -1,20 +1,20 @@ /* SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2012-2014 Cyril Hrubis chrubis@suse.cz + * Copyright (C) 2021 Xie Ziyao */ - /* - - These functions helps you wait till a process with given pid changes state. - This is for example useful when you need to wait in parent until child - blocks. - - */ +/* + * These functions helps you wait till a process with given pid changes state. + * This is for example useful when you need to wait in parent until child blocks. + */ #ifndef TST_PROCESS_STATE__ #define TST_PROCESS_STATE__ #include +#ifdef TST_TEST_H__ + /* * Waits for process state change. * @@ -26,11 +26,16 @@ * Z - zombie process * T - process is traced */ -#ifdef TST_TEST_H__ - #define TST_PROCESS_STATE_WAIT(pid, state, msec_timeout) \ tst_process_state_wait(__FILE__, __LINE__, NULL, \ - (pid), (state), (msec_timeout)) + (pid), (state), (msec_timeout)) + +/* + * Check that a given pid is present on the system + */ +#define TST_PROCESS_EXIT_WAIT(pid, msec_timeout) \ + tst_process_exit_wait((pid), (msec_timeout)) + #else /* * The same as above but does not use tst_brkm() interface. @@ -41,13 +46,14 @@ */ int tst_process_state_wait2(pid_t pid, const char state); -# define TST_PROCESS_STATE_WAIT(cleanup_fn, pid, state) \ - tst_process_state_wait(__FILE__, __LINE__, (cleanup_fn), \ - (pid), (state), 0) +#define TST_PROCESS_STATE_WAIT(cleanup_fn, pid, state) \ + tst_process_state_wait(__FILE__, __LINE__, (cleanup_fn), \ + (pid), (state), 0) #endif int tst_process_state_wait(const char *file, const int lineno, - void (*cleanup_fn)(void), pid_t pid, - const char state, unsigned int msec_timeout); + void (*cleanup_fn)(void), pid_t pid, + const char state, unsigned int msec_timeout); +int tst_process_exit_wait(pid_t pid, unsigned int msec_timeout); #endif /* TST_PROCESS_STATE__ */ diff --git a/include/tst_res_flags.h b/include/tst_res_flags.h old mode 100644 new mode 100755 diff --git a/include/tst_rtctime.h b/include/tst_rtctime.h new file mode 100755 index 0000000000000000000000000000000000000000..c2c282e90d3364cdd7fe657ebd15117c3710ff88 --- /dev/null +++ b/include/tst_rtctime.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Unisoc Inc. + */ + +#ifndef TST_RTCTIME +#define TST_RTCTIME + +#include +#include + +int tst_rtc_ioctl(const char *rtc_dev, unsigned long request, + struct rtc_time *rtc_tm); + +static inline int tst_rtc_gettime(const char *rtc_dev, struct rtc_time *rtc_tm) +{ + return tst_rtc_ioctl(rtc_dev, RTC_RD_TIME, rtc_tm); +} + +static inline int tst_rtc_settime(const char *rtc_dev, struct rtc_time *rtc_tm) +{ + return tst_rtc_ioctl(rtc_dev, RTC_SET_TIME, rtc_tm); +} + +void tst_rtc_time_to_tm(long long time, struct rtc_time *tm); + +long long tst_rtc_tm_to_time(struct rtc_time *tm); + +#endif /* TST_RTCTIME */ diff --git a/include/tst_rtnetlink.h b/include/tst_rtnetlink.h new file mode 100755 index 0000000000000000000000000000000000000000..6a0c53df4f5eaea516bcd3bcb409d74f4a0373cd --- /dev/null +++ b/include/tst_rtnetlink.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2021 Linux Test Project + */ + +#ifndef TST_RTNETLINK_H +#define TST_RTNETLINK_H + +struct tst_rtnl_context; + +struct tst_rtnl_attr_list { + unsigned short type; + const void *data; + ssize_t len; + const struct tst_rtnl_attr_list *sublist; +}; + +struct tst_rtnl_message { + struct nlmsghdr *header; + struct nlmsgerr *err; + void *payload; + size_t payload_size; +}; + +extern int tst_rtnl_errno; + +/* Open a netlink socket */ +struct tst_rtnl_context *tst_rtnl_create_context(const char *file, + const int lineno); +#define RTNL_CREATE_CONTEXT() tst_rtnl_create_context(__FILE__, __LINE__) + +/* Free a tst_rtnl_message array returned by tst_rtnl_recv() */ +void tst_rtnl_free_message(struct tst_rtnl_message *msg); +#define RTNL_FREE_MESSAGE tst_rtnl_free_message + +/* Close netlink socket */ +void tst_rtnl_destroy_context(const char *file, const int lineno, + struct tst_rtnl_context *ctx); +#define RTNL_DESTROY_CONTEXT(ctx) \ + tst_rtnl_destroy_context(__FILE__, __LINE__, (ctx)) + +/* Send all messages in given buffer */ +int tst_rtnl_send(const char *file, const int lineno, + struct tst_rtnl_context *ctx); +#define RTNL_SEND(ctx) tst_rtnl_send(__FILE__, __LINE__, (ctx)) + +/* Send all messages in given buffer and validate kernel response */ +int tst_rtnl_send_validate(const char *file, const int lineno, + struct tst_rtnl_context *ctx); +#define RTNL_SEND_VALIDATE(ctx) \ + tst_rtnl_send_validate(__FILE__, __LINE__, (ctx)) + +/* Wait until data is available for reading from the netlink socket */ +int tst_rtnl_wait(struct tst_rtnl_context *ctx); +#define RTNL_WAIT tst_rtnl_wait + +/* + * Read from netlink socket and return an array of partially parsed messages. + * header == NULL indicates end of array. + */ +struct tst_rtnl_message *tst_rtnl_recv(const char *file, const int lineno, + struct tst_rtnl_context *ctx); +#define RTNL_RECV(ctx) tst_rtnl_recv(__FILE__, __LINE__, (ctx)) + +/* Add new message to buffer */ +int tst_rtnl_add_message(const char *file, const int lineno, + struct tst_rtnl_context *ctx, const struct nlmsghdr *header, + const void *payload, size_t payload_size); +#define RTNL_ADD_MESSAGE(ctx, header, payload, psize) \ + tst_rtnl_add_message(__FILE__, __LINE__, (ctx), (header), (payload), \ + (psize)) + +/* Add arbitrary attribute to last message */ +int tst_rtnl_add_attr(const char *file, const int lineno, + struct tst_rtnl_context *ctx, unsigned short type, const void *data, + unsigned short len); +#define RTNL_ADD_ATTR(ctx, type, data, len) \ + tst_rtnl_add_attr(__FILE__, __LINE__, (ctx), (type), (data), (len)) + +/* Add string attribute to last message */ +int tst_rtnl_add_attr_string(const char *file, const int lineno, + struct tst_rtnl_context *ctx, unsigned short type, const char *data); +#define RTNL_ADD_ATTR_STRING(ctx, type, data) \ + tst_rtnl_add_attr_string(__FILE__, __LINE__, (ctx), (type), (data)) + +/* + * Add list of arbitrary attributes to last message. The list is terminated + * by attribute with negative length. Nested sublists are supported. + */ +int tst_rtnl_add_attr_list(const char *file, const int lineno, + struct tst_rtnl_context *ctx, const struct tst_rtnl_attr_list *list); +#define RTNL_ADD_ATTR_LIST(ctx, list) \ + tst_rtnl_add_attr_list(__FILE__, __LINE__, (ctx), (list)) + +/* Check that all sent messages with NLM_F_ACK flag have been acked without + * error. Usage: + * + * tst_rtnl_send(ctx); + * tst_rtnl_wait(ctx); + * response = tst_rtnl_recv(ctx); + * if (!tst_rtnl_check_acks(ctx, response)) { ... } + * tst_rtnl_free_message(response); + */ +int tst_rtnl_check_acks(const char *file, const int lineno, + struct tst_rtnl_context *ctx, struct tst_rtnl_message *response); +#define RTNL_CHECK_ACKS(ctx, response) \ + tst_rtnl_context(__FILE__, __LINE__, (ctx), (response)) + +#endif /* TST_RTNETLINK_H */ diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h old mode 100644 new mode 100755 index 27e8bda45589a7f9ea14438db3dc8220419c3292..5661ce57bf7c7b2b0eb3ada9d01049abdd99dab0 --- a/include/tst_safe_clocks.h +++ b/include/tst_safe_clocks.h @@ -15,59 +15,139 @@ #include "lapi/syscalls.h" #include "lapi/posix_clocks.h" -static inline void safe_clock_getres(const char *file, const int lineno, +static inline int safe_clock_getres(const char *file, const int lineno, clockid_t clk_id, struct timespec *res) { int rval; rval = clock_getres(clk_id, res); - if (rval != 0) { - tst_brk(TBROK | TERRNO, - "%s:%d clock_getres(%s) failed", - file, lineno, tst_clock_name(clk_id)); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "clock_getres(%s) failed", tst_clock_name(clk_id)); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid clock_getres(%s) return value %d", + tst_clock_name(clk_id), rval); } + + return rval; } -static inline void safe_clock_gettime(const char *file, const int lineno, +static inline int safe_clock_gettime(const char *file, const int lineno, clockid_t clk_id, struct timespec *tp) { int rval; rval = clock_gettime(clk_id, tp); - if (rval != 0) { - tst_brk(TBROK | TERRNO, - "%s:%d clock_gettime(%s) failed", - file, lineno, tst_clock_name(clk_id)); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "clock_gettime(%s) failed", tst_clock_name(clk_id)); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid clock_gettime(%s) return value %d", + tst_clock_name(clk_id), rval); } + + return rval; } -static inline void safe_clock_settime(const char *file, const int lineno, +static inline int safe_clock_settime(const char *file, const int lineno, clockid_t clk_id, struct timespec *tp) { int rval; rval = clock_settime(clk_id, tp); - if (rval != 0) { - tst_brk(TBROK | TERRNO, - "%s:%d clock_gettime(%s) failed", - file, lineno, tst_clock_name(clk_id)); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "clock_gettime(%s) failed", tst_clock_name(clk_id)); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid clock_gettime(%s) return value %d", + tst_clock_name(clk_id), rval); } + + return rval; } -static inline int safe_clock_adjtime(const char *file, const int lineno, - clockid_t clk_id, struct timex *txc) +static inline int safe_timer_create(const char *file, const int lineno, + clockid_t clockid, struct sigevent *sevp, timer_t *timerid) { - int rval; + int ret; + + errno = 0; + ret = timer_create(clockid, sevp, timerid); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "timer_create(%s) failed", tst_clock_name(clockid)); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid timer_create(%s) return value %d", + tst_clock_name(clockid), ret); + } + + return ret; +} - rval = tst_syscall(__NR_clock_adjtime, clk_id, txc); - if (rval < 0) { - tst_brk(TBROK | TERRNO, - "%s:%d clock_adjtime(%s) failed %i", - file, lineno, tst_clock_name(clk_id), rval); +static inline int safe_timer_settime(const char *file, const int lineno, + timer_t timerid, int flags, const struct itimerspec *new_value, + struct itimerspec *old_value) +{ + int ret; + + errno = 0; + ret = timer_settime(timerid, flags, new_value, old_value); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "timer_settime() failed"); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid timer_settime() return value %d", ret); } - return rval; + return ret; +} + +static inline int safe_timer_gettime(const char *file, const int lineno, + timer_t timerid, struct itimerspec *curr_value) +{ + int ret; + + errno = 0; + ret = timer_gettime(timerid, curr_value); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "timer_gettime() failed"); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid timer_gettime() return value %d", ret); + } + + return ret; +} + +static inline int safe_timer_delete(const char *file, const int lineno, + timer_t timerid) +{ + int ret; + + errno = 0; + ret = timer_delete(timerid); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, "timer_delete() failed"); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid timer_delete() return value %d", ret); + } + + return ret; } #define SAFE_CLOCK_GETRES(clk_id, res)\ @@ -79,7 +159,17 @@ static inline int safe_clock_adjtime(const char *file, const int lineno, #define SAFE_CLOCK_SETTIME(clk_id, tp)\ safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp)) -#define SAFE_CLOCK_ADJTIME(clk_id, txc)\ - safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc)) +#define SAFE_TIMER_CREATE(clockid, sevp, timerid)\ + safe_timer_create(__FILE__, __LINE__, (clockid), (sevp), (timerid)) + +#define SAFE_TIMER_SETTIME(timerid, flags, new_value, old_value)\ + safe_timer_settime(__FILE__, __LINE__, (timerid), (flags),\ + (new_value), (old_value)) + +#define SAFE_TIMER_GETTIME(timerid, curr_value)\ + safe_timer_gettime(__FILE__, __LINE__, (timerid), (curr_value)) + +#define SAFE_TIMER_DELETE(timerid)\ + safe_timer_delete(__FILE__, __LINE__, timerid) #endif /* SAFE_CLOCKS_H__ */ diff --git a/include/tst_safe_file_at.h b/include/tst_safe_file_at.h new file mode 100755 index 0000000000000000000000000000000000000000..8df34227ff191428f2df1f31b038d49927bcd437 --- /dev/null +++ b/include/tst_safe_file_at.h @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 SUSE LLC + */ + +#ifndef TST_SAFE_FILE_AT_H +#define TST_SAFE_FILE_AT_H + +#include +#include + +#define SAFE_OPENAT(dirfd, path, oflags, ...) \ + safe_openat(__FILE__, __LINE__, \ + (dirfd), (path), (oflags), ## __VA_ARGS__) + +#define SAFE_FILE_READAT(dirfd, path, buf, nbyte) \ + safe_file_readat(__FILE__, __LINE__, \ + (dirfd), (path), (buf), (nbyte)) + + +#define SAFE_FILE_PRINTFAT(dirfd, path, fmt, ...) \ + safe_file_printfat(__FILE__, __LINE__, \ + (dirfd), (path), (fmt), __VA_ARGS__) + +#define SAFE_UNLINKAT(dirfd, path, flags) \ + safe_unlinkat(__FILE__, __LINE__, (dirfd), (path), (flags)) + +const char *tst_decode_fd(const int fd) + __attribute__((warn_unused_result)); + +int safe_openat(const char *const file, const int lineno, const int dirfd, + const char *const path, const int oflags, ...) + __attribute__((nonnull, warn_unused_result)); + +ssize_t safe_file_readat(const char *const file, const int lineno, + const int dirfd, const char *const path, + char *const buf, const size_t nbyte) + __attribute__ ((nonnull)); + +int tst_file_vprintfat(const int dirfd, const char *const path, + const char *const fmt, va_list va) + __attribute__((nonnull)); +int tst_file_printfat(const int dirfd, const char *const path, + const char *const fmt, ...) + __attribute__ ((format (printf, 3, 4), nonnull)); + +int safe_file_vprintfat(const char *const file, const int lineno, + const int dirfd, const char *const path, + const char *const fmt, va_list va) + __attribute__ ((nonnull)); + +int safe_file_printfat(const char *const file, const int lineno, + const int dirfd, const char *const path, + const char *const fmt, ...) + __attribute__ ((format (printf, 5, 6), nonnull)); + +int safe_unlinkat(const char *const file, const int lineno, + const int dirfd, const char *const path, const int flags) + __attribute__ ((nonnull)); + +#endif diff --git a/include/tst_safe_file_ops.h b/include/tst_safe_file_ops.h old mode 100644 new mode 100755 index 894c16123d8dc7d26fa409c2f748602239646618..62f6600eca56d042542f5b980b99dfd57c138086 --- a/include/tst_safe_file_ops.h +++ b/include/tst_safe_file_ops.h @@ -7,6 +7,9 @@ #include "safe_file_ops_fn.h" +#define FILE_SCANF(path, fmt, ...) \ + file_scanf(__FILE__, __LINE__, (path), (fmt), ## __VA_ARGS__) + #define SAFE_FILE_SCANF(path, fmt, ...) \ safe_file_scanf(__FILE__, __LINE__, NULL, \ (path), (fmt), ## __VA_ARGS__) @@ -25,6 +28,14 @@ &tst_rval); \ tst_rval;}) +#define SAFE_READ_PROC_STATUS(pid, item) \ + ({long tst_rval_; \ + char tst_path_[128]; \ + sprintf(tst_path_, "/proc/%d/status", pid); \ + SAFE_FILE_LINES_SCANF(tst_path_, item " %ld", \ + &tst_rval_); \ + tst_rval_;}) + #define FILE_PRINTF(path, fmt, ...) \ file_printf(__FILE__, __LINE__, \ (path), (fmt), ## __VA_ARGS__) @@ -33,6 +44,11 @@ safe_file_printf(__FILE__, __LINE__, NULL, \ (path), (fmt), ## __VA_ARGS__) +/* Same as SAFE_FILE_PRINTF() but returns quietly if the path doesn't exist */ +#define SAFE_TRY_FILE_PRINTF(path, fmt, ...) \ + safe_try_file_printf(__FILE__, __LINE__, NULL, \ + (path), (fmt), ## __VA_ARGS__) + #define SAFE_CP(src, dst) \ safe_cp(__FILE__, __LINE__, NULL, (src), (dst)) diff --git a/include/tst_safe_io_uring.h b/include/tst_safe_io_uring.h new file mode 100755 index 0000000000000000000000000000000000000000..cb26aec1e16c1030e39ee9e64565d5ba17588942 --- /dev/null +++ b/include/tst_safe_io_uring.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) Linux Test Project, 2021 + */ + +#ifndef TST_IO_URING_H__ +#define TST_IO_URING_H__ + +#include "config.h" +#include "lapi/io_uring.h" + +struct tst_io_uring { + int fd; + void *sqr_base, *cqr_base; + /* buffer sizes in bytes for unmapping */ + size_t sqr_mapsize, cqr_mapsize; + + /* Number of entries in the ring buffers */ + uint32_t sqr_size, cqr_size; + + /* Submission queue pointers */ + struct io_uring_sqe *sqr_entries; + const uint32_t *sqr_head, *sqr_mask, *sqr_flags, *sqr_dropped; + uint32_t *sqr_tail, *sqr_array; + + /* Completion queue pointers */ + const struct io_uring_cqe *cqr_entries; + const uint32_t *cqr_tail, *cqr_mask, *cqr_overflow; + uint32_t *cqr_head; +}; + +/* + * Call io_uring_setup() with given arguments and prepare memory mappings + * into the tst_io_uring structure passed in the third argument. + */ +#define SAFE_IO_URING_INIT(entries, params, uring) \ + safe_io_uring_init(__FILE__, __LINE__, (entries), (params), (uring)) +int safe_io_uring_init(const char *file, const int lineno, + unsigned int entries, struct io_uring_params *params, + struct tst_io_uring *uring); + +/* + * Release io_uring mappings and close the file descriptor. uring->fd will + * be set to -1 after close. + */ +#define SAFE_IO_URING_CLOSE(uring) \ + safe_io_uring_close(__FILE__, __LINE__, (uring)) +int safe_io_uring_close(const char *file, const int lineno, + struct tst_io_uring *uring); + +/* + * Call io_uring_enter() and check for errors. The "strict" argument controls + * pedantic check whether return value is equal to "to_submit" argument. + */ +#define SAFE_IO_URING_ENTER(strict, fd, to_submit, min_complete, flags, sig) \ + safe_io_uring_enter(__FILE__, __LINE__, (strict), (fd), (to_submit), \ + (min_complete), (flags), (sig)) +int safe_io_uring_enter(const char *file, const int lineno, int strict, + int fd, unsigned int to_submit, unsigned int min_complete, + unsigned int flags, sigset_t *sig); + +#endif /* TST_IO_URING_H__ */ diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h old mode 100644 new mode 100755 index c39d8768b1fbd436dc7c77d9f38dbcdd05ee80d4..d99441c86f123787eeb73daf977eca65850bae8c --- a/include/tst_safe_macros.h +++ b/include/tst_safe_macros.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -44,22 +45,16 @@ int safe_chroot(const char *file, const int lineno, const char *path); #define SAFE_DIRNAME(path) \ safe_dirname(__FILE__, __LINE__, NULL, (path)) -static inline int safe_dup(const char *file, const int lineno, - int oldfd) -{ - int rval; +int safe_dup(const char *file, const int lineno, int oldfd); - rval = dup(oldfd); - if (rval == -1) { - tst_brk_(file, lineno, TBROK | TERRNO, - "dup(%i) failed", oldfd); - } - - return rval; -} #define SAFE_DUP(oldfd) \ safe_dup(__FILE__, __LINE__, (oldfd)) +int safe_dup2(const char *file, const int lineno, int oldfd, int newfd); + +#define SAFE_DUP2(oldfd, newfd) \ + safe_dup2(__FILE__, __LINE__, (oldfd), (newfd)) + #define SAFE_GETCWD(buf, size) \ safe_getcwd(__FILE__, __LINE__, NULL, (buf), (size)) @@ -72,6 +67,11 @@ static inline int safe_dup(const char *file, const int lineno, #define SAFE_MALLOC(size) \ safe_malloc(__FILE__, __LINE__, NULL, (size)) +void *safe_realloc(const char *file, const int lineno, void *ptr, size_t size); + +#define SAFE_REALLOC(ptr, size) \ + safe_realloc(__FILE__, __LINE__, (ptr), (size)) + #define SAFE_MKDIR(pathname, mode) \ safe_mkdir(__FILE__, __LINE__, NULL, (pathname), (mode)) @@ -120,6 +120,16 @@ int safe_setreuid(const char *file, const int lineno, #define SAFE_SETREUID(ruid, euid) \ safe_setreuid(__FILE__, __LINE__, (ruid), (euid)) +int safe_setresgid(const char *file, const int lineno, + gid_t rgid, gid_t egid, gid_t sgid); +#define SAFE_SETRESGID(rgid, egid, sgid) \ + safe_setresgid(__FILE__, __LINE__, (rgid), (egid), (sgid)) + +int safe_setresuid(const char *file, const int lineno, + uid_t ruid, uid_t euid, uid_t suid); +#define SAFE_SETRESUID(ruid, euid, suid) \ + safe_setresuid(__FILE__, __LINE__, (ruid), (euid), (suid)) + #define SAFE_GETRESUID(ruid, euid, suid) \ safe_getresuid(__FILE__, __LINE__, NULL, (ruid), (euid), (suid)) @@ -129,18 +139,28 @@ int safe_setreuid(const char *file, const int lineno, int safe_setpgid(const char *file, const int lineno, pid_t pid, pid_t pgid); #define SAFE_SETPGID(pid, pgid) \ - safe_setpgid(__FILE__, __LINE__, (pid), (pgid)); + safe_setpgid(__FILE__, __LINE__, (pid), (pgid)) pid_t safe_getpgid(const char *file, const int lineno, pid_t pid); #define SAFE_GETPGID(pid) \ safe_getpgid(__FILE__, __LINE__, (pid)) +int safe_setgroups(const char *file, const int lineno, size_t size, const gid_t *list); + +#define SAFE_SETGROUPS(size, list) \ + safe_setgroups(__FILE__, __LINE__, (size), (list)) + +int safe_getgroups(const char *file, const int lineno, int size, gid_t list[]); + +#define SAFE_GETGROUPS(size, list) \ + safe_getgroups(__FILE__, __LINE__, (size), (list)) + #define SAFE_UNLINK(pathname) \ safe_unlink(__FILE__, __LINE__, NULL, (pathname)) #define SAFE_LINK(oldpath, newpath) \ - safe_link(__FILE__, __LINE__, NULL, (oldpath), (newpath)) + safe_link(__FILE__, __LINE__, NULL, (oldpath), (newpath)) #define SAFE_LINKAT(olddirfd, oldpath, newdirfd, newpath, flags) \ safe_linkat(__FILE__, __LINE__, NULL, (olddirfd), (oldpath), \ @@ -150,7 +170,7 @@ pid_t safe_getpgid(const char *file, const int lineno, pid_t pid); safe_readlink(__FILE__, __LINE__, NULL, (path), (buf), (bufsize)) #define SAFE_SYMLINK(oldpath, newpath) \ - safe_symlink(__FILE__, __LINE__, NULL, (oldpath), (newpath)) + safe_symlink(__FILE__, __LINE__, NULL, (oldpath), (newpath)) #define SAFE_WRITE(len_strict, fildes, buf, nbyte) \ safe_write(__FILE__, __LINE__, NULL, (len_strict), (fildes), (buf), (nbyte)) @@ -177,10 +197,10 @@ pid_t safe_getpgid(const char *file, const int lineno, pid_t pid); safe_fchown(__FILE__, __LINE__, NULL, (fd), (owner), (group)) #define SAFE_WAIT(status) \ - safe_wait(__FILE__, __LINE__, NULL, (status)) + safe_wait(__FILE__, __LINE__, NULL, (status)) #define SAFE_WAITPID(pid, status, opts) \ - safe_waitpid(__FILE__, __LINE__, NULL, (pid), (status), (opts)) + safe_waitpid(__FILE__, __LINE__, NULL, (pid), (status), (opts)) #define SAFE_KILL(pid, sig) \ safe_kill(__FILE__, __LINE__, NULL, (pid), (sig)) @@ -211,13 +231,16 @@ pid_t safe_getpgid(const char *file, const int lineno, pid_t pid); #define SAFE_READDIR(dirp) \ safe_readdir(__FILE__, __LINE__, NULL, (dirp)) -#define SAFE_IOCTL(fd, request, ...) \ +#define SAFE_IOCTL_(file, lineno, fd, request, ...) \ ({int tst_ret_ = ioctl(fd, request, ##__VA_ARGS__); \ tst_ret_ < 0 ? \ - tst_brk(TBROK | TERRNO, \ + tst_brk_((file), (lineno), TBROK | TERRNO, \ "ioctl(%i,%s,...) failed", fd, #request), 0 \ : tst_ret_;}) +#define SAFE_IOCTL(fd, request, ...) \ + SAFE_IOCTL_(__FILE__, __LINE__, (fd), (request), ##__VA_ARGS__) + #define SAFE_FCNTL(fd, cmd, ...) \ ({int tst_ret_ = fcntl(fd, cmd, ##__VA_ARGS__); \ tst_ret_ == -1 ? \ @@ -227,7 +250,7 @@ pid_t safe_getpgid(const char *file, const int lineno, pid_t pid); /* * following functions are inline because the behaviour may depend on - * -D_FILE_OFFSET_BITS=64 -DOFF_T=off64_t compile flags + * -D_FILE_OFFSET_BITS=64 compile flag */ static inline void *safe_mmap(const char *file, const int lineno, @@ -255,10 +278,14 @@ static inline int safe_ftruncate(const char *file, const int lineno, int rval; rval = ftruncate(fd, length); + if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "ftruncate(%d,%ld) failed", - fd, (long)length); + "ftruncate(%d,%ld) failed", fd, (long)length); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid ftruncate(%d,%ld) return value %d", fd, + (long)length, rval); } return rval; @@ -272,10 +299,14 @@ static inline int safe_truncate(const char *file, const int lineno, int rval; rval = truncate(path, length); + if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "truncate(%s,%ld) failed", - path, (long)length); + "truncate(%s,%ld) failed", path, (long)length); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid truncate(%s,%ld) return value %d", path, + (long)length, rval); } return rval; @@ -292,7 +323,11 @@ static inline int safe_stat(const char *file, const int lineno, if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "stat(%s,%p) failed", path, buf); + "stat(%s,%p) failed", path, buf); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid stat(%s,%p) return value %d", path, buf, + rval); } return rval; @@ -310,6 +345,9 @@ static inline int safe_fstat(const char *file, const int lineno, if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, "fstat(%d,%p) failed", fd, buf); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid fstat(%d,%p) return value %d", fd, buf, rval); } return rval; @@ -327,6 +365,10 @@ static inline int safe_lstat(const char *file, const int lineno, if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, "lstat(%s,%p) failed", path, buf); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid lstat(%s,%p) return value %d", path, buf, + rval); } return rval; @@ -343,13 +385,17 @@ static inline int safe_statfs(const char *file, const int lineno, if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "statfs(%s,%p) failed", path, buf); + "statfs(%s,%p) failed", path, buf); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid statfs(%s,%p) return value %d", path, buf, + rval); } return rval; } #define SAFE_STATFS(path, buf) \ - safe_statfs(__FILE__, __LINE__, (path), (buf)) + safe_statfs(__FILE__, __LINE__, (path), (buf)) static inline off_t safe_lseek(const char *file, const int lineno, int fd, off_t offset, int whence) @@ -360,8 +406,11 @@ static inline off_t safe_lseek(const char *file, const int lineno, if (rval == (off_t) -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "lseek(%d,%ld,%d) failed", - fd, (long)offset, whence); + "lseek(%d,%ld,%d) failed", fd, (long)offset, whence); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid lseek(%d,%ld,%d) return value %ld", fd, + (long)offset, whence, (long)rval); } return rval; @@ -378,8 +427,11 @@ static inline int safe_getrlimit(const char *file, const int lineno, if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "getrlimit(%d,%p) failed", - resource, rlim); + "getrlimit(%d,%p) failed", resource, rlim); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid getrlimit(%d,%p) return value %d", resource, + rlim, rval); } return rval; @@ -396,8 +448,11 @@ static inline int safe_setrlimit(const char *file, const int lineno, if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "setrlimit(%d,%p) failed", - resource, rlim); + "setrlimit(%d,%p) failed", resource, rlim); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid setrlimit(%d,%p) return value %d", resource, + rlim, rval); } return rval; @@ -406,21 +461,8 @@ static inline int safe_setrlimit(const char *file, const int lineno, safe_setrlimit(__FILE__, __LINE__, (resource), (rlim)) typedef void (*sighandler_t)(int); -static inline sighandler_t safe_signal(const char *file, const int lineno, - int signum, sighandler_t handler) -{ - sighandler_t rval; - - rval = signal(signum, handler); - - if (rval == SIG_ERR) { - tst_brk_(file, lineno, TBROK | TERRNO, - "signal(%d,%p) failed", - signum, handler); - } - - return rval; -} +sighandler_t safe_signal(const char *file, const int lineno, + int signum, sighandler_t handler); #define SAFE_SIGNAL(signum, handler) \ safe_signal(__FILE__, __LINE__, (signum), (handler)) @@ -431,6 +473,36 @@ int safe_sigaction(const char *file, const int lineno, #define SAFE_SIGACTION(signum, act, oldact) \ safe_sigaction(__FILE__, __LINE__, (signum), (act), (oldact)) +int safe_sigaddset(const char *file, const int lineno, + sigset_t *sigs, int signo); +#define SAFE_SIGADDSET(sigs, signo) \ + safe_sigaddset(__FILE__, __LINE__, (sigs), (signo)) + +int safe_sigdelset(const char *file, const int lineno, + sigset_t *sigs, int signo); +#define SAFE_SIGDELSET(sigs, signo) \ + safe_sigdelset(__FILE__, __LINE__, (sigs), (signo)) + +int safe_sigemptyset(const char *file, const int lineno, + sigset_t *sigs); +#define SAFE_SIGEMPTYSET(sigs) \ + safe_sigemptyset(__FILE__, __LINE__, (sigs)) + +int safe_sigfillset(const char *file, const int lineno, + sigset_t *sigs); +#define SAFE_SIGFILLSET(sigs) \ + safe_sigfillset(__FILE__, __LINE__, (sigs)) + +int safe_sigprocmask(const char *file, const int lineno, + int how, sigset_t *set, sigset_t *oldset); +#define SAFE_SIGPROCMASK(how, set, oldset) \ + safe_sigprocmask(__FILE__, __LINE__, (how), (set), (oldset)) + +int safe_sigwait(const char *file, const int lineno, + sigset_t *set, int *sig); +#define SAFE_SIGWAIT(set, sig) \ + safe_sigwait(__FILE__, __LINE__, (set), (sig)) + #define SAFE_EXECLP(file, arg, ...) do { \ execlp((file), (arg), ##__VA_ARGS__); \ tst_brk_(__FILE__, __LINE__, TBROK | TERRNO, \ @@ -443,6 +515,12 @@ int safe_sigaction(const char *file, const int lineno, "execl(%s, %s, ...) failed", file, arg); \ } while (0) +#define SAFE_EXECVP(file, arg) do { \ + execvp((file), (arg)); \ + tst_brk_(__FILE__, __LINE__, TBROK | TERRNO, \ + "execvp(%s, %p) failed", file, arg); \ + } while (0) + int safe_getpriority(const char *file, const int lineno, int which, id_t who); #define SAFE_GETPRIORITY(which, who) \ safe_getpriority(__FILE__, __LINE__, (which), (who)) @@ -520,11 +598,6 @@ int safe_mincore(const char *file, const int lineno, void *start, #define SAFE_MINCORE(start, length, vec) \ safe_mincore(__FILE__, __LINE__, (start), (length), (vec)) -int safe_fanotify_init(const char *file, const int lineno, - unsigned int flags, unsigned int event_f_flags); -#define SAFE_FANOTIFY_INIT(fan, mode) \ - safe_fanotify_init(__FILE__, __LINE__, (fan), (mode)) - int safe_personality(const char *filename, unsigned int lineno, unsigned long persona); #define SAFE_PERSONALITY(persona) safe_personality(__FILE__, __LINE__, persona) @@ -537,25 +610,15 @@ int safe_personality(const char *filename, unsigned int lineno, } \ } while (0) -void safe_unshare(const char *file, const int lineno, int flags); +int safe_unshare(const char *file, const int lineno, int flags); #define SAFE_UNSHARE(flags) safe_unshare(__FILE__, __LINE__, (flags)) -void safe_setns(const char *file, const int lineno, int fd, int nstype); -#define SAFE_SETNS(fd, nstype) safe_setns(__FILE__, __LINE__, (fd), (nstype)); +int safe_setns(const char *file, const int lineno, int fd, int nstype); +#define SAFE_SETNS(fd, nstype) safe_setns(__FILE__, __LINE__, (fd), (nstype)) -static inline void safe_cmd(const char *file, const int lineno, const char *const argv[], - const char *stdout_path, const char *stderr_path) -{ - int rval; +void safe_cmd(const char *file, const int lineno, const char *const argv[], + const char *stdout_path, const char *stderr_path); - switch ((rval = tst_cmd(argv, stdout_path, stderr_path, - TST_CMD_PASS_RETVAL | TST_CMD_TCONF_ON_MISSING))) { - case 0: - break; - default: - tst_brk(TBROK, "%s:%d: %s failed (%d)", file, lineno, argv[0], rval); - } -} #define SAFE_CMD(argv, stdout_path, stderr_path) \ safe_cmd(__FILE__, __LINE__, (argv), (stdout_path), (stderr_path)) /* @@ -568,4 +631,8 @@ long tst_safe_ptrace(const char *file, const int lineno, int req, pid_t pid, #define SAFE_PTRACE(req, pid, addr, data) \ tst_safe_ptrace(__FILE__, __LINE__, req, pid, addr, data) +int safe_sysinfo(const char *file, const int lineno, struct sysinfo *info); +#define SAFE_SYSINFO(info) \ + safe_sysinfo(__FILE__, __LINE__, (info)) + #endif /* SAFE_MACROS_H__ */ diff --git a/include/tst_safe_net.h b/include/tst_safe_net.h old mode 100644 new mode 100755 index 78a488a18d5df931a237d4016a738d4568c00c30..e85b79a3e7f0533f87d19e57287c37d0e1d93f38 --- a/include/tst_safe_net.h +++ b/include/tst_safe_net.h @@ -42,6 +42,9 @@ #define SAFE_SENDMSG(msg_len, fd, msg, flags) \ safe_sendmsg(__FILE__, __LINE__, msg_len, fd, msg, flags) +#define SAFE_RECV(msg_len, fd, buf, size, flags) \ + safe_recv(__FILE__, __LINE__, (msg_len), (fd), (buf), (size), (flags)) + #define SAFE_RECVMSG(msg_len, fd, msg, flags) \ safe_recvmsg(__FILE__, __LINE__, msg_len, fd, msg, flags) diff --git a/include/tst_safe_posix_ipc.h b/include/tst_safe_posix_ipc.h old mode 100644 new mode 100755 index d74ef4ee895f20020de37032c819e196ecfdc87a..b60c12c9e5c868322f9737dd7470e5f6308a37d6 --- a/include/tst_safe_posix_ipc.h +++ b/include/tst_safe_posix_ipc.h @@ -36,9 +36,11 @@ static inline int safe_mq_open(const char *file, const int lineno, va_end(ap); rval = mq_open(pathname, oflags, mode, attr); + if (rval == -1) { - tst_brk(TBROK | TERRNO, "%s:%d: mq_open(%s,%d,0%o,%p) failed", - file, lineno, pathname, oflags, mode, attr); + tst_brk_(file, lineno, TBROK | TERRNO, + "mq_open(%s,%d,%04o,%p) failed", pathname, oflags, + mode, attr); } return rval; diff --git a/include/tst_safe_prw.h b/include/tst_safe_prw.h old mode 100644 new mode 100755 index 01a684da31c678b650da526dfe04f36ee7b6fb0d..2e506cb41072e2849978edb99eaeec5a6e522399 --- a/include/tst_safe_prw.h +++ b/include/tst_safe_prw.h @@ -15,8 +15,12 @@ static inline ssize_t safe_pread(const char *file, const int lineno, if (rval == -1 || (len_strict && (size_t)rval != nbyte)) { tst_brk_(file, lineno, TBROK | TERRNO, - "pread(%d,%p,%zu,%lld) failed", - fildes, buf, nbyte, (long long)offset); + "pread(%d,%p,%zu,%lld) failed", + fildes, buf, nbyte, (long long)offset); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid pread(%d,%p,%zu,%lld) return value %zd", + fildes, buf, nbyte, (long long)offset, rval); } return rval; @@ -34,8 +38,12 @@ static inline ssize_t safe_pwrite(const char *file, const int lineno, rval = pwrite(fildes, buf, nbyte, offset); if (rval == -1 || (len_strict && (size_t)rval != nbyte)) { tst_brk_(file, lineno, TBROK | TERRNO, - "pwrite(%d,%p,%zu,%lld) failed", - fildes, buf, nbyte, (long long)offset); + "pwrite(%d,%p,%zu,%lld) failed", + fildes, buf, nbyte, (long long)offset); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid pwrite(%d,%p,%zu,%lld) return value %zd", + fildes, buf, nbyte, (long long)offset, rval); } return rval; diff --git a/include/tst_safe_pthread.h b/include/tst_safe_pthread.h old mode 100644 new mode 100755 diff --git a/include/tst_safe_stdio.h b/include/tst_safe_stdio.h old mode 100644 new mode 100755 diff --git a/include/tst_safe_sysv_ipc.h b/include/tst_safe_sysv_ipc.h old mode 100644 new mode 100755 index 3e0e50e8dea4069e95e4a7666f6392d691ac4ca9..7804ce192ad6af9508ba1aba5427a4c1bf5ac41c --- a/include/tst_safe_sysv_ipc.h +++ b/include/tst_safe_sysv_ipc.h @@ -9,6 +9,7 @@ #include #include #include +#include int safe_msgget(const char *file, const int lineno, key_t key, int msgflg); #define SAFE_MSGGET(key, msgflg) \ @@ -51,4 +52,21 @@ int safe_shmctl(const char *file, const int lineno, int shmid, int cmd, (shmid) = ((cmd) == IPC_RMID ? -1 : (shmid)); \ tst_ret_;}) +int safe_semget(const char *file, const int lineno, key_t key, int nsems, + int semflg); +#define SAFE_SEMGET(key, nsems, semflg) \ + safe_semget(__FILE__, __LINE__, (key), (nsems), (semflg)) + +int safe_semctl(const char *file, const int lineno, int semid, int semnum, + int cmd, ...); +#define SAFE_SEMCTL(semid, semnum, cmd, ...) ({ \ + int tst_ret_ = safe_semctl(__FILE__, __LINE__, (semid), (semnum), \ + (cmd), ##__VA_ARGS__); \ + (semid) = ((cmd) == IPC_RMID ? -1 : (semid)); \ + tst_ret_; }) + +int safe_semop(const char *file, const int lineno, int semid, struct sembuf *sops, + size_t nsops); +#define SAFE_SEMOP(semid, sops, nsops) \ + safe_semop(__FILE__, __LINE__, (semid), (sops), (nsops)) #endif /* TST_SAFE_SYSV_IPC_H__ */ diff --git a/include/tst_safe_timerfd.h b/include/tst_safe_timerfd.h old mode 100644 new mode 100755 diff --git a/include/tst_sched.h b/include/tst_sched.h new file mode 100755 index 0000000000000000000000000000000000000000..700afe3f200d8c7ade0775b669c5987a2aa1ff97 --- /dev/null +++ b/include/tst_sched.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021, BELLSOFT. All rights reserved. + */ + +#ifndef TST_SCHED_H_ +#define TST_SCHED_H_ + +#include + +#include "lapi/syscalls.h" + +#define TST_LIBC_SCHED_SCALL_(SCALL, ...)({ \ + int tst_ret = SCALL(__VA_ARGS__); \ + if (tst_ret == -1 && errno == ENOSYS) { \ + tst_brk(TCONF, #SCALL " not supported"); \ + } \ + tst_ret; \ +}) + +static inline int sys_sched_setparam(pid_t pid, const struct sched_param *param) +{ + return tst_syscall(__NR_sched_setparam, pid, param); +} + +static inline int sys_sched_getparam(pid_t pid, struct sched_param *param) +{ + return tst_syscall(__NR_sched_getparam, pid, param); +} + +static inline int sys_sched_setscheduler(pid_t pid, int policy, const struct sched_param *param) +{ + return tst_syscall(__NR_sched_setscheduler, pid, policy, param); +} + +static inline int sys_sched_getscheduler(pid_t pid) +{ + return tst_syscall(__NR_sched_getscheduler, pid); +} + +static inline int libc_sched_setparam(pid_t pid, const struct sched_param *param) +{ + return TST_LIBC_SCHED_SCALL_(sched_setparam, pid, param); +} + +static inline int libc_sched_getparam(pid_t pid, struct sched_param *param) +{ + return TST_LIBC_SCHED_SCALL_(sched_getparam, pid, param); +} + +static inline int libc_sched_setscheduler(pid_t pid, int policy, const struct sched_param *param) +{ + return TST_LIBC_SCHED_SCALL_(sched_setscheduler, pid, policy, param); +} + +static inline int libc_sched_getscheduler(pid_t pid) +{ + return TST_LIBC_SCHED_SCALL_(sched_getscheduler, pid); +} + +struct sched_variant { + char *desc; + + int (*sched_setparam)(pid_t pid, const struct sched_param *param); + int (*sched_getparam)(pid_t pid, struct sched_param *param); + int (*sched_setscheduler)(pid_t pid, int policy, const struct sched_param *param); + int (*sched_getscheduler)(pid_t pid); + +} sched_variants[] = { + { .sched_setparam = libc_sched_setparam, + .sched_getparam = libc_sched_getparam, + .sched_setscheduler = libc_sched_setscheduler, + .sched_getscheduler = libc_sched_getscheduler, + .desc = "libc" + }, + { .sched_setparam = sys_sched_setparam, + .sched_getparam = sys_sched_getparam, + .sched_setscheduler = sys_sched_setscheduler, + .sched_getscheduler = sys_sched_getscheduler, + .desc = "syscall" + }, +}; + +#endif /* TST_SCHED_H_ */ diff --git a/include/tst_sig_proc.h b/include/tst_sig_proc.h old mode 100644 new mode 100755 diff --git a/include/tst_sys_conf.h b/include/tst_sys_conf.h old mode 100644 new mode 100755 diff --git a/include/tst_taint.h b/include/tst_taint.h old mode 100644 new mode 100755 index 0acc1140cde7a807480b71e31f383baa495d48dd..bd8076c1c29e8051fe26e0851f2c0229d497ec2e --- a/include/tst_taint.h +++ b/include/tst_taint.h @@ -7,14 +7,12 @@ * * ... * #include "tst_test.h" - * #include "tst_taint.h" * .. - * void setup(void) - * { + * static struct tst_test test = { * ... - * tst_taint_init(TST_TAINT_W | TST_TAINT_D)); + * .taint_check = TST_TAINT_W | TST_TAINT_D, * ... - * } + * }; * * void run(void) * { @@ -29,10 +27,14 @@ * * * - * The above code checks, if the kernel issued a warning (TST_TAINT_W) + * The above code checks whether the kernel issued a warning (TST_TAINT_W) * or even died (TST_TAINT_D) during test execution. * If these are set after running a test case, we most likely * triggered a kernel bug. + * + * You do not need to use tst_taint_check() explicitly because it'll be called + * automatically at the end of testing by the LTP library if + * tst_test.taint_check in non-zero. */ #ifndef TST_TAINTED_H__ @@ -60,10 +62,14 @@ #define TST_TAINT_E (1 << 13) /* unsigned module was loaded */ #define TST_TAINT_L (1 << 14) /* A soft lock-up has previously occurred */ #define TST_TAINT_K (1 << 15) /* kernel has been live-patched */ -#define TST_TAINT_X (1 << 16) /* auxiliary taint, for distro's use */ +#define TST_TAINT_X (1 << 16) /* auxiliary taint, for distro's use */ +#define TST_TAINT_T (1 << 17) /* kernel was built with the struct randomization plugin */ /* - * Initialize and prepare support for checking tainted kernel. + * Initialize and prepare support for checking tainted kernel. Called + * automatically by LTP library during test setup if tst_test.taint_check + * is non-zero. The value of tst_test.taint_check will be passed as the mask + * argument. * * supply the mask of TAINT-flags you want to check, for example * (TST_TAINT_W | TST_TAINT_D) when you want to check if the kernel issued @@ -71,7 +77,7 @@ * * This function tests if the requested flags are supported on the * locally running kernel. In case the tainted-flags are already set by - * the kernel, there is no reason to continue and TCONF is generated. + * the kernel, there is no reason to continue and TBROK is generated. * * The mask must not be zero. */ diff --git a/include/tst_test.h b/include/tst_test.h old mode 100644 new mode 100755 index 5bedb4f6fe266e002bd6895450fed46c01010447..450ddf0869b504c62fb4d8cc0645d57cfd9ac83f --- a/include/tst_test.h +++ b/include/tst_test.h @@ -18,6 +18,7 @@ #include "tst_common.h" #include "tst_res_flags.h" +#include "tst_test_macros.h" #include "tst_checkpoint.h" #include "tst_device.h" #include "tst_mkfs.h" @@ -28,7 +29,6 @@ #include "tst_process_state.h" #include "tst_atomic.h" #include "tst_kvercmp.h" -#include "tst_clone.h" #include "tst_kernel.h" #include "tst_minmax.h" #include "tst_get_bad_addr.h" @@ -39,6 +39,11 @@ #include "tst_capability.h" #include "tst_hugepage.h" #include "tst_assert.h" +#include "tst_lockdown.h" +#include "tst_fips.h" +#include "tst_taint.h" +#include "tst_memutils.h" +#include "tst_arch.h" /* * Reports testcase result. @@ -76,6 +81,9 @@ void tst_brk_(const char *file, const int lineno, int ttype, tst_brk_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__);\ }) +void tst_printf(const char *const fmt, ...) + __attribute__((nonnull(1), format (printf, 1, 2))); + /* flush stderr and stdout */ void tst_flush(void); @@ -90,6 +98,7 @@ pid_t safe_fork(const char *filename, unsigned int lineno); #include "tst_safe_macros.h" #include "tst_safe_file_ops.h" #include "tst_safe_net.h" +#include "tst_clone.h" /* * Wait for all children and exit with TBROK if @@ -113,6 +122,7 @@ struct tst_option { int tst_parse_int(const char *str, int *val, int min, int max); int tst_parse_long(const char *str, long *val, long min, long max); int tst_parse_float(const char *str, float *val, float min, float max); +int tst_parse_filesize(const char *str, long long *val, long long min, long long max); struct tst_tag { const char *name; @@ -121,6 +131,8 @@ struct tst_tag { extern unsigned int tst_variant; +#define TST_NO_HUGEPAGES ((unsigned long)-1) + struct tst_test { /* number of tests available in test() function */ unsigned int tcnt; @@ -129,6 +141,12 @@ struct tst_test { const char *min_kver; + /* + * The supported_archs is a NULL terminated list of archs the test + * does support. + */ + const char *const *supported_archs; + /* If set the test is compiled out */ const char *tconf_msg; @@ -153,6 +171,18 @@ struct tst_test { * to the test function. */ int all_filesystems:1; + int skip_in_lockdown:1; + int skip_in_compat:1; + + /* + * The skip_filesystem is a NULL terminated list of filesystems the + * test does not support. It can also be used to disable whole class of + * filesystems with a special keyworks such as "fuse". + */ + const char *const *skip_filesystems; + + /* Minimum number of online CPU required by the test */ + unsigned long min_cpus; /* * If set non-zero number of request_hugepages, test will try to reserve the @@ -160,12 +190,21 @@ struct tst_test { * have enough hpage for using, it will try the best to reserve 80% available * number of hpages. With success test stores the reserved hugepage number in * 'tst_hugepages. For the system without hugetlb supporting, variable - * 'tst_hugepages' will be set to 0. + * 'tst_hugepages' will be set to 0. If the hugepage number needs to be set to + * 0 on supported hugetlb system, please use '.request_hugepages = TST_NO_HUGEPAGES'. * * Also, we do cleanup and restore work for the hpages resetting automatically. */ unsigned long request_hugepages; + /* + * If set to non-zero, call tst_taint_init(taint_check) during setup + * and check kernel taint at the end of the test. If all_filesystems + * is non-zero, taint check will be performed after each FS test and + * testing will be terminated by TBROK if taint is detected. + */ + unsigned int taint_check; + /* * If set non-zero denotes number of test variant, the test is executed * variants times each time with tst_variant set to different number. @@ -181,8 +220,6 @@ struct tst_test { /* Device filesystem type override NULL == default */ const char *dev_fs_type; - /* Flags to be passed to tst_get_supported_fs_types() */ - int dev_fs_flags; /* Options passed to SAFE_MKFS() when format_device is set */ const char *const *dev_fs_opts; @@ -251,6 +288,8 @@ struct tst_test { void tst_run_tcases(int argc, char *argv[], struct tst_test *self) __attribute__ ((noreturn)); +#define IPC_ENV_VAR "LTP_IPC_PATH" + /* * Does library initialization for child processes started by exec() * @@ -258,33 +297,6 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) */ void tst_reinit(void); -//TODO Clean? -#define TEST(SCALL) \ - do { \ - errno = 0; \ - TST_RET = SCALL; \ - TST_ERR = errno; \ - } while (0) - -#define TEST_VOID(SCALL) \ - do { \ - errno = 0; \ - SCALL; \ - TST_ERR = errno; \ - } while (0) - -extern long TST_RET; -extern int TST_ERR; - -extern void *TST_RET_PTR; - -#define TESTPTR(SCALL) \ - do { \ - errno = 0; \ - TST_RET_PTR = (void*)SCALL; \ - TST_ERR = errno; \ - } while (0) - /* * Functions to convert ERRNO to its name and SIGNAL to its name. */ diff --git a/include/tst_test_macros.h b/include/tst_test_macros.h new file mode 100755 index 0000000000000000000000000000000000000000..ec8c385233440c2204485c31863e6a92209236c0 --- /dev/null +++ b/include/tst_test_macros.h @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015-2020 Cyril Hrubis + */ + +#ifndef TST_TEST_MACROS_H__ +#define TST_TEST_MACROS_H__ + +#define TEST(SCALL) \ + do { \ + errno = 0; \ + TST_RET = SCALL; \ + TST_ERR = errno; \ + } while (0) + +#define TEST_VOID(SCALL) \ + do { \ + errno = 0; \ + SCALL; \ + TST_ERR = errno; \ + } while (0) + +extern long TST_RET; +extern int TST_ERR; +extern int TST_PASS; + +extern void *TST_RET_PTR; + +#define TESTPTR(SCALL) \ + do { \ + errno = 0; \ + TST_RET_PTR = (void*)SCALL; \ + TST_ERR = errno; \ + } while (0) + + +#define TST_2_(_1, _2, ...) _2 + +#define TST_FMT_(FMT, _1, ...) FMT, ##__VA_ARGS__ + +#define TST_MSG_(RES, FMT, SCALL, ...) \ + tst_res_(__FILE__, __LINE__, RES, \ + TST_FMT_(TST_2_(dummy, ##__VA_ARGS__, SCALL) FMT, __VA_ARGS__)) + +#define TST_MSGP_(RES, FMT, PAR, SCALL, ...) \ + tst_res_(__FILE__, __LINE__, RES, \ + TST_FMT_(TST_2_(dummy, ##__VA_ARGS__, SCALL) FMT, __VA_ARGS__), PAR) + +#define TST_MSGP2_(RES, FMT, PAR, PAR2, SCALL, ...) \ + tst_res_(__FILE__, __LINE__, RES, \ + TST_FMT_(TST_2_(dummy, ##__VA_ARGS__, SCALL) FMT, __VA_ARGS__), PAR, PAR2) + +#define TST_EXP_POSITIVE_(SCALL, SSCALL, ...) \ + do { \ + TEST(SCALL); \ + \ + TST_PASS = 0; \ + \ + if (TST_RET == -1) { \ + TST_MSG_(TFAIL | TTERRNO, " failed", \ + SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + if (TST_RET < 0) { \ + TST_MSGP_(TFAIL | TTERRNO, " invalid retval %ld", \ + TST_RET, SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + TST_PASS = 1; \ + \ + } while (0) + +#define TST_EXP_POSITIVE(SCALL, ...) \ + do { \ + TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__); \ + \ + if (TST_PASS) { \ + TST_MSGP_(TPASS, " returned %ld", \ + TST_RET, #SCALL, ##__VA_ARGS__); \ + } \ + } while (0) + +#define TST_EXP_FD_SILENT(SCALL, ...) TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__) + +#define TST_EXP_FD(SCALL, ...) \ + do { \ + TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__); \ + \ + if (TST_PASS) \ + TST_MSGP_(TPASS, " returned fd %ld", TST_RET, \ + #SCALL, ##__VA_ARGS__); \ + } while (0) + +#define TST_EXP_PID_SILENT(SCALL, ...) TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__) + +#define TST_EXP_PID(SCALL, ...) \ + do { \ + TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__); \ + \ + if (TST_PASS) \ + TST_MSGP_(TPASS, " returned pid %ld", TST_RET, \ + #SCALL, ##__VA_ARGS__); \ + } while (0) + +#define TST_EXP_VAL_SILENT_(SCALL, VAL, SSCALL, ...) \ + do { \ + TEST(SCALL); \ + \ + TST_PASS = 0; \ + \ + if (TST_RET != VAL) { \ + TST_MSGP2_(TFAIL | TTERRNO, " retval %ld != %ld", \ + TST_RET, (long)VAL, SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + TST_PASS = 1; \ + \ + } while (0) + +#define TST_EXP_VAL_SILENT(SCALL, VAL, ...) TST_EXP_VAL_SILENT_(SCALL, VAL, #SCALL, ##__VA_ARGS__) + +#define TST_EXP_VAL(SCALL, VAL, ...) \ + do { \ + TST_EXP_VAL_SILENT_(SCALL, VAL, #SCALL, ##__VA_ARGS__); \ + \ + if (TST_PASS) \ + TST_MSG_(TPASS, " passed", #SCALL, ##__VA_ARGS__); \ + \ + } while(0) + +#define TST_EXP_PASS_SILENT_(SCALL, SSCALL, ...) \ + do { \ + TEST(SCALL); \ + \ + TST_PASS = 0; \ + \ + if (TST_RET == -1) { \ + TST_MSG_(TFAIL | TTERRNO, " failed", \ + SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + if (TST_RET != 0) { \ + TST_MSGP_(TFAIL | TTERRNO, " invalid retval %ld", \ + TST_RET, SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + TST_PASS = 1; \ + \ + } while (0) + +#define TST_EXP_PASS_SILENT(SCALL, ...) TST_EXP_PASS_SILENT_(SCALL, #SCALL, ##__VA_ARGS__) + +#define TST_EXP_PASS(SCALL, ...) \ + do { \ + TST_EXP_PASS_SILENT_(SCALL, #SCALL, ##__VA_ARGS__); \ + \ + if (TST_PASS) \ + TST_MSG_(TPASS, " passed", #SCALL, ##__VA_ARGS__); \ + } while (0) \ + +#define TST_EXP_FAIL_(PASS_COND, SCALL, SSCALL, ERRNO, ...) \ + do { \ + TEST(SCALL); \ + \ + TST_PASS = 0; \ + \ + if (PASS_COND) { \ + TST_MSG_(TFAIL, " succeeded", SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + if (TST_RET != -1) { \ + TST_MSGP_(TFAIL | TTERRNO, " invalid retval %ld", \ + TST_RET, SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + if (TST_ERR == (ERRNO)) { \ + TST_MSG_(TPASS | TTERRNO, " ", \ + SSCALL, ##__VA_ARGS__); \ + TST_PASS = 1; \ + } else { \ + TST_MSGP_(TFAIL | TTERRNO, " expected %s", \ + tst_strerrno(ERRNO), \ + SSCALL, ##__VA_ARGS__); \ + } \ + } while (0) + +#define TST_EXP_FAIL(SCALL, ERRNO, ...) TST_EXP_FAIL_(TST_RET == 0, SCALL, #SCALL, ERRNO, ##__VA_ARGS__) + +#define TST_EXP_FAIL2(SCALL, ERRNO, ...) TST_EXP_FAIL_(TST_RET >= 0, SCALL, #SCALL, ERRNO, ##__VA_ARGS__) + +#define TST_EXP_EXPR(EXPR, FMT, ...) \ + tst_res_(__FILE__, __LINE__, (EXPR) ? TPASS : TFAIL, "Expect: " FMT, ##__VA_ARGS__); + +#endif /* TST_TEST_MACROS_H__ */ diff --git a/include/tst_timer.h b/include/tst_timer.h old mode 100644 new mode 100755 index 256e1d71e1bcf97cbc4644587222fb271da05c10..703f03294eae93d6ec2c2f9f9704a2a26c7b873e --- a/include/tst_timer.h +++ b/include/tst_timer.h @@ -12,9 +12,13 @@ #ifndef TST_TIMER #define TST_TIMER +#include #include +#include #include #include "tst_test.h" +#include "lapi/common_timers.h" +#include "lapi/posix_types.h" #include "lapi/syscalls.h" /* @@ -22,7 +26,7 @@ */ static inline long long tst_timeval_to_us(struct timeval t) { - return t.tv_sec * 1000000 + t.tv_usec; + return ((long long)t.tv_sec) * 1000000 + t.tv_usec; } /* @@ -30,7 +34,7 @@ static inline long long tst_timeval_to_us(struct timeval t) */ static inline long long tst_timeval_to_ms(struct timeval t) { - return t.tv_sec * 1000 + (t.tv_usec + 500) / 1000; + return ((long long)t.tv_sec) * 1000 + (t.tv_usec + 500) / 1000; } /* @@ -93,27 +97,46 @@ static inline long long tst_timeval_diff_ms(struct timeval t1, #ifndef __kernel_timespec -#if defined(__x86_64__) && defined(__ILP32__) -typedef long long __kernel_long_t; -#else -typedef long __kernel_long_t; -#endif - typedef __kernel_long_t __kernel_old_time_t; +#ifndef HAVE_STRUCT___KERNEL_OLD_TIMEVAL +struct __kernel_old_timeval { + __kernel_old_time_t tv_sec; /* seconds */ + __kernel_suseconds_t tv_usec; /* microseconds */ +}; +#endif + +#ifndef HAVE_STRUCT___KERNEL_OLD_TIMESPEC struct __kernel_old_timespec { __kernel_old_time_t tv_sec; /* seconds */ __kernel_old_time_t tv_nsec; /* nanoseconds */ }; +#endif typedef long long __kernel_time64_t; +#ifndef HAVE_STRUCT___KERNEL_TIMESPEC struct __kernel_timespec { __kernel_time64_t tv_sec; /* seconds */ long long tv_nsec; /* nanoseconds */ }; #endif +#ifndef HAVE_STRUCT___KERNEL_OLD_ITIMERSPEC +struct __kernel_old_itimerspec { + struct __kernel_old_timespec it_interval; /* timer period */ + struct __kernel_old_timespec it_value; /* timer expiration */ +}; +#endif + +#ifndef HAVE_STRUCT___KERNEL_ITIMERSPEC +struct __kernel_itimerspec { + struct __kernel_timespec it_interval; /* timer period */ + struct __kernel_timespec it_value; /* timer expiration */ +}; +#endif +#endif + enum tst_ts_type { TST_LIBC_TIMESPEC, TST_KERN_OLD_TIMESPEC, @@ -129,6 +152,14 @@ struct tst_ts { } ts; }; +struct tst_its { + enum tst_ts_type type; + union { + struct __kernel_old_itimerspec kern_old_its; + struct __kernel_itimerspec kern_its; + } ts; +}; + static inline void *tst_ts_get(struct tst_ts *t) { if (!t) @@ -147,6 +178,22 @@ static inline void *tst_ts_get(struct tst_ts *t) } } +static inline void *tst_its_get(struct tst_its *t) +{ + if (!t) + return NULL; + + switch (t->type) { + case TST_KERN_OLD_TIMESPEC: + return &t->ts.kern_old_its; + case TST_KERN_TIMESPEC: + return &t->ts.kern_its; + default: + tst_brk(TBROK, "Invalid type: %d", t->type); + return NULL; + } +} + static inline int libc_clock_getres(clockid_t clk_id, void *ts) { return clock_getres(clk_id, ts); @@ -212,6 +259,117 @@ static inline int sys_clock_nanosleep64(clockid_t clk_id, int flags, request, remain); } +static inline int sys_futex(int *uaddr, int futex_op, int val, void *to, + int *uaddr2, int val3) +{ + return tst_syscall(__NR_futex, uaddr, futex_op, val, to, uaddr2, val3); +} + +static inline int sys_futex_time64(int *uaddr, int futex_op, int val, void *to, + int *uaddr2, int val3) +{ + return tst_syscall(__NR_futex_time64, uaddr, futex_op, val, to, uaddr2, val3); +} + +static inline int libc_mq_timedsend(mqd_t mqdes, const char *msg_ptr, + size_t msg_len, unsigned int msg_prio, void *abs_timeout) +{ + return mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout); +} + +static inline int sys_mq_timedsend(mqd_t mqdes, const char *msg_ptr, + size_t msg_len, unsigned int msg_prio, void *abs_timeout) +{ + return tst_syscall(__NR_mq_timedsend, mqdes, msg_ptr, msg_len, msg_prio, + abs_timeout); +} + +static inline int sys_mq_timedsend64(mqd_t mqdes, const char *msg_ptr, + size_t msg_len, unsigned int msg_prio, void *abs_timeout) +{ + return tst_syscall(__NR_mq_timedsend_time64, mqdes, msg_ptr, msg_len, + msg_prio, abs_timeout); +} + +static inline ssize_t libc_mq_timedreceive(mqd_t mqdes, char *msg_ptr, + size_t msg_len, unsigned int *msg_prio, void *abs_timeout) +{ + return mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout); +} + +static inline ssize_t sys_mq_timedreceive(mqd_t mqdes, char *msg_ptr, + size_t msg_len, unsigned int *msg_prio, void *abs_timeout) +{ + return tst_syscall(__NR_mq_timedreceive, mqdes, msg_ptr, msg_len, + msg_prio, abs_timeout); +} + +static inline ssize_t sys_mq_timedreceive64(mqd_t mqdes, char *msg_ptr, + size_t msg_len, unsigned int *msg_prio, void *abs_timeout) +{ + return tst_syscall(__NR_mq_timedreceive_time64, mqdes, msg_ptr, msg_len, + msg_prio, abs_timeout); +} + +static inline int libc_sched_rr_get_interval(pid_t pid, void *ts) +{ + return sched_rr_get_interval(pid, ts); +} + +static inline int sys_sched_rr_get_interval(pid_t pid, void *ts) +{ + return tst_syscall(__NR_sched_rr_get_interval, pid, ts); +} + +static inline int sys_sched_rr_get_interval64(pid_t pid, void *ts) +{ + return tst_syscall(__NR_sched_rr_get_interval_time64, pid, ts); +} + +static inline int sys_timer_gettime(kernel_timer_t timerid, void *its) +{ + return tst_syscall(__NR_timer_gettime, timerid, its); +} + +static inline int sys_timer_gettime64(kernel_timer_t timerid, void *its) +{ + return tst_syscall(__NR_timer_gettime64, timerid, its); +} + +static inline int sys_timer_settime(kernel_timer_t timerid, int flags, void *its, + void *old_its) +{ + return tst_syscall(__NR_timer_settime, timerid, flags, its, old_its); +} + +static inline int sys_timer_settime64(kernel_timer_t timerid, int flags, void *its, + void *old_its) +{ + return tst_syscall(__NR_timer_settime64, timerid, flags, its, old_its); +} + +static inline int sys_timerfd_gettime(int fd, void *its) +{ + return tst_syscall(__NR_timerfd_gettime, fd, its); +} + +static inline int sys_timerfd_gettime64(int fd, void *its) +{ + return tst_syscall(__NR_timerfd_gettime64, fd, its); +} + +static inline int sys_timerfd_settime(int fd, int flags, void *its, + void *old_its) +{ + return tst_syscall(__NR_timerfd_settime, fd, flags, its, old_its); +} + +static inline int sys_timerfd_settime64(int fd, int flags, void *its, + void *old_its) +{ + return tst_syscall(__NR_timerfd_settime64, fd, flags, its, old_its); +} + /* * Returns tst_ts seconds. */ @@ -248,27 +406,6 @@ static inline long long tst_ts_get_nsec(struct tst_ts ts) } } -/* - * Checks that timespec is valid, i.e. that the timestamp is not zero and that - * the nanoseconds are normalized i.e. in <0, 1s) interval. - * - * 0: On success, i.e. timespec updated correctly. - * -1: Error, timespec not updated. - * -2: Error, tv_nsec is corrupted. - */ -static inline int tst_ts_valid(struct tst_ts *t) -{ - long long nsec = tst_ts_get_nsec(*t); - - if (nsec < 0 || nsec >= 1000000000) - return -2; - - if (tst_ts_get_sec(*t) == 0 && tst_ts_get_nsec(*t) == 0) - return -1; - - return 0; -} - /* * Sets tst_ts seconds. */ @@ -309,6 +446,163 @@ static inline void tst_ts_set_nsec(struct tst_ts *ts, long long nsec) } } +/* + * Returns tst_its it_interval seconds. + */ +static inline long long tst_its_get_interval_sec(struct tst_its its) +{ + switch (its.type) { + case TST_KERN_OLD_TIMESPEC: + return its.ts.kern_old_its.it_interval.tv_sec; + case TST_KERN_TIMESPEC: + return its.ts.kern_its.it_interval.tv_sec; + default: + tst_brk(TBROK, "Invalid type: %d", its.type); + return -1; + } +} + +/* + * Returns tst_its it_interval nanoseconds. + */ +static inline long long tst_its_get_interval_nsec(struct tst_its its) +{ + switch (its.type) { + case TST_KERN_OLD_TIMESPEC: + return its.ts.kern_old_its.it_interval.tv_nsec; + case TST_KERN_TIMESPEC: + return its.ts.kern_its.it_interval.tv_nsec; + default: + tst_brk(TBROK, "Invalid type: %d", its.type); + return -1; + } +} + +/* + * Sets tst_its it_interval seconds. + */ +static inline void tst_its_set_interval_sec(struct tst_its *its, long long sec) +{ + switch (its->type) { + break; + case TST_KERN_OLD_TIMESPEC: + its->ts.kern_old_its.it_interval.tv_sec = sec; + break; + case TST_KERN_TIMESPEC: + its->ts.kern_its.it_interval.tv_sec = sec; + break; + default: + tst_brk(TBROK, "Invalid type: %d", its->type); + } +} + +/* + * Sets tst_its it_interval nanoseconds. + */ +static inline void tst_its_set_interval_nsec(struct tst_its *its, long long nsec) +{ + switch (its->type) { + break; + case TST_KERN_OLD_TIMESPEC: + its->ts.kern_old_its.it_interval.tv_nsec = nsec; + break; + case TST_KERN_TIMESPEC: + its->ts.kern_its.it_interval.tv_nsec = nsec; + break; + default: + tst_brk(TBROK, "Invalid type: %d", its->type); + } +} + +/* + * Returns tst_its it_value seconds. + */ +static inline long long tst_its_get_value_sec(struct tst_its its) +{ + switch (its.type) { + case TST_KERN_OLD_TIMESPEC: + return its.ts.kern_old_its.it_value.tv_sec; + case TST_KERN_TIMESPEC: + return its.ts.kern_its.it_value.tv_sec; + default: + tst_brk(TBROK, "Invalid type: %d", its.type); + return -1; + } +} + +/* + * Returns tst_its it_value nanoseconds. + */ +static inline long long tst_its_get_value_nsec(struct tst_its its) +{ + switch (its.type) { + case TST_KERN_OLD_TIMESPEC: + return its.ts.kern_old_its.it_value.tv_nsec; + case TST_KERN_TIMESPEC: + return its.ts.kern_its.it_value.tv_nsec; + default: + tst_brk(TBROK, "Invalid type: %d", its.type); + return -1; + } +} + +/* + * Sets tst_its it_value seconds. + */ +static inline void tst_its_set_value_sec(struct tst_its *its, long long sec) +{ + switch (its->type) { + break; + case TST_KERN_OLD_TIMESPEC: + its->ts.kern_old_its.it_value.tv_sec = sec; + break; + case TST_KERN_TIMESPEC: + its->ts.kern_its.it_value.tv_sec = sec; + break; + default: + tst_brk(TBROK, "Invalid type: %d", its->type); + } +} + +/* + * Sets tst_its it_value nanoseconds. + */ +static inline void tst_its_set_value_nsec(struct tst_its *its, long long nsec) +{ + switch (its->type) { + break; + case TST_KERN_OLD_TIMESPEC: + its->ts.kern_old_its.it_value.tv_nsec = nsec; + break; + case TST_KERN_TIMESPEC: + its->ts.kern_its.it_value.tv_nsec = nsec; + break; + default: + tst_brk(TBROK, "Invalid type: %d", its->type); + } +} + +/* + * Checks that timespec is valid, i.e. that the timestamp is not zero and that + * the nanoseconds are normalized i.e. in <0, 1s) interval. + * + * 0: On success, i.e. timespec updated correctly. + * -1: Error, timespec not updated. + * -2: Error, tv_nsec is corrupted. + */ +static inline int tst_ts_valid(struct tst_ts *t) +{ + long long nsec = tst_ts_get_nsec(*t); + + if (nsec < 0 || nsec >= 1000000000) + return -2; + + if (tst_ts_get_sec(*t) == 0 && tst_ts_get_nsec(*t) == 0) + return -1; + + return 0; +} + /* * Converts timespec to tst_ts. */ @@ -433,6 +727,46 @@ tst_timespec_from_ms(long long ms) return tst_ts_to_timespec(tst_ts_from_ms(TST_LIBC_TIMESPEC, ms)); } +/* + * Sets tst_its it_value from microseconds. + */ +static inline void tst_its_set_interval_from_us(struct tst_its *its, long long usec) +{ + struct timespec tp = tst_timespec_from_us(usec); + + tst_its_set_interval_sec(its, tp.tv_sec); + tst_its_set_interval_nsec(its, tp.tv_nsec); +} + +/* + * Sets tst_its it_value from microseconds. + */ +static inline void tst_its_set_value_from_us(struct tst_its *its, long long usec) +{ + struct timespec tp = tst_timespec_from_us(usec); + + tst_its_set_value_sec(its, tp.tv_sec); + tst_its_set_value_nsec(its, tp.tv_nsec); +} + +/* + * Sets tst_its it_interval from tst_ts. + */ +static inline void tst_its_set_interval_from_ts(struct tst_its *its, struct tst_ts ts) +{ + tst_its_set_interval_sec(its, tst_ts_get_sec(ts)); + tst_its_set_interval_nsec(its, tst_ts_get_nsec(ts)); +} + +/* + * Sets tst_its it_value from tst_ts. + */ +static inline void tst_its_set_value_from_ts(struct tst_its *its, struct tst_ts ts) +{ + tst_its_set_value_sec(its, tst_ts_get_sec(ts)); + tst_its_set_value_nsec(its, tst_ts_get_nsec(ts)); +} + /* * Returns if t1 less than t2. Both t1 and t2 must be normalized. */ diff --git a/include/tst_timer_test.h b/include/tst_timer_test.h old mode 100644 new mode 100755 diff --git a/testcases/realtime/include/libtsc.h b/include/tst_tsc.h old mode 100644 new mode 100755 similarity index 53% rename from testcases/realtime/include/libtsc.h rename to include/tst_tsc.h index 9ad5fd659911d8f65b1b8a7984faf3e18ea34921..3f49a6ca7e4d8fd06e8766162d9b79877e6a789a --- a/testcases/realtime/include/libtsc.h +++ b/include/tst_tsc.h @@ -1,28 +1,6 @@ -/****************************************************************************** - * - * Copyright © International Business Machines Corp., 2006-2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * NAME - * libtsc.h - * - * DESCRIPTION - * - * USAGE: - * To be included in some testcases. +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright © International Business Machines Corp., 2006-2008 * * AUTHOR * Darren Hart @@ -30,8 +8,10 @@ * * HISTORY * It directly comes from the librttest.h (see its HISTORY). - * - *****************************************************************************/ + */ + +#ifndef TST_TSC_H +#define TST_TSC_H #undef TSC_UNSUPPORTED @@ -70,3 +50,4 @@ #define TSC_UNSUPPORTED #endif +#endif diff --git a/include/tst_uid.h b/include/tst_uid.h new file mode 100755 index 0000000000000000000000000000000000000000..e604effce9b281997e7f5cc7121ab3cd460d700c --- /dev/null +++ b/include/tst_uid.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2021 Linux Test Project + */ + +#ifndef TST_UID_H_ +#define TST_UID_H_ + +#include + +/* + * Find unassigned gid. The skip argument can be used to ignore e.g. the main + * group of a specific user in case it's not listed in the group file. If you + * do not need to skip any specific gid, simply set it to 0. + */ +gid_t tst_get_free_gid_(const char *file, const int lineno, gid_t skip); +#define tst_get_free_gid(skip) tst_get_free_gid_(__FILE__, __LINE__, (skip)) + +/* + * Get a specific number of unique existing non-root user or group IDs. + * The "start" parameter is the number of buffer entries that are already + * filled and will not be modified. The function will fill the remaining + * (size-start) entries with unique UID/GID values. + */ +void tst_get_uids(uid_t *buf, unsigned int start, unsigned int size); +void tst_get_gids(gid_t *buf, unsigned int start, unsigned int size); + +/* + * Helper functions for checking current proces UIDs/GIDs. + */ +int tst_check_resuid_(const char *file, const int lineno, const char *callstr, + uid_t exp_ruid, uid_t exp_euid, uid_t exp_suid); +#define tst_check_resuid(cstr, ruid, euid, suid) \ + tst_check_resuid_(__FILE__, __LINE__, (cstr), (ruid), (euid), (suid)) + +int tst_check_resgid_(const char *file, const int lineno, const char *callstr, + gid_t exp_rgid, gid_t exp_egid, gid_t exp_sgid); +#define tst_check_resgid(cstr, rgid, egid, sgid) \ + tst_check_resgid_(__FILE__, __LINE__, (cstr), (rgid), (egid), (sgid)) + +#endif /* TST_UID_H_ */ diff --git a/include/tst_uinput.h b/include/tst_uinput.h old mode 100644 new mode 100755 diff --git a/include/tst_wallclock.h b/include/tst_wallclock.h old mode 100644 new mode 100755 index 7d6723a7ac116feb9df58b5519d93d559511c21d..1d142c5ca85547bc37068e7e78cd70fdbf3cfca4 --- a/include/tst_wallclock.h +++ b/include/tst_wallclock.h @@ -12,4 +12,8 @@ void tst_wallclock_save(void); void tst_wallclock_restore(void); +void tst_rtc_clock_save(const char *rtc_dev); + +void tst_rtc_clock_restore(const char *rtc_dev); + #endif /* TST_WALLCLK_H__ */ diff --git a/lib/Makefile b/lib/Makefile old mode 100644 new mode 100755 index e7fc753da0b9abccd94546cab17b15f336c28009..9b9906f25d34384ac02fafd3b5951ff9815ffb76 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,24 +1,6 @@ -# -# lib Makefile. -# -# Copyright (C) 2009, Cisco Systems Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2009, Cisco Systems Inc. # Ngie Cooper, July 2009 -# top_srcdir ?= .. @@ -32,7 +14,7 @@ else FILTER_OUT_LIBSRCS += tlibio.c tst_safe_sysv_ipc.c endif -LIB := libltp.a +INTERNAL_LIB := libltp.a pc_file := $(DESTDIR)/$(datarootdir)/pkgconfig/ltp.pc diff --git a/lib/README.md b/lib/README.md new file mode 100755 index 0000000000000000000000000000000000000000..cc7f706d2fad85655c1803acc9c3fe1c82087154 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,152 @@ +# Test library design document + +## High-level picture + + library process + +----------------------------+ + | main | + | tst_run_tcases | + | do_setup | + | for_each_variant | + | for_each_filesystem | test process + | fork_testrun ------------->+--------------------------------------------+ + | waitpid | | testrun | + | | | do_test_setup | + | | | tst_test->setup | + | | | run_tests | + | | | tst_test->test(i) or tst_test->test_all | + | | | do_test_cleanup | + | | | tst_test->cleanup | + | | | exit(0) | + | do_exit | +--------------------------------------------+ + | do_cleanup | + | exit(ret) | + +----------------------------+ + +## Test lifetime overview + +When a test is executed the very first thing to happen is that we check for +various test prerequisites. These are described in the tst\_test structure and +range from simple '.require\_root' to a more complicated kernel .config boolean +expressions such as: "CONFIG\_X86\_INTEL\_UMIP=y | CONFIG\_X86\_UMIP=y". + +If all checks are passed the process carries on with setting up the test +environment as requested in the tst\_test structure. There are many different +setup steps that have been put into the test library again ranging from rather +simple creation of a unique test temporary directory to a bit more complicated +ones such as preparing, formatting, and mounting a block device. + +The test library also intializes shrared memory used for IPC at this step. + +Once all the prerequisites are checked and test environment has been prepared +we can move on executing the testcase itself. The actual test is executed in a +forked process, however there are a few hops before we get there. + +First of all there are test variants, which means that the test is re-executed +several times with a slightly different setting. This is usually used to test a +family of similar syscalls, where we test each of these syscalls exactly the +same, but without re-executing the test binary itself. Test variants are +implemented as a simple global variable counter that gets increased on each +iteration. In a case of syscall tests we switch between which syscall to call +based on the global counter. + +Then there is all\_filesystems flag which is mostly the same as test variants +but executes the test for each filesystem supported by the system. Note that we +can get cartesian product between test variants and all filesystems as well. + +In a pseudo code it could be expressed as: + +``` +for test_variants: + for all_filesystems: + fork_testrun() +``` + +Before we fork() the test process the test library sets up a timeout alarm and +also a heartbeat signal handlers and also sets up an alarm(2) accordingly to +the test timeout. When a test times out the test library gets SIGALRM and the +alarm handler mercilessly kills all forked children by sending SIGKILL to the +whole process group. The heartbeat handler is used by the test process to reset +this timer for example when the test functions run in a loop. + +With that done we finally fork() the test process. The test process firstly +resets signal handlers and sets its pid to be a process group leader so that we +can slaughter all children if needed. The test library proceeds with suspending +itself in waitpid() syscall and waits for the child to finish at this point. + +The test process goes ahead and calls the test setup() function if present in +the tst\_test structure. It's important that we execute all test callbacks +after we have forked the process, that way we cannot crash the test library +process. The setup can also cause the test to exit prematurely by either direct +or indirect (SAFE\_MACROS()) call to tst\_brk(). In this case the +fork\_testrun() function exits, but the loops for test variants or filesystems +carries on. + +All that is left to be done is to actually execute the tests, what happnes now +depends on the -i and -I command line parameters that can request that the +run() or run\_all() callbacks are executed N times or for N seconds. Again the +test can exit at any time by direct or indirect call to tst\_brk(). + +Once the test is finished all that is left for the test process is the test +cleanup(). So if a there is a cleanup() callback in the tst\_test structure +it's executed. The cleanup() callback runs in a special context where the +tst\_brk(TBROK, ...) calls are converted into tst\_res(TWARN, ...) calls. This +is because we found out that carrying on with partially broken cleanup is +usually better option than exiting it in the middle. + +The test cleanup() is also called by the tst\_brk() handler in order to cleanup +before exiting the test process, hence it must be able to cope even with +partial test setup. Usually it suffices to make sure to clean up only +resources that already have been set up and to do that in an inverse order that +we did in setup(). + +Once the test process exits or leaves the run() or run\_all() function the test +library wakes up from the waitpid() call, and checks if the test process +exitted normally. + +Once the testrun is finished the test library does a cleanup() as well to clean +up resources set up in the test library setup(), reports test results and +finally exits the process. + +### Test library and fork()-ing + +Things are a bit more complicated when fork()-ing is involved, however the test +results are stored in a page of a shared memory and incremented by atomic +operations, hence the results are stored right after the test reporting +function returns from the test library and the access is, by definition, +race-free as well. + +On the other hand the test library, apart from sending a SIGKILL to the whole +process group on timeout, does not track grandchildren. + +This especially means that: + +- The test exits once the main test process exits. + +- While the test results are, by the design, propagated to the test library + we may still miss a child that gets killed by a signal or exits unexpectedly. + +The test writer should, because of this, take care for reaping these proceses +properly, in most cases this could be simply done by calling +tst\_reap\_children() to collect and dissect deceased. + +Also note that tst\_brk() does exit only the current process, so if a child +process calls tst\_brk() the counters are incremented and only the process +exits. + +### Test library and exec() + +The piece of mapped memory to store the results to is not preserved over +exec(2), hence to use the test library from a binary started by an exec() it +has to be remaped. In this case the process must to call tst\_reinit() before +calling any other library functions. In order to make this happen the program +environment carries LTP\_IPC\_PATH variable with a path to the backing file on +tmpfs. This also allows us to use the test library from shell testcases. + +### Test library and process synchronization + +The piece of mapped memory is also used as a base for a futex-based +synchronization primitives called checkpoints. And as said previously the +memory can be mapped to any process by calling the tst\_reinit() function. As a +matter of a fact there is even a tst\_checkpoint binary that allows us to use +the checkpoints from shell code as well. diff --git a/lib/android_libpthread/Makefile b/lib/android_libpthread/Makefile old mode 100644 new mode 100755 index 2946d093fd1d2f11f68db1ddaac86b1a5bc97622..441cadcb95fa4aebfc4e16ac98b69bf3c4e14456 --- a/lib/android_libpthread/Makefile +++ b/lib/android_libpthread/Makefile @@ -2,6 +2,6 @@ top_srcdir ?= ../.. include $(top_srcdir)/include/mk/env_pre.mk -LIB := libpthread.a +INTERNAL_LIB := libpthread.a include $(top_srcdir)/include/mk/lib.mk diff --git a/lib/android_libpthread/stub.c b/lib/android_libpthread/stub.c old mode 100644 new mode 100755 diff --git a/lib/android_librt/Makefile b/lib/android_librt/Makefile old mode 100644 new mode 100755 index ecb1fbe6cc6e8c3177f28d3b12e733085f451f97..70d520c0ae261e207c0f1eec0d2f0f68b2307ca6 --- a/lib/android_librt/Makefile +++ b/lib/android_librt/Makefile @@ -2,6 +2,6 @@ top_srcdir ?= ../.. include $(top_srcdir)/include/mk/env_pre.mk -LIB := librt.a +INTERNAL_LIB := librt.a include $(top_srcdir)/include/mk/lib.mk diff --git a/lib/android_librt/stub.c b/lib/android_librt/stub.c old mode 100644 new mode 100755 diff --git a/lib/cloner.c b/lib/cloner.c old mode 100644 new mode 100755 diff --git a/lib/errnos.h b/lib/errnos.h old mode 100644 new mode 100755 diff --git a/lib/get_path.c b/lib/get_path.c old mode 100644 new mode 100755 diff --git a/lib/ltp.pc.in b/lib/ltp.pc.in old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/.gitignore b/lib/newlib_tests/.gitignore old mode 100644 new mode 100755 index fee8795b6bc0882ecf0d6e5ac83605b9f6e493ad..f4414f6a1c3b057c09fbb3e5ef27968ce963417a --- a/lib/newlib_tests/.gitignore +++ b/lib/newlib_tests/.gitignore @@ -13,22 +13,46 @@ test12 test13 test14 test15 -test16 tst_capability01 tst_capability02 +tst_cgroup01 +tst_cgroup02 tst_device tst_safe_fileops tst_res_hexd tst_strstatus -test17 +tst_print_result test18 test19 test20 +test22 tst_expiration_timer test_assert test_timer test_exec test_exec_child test_kconfig +test_kconfig01 +test_kconfig02 variant test_guarded_buf +tst_bool_expr +test_macros01 +test_macros02 +test_macros03 +test_macros04 +test_macros05 +test_macros06 +tst_fuzzy_sync01 +tst_fuzzy_sync02 +tst_fuzzy_sync03 +test_zero_hugepage +test_parse_filesize +tst_needs_cmds01 +tst_needs_cmds02 +tst_needs_cmds03 +tst_needs_cmds04 +tst_needs_cmds05 +tst_needs_cmds06 +tst_needs_cmds07 +tst_needs_cmds08 diff --git a/lib/newlib_tests/Makefile b/lib/newlib_tests/Makefile old mode 100644 new mode 100755 index 2fc50160a995c2d0aba87d23d1286f7b4a557718..1fbf7649a080d7725231e93de4ae46702601fa1e --- a/lib/newlib_tests/Makefile +++ b/lib/newlib_tests/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later top_srcdir ?= ../.. include $(top_srcdir)/include/mk/env_pre.mk @@ -5,12 +6,8 @@ include $(top_srcdir)/include/mk/env_pre.mk CFLAGS += -W -Wall LDLIBS += -lltp -test08: CFLAGS+=-pthread -test09: CFLAGS+=-pthread -test15: CFLAGS+=-pthread -test16: CFLAGS+=-pthread -test16: LDLIBS+=-lrt -tst_expiration_timer: LDLIBS+=-lrt +test08 test09 test15 tst_fuzzy_sync01 tst_fuzzy_sync02 tst_fuzzy_sync03: CFLAGS += -pthread +tst_expiration_timer tst_fuzzy_sync03: LDLIBS += -lrt ifeq ($(ANDROID),1) FILTER_OUT_MAKE_TARGETS += test08 diff --git a/lib/newlib_tests/config01 b/lib/newlib_tests/config01 old mode 100644 new mode 100755 index 96d68d8368b71a74fafc519c44b6171b54a1944f..1d94d810a6cd51e3066ae87ab827c8460250c068 --- a/lib/newlib_tests/config01 +++ b/lib/newlib_tests/config01 @@ -2,3 +2,4 @@ CONFIG_MMU=y CONFIG_EXT4_FS=m CONFIG_PGTABLE_LEVELS=4 +CONFIG_DEFAULT_HOSTNAME="(none)" diff --git a/lib/newlib_tests/config02 b/lib/newlib_tests/config02 old mode 100644 new mode 100755 index 2de45cff8d7dd85ca8352f06fafa88fae1e61fcd..e1b0e8086b6f35b6107969fa666a4550a9e41882 --- a/lib/newlib_tests/config02 +++ b/lib/newlib_tests/config02 @@ -2,3 +2,4 @@ # CONFIG_MMU is not set CONFIG_EXT4_FS=m CONFIG_PGTABLE_LEVELS=4 +CONFIG_DEFAULT_HOSTNAME="(none)" diff --git a/lib/newlib_tests/config03 b/lib/newlib_tests/config03 old mode 100644 new mode 100755 index 1a3b9e64856600c43ccccf7578ca5fb903160495..05c8e194a1918eaed531932ea39dfb6b87d44fe5 --- a/lib/newlib_tests/config03 +++ b/lib/newlib_tests/config03 @@ -2,3 +2,4 @@ CONFIG_MMU=y CONFIG_EXT4_FS=m CONFIG_PGTABLE_LEVELS=44 +CONFIG_DEFAULT_HOSTNAME="(none)" diff --git a/lib/newlib_tests/config04 b/lib/newlib_tests/config04 old mode 100644 new mode 100755 index cce7051ae84fe5fc69c00664ea3d62f0680136f4..da01579b638fe665c53621628a7d8803770812ba --- a/lib/newlib_tests/config04 +++ b/lib/newlib_tests/config04 @@ -2,3 +2,4 @@ CONFIG_MMU=y CONFIG_EXT4_FS=y CONFIG_PGTABLE_LEVELS=4 +CONFIG_DEFAULT_HOSTNAME="(none)" diff --git a/lib/newlib_tests/config05 b/lib/newlib_tests/config05 old mode 100644 new mode 100755 index a9d7bab4dc08b385d6f481fc2e9320aba673b124..490f94fa612f1a8ed7bbc7c05811d17d2fdbb966 --- a/lib/newlib_tests/config05 +++ b/lib/newlib_tests/config05 @@ -1,3 +1,4 @@ # Everything is wrong CONFIG_EXT4_FS=y CONFIG_PGTABLE_LEVELS=44 +CONFIG_DEFAULT_HOSTNAME="" diff --git a/lib/newlib_tests/config06 b/lib/newlib_tests/config06 new file mode 100755 index 0000000000000000000000000000000000000000..b7db25411d06ab75b08bbd4a12922545f89ad22a --- /dev/null +++ b/lib/newlib_tests/config06 @@ -0,0 +1 @@ +# Empty diff --git a/lib/newlib_tests/config07 b/lib/newlib_tests/config07 new file mode 100755 index 0000000000000000000000000000000000000000..3310d575ea9e936b8f2de1cba11c63fde97ec446 --- /dev/null +++ b/lib/newlib_tests/config07 @@ -0,0 +1,5 @@ +# The default hostname value mismatch +CONFIG_MMU=y +CONFIG_EXT4_FS=m +CONFIG_PGTABLE_LEVELS=4 +CONFIG_DEFAULT_HOSTNAME=m diff --git a/lib/newlib_tests/runtest.sh b/lib/newlib_tests/runtest.sh new file mode 100755 index 0000000000000000000000000000000000000000..92fd3860e519ac092af0f7c06e5f7ca460ab4737 --- /dev/null +++ b/lib/newlib_tests/runtest.sh @@ -0,0 +1,194 @@ +#!/bin/sh +# Copyright (c) 2021 Petr Vorel + +LTP_C_API_TESTS="${LTP_C_API_TESTS:-test05 test07 test09 test12 test15 test18 +tst_needs_cmds01 tst_needs_cmds02 tst_needs_cmds03 tst_needs_cmds06 +tst_needs_cmds07 tst_bool_expr test_exec test_timer tst_res_hexd tst_strstatus +tst_fuzzy_sync03 test_zero_hugepage.sh test_kconfig.sh}" + +LTP_SHELL_API_TESTS="${LTP_SHELL_API_TESTS:-shell/tst_check_driver.sh +shell/tst_check_kconfig0[1-5].sh shell/net/*.sh}" + +cd $(dirname $0) +PATH="$PWD/../../testcases/lib/:$PATH" + +. tst_ansi_color.sh + +usage() +{ + cat << EOF +Usage: $0 [-b DIR ] [-c|-s] +-b DIR build directory (required for out-of-tree build) +-c run C API tests only +-s run shell API tests only +-h print this help +EOF +} + +tst_flag2mask() +{ + case "$1" in + TPASS) return 0;; + TFAIL) return 1;; + TBROK) return 2;; + TWARN) return 4;; + TINFO) return 16;; + TCONF) return 32;; + esac +} + +runtest_res() +{ + if [ $# -eq 0 ]; then + echo >&2 + return + fi + + local res="$1" + shift + + tst_color_enabled + local color=$? + + printf "runtest " >&2 + tst_print_colored $res "$res: " >&2 + echo "$@" >&2 + +} + +runtest_brk() +{ + local res="$1" + shift + + tst_flag2mask "$res" + local mask=$? + + runtest_res + runtest_res $res $@ + + exit $mask +} + +run_tests() +{ + local target="$1" + local srcdir="$2" + local dir i res ret=0 tbrok tconf tfail tpass twarn vars + + eval vars="\$LTP_${target}_API_TESTS" + + runtest_res TINFO "=== Run $target tests ===" + + for i in $vars; do + runtest_res TINFO "* $i" + if [ -f "$i" ]; then + dir="." + elif [ "$srcdir" -a -f "$srcdir/$i" ]; then + dir="$srcdir" + else + runtest_brk TBROK "Error: $i file not found (PWD: $PWD)" + fi + + $dir/$i 1>&2 + res=$? + + [ $res -ne 0 -a $res -ne 32 ] && ret=1 + + case $res in + 0) tpass="$tpass $i";; + 1) tfail="$tfail $i";; + 2) tbrok="$tbrok $i";; + 4) twarn="$twarn $i";; + 32) tconf="$tconf $i";; + 127) runtest_brk TBROK "Error: file not found (wrong PATH? out-of-tree build without -b?), exit code: $res";; + *) runtest_brk TBROK "Error: unknown failure, exit code: $res";; + esac + runtest_res + done + + runtest_res TINFO "=== $target TEST RESULTS ===" + runtest_res TINFO "$(echo $tpass | wc -w)x TPASS:$tpass" + runtest_res TINFO "$(echo $tfail | wc -w)x TFAIL:$tfail" + runtest_res TINFO "$(echo $tbrok | wc -w)x TBROK:$tbrok" + runtest_res TINFO "$(echo $twarn | wc -w)x TWARN:$twarn" + runtest_res TINFO "$(echo $tconf | wc -w)x TCONF:$tconf" + runtest_res + + return $ret +} + +run_c_tests() +{ + local ret srcdir="$PWD" + + if [ "$builddir" ]; then + cd $builddir/lib/newlib_tests + fi + + run_tests "C" "$srcdir" + ret=$? + + if [ "$builddir" ]; then + cd "$srcdir" + fi + + return $ret +} + +run_shell_tests() +{ + run_tests "SHELL" +} + + +print_result() +{ + local target="$1" + local res="$2" + + + if [ -z "$res" ]; then + runtest_res TCONF "$target tests skipped" + elif [ $res -eq 0 ]; then + runtest_res TPASS "All $target tests TCONF/TPASS" + else + runtest_res TFAIL "Some $target test(s) TBROK/TFAIL/TWARN" + fi +} + +builddir= +c_fail= +run= +shell_fail= + +while getopts b:chs opt; do + case $opt in + 'h') usage; exit 0;; + 'b') builddir=$OPTARG; PATH="$builddir/testcases/lib:$PATH";; + 'c') run="c";; + 's') run="s";; + *) usage; runtest_brk TBROK "Error: invalid option";; + esac +done + +runtest_res TINFO "PATH='$PATH'" + +if [ -z "$run" -o "$run" = "c" ]; then + run_c_tests + c_fail=$? +fi + +if [ -z "$run" -o "$run" = "s" ]; then + export KCONFIG_PATH=config02 + runtest_res TINFO "KCONFIG_PATH='$KCONFIG_PATH'" + run_shell_tests + shell_fail=$? +fi + +runtest_res TINFO "=== FINAL TEST RESULTS ===" + +print_result "C" "$c_fail" +print_result "shell" "$shell_fail" + +exit $((c_fail|shell_fail)) diff --git a/lib/newlib_tests/shell/net/tst_ipaddr_un.sh b/lib/newlib_tests/shell/net/tst_ipaddr_un.sh index 512d6d8804994d61ea8ea6fd529a38bc61167057..e7730b8d016190cce516315ff56f1a20355de44a 100755 --- a/lib/newlib_tests/shell/net/tst_ipaddr_un.sh +++ b/lib/newlib_tests/shell/net/tst_ipaddr_un.sh @@ -7,8 +7,11 @@ TST_CNT=2 PATH="$(dirname $0)/../../../../testcases/lib/:$PATH" -# workaround to disable netns initialization -RHOST="foo" +TST_NET_SKIP_VARIABLE_INIT=1 + +# from tst_net_vars.c +IPV4_NET16_UNUSED="10.23" +IPV6_NET32_UNUSED="fd00:23" . tst_net.sh diff --git a/lib/newlib_tests/shell/net/tst_rhost_run.sh b/lib/newlib_tests/shell/net/tst_rhost_run.sh new file mode 100755 index 0000000000000000000000000000000000000000..119247f8e0e3b93544568bc19b53ac12c7ed4162 --- /dev/null +++ b/lib/newlib_tests/shell/net/tst_rhost_run.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2020 Petr Vorel + +TST_TESTFUNC=do_test +PATH="$(dirname $0)/../../../../testcases/lib/:$PATH" +. tst_net.sh + +export TST_NET_RHOST_RUN_DEBUG=1 + +do_test() +{ + local file="/etc/fstab" + + tst_rhost_run -c 'which grep' > /dev/null || \ + tst_brk TCONF "grep not found on rhost" + + tst_rhost_run -c "[ -f $file ]" || \ + tst_brk TCONF "$file not found on rhost" + + tst_rhost_run -s -c "grep -q \"[^ ]\" $file" + tst_rhost_run -s -c "grep -q '[^ ]' $file" + + tst_res TPASS "tst_rhost_run is working" +} + +tst_run diff --git a/lib/newlib_tests/shell/test_timeout.sh b/lib/newlib_tests/shell/test_timeout.sh index 26477d6f2a9f02790665ad9e0c8fb04ff4f19880..c70e22f27aa7e23f83fa0bd3bac2912d96ba88b4 100755 --- a/lib/newlib_tests/shell/test_timeout.sh +++ b/lib/newlib_tests/shell/test_timeout.sh @@ -1,42 +1,178 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2019 Petr Vorel +# Copyright (c) 2021 Joerg Vehlow PATH="$(dirname $0):$(dirname $0)/../../../testcases/lib/:$PATH" +# Test cases are separated by newlines. +# Every test has the following fields in this order: +# file +# timeout_mul +# use_cat +# max_runtime +# expected_exit_code +# expected passes +# expected failed +# expected broken +# description +# Whole lines can be commented out using "#" DATA=" -timeout01.sh||0 -timeout02.sh||0 -timeout02.sh|foo|2 -timeout02.sh|2|0 -timeout01.sh|2|0 -timeout02.sh|1.1|0 -timeout02.sh|-10|2 -timeout02.sh|-0.1|0 -timeout02.sh|-1.1|2 -timeout02.sh|-10.1|2 +timeout01.sh| |0| |0 +timeout02.sh| |0| |0 +timeout02.sh| foo|0| |2 +timeout02.sh| 2|0| |0 +timeout01.sh| 2|0| |0 +timeout02.sh| 1.1|0| |0 +timeout02.sh| -10|0| |2 +timeout02.sh| -0.1|0| |0 +timeout02.sh| -1.1|0| |2 +timeout02.sh|-10.1|0| |2 +timeout03.sh| |0|12|137| | | |Test is killed, if it does not terminate after SIGTERM +timeout04.sh| |0| | 2|0|0|1|Verify that timeout is enforced +timeout02.sh| 2|1| 2| |1|0|0|Test termination of timeout process " +# Executes a test +# Parameter: +# - test: The test to execute +# - timeout: The timeout multiplicator (optional) +# - use_cat: Pipe the output of the command through cat (optional) +# If this is used, the exit code is NOT returned! +# +# The function returns the following global variables: +# - test_exit: The exit code of the test +# - test_duration: The duration of the test in seconds +# - test_output: The full output of the test +# - test_passed: The number of passed tests parsed from the summary +# - test_failed: The number of failed tests parsed from the summary +# - test_broken: The number of broken tests parsed from the summary +run_test() +{ + local test=$1 + local timeout=$2 + local use_cat=$3 + local tmpfile start end; + + tmpfile=$(mktemp -t ltp_timeout_XXXXXXXX) + start=$(date +%s) + # We have to use set monitor mode (set -m) here. + # In most shells in most cases this creates a + # new process group for the next command. + # A process group is required for the timeout functionality, + # because it sends signals to the whole process group. + set -m + # The use_cat is for testing if any programm using stdout + # is still running, after the test finished. + # cat will wait for its stdin to be closed. + # + # In the pure shell implementation of the timeout handling, + # the sleep process was never killed, when a test finished + # before the timeout. + if [ "$use_cat" = "1" ]; then + LTP_TIMEOUT_MUL=$timeout $test 2>&1 | cat >$tmpfile + else + LTP_TIMEOUT_MUL=$timeout $test 1>$tmpfile 2>&1 + fi + test_exit=$? + set +m + end=$(date +%s) + + test_duration=$((end - start)) + test_output=$(cat $tmpfile) + rm $tmpfile + + eval $(echo "$test_output" | awk ' + BEGIN {sum=0} + $1 == "Summary:" { + sum=1; + } + sum && ( \ + $1 == "passed" \ + || $1 == "failed" \ + || $1 == "broken") { + print "test_" $1 "=" $2 + } + ') +} + echo "Testing timeout in shell API" echo failed=0 -for i in $DATA; do - file=$(echo $i | cut -d'|' -f1) - timeout=$(echo $i | cut -d'|' -f2) - exp_exit=$(echo $i | cut -d'|' -f3) - - echo "=== $file (LTP_TIMEOUT_MUL='$timeout') ===" - LTP_TIMEOUT_MUL=$timeout $file - ret=$? - if [ $ret -ne $exp_exit ]; then - echo "FAILED (exit code: $ret, expected $exp_exit)" - failed=$((failed+1)) +test_nr=0 + +old_ifs="$IFS" +IFS=$(printf "\n\b") + +# Remove comments and empty lines +CLEANED_DATA=$(echo "$DATA" | sed '/^\s*#/d;/^\s*$/d') +test_max=$(echo "$CLEANED_DATA" | wc -l) +for d in $CLEANED_DATA; do + IFS="$old_ifs" + + file=$(echo $d | cut -d'|' -f1 | xargs) + timeout=$(echo $d | cut -d'|' -f2 | xargs) + use_cat=$(echo $d | cut -d'|' -f3 | xargs) + max_runtime=$(echo $d | cut -d'|' -f4 | xargs) + max_runtime=${max_runtime:--1} + exp_exit=$(echo $d | cut -d'|' -f5 | xargs) + exp_exit=${exp_exit:--1} + exp_passed=$(echo $d | cut -d'|' -f6 | xargs) + exp_passed=${exp_passed:--1} + exp_failed=$(echo $d | cut -d'|' -f7 | xargs) + exp_failed=${exp_failed:--1} + exp_broken=$(echo $d | cut -d'|' -f8 | xargs) + exp_broken=${exp_broken:--1} + description=$(echo $d | cut -d'|' -f9) + + test_nr=$(($test_nr + 1)) + + cur_fails=0 + + if [ -z "$description" ]; then + description="$file (LTP_TIMEOUT_MUL='$timeout')" + fi + + echo "=== $test_nr/$test_max $description ===" + run_test "$file" "$timeout" "$use_cat" + + if [ $max_runtime -ne -1 ] && [ $test_duration -gt $max_runtime ]; then + echo "FAILED (runtime: $test_duration, expected less than $max_runtime)" + cur_fails=$((cur_fails + 1)) + fi + + if [ $exp_passed -ne -1 ] && [ $exp_passed -ne $test_passed ]; then + echo "FAILED (passes: $test_passed, expected $exp_passed)" + cur_fails=$((cur_fails + 1)) + fi + + if [ $exp_failed -ne -1 ] && [ $exp_failed -ne $test_failed ]; then + echo "FAILED (failed: $test_failed, expected $exp_failed)" + cur_fails=$((cur_fails + 1)) + fi + + if [ $exp_broken -ne -1 ] && [ $exp_broken -ne $test_broken ]; then + echo "FAILED (broken: $test_broken, expected $exp_broken)" + cur_fails=$((cur_fails + 1)) + fi + + if [ $exp_exit -ne -1 ] && [ $test_exit -ne $exp_exit ]; then + echo "FAILED (exit code: $test_exit, expected $exp_exit)" + cur_fails=$((cur_fails + 1)) + fi + + if [ $cur_fails -gt 0 ]; then + failed=$((failed + 1)) + echo "--------" + echo "$test_output" + echo "--------" else echo "PASSED" fi echo done +IFS="$old_ifs" echo "Failed tests: $failed" exit $failed diff --git a/lib/newlib_tests/shell/timeout03.sh b/lib/newlib_tests/shell/timeout03.sh new file mode 100755 index 0000000000000000000000000000000000000000..eec2d40bc276083253cfb26cc84847e5c924a11d --- /dev/null +++ b/lib/newlib_tests/shell/timeout03.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2021 Petr Vorel + +# testing shell timeout handling in tst_timeout_kill +# expected output: +# timeout03 1 TINFO: timeout per run is 0h 0m 1s +# timeout03 1 TINFO: testing killing test after TST_TIMEOUT +# Test timed out, sending SIGTERM! +# If you are running on slow machine, try exporting LTP_TIMEOUT_MUL > 1 +# Terminated +# timeout03 1 TBROK: test terminated +# timeout03 1 TPASS: test run cleanup after timeout +# Test is still running... 10 +# Test is still running... 9 +# Test is still running... 8 +# Test is still running... 7 +# Test is still running... 6 +# Test is still running... 5 +# Test is still running... 4 +# Test is still running... 3 +# Test is still running... 2 +# Test is still running... 1 +# Test is still running, sending SIGKILL +# Killed + +TST_TESTFUNC=do_test +TST_CLEANUP=cleanup + +TST_TIMEOUT=1 +. tst_test.sh + +do_test() +{ + tst_res TINFO "testing killing test after TST_TIMEOUT" + + sleep 2 + tst_res TFAIL "test: running after TST_TIMEOUT" +} + +cleanup() +{ + tst_res TPASS "test run cleanup after timeout" + + sleep 15 # must be higher than wait time in _tst_kill_test + tst_res TFAIL "cleanup: running after TST_TIMEOUT" +} + +tst_run diff --git a/lib/newlib_tests/shell/timeout04.sh b/lib/newlib_tests/shell/timeout04.sh new file mode 100755 index 0000000000000000000000000000000000000000..c702905f390d23ad2af8658d08b03f480a05d4c2 --- /dev/null +++ b/lib/newlib_tests/shell/timeout04.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2021 Joerg Vehlow + +TST_TESTFUNC=do_test + +TST_TIMEOUT=1 +. tst_test.sh + +do_test() +{ + tst_res TINFO "Start" + sleep 5 + tst_res TFAIL "End" +} + +do_cleanup() +{ + tst_res TINFO "cleanup" +} + +tst_run diff --git a/lib/newlib_tests/shell/tst_check_driver.sh b/lib/newlib_tests/shell/tst_check_driver.sh new file mode 100755 index 0000000000000000000000000000000000000000..d188b6f7750ead5166fdbd1cedce7906d24c6f12 --- /dev/null +++ b/lib/newlib_tests/shell/tst_check_driver.sh @@ -0,0 +1,63 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2021 Petr Vorel + +TST_TESTFUNC=test +TST_SETUP=setup +TST_CNT=3 +TST_NEEDS_CMDS="tst_check_drivers find grep head sed" +. tst_test.sh + +MODULES_DIR="${MODULES_DIR:-/lib/modules/$(uname -r)}" + +setup() +{ + tst_res TINFO "using modules directory '$MODULES_DIR'" + + [ -d "$MODULES_DIR" ] || \ + tst_brk TCONF "modules directory '$MODULES_DIR' missing" +} + +test_drivers() +{ + local paths="$*" + local drv + + if [ -z "$paths" ]; then + tst_res TCONF "no modules found" + return + fi + + for drv in $paths; do + drv="$(echo $drv | sed 's/.*\/\([^/]\+\)\.ko.*/\1/')" + EXPECT_PASS tst_check_drivers $drv + drv="$(echo $drv | sed 's/_/-/g')" + EXPECT_PASS tst_check_drivers $drv + done +} + +test1() +{ + tst_res TINFO "check loadable module detection" + test_drivers $(find $MODULES_DIR | grep -E '_[^/]+\.ko' | head -3) +} + +test2() +{ + tst_res TINFO "check non-existing module detection" + EXPECT_FAIL tst_check_drivers not-existing-kernel-module +} + +test3() +{ + local f="$MODULES_DIR/modules.builtin" + + tst_res TINFO "check built-in module detection" + + [ -f "$f" ] || \ + tst_brk TCONF "missing '$f'" + + test_drivers $(grep -E '_[^/]+\.ko' $f | head -3) +} + +tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig01.sh b/lib/newlib_tests/shell/tst_check_kconfig01.sh new file mode 100755 index 0000000000000000000000000000000000000000..03f86266d10d7f42b06a01cf3ea2f4ba2b06a9eb --- /dev/null +++ b/lib/newlib_tests/shell/tst_check_kconfig01.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + +TST_TESTFUNC=do_test +TST_NEEDS_KCONFIGS="CONFIG_EXT4" + +. tst_test.sh + +do_test() +{ + tst_res TFAIL "kernel .config doesn't have CONFIG_EXT4" +} + +tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig02.sh b/lib/newlib_tests/shell/tst_check_kconfig02.sh new file mode 100755 index 0000000000000000000000000000000000000000..6a20cfc3d023fa921491a92ce069b8bda7ad222d --- /dev/null +++ b/lib/newlib_tests/shell/tst_check_kconfig02.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + +TST_TESTFUNC=do_test +TST_NEEDS_KCONFIGS="CONFIG_EXT4_FS : CONFIG_XFS_FS" +. tst_test.sh + +do_test() +{ + tst_res TFAIL "invalid kconfig delimter" +} + +tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig03.sh b/lib/newlib_tests/shell/tst_check_kconfig03.sh new file mode 100755 index 0000000000000000000000000000000000000000..361b6bf0b10493cd313bcd3f129fd337fb114765 --- /dev/null +++ b/lib/newlib_tests/shell/tst_check_kconfig03.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + +TST_TESTFUNC=do_test +TST_NEEDS_KCONFIGS="CONFIG_EXT4_FS : CONFIG_XFS_FS" +TST_NEEDS_KCONFIGS_IFS=":" +. tst_test.sh + +do_test() +{ + tst_res TPASS "valid kconfig delimter" +} + +tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig04.sh b/lib/newlib_tests/shell/tst_check_kconfig04.sh new file mode 100755 index 0000000000000000000000000000000000000000..21cd998dd737dcc3f1b353e7d114363e289c010c --- /dev/null +++ b/lib/newlib_tests/shell/tst_check_kconfig04.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + +TST_TESTFUNC=do_test +. tst_test.sh + +do_test() +{ + tst_check_kconfigs "CONFIG_EXT4_FS" + if [ $? -eq 0 ]; then + tst_res TPASS "kernel .config has CONFIG_EXT4_FS" + else + tst_res TFAIL "kernel .config doesn't have CONFIG_EXT4_FS" + fi + + tst_check_kconfigs "CONFIG_EXT4" + if [ $? -eq 0 ]; then + tst_res TFAIL "kernel .config has CONFIG_EXT4" + else + tst_res TPASS "kernel .config doesn't have CONFIG_EXT4" + fi +} +tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig05.sh b/lib/newlib_tests/shell/tst_check_kconfig05.sh new file mode 100755 index 0000000000000000000000000000000000000000..f118f27a5a4712f59ca262ee0b6fbd194452b591 --- /dev/null +++ b/lib/newlib_tests/shell/tst_check_kconfig05.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + +TST_TESTFUNC=do_test +. tst_test.sh + +do_test() +{ + tst_require_kconfigs "CONFIG_EXT4_FS" + tst_res TPASS "kernel .config has CONFIG_EXT4_FS" + + tst_require_kconfigs "CONFIG_EXT4" + tst_res TFAIL "kernel .config has CONFIG_EXT4" +} +tst_run diff --git a/lib/newlib_tests/test01.c b/lib/newlib_tests/test01.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test02.c b/lib/newlib_tests/test02.c old mode 100644 new mode 100755 index f1b6a7ca46268f380d56190928c09c67c6b447c5..ec2a1d13dc385ef12eba4a995732796b694259b6 --- a/lib/newlib_tests/test02.c +++ b/lib/newlib_tests/test02.c @@ -10,7 +10,7 @@ #include "tst_test.h" void tst_resm_(char *, int, int, char *); -void tst_brkm_(char *, int, int, void (*)(void), char *); +void tst_brkm__(char *, int, int, void (*)(void), char *); static void cleanup(void) { @@ -24,7 +24,7 @@ static void do_test(unsigned int i) tst_resm_(__FILE__, __LINE__, TPASS, "passed message"); break; case 1: - tst_brkm_(__FILE__, __LINE__, TCONF, cleanup, "Non-NULL cleanup"); + tst_brkm__(__FILE__, __LINE__, TCONF, cleanup, "Non-NULL cleanup"); break; } } diff --git a/lib/newlib_tests/test03.c b/lib/newlib_tests/test03.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test04.c b/lib/newlib_tests/test04.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test05.c b/lib/newlib_tests/test05.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test06.c b/lib/newlib_tests/test06.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test07.c b/lib/newlib_tests/test07.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test08.c b/lib/newlib_tests/test08.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test09.c b/lib/newlib_tests/test09.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test10.c b/lib/newlib_tests/test10.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test11.c b/lib/newlib_tests/test11.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test12.c b/lib/newlib_tests/test12.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test13.c b/lib/newlib_tests/test13.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test14.c b/lib/newlib_tests/test14.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test15.c b/lib/newlib_tests/test15.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test18.c b/lib/newlib_tests/test18.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test19.c b/lib/newlib_tests/test19.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test20.c b/lib/newlib_tests/test20.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test22.c b/lib/newlib_tests/test22.c new file mode 100755 index 0000000000000000000000000000000000000000..520b8dad8894eaedac63aed301f30ce321d1ffb3 --- /dev/null +++ b/lib/newlib_tests/test22.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + */ + +/* + * Test that TBROK is propagated correctly to the results even if we wait on + * child and throw away the status. + */ +#include "tst_test.h" + +static void do_test(void) +{ + int pid = SAFE_FORK(); + + if (pid) { + tst_res(TPASS, "Test main pid"); + SAFE_WAITPID(pid, NULL, 0); + return; + } + + if (tst_variant == 1) + tst_brk(TBROK, "Test child!"); + else + tst_brk(TCONF, "Test child!"); + + tst_res(TPASS, "Test child"); +} + +static struct tst_test test = { + .test_all = do_test, + .test_variants = 2, + .forks_child = 1, +}; diff --git a/lib/newlib_tests/test_assert.c b/lib/newlib_tests/test_assert.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test_exec.c b/lib/newlib_tests/test_exec.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test_exec_child.c b/lib/newlib_tests/test_exec_child.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test_guarded_buf.c b/lib/newlib_tests/test_guarded_buf.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test_kconfig.c b/lib/newlib_tests/test_kconfig.c old mode 100644 new mode 100755 index d9c662fc500d3ebbc0ce1ee06795186b601f4e02..cea36b5ee8cad4d3ca782e6bf8c5063b8b8877f4 --- a/lib/newlib_tests/test_kconfig.c +++ b/lib/newlib_tests/test_kconfig.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2018 Cyril Hrubis */ @@ -14,6 +15,9 @@ static const char *kconfigs[] = { "CONFIG_MMU", "CONFIG_EXT4_FS=m", "CONFIG_PGTABLE_LEVELS=4", + "CONFIG_MMU & CONFIG_EXT4_FS=m", + "CONFIG_EXT4_FS=m | CONFIG_MMU", + "CONFIG_DEFAULT_HOSTNAME=\"(none)\"", NULL }; diff --git a/lib/newlib_tests/test_kconfig01.c b/lib/newlib_tests/test_kconfig01.c new file mode 100755 index 0000000000000000000000000000000000000000..ee919dcacb8dae39c82edd78bd0393ec41b360ce --- /dev/null +++ b/lib/newlib_tests/test_kconfig01.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + * + * Invalid boolean expression test. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TPASS, "Test passed!"); +} + +static const char *kconfigs[] = { + "CONFIG_EXT4_FS=m | CONFIG_MMU)", + NULL +}; + +static struct tst_test test = { + .test_all = do_test, + .needs_kconfigs = kconfigs, +}; diff --git a/lib/newlib_tests/test_kconfig02.c b/lib/newlib_tests/test_kconfig02.c new file mode 100755 index 0000000000000000000000000000000000000000..176929222a0f01ba8b6ef45fde9b3a621c9b9c37 --- /dev/null +++ b/lib/newlib_tests/test_kconfig02.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + * + * Invalid boolean expression test. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TPASS, "Test passed!"); +} + +static const char *kconfigs[] = { + "\"CONFIG_FOO=val\"", + "CONFIG_a=1", + "CONFIG_FOO=", + "CONFIG_DEFAULT_HOSTNAME=\"(none", + "CONFIG_DEFAULT_HOSTNAME=\"(none)\"a", + "CONFIG_BROKEN=a\" | CONFIG_FOO", + "CONFIG_BROKEN=a=", + NULL +}; + +static struct tst_test test = { + .test_all = do_test, + .needs_kconfigs = kconfigs, +}; diff --git a/lib/newlib_tests/test_macros01.c b/lib/newlib_tests/test_macros01.c new file mode 100755 index 0000000000000000000000000000000000000000..c04c9436372d8447a6252822373e1d8e5f8c9ccb --- /dev/null +++ b/lib/newlib_tests/test_macros01.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + */ + +/* + * Test TST_EXP_FD and TST_EXP_FD_SILENT macro. + */ + +#include "tst_test.h" + +static int fail_fd(void) +{ + errno = EINVAL; + return -1; +} + +static int pass_fd(void) +{ + return 42; +} + +static int inval_val(void) +{ + return -42; +} + +static int zero_val(void) +{ + return 0; +} + +static void do_test(void) +{ + tst_res(TINFO, "Testing TST_EXP_FD macro"); + TST_EXP_FD(fail_fd(), "fail_fd()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FD(pass_fd(), "pass_fd()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FD(inval_val(), "inval_val()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FD(zero_val(), "zero_val()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + + tst_res(TINFO, "Testing TST_EXP_FD_SILENT macro"); + TST_EXP_FD_SILENT(fail_fd(), "fail_fd()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FD_SILENT(pass_fd(), "%s", "pass_fd()"); + tst_res(TINFO, "TST_PASS = %i from TST_EXP_FD_SILENT(pass_fd, ...)", TST_PASS); + TST_EXP_FD_SILENT(inval_val(), "inval_val()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FD_SILENT(zero_val(), "zero_val()"); + tst_res(TINFO, "TST_PASS = %i from TST_EXP_FD_SILENT(zero_val, ...)", TST_PASS); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/lib/newlib_tests/test_macros02.c b/lib/newlib_tests/test_macros02.c new file mode 100755 index 0000000000000000000000000000000000000000..647f73682e7e2e13aee42163828ee36995787785 --- /dev/null +++ b/lib/newlib_tests/test_macros02.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + */ + +/* + * Test TST_EXP_FAIL and TST_EXP_FAIL2 macro. + */ + +#include "tst_test.h" + +static int fail_fn(void) +{ + errno = EINVAL; + return -1; +} + +static int pass_fn(void) +{ + return 0; +} + +static int inval_ret_fn(void) +{ + return 42; +} + +static void do_test(void) +{ + tst_res(TINFO, "Testing TST_EXP_FAIL macro"); + TST_EXP_FAIL(fail_fn(), EINVAL, "fail_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FAIL(fail_fn(), ENOTTY, "fail_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FAIL(pass_fn(), ENOTTY, "pass_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FAIL(inval_ret_fn(), ENOTTY, "inval_ret_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + + tst_res(TINFO, "Testing TST_EXP_FAIL2 macro"); + TST_EXP_FAIL2(fail_fn(), EINVAL, "fail_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FAIL2(fail_fn(), ENOTTY, "fail_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FAIL2(pass_fn(), ENOTTY, "pass_fn"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_FAIL2(inval_ret_fn(), ENOTTY, "inval_ret_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/lib/newlib_tests/test_macros03.c b/lib/newlib_tests/test_macros03.c new file mode 100755 index 0000000000000000000000000000000000000000..19a0ad6fd3dff3ceaa1f593c919548d166bbdd70 --- /dev/null +++ b/lib/newlib_tests/test_macros03.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + */ + +/* + * Test TST_EXP_PASS and TST_EXP_PASS_SILENT macro. + */ + +#include "tst_test.h" + +static int fail_fn(void) +{ + errno = EINVAL; + return -1; +} + +static int pass_fn(void) +{ + return 0; +} + +static int inval_ret_fn(void) +{ + return 42; +} + +static void do_test(void) +{ + tst_res(TINFO, "Testing TST_EXP_PASS macro"); + TST_EXP_PASS(fail_fn(), "fail_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_PASS(pass_fn(), "pass_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_PASS(inval_ret_fn(), "inval_ret_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + + tst_res(TINFO, "Testing TST_EXP_PASS_SILENT macro"); + TST_EXP_PASS_SILENT(fail_fn(), "fail_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_PASS_SILENT(pass_fn(), "pass_fn()"); + tst_res(TINFO, "TST_PASS = %i from TST_EXP_PASS_SILENT(pass_fn, ...)", TST_PASS); + TST_EXP_PASS_SILENT(inval_ret_fn(), "inval_ret_fn()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/lib/newlib_tests/test_macros04.c b/lib/newlib_tests/test_macros04.c new file mode 100755 index 0000000000000000000000000000000000000000..e0111807fe3ee8f79b04968b7a9b6fd38ea4fc7e --- /dev/null +++ b/lib/newlib_tests/test_macros04.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Test TST_EXP_PID and TST_EXP_PID_SILENT macro. + */ + +#include "tst_test.h" + +static int fail_pid(void) +{ + errno = EINVAL; + return -1; +} + +static int pass_pid(void) +{ + return 42; +} + +static int inval_val(void) +{ + return -42; +} + +static int zero_val(void) +{ + return 0; +} + +static void do_test(void) +{ + tst_res(TINFO, "Testing TST_EXP_PID macro"); + TST_EXP_PID(fail_pid(), "fail_pid()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_PID(pass_pid(), "pass_pid()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_PID(inval_val(), "inval_val()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_PID(zero_val(), "zero_val()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + + tst_res(TINFO, "Testing TST_EXP_PID_SILENT macro"); + TST_EXP_PID_SILENT(fail_pid(), "fail_pid()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_PID_SILENT(pass_pid(), "%s", "pass_pid()"); + tst_res(TINFO, "TST_PASS = %i from TST_EXP_PID_SILENT(pass_pid, ...)", TST_PASS); + TST_EXP_PID_SILENT(inval_val(), "inval_val()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_PID_SILENT(zero_val(), "zero_val()"); + tst_res(TINFO, "TST_PASS = %i from TST_EXP_PID_SILENT(zero_val, ...)", TST_PASS); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/lib/newlib_tests/test_macros05.c b/lib/newlib_tests/test_macros05.c new file mode 100755 index 0000000000000000000000000000000000000000..fda1410a237499c2a0deeda57f4d79d9716b734b --- /dev/null +++ b/lib/newlib_tests/test_macros05.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Cyril Hrubis + */ + +/* + * Tests various corner conditions: + * + * - default message, i.e. first argument stringification + * - macro indirection, i.e. we have to stringify early + * + * The output should include the MACRO_FAIL() as the either fail of pass + * message. If it's missing or if it has been replaced by the function name + * there is a bug in the TST_EXP_*() macro. + */ + +#include "tst_test.h" + +static int fail_fn_should_not_be_seen_in_output(void) +{ + errno = EINVAL; + return -1; +} + +#define MACRO_FAIL() fail_fn_should_not_be_seen_in_output() + +static void do_test(void) +{ + TST_EXP_VAL(MACRO_FAIL(), -2); + TST_EXP_VAL_SILENT(MACRO_FAIL(), -2); + + TST_EXP_FAIL(MACRO_FAIL(), EINVAL); + TST_EXP_FAIL2(MACRO_FAIL(), EINVAL); + + TST_EXP_PASS(MACRO_FAIL()); + TST_EXP_PASS_SILENT(MACRO_FAIL()); + + TST_EXP_PID(MACRO_FAIL()); + TST_EXP_PID_SILENT(MACRO_FAIL()); + + TST_EXP_FD(MACRO_FAIL()); + TST_EXP_FD_SILENT(MACRO_FAIL()); + + TST_EXP_POSITIVE(MACRO_FAIL()); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/lib/newlib_tests/test_macros06.c b/lib/newlib_tests/test_macros06.c new file mode 100755 index 0000000000000000000000000000000000000000..4d300d7977c34956f16e7c2af12c4ff853eea97a --- /dev/null +++ b/lib/newlib_tests/test_macros06.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 zhanglianjie + */ + +/* + * Test TST_EXP_VAL and TST_EXP_VAL_SILENT macro. + */ + +#include "tst_test.h" + +static int fail_val(void) +{ + errno = EINVAL; + return 42; +} + +static int pass_val(void) +{ + return 42; +} + +static void do_test(void) +{ + tst_res(TINFO, "Testing TST_EXP_VAL macro"); + TST_EXP_VAL(fail_val(), 40, "fail_val()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + TST_EXP_VAL(pass_val(), 42, "pass_val()"); + tst_res(TINFO, "TST_PASS = %i", TST_PASS); + + tst_res(TINFO, "Testing TST_EXP_VAL_SILENT macro"); + TST_EXP_VAL_SILENT(fail_val(), 40, "fail_val()"); + tst_res(TINFO, "TST_PASS = %i from TST_EXP_VAL_SILENT(fail_val, ...)", TST_PASS); + TST_EXP_VAL_SILENT(pass_val(), 42, "pass_val()"); + tst_res(TINFO, "TST_PASS = %i from TST_EXP_VAL_SILENT(pass_val, ...)", TST_PASS); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/lib/newlib_tests/test_parse_filesize.c b/lib/newlib_tests/test_parse_filesize.c new file mode 100755 index 0000000000000000000000000000000000000000..d60d7dc6a42f702f970cd2c388fe5d0b7ec7033b --- /dev/null +++ b/lib/newlib_tests/test_parse_filesize.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/* + * Tests for tst_parse_filesize. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + long long val = 0; + int ret = 0; + + if ((ret = tst_parse_filesize("1", &val, LLONG_MIN, LLONG_MAX))) { + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + if (val == 1LL) + tst_res(TPASS, "value is %lli", val); + else + tst_res(TFAIL, "%lli != %lli", val, 1LL); + } + + /* small letters */ + if ((ret = tst_parse_filesize("1k", &val, LLONG_MIN, LLONG_MAX))) { + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + if (val == 1024LL) + tst_res(TPASS, "value is %lli", val); + else + tst_res(TFAIL, "%lli != %lli", val, 1024LL); + } + + if ((ret = tst_parse_filesize("1m", &val, LLONG_MIN, LLONG_MAX))) { + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + if (val == 1048576LL) + tst_res(TPASS, "value is %lli", val); + else + tst_res(TFAIL, "%lli != %lli", val, 1048576LL); + } + + if ((ret = tst_parse_filesize("1g", &val, LLONG_MIN, LLONG_MAX))) { + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + if (val == 1073741824LL) + tst_res(TPASS, "value is %lli", val); + else + tst_res(TFAIL, "%lli != %lli", val, 1073741824LL); + } + + /* big letters */ + if ((ret = tst_parse_filesize("1K", &val, LLONG_MIN, LLONG_MAX))) { + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + if (val == 1024LL) + tst_res(TPASS, "value is %lli", val); + else + tst_res(TFAIL, "%lli != %lli", val, 1024LL); + } + + if ((ret = tst_parse_filesize("1M", &val, LLONG_MIN, LLONG_MAX))) { + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + if (val == 1048576LL) + tst_res(TPASS, "value is %lli", val); + else + tst_res(TFAIL, "%lli != %lli", val, 1048576LL); + } + + if ((ret = tst_parse_filesize("1G", &val, LLONG_MIN, LLONG_MAX))) { + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + if (val == 1073741824LL) + tst_res(TPASS, "value is %lli", val); + else + tst_res(TFAIL, "%lli != %lli", val, 1073741824LL); + } + + /* test errors */ + if ((ret = tst_parse_filesize("k", &val, LLONG_MIN, LLONG_MAX))) { + if (ret == EINVAL) + tst_res(TPASS, "return code %d (%s)", ret, tst_strerrno(ret)); + else + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + tst_res(TFAIL, "tst_parse_filesize should have failed"); + } + + if ((ret = tst_parse_filesize("100", &val, LLONG_MIN, 10))) { + if (ret == ERANGE) + tst_res(TPASS, "return code %d (%s)", ret, tst_strerrno(ret)); + else + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + tst_res(TFAIL, "tst_parse_filesize should have failed"); + } + + if ((ret = tst_parse_filesize("10", &val, 100, LLONG_MAX))) { + if (ret == ERANGE) + tst_res(TPASS, "return code %d (%s)", ret, tst_strerrno(ret)); + else + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + tst_res(TFAIL, "tst_parse_filesize should have failed"); + } + + if ((ret = tst_parse_filesize("10garbage", &val, LLONG_MIN, LLONG_MAX))) { + if (ret == EINVAL) + tst_res(TPASS, "return code %d (%s)", ret, tst_strerrno(ret)); + else + tst_res(TFAIL, "return code %d (%s)", ret, tst_strerrno(ret)); + } else { + tst_res(TFAIL, "tst_parse_filesize should have failed"); + } +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/lib/newlib_tests/test_timer.c b/lib/newlib_tests/test_timer.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/test_zero_hugepage.c b/lib/newlib_tests/test_zero_hugepage.c new file mode 100755 index 0000000000000000000000000000000000000000..0d85ce8666602a6777819e551e28206e63f88d03 --- /dev/null +++ b/lib/newlib_tests/test_zero_hugepage.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Tests .request_hugepages = TST_NO_HUGEPAGES + */ + +#include "tst_test.h" +#include "tst_hugepage.h" +#include "tst_sys_conf.h" + +static void do_test(void) +{ + unsigned long val, hpages; + + SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val); + if (val != 0) + tst_brk(TBROK, "nr_hugepages = %lu, but expect 0", val); + else + tst_res(TPASS, "test .request_hugepages = TST_NO_HUGEPAGES"); + + hpages = tst_request_hugepages(3); + SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val); + if (val != hpages) + tst_brk(TBROK, "nr_hugepages = %lu, but expect %lu", val, hpages); + else + tst_res(TPASS, "tst_request_hugepages"); +} + +static struct tst_test test = { + .test_all = do_test, + .request_hugepages = TST_NO_HUGEPAGES, +}; diff --git a/lib/newlib_tests/test_zero_hugepage.sh b/lib/newlib_tests/test_zero_hugepage.sh new file mode 100755 index 0000000000000000000000000000000000000000..92bd7e33147f34c206ac3c6ad4be68453318c9bc --- /dev/null +++ b/lib/newlib_tests/test_zero_hugepage.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2021 Yang Xu +# Copyright (c) 2021 Petr Vorel + +tconf() +{ + echo "TCONF: $1" + exit 32 +} + +echo "Testing .request_hugepages = TST_NO_HUGEPAGES" + +orig_value=`cat /proc/sys/vm/nr_hugepages` + +if grep -q -E '^proc /proc(/sys)? proc ro' /proc/mounts; then + tconf "/proc or /proc/sys mounted as read-only" +fi + +if [ ! -f /proc/sys/vm/nr_hugepages ]; then + tconf "/proc/sys/vm/nr_hugepages does not exist" +fi + +if [ ! -w /proc/sys/vm/nr_hugepages ]; then + tconf "no write permission to /proc/sys/vm/nr_hugepages (run as root)" +fi + +echo 4 > /proc/sys/vm/nr_hugepages + +./test_zero_hugepage + +echo $orig_value > /proc/sys/vm/nr_hugepages diff --git a/lib/newlib_tests/tst_bool_expr.c b/lib/newlib_tests/tst_bool_expr.c new file mode 100755 index 0000000000000000000000000000000000000000..8f0929d35f84d7ce35552dc7bfd4aee8e66722ee --- /dev/null +++ b/lib/newlib_tests/tst_bool_expr.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + */ + +/* + * Basic unit test for the bolean expression parser and evaluator. + */ + +#include +#include +#include "tst_test.h" +#include "tst_bool_expr.h" + +static int a, b, c; + +static int map(struct tst_expr_tok *var) +{ + if (!strncmp(var->tok, "A", var->tok_len)) + return a; + + if (!strncmp(var->tok, "B", var->tok_len)) + return b; + + if (!strncmp(var->tok, "C", var->tok_len)) + return c; + + if (!strncmp(var->tok, "True", var->tok_len)) + return 1; + + if (!strncmp(var->tok, "False", var->tok_len)) + return 0; + + return -1; +} + +static void parse_fail(const char *expr) +{ + struct tst_expr *res; + + tst_res(TINFO, "Parsing '%s'", expr); + + res = tst_bool_expr_parse(expr); + + if (res) { + printf("In RPN: "); + tst_bool_expr_print(stdout, res); + printf("\n"); + tst_bool_expr_free(res); + tst_res(TFAIL, "Expression was parsed"); + } else { + tst_res(TPASS, "Parser returned an error"); + } +} + +static void do_eval_test(const char *expr_str, int set_a, int set_b, int set_c, int exp_res) +{ + struct tst_expr *expr; + int res; + + a = set_a; + b = set_b; + c = set_c; + + tst_res(TINFO, "'%s' A=%i B=%i C=%i == %i", expr_str, a, b, c, exp_res); + + expr = tst_bool_expr_parse(expr_str); + + if (!expr) { + tst_res(TFAIL, "Parser returned error"); + return; + } + + printf("In RPN: "); + tst_bool_expr_print(stdout, expr); + printf("\n"); + + res = tst_bool_expr_eval(expr, map); + + if (res == exp_res) + tst_res(TPASS, "Got %i", res); + else + tst_res(TFAIL, "Got %i", res); + + tst_bool_expr_free(expr); +} + +static void do_test(void) +{ + do_eval_test("(A | B) & !!C", 0, 0, 0, 0); + do_eval_test("(A | B) & !!C", 1, 0, 1, 1); + do_eval_test("!A & B", 1, 0, 0, 0); + do_eval_test("!A & B", 0, 1, 0, 1); + do_eval_test("A & !B", 1, 0, 0, 1); + do_eval_test("!!A & !!B", 0, 1, 0, 0); + do_eval_test("!!A & !!B", 1, 1, 0, 1); + do_eval_test("!(A & B) & C", 1, 1, 0, 0); + do_eval_test("A & (B | C)", 1, 1, 0, 1); + do_eval_test("A & B | C", 1, 1, 0, 1); + do_eval_test("((((A)))&(B))", 1, 1, 0, 1); + do_eval_test(" A \t", 0, 0, 0, 0); + do_eval_test("False & A", 1, 0, 0, 0); + do_eval_test("! Undefined", 0, 0, 0, -1); + + do_eval_test("\"(none)\"", 0, 0, 0, -1); + do_eval_test("\"(none)\" & \" \"", 0, 0, 0, -1); + + parse_fail("A!"); + parse_fail("A &"); + parse_fail("A B"); + parse_fail("A ) B"); + parse_fail("A ( B"); + parse_fail("A ( B )"); + parse_fail("A |"); + parse_fail("A ! B"); + parse_fail("A! & B"); + parse_fail("A & | B"); + parse_fail("A & (B |)"); + parse_fail("A & ( | B)"); + parse_fail("A & B &"); + parse_fail("((A )"); + parse_fail("& A"); + parse_fail("! &"); + parse_fail(")"); + parse_fail("| A"); + parse_fail(""); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/lib/newlib_tests/tst_capability01.c b/lib/newlib_tests/tst_capability01.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/tst_capability02.c b/lib/newlib_tests/tst_capability02.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/tst_cgroup01.c b/lib/newlib_tests/tst_cgroup01.c new file mode 100755 index 0000000000000000000000000000000000000000..54a3703625c78b38a3e75e37266ccc51d3494878 --- /dev/null +++ b/lib/newlib_tests/tst_cgroup01.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2021 SUSE LLC */ + +#include + +#include "tst_test.h" +#include "tst_cgroup.h" + +static char *only_mount_v1; +static char *no_cleanup; +static struct tst_option opts[] = { + {"v", &only_mount_v1, "-v\tOnly try to mount CGroups V1"}, + {"n", &no_cleanup, "-n\tLeave CGroups created by test"}, + {NULL, NULL, NULL}, +}; +struct tst_cgroup_opts cgopts; + +static void do_test(void) +{ + tst_res(TPASS, "pass"); +} + +static void setup(void) +{ + cgopts.only_mount_v1 = !!only_mount_v1, + + tst_cgroup_scan(); + tst_cgroup_print_config(); + + tst_cgroup_require("memory", &cgopts); + tst_cgroup_print_config(); + tst_cgroup_require("cpuset", &cgopts); + tst_cgroup_print_config(); +} + +static void cleanup(void) +{ + if (no_cleanup) { + tst_res(TINFO, "no cleanup"); + } else { + tst_res(TINFO, "cleanup"); + tst_cgroup_cleanup(); + } +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .options = opts, +}; diff --git a/lib/newlib_tests/tst_cgroup02.c b/lib/newlib_tests/tst_cgroup02.c new file mode 100755 index 0000000000000000000000000000000000000000..64b0a1e943b1c9a741eceffb68b066e1b905564c --- /dev/null +++ b/lib/newlib_tests/tst_cgroup02.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2021 SUSE LLC */ + +#include +#include + +#include "tst_test.h" +#include "tst_cgroup.h" + +static char *only_mount_v1; +static char *no_cleanup; +static struct tst_option opts[] = { + {"v", &only_mount_v1, "-v\tOnly try to mount CGroups V1"}, + {"n", &no_cleanup, "-n\tLeave CGroups created by test"}, + {NULL, NULL, NULL}, +}; +static struct tst_cgroup_opts cgopts; +static const struct tst_cgroup_group *cg; +static const struct tst_cgroup_group *cg_drain; +static struct tst_cgroup_group *cg_child; + +static void do_test(void) +{ + char buf[BUFSIZ]; + size_t mem; + + if (!TST_CGROUP_VER_IS_V1(cg, "memory")) + SAFE_CGROUP_PRINT(cg, "cgroup.subtree_control", "+memory"); + if (!TST_CGROUP_VER_IS_V1(cg, "cpuset")) + SAFE_CGROUP_PRINT(cg, "cgroup.subtree_control", "+cpuset"); + + cg_child = tst_cgroup_group_mk(cg, "child"); + if (!SAFE_FORK()) { + SAFE_CGROUP_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + + SAFE_CGROUP_SCANF(cg_child, "memory.current", "%zu", &mem); + tst_res(TPASS, "child/memory.current = %zu", mem); + SAFE_CGROUP_PRINTF(cg_child, "memory.max", + "%zu", (1UL << 24) - 1); + SAFE_CGROUP_PRINTF(cg_child, "memory.swap.max", + "%zu", 1UL << 31); + + SAFE_CGROUP_READ(cg_child, "cpuset.mems", buf, sizeof(buf)); + tst_res(TPASS, "child/cpuset.mems = %s", buf); + SAFE_CGROUP_PRINT(cg_child, "cpuset.mems", buf); + + exit(0); + } + + SAFE_CGROUP_PRINTF(cg, "memory.max", "%zu", (1UL << 24) - 1); + SAFE_CGROUP_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + SAFE_CGROUP_SCANF(cg, "memory.current", "%zu", &mem); + tst_res(TPASS, "memory.current = %zu", mem); + + tst_reap_children(); + SAFE_CGROUP_PRINTF(cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cgroup_group_rm(cg_child); +} + +static void setup(void) +{ + cgopts.only_mount_v1 = !!only_mount_v1, + + tst_cgroup_scan(); + tst_cgroup_print_config(); + + tst_cgroup_require("memory", &cgopts); + tst_cgroup_require("cpuset", &cgopts); + + cg = tst_cgroup_get_test_group(); + cg_drain = tst_cgroup_get_drain_group(); +} + +static void cleanup(void) +{ + if (cg_child) { + SAFE_CGROUP_PRINTF(cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cgroup_group_rm(cg_child); + } + if (!no_cleanup) + tst_cgroup_cleanup(); +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .options = opts, + .forks_child = 1, +}; diff --git a/lib/newlib_tests/tst_device.c b/lib/newlib_tests/tst_device.c old mode 100644 new mode 100755 index 1344495b33a73c2c4950f71665ecbefad326756b..0bee0a9397e29c37e3bde90ec351a355b7f2dff0 --- a/lib/newlib_tests/tst_device.c +++ b/lib/newlib_tests/tst_device.c @@ -13,6 +13,7 @@ static void do_test(void) { int fd; const char *dev; + char block_dev[100]; uint64_t ltp_dev_size; dev = tst_device->dev; @@ -29,9 +30,17 @@ static void do_test(void) tst_res(TPASS, "Got expected device size"); else tst_res(TFAIL, "Got unexpected device size"); + + tst_find_backing_dev("/boot", block_dev); + tst_res(TPASS, "/boot belongs to %s block dev", block_dev); + tst_find_backing_dev("/", block_dev); + tst_res(TPASS, "/ belongs to %s block dev", block_dev); + tst_find_backing_dev("/tmp", block_dev); + tst_find_backing_dev("/boot/xuyang", block_dev); } static struct tst_test test = { + .needs_root = 1, .needs_device = 1, .dev_min_size = 300, .test_all = do_test, diff --git a/lib/newlib_tests/tst_expiration_timer.c b/lib/newlib_tests/tst_expiration_timer.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/tst_fuzzy_sync01.c b/lib/newlib_tests/tst_fuzzy_sync01.c new file mode 100755 index 0000000000000000000000000000000000000000..ae3ea4e09d1c5891d4ba253ee65bc8ef89334ac0 --- /dev/null +++ b/lib/newlib_tests/tst_fuzzy_sync01.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Richard Palethorpe + */ +/*\ + * [Description] + * + * This verifies Fuzzy Sync's basic ability to reproduce a particular + * outcome to a data race when the critical sections are not aligned. + * + * We make the simplifying assumptions that: + * - Each thread contains a single contiguous critical section. + * - The threads only interact through a single variable. + * - The various timings are constant except for variations introduced + * by the environment. + * + * If a single data race has N critical sections then we may remove + * N-1 sections to produce a more difficult race. We may then test + * only the more difficult race and induce from this the outcome of + * testing the easier races. + * + * In real code, the threads may interact through many side + * effects. While some of these side effects may not result in a bug, + * they may effect the total time it takes to execute either + * thread. This will be handled in tst_fuzzy_sync02. + * + * The number of variables which two threads interact through is + * irrelevant as the combined state of two variables can be + * represented with a single variable. We may also reduce the number + * of states to simply those required to show the thread is inside or + * outside of the critical section. + * + * There are two fundamental races which require alignment under these + * assumptions: + * 1 2 + * A +-----+ +----+ The outer box is total execution time. + * | # | | # | The '#' is the critical section. + * + * | # | | # | + * B +----+ +-----+ + * + * So we can either have the critical section of the shorter race + * before that of the longer one. Or the critical section of the + * longer one before the shorter. + * + * In reality both threads will never be the same length, but we can + * test that anyway. We also test with both A as the shorter and B as + * the shorter. We also vary the distance of the critical section from + * the start or end. The delay times are cubed to ensure that a delay + * range is required. + * + * When entering their critical sections, both threads increment the + * 'c' counter variable atomically. They both also increment it when + * leaving their critical sections. We record the value of 'c' when A + * increments it. From the recorded values of 'c' we can deduce if the + * critical sections overlap and their ordering. + * + * Start (cs) | End (ct) | Ordering + * -------------------------------------------- + * 1 | 2 | A before B + * 3 | 4 | B before A + * + * Any other combination of 'cs' and 'ct' means the critical sections + * overlapped. +\*/ + +#include "tst_test.h" +#include "tst_fuzzy_sync.h" + +/* Scale all the delay times by this function. The races become harder + * the faster this function grows. With cubic scaling the race windows + * will be 27 times smaller than the entry or return delays. Because + * TIME_SCALE(1) = 1*1*1, TIME_SCALE(3) = 3*3*3. + */ +#define TIME_SCALE(x) ((x) * (x) * (x)) + +/* The time signature of a code path containing a critical section. */ +struct window { + /* The delay until the start of the critical section */ + const int critical_s; + /* The length of the critical section */ + const int critical_t; + /* The remaining delay until the method returns */ + const int return_t; +}; + +/* The time signatures of threads A and B */ +struct race { + const struct window a; + const struct window b; +}; + +static int c; +static struct tst_fzsync_pair pair; + +static const struct race races[] = { + /* Degnerate cases where the critical sections are already + * aligned. The first case will fail when ncpu < 2 as a yield + * inside the critical section is required for the other + * thread to run. + */ + { .a = { 0, 0, 0 }, .b = { 0, 0, 0 } }, + { .a = { 0, 1, 0 }, .b = { 0, 1, 0 } }, + { .a = { 1, 1, 1 }, .b = { 1, 1, 1 } }, + { .a = { 3, 1, 1 }, .b = { 3, 1, 1 } }, + + /* Both windows are the same length */ + { .a = { 3, 1, 1 }, .b = { 1, 1, 3 } }, + { .a = { 1, 1, 3 }, .b = { 3, 1, 1 } }, + + /* Different sized windows */ + { .a = { 3, 1, 1 }, .b = { 1, 1, 2 } }, + { .a = { 1, 1, 3 }, .b = { 2, 1, 1 } }, + { .a = { 2, 1, 1 }, .b = { 1, 1, 3 } }, + { .a = { 1, 1, 2 }, .b = { 3, 1, 1 } }, + + /* Same as above, but with critical section at entry or exit */ + { .a = { 3, 1, 0 }, .b = { 0, 1, 3 } }, + { .a = { 0, 1, 3 }, .b = { 3, 1, 0 } }, + + { .a = { 3, 1, 0 }, .b = { 0, 1, 2 } }, + { .a = { 0, 1, 3 }, .b = { 2, 1, 0 } }, + { .a = { 2, 1, 0 }, .b = { 0, 1, 3 } }, + { .a = { 0, 1, 2 }, .b = { 3, 1, 0 } }, + + /* One side is very short */ + { .a = { 3, 1, 1 }, .b = { 0, 1, 0 } }, + { .a = { 1, 1, 3 }, .b = { 0, 1, 0 } }, + { .a = { 0, 1, 0 }, .b = { 1, 1, 3 } }, + { .a = { 0, 1, 0 }, .b = { 3, 1, 1 } }, + + { .a = { 3, 1, 1 }, .b = { 0, 0, 0 } }, + { .a = { 1, 1, 3 }, .b = { 0, 0, 0 } }, + { .a = { 0, 0, 0 }, .b = { 1, 1, 3 } }, + { .a = { 0, 0, 0 }, .b = { 3, 1, 1 } }, + +}; + +static void cleanup(void) +{ + tst_fzsync_pair_cleanup(&pair); +} + +static void setup(void) +{ + pair.min_samples = 10000; + + tst_fzsync_pair_init(&pair); +} + +static void delay(const int t) +{ + int k = TIME_SCALE(t); + + while (k--) + sched_yield(); +} + +static void *worker(void *v) +{ + unsigned int i = *(unsigned int *)v; + const struct window b = races[i].b; + + while (tst_fzsync_run_b(&pair)) { + if (tst_atomic_load(&c)) + tst_brk(TBROK, "Counter should now be zero"); + + tst_fzsync_start_race_b(&pair); + delay(b.critical_s); + + tst_atomic_add_return(1, &c); + delay(b.critical_t); + tst_atomic_add_return(1, &c); + + delay(b.return_t); + tst_fzsync_end_race_b(&pair); + } + + return NULL; +} + +static void run(unsigned int i) +{ + const struct window a = races[i].a; + struct tst_fzsync_run_thread wrap_run_b = { + .func = worker, + .arg = &i, + }; + int cs, ct, r, too_early = 0, critical = 0, too_late = 0; + + tst_fzsync_pair_reset(&pair, NULL); + SAFE_PTHREAD_CREATE(&pair.thread_b, 0, tst_fzsync_thread_wrapper, + &wrap_run_b); + + while (tst_fzsync_run_a(&pair)) { + + tst_fzsync_start_race_a(&pair); + delay(a.critical_s); + + cs = tst_atomic_add_return(1, &c); + delay(a.critical_t); + ct = tst_atomic_add_return(1, &c); + + delay(a.return_t); + tst_fzsync_end_race_a(&pair); + + if (cs == 1 && ct == 2) + too_early++; + else if (cs == 3 && ct == 4) + too_late++; + else + critical++; + + r = tst_atomic_add_return(-4, &c); + if (r) + tst_brk(TBROK, "cs = %d, ct = %d, r = %d", cs, ct, r); + + if (critical > 100) { + tst_fzsync_pair_cleanup(&pair); + break; + } + } + + tst_res(critical > 50 ? TPASS : TFAIL, + "acs:%-2d act:%-2d art:%-2d | =:%-4d -:%-4d +:%-4d", + a.critical_s, a.critical_t, a.return_t, + critical, too_early, too_late); +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(races), + .test = run, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/lib/newlib_tests/tst_fuzzy_sync02.c b/lib/newlib_tests/tst_fuzzy_sync02.c new file mode 100755 index 0000000000000000000000000000000000000000..51075f3c34ec88007952a78e03a5d296f69edcc7 --- /dev/null +++ b/lib/newlib_tests/tst_fuzzy_sync02.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Richard Palethorpe + */ +/*\ + * [Description] + * + * This verifies Fuzzy Sync's ability to reproduce a particular + * outcome to a data race when multiple races are present. + * + * We make the simplifying assumptions that: + * - There is one data race we want to hit and one to avoid. + * - Each thread contains two contiguous critical sections. One for each race. + * - The threads only interact through two variables, one for each race. + * - If we hit the race we want to avoid then it causes thread A to exit early. + * + * We don't consider more complicated dynamic interactions between the + * two threads. Fuzzy Sync will eventually trigger a race so long as + * the delay range is large enough. Assuming the race is possible to + * reproduce without further tampering to increase the race window (a + * technique specific to each race). So I conject that beyond a lower + * threshold of complexity, increasing the complexity of the race is + * no different from adding random noise. + * + * Emperically this appears to be true. So far we have seen in + * reproducers that there are no more than two significant data + * races. One we wish to reproduce and one we wish to avoid. It is + * possible that the code contains multiple data races, but that they + * appear only as two to us. + * + * Indeed it is also only possible to add a delay to A or B. So + * regardless of the underlying complexity we really only have two + * options. + * + * Here we only test a bias to delay B. A delay of A would be + * identical except that the necessary delay bias would be negative. + * +\*/ + +#include "tst_test.h" +#include "tst_fuzzy_sync.h" + +/* The time signature of a code path containing a critical section. */ +struct window { + /* The delay until the start of the critical section */ + const int critical_s; + /* The length of the critical section */ + const int critical_t; + /* The remaining delay until the method returns */ + const int return_t; +}; + +/* The time signatures of threads A and B. We interlace the two + * windows for each thread. bd.return_t is ignored, but ad.return_t is + * used instead of a.return_t if the ad and bd critical sections + * overlap. This may result in the critical section of a never being + * reached. + */ +struct race { + const struct window ad; + const struct window a; + const struct window bd; + const struct window b; +}; + +static int c, d; +static struct tst_fzsync_pair pair; + +static const struct race races[] = { + { .a = { 1, 1, 1 }, .b = { 1, 1, 1 }, + .ad = { 0, 1, 0 }, .bd = { 0, 1, 0 } }, + { .a = { 30, 1, 1 }, .b = { 1, 1, 1 }, + .ad = { 0, 1, 0 }, .bd = { 0, 20, 0 } }, + { .a = { 40, 1, 0 }, .b = { 1, 1, 20 }, + .ad = { 1, 10, 0 }, .bd = { 1, 10, 0 } }, +}; + +static void cleanup(void) +{ + tst_fzsync_pair_cleanup(&pair); +} + +static void setup(void) +{ + pair.min_samples = 10000; + + tst_fzsync_pair_init(&pair); +} + +static struct window to_abs(const struct window w) +{ + const struct window wc = { + w.critical_s, + w.critical_s + w.critical_t, + w.critical_s + w.critical_t + w.return_t, + }; + + return wc; +} + +static void *worker(void *v) +{ + unsigned int i = *(unsigned int *)v; + const struct window b = to_abs(races[i].b); + const struct window bd = to_abs(races[i].bd); + int now, fin = MAX(b.return_t, bd.return_t); + + while (tst_fzsync_run_b(&pair)) { + tst_fzsync_start_race_b(&pair); + for (now = 0; now <= fin; now++) { + if (now == b.critical_s || now == b.critical_t) + tst_atomic_add_return(1, &c); + if (now == bd.critical_s || now == bd.critical_t) + tst_atomic_add_return(1, &d); + + sched_yield(); + } + tst_fzsync_end_race_b(&pair); + } + + return NULL; +} + +static void run(unsigned int i) +{ + const struct window a = to_abs(races[i].a); + const struct window ad = to_abs(races[i].ad); + struct tst_fzsync_run_thread wrap_run_b = { + .func = worker, + .arg = &i, + }; + int critical = 0; + int now, fin; + + tst_fzsync_pair_reset(&pair, NULL); + SAFE_PTHREAD_CREATE(&pair.thread_b, 0, tst_fzsync_thread_wrapper, + &wrap_run_b); + + while (tst_fzsync_run_a(&pair)) { + c = 0; + d = 0; + fin = a.return_t; + + tst_fzsync_start_race_a(&pair); + for (now = 0; now <= fin; now++) { + if (now >= ad.critical_s && + now <= ad.critical_t && tst_atomic_load(&d) > 0) + fin = ad.return_t; + + if (now >= a.critical_s && + now <= a.critical_t && tst_atomic_load(&c) == 1) { + tst_atomic_add_return(1, &c); + critical++; + } + + sched_yield(); + } + tst_fzsync_end_race_a(&pair); + + if (fin == ad.return_t) + tst_fzsync_pair_add_bias(&pair, 1); + + if (critical > 100) { + tst_fzsync_pair_cleanup(&pair); + break; + } + } + + tst_res(critical > 50 ? TPASS : TFAIL, "%d| =:%-4d", i, critical); +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(races), + .test = run, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/lib/newlib_tests/test16.c b/lib/newlib_tests/tst_fuzzy_sync03.c old mode 100644 new mode 100755 similarity index 100% rename from lib/newlib_tests/test16.c rename to lib/newlib_tests/tst_fuzzy_sync03.c diff --git a/lib/newlib_tests/tst_needs_cmds01.c b/lib/newlib_tests/tst_needs_cmds01.c new file mode 100755 index 0000000000000000000000000000000000000000..777c695057893e977affbf5f9b5456436585a634 --- /dev/null +++ b/lib/newlib_tests/tst_needs_cmds01.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TPASS, "Testing tst_check_cmd() functionality OK."); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4", + "mkfs.ext4 >= 1.0.0", + "mkfs.ext4 <= 2.0.0", + "mkfs.ext4 != 2.0.0", + "mkfs.ext4 > 1.0.0", + "mkfs.ext4 < 2.0.0", + NULL + } +}; diff --git a/lib/newlib_tests/tst_needs_cmds02.c b/lib/newlib_tests/tst_needs_cmds02.c new file mode 100755 index 0000000000000000000000000000000000000000..455a275ea61bb67c6e2a08920d6705186049ec35 --- /dev/null +++ b/lib/newlib_tests/tst_needs_cmds02.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Test Illegal format by using non-existing cmd. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Nonexisting command is present!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext45 >= 1.43.0", + NULL + } +}; diff --git a/lib/newlib_tests/tst_needs_cmds03.c b/lib/newlib_tests/tst_needs_cmds03.c new file mode 100755 index 0000000000000000000000000000000000000000..bdc1cdf6ae76262843430acbb4272b965c9580e8 --- /dev/null +++ b/lib/newlib_tests/tst_needs_cmds03.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Test Illegal format by using Illegal operation. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Wrong operator was evaluated!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4 ! 1.43.0", + NULL + } +}; diff --git a/lib/newlib_tests/tst_needs_cmds04.c b/lib/newlib_tests/tst_needs_cmds04.c new file mode 100755 index 0000000000000000000000000000000000000000..de10b8f3e05fa95e0e26f7d6e13ac4c7e6961096 --- /dev/null +++ b/lib/newlib_tests/tst_needs_cmds04.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Test Illegal format by using incomplete version. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Incomplete version was parsed!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4 > 1.43", + NULL + } +}; diff --git a/lib/newlib_tests/tst_needs_cmds05.c b/lib/newlib_tests/tst_needs_cmds05.c new file mode 100755 index 0000000000000000000000000000000000000000..c3b2b3b9acf2f1183a75f485e3402adf88221377 --- /dev/null +++ b/lib/newlib_tests/tst_needs_cmds05.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Test Illegal format by using version that has garbage. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Garbage version was parsed!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4 > 1.43.0-1", + NULL + } +}; diff --git a/lib/newlib_tests/tst_needs_cmds06.c b/lib/newlib_tests/tst_needs_cmds06.c new file mode 100755 index 0000000000000000000000000000000000000000..40b1cf09cedcbd656356a6f8190dd931058a4a3b --- /dev/null +++ b/lib/newlib_tests/tst_needs_cmds06.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Test Illegal format with garbage. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Garbage format was parsed!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4 > 1.43.0 2", + NULL + } +}; diff --git a/lib/newlib_tests/tst_needs_cmds07.c b/lib/newlib_tests/tst_needs_cmds07.c new file mode 100755 index 0000000000000000000000000000000000000000..d0b4ce2ff119aa2f5d6e1f04c1353e5c5642b8aa --- /dev/null +++ b/lib/newlib_tests/tst_needs_cmds07.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Test non-existed cmd whether still can be detected. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Nonexisting command is present!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext45", + NULL + } +}; diff --git a/lib/newlib_tests/tst_needs_cmds08.c b/lib/newlib_tests/tst_needs_cmds08.c new file mode 100755 index 0000000000000000000000000000000000000000..38df2ef6d7142fd1feea412878d5052639375aff --- /dev/null +++ b/lib/newlib_tests/tst_needs_cmds08.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Test mkfs.xfs that it doesn't have own parser and table_get function + * at the version_parsers structure in lib/tst_cmd.c. + * So it should report parser function for this cmd is not implemented. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Nonexisting parser function for mkfs.xfs is present!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.xfs", + "mkfs.xfs >= 4.20.0", + NULL + } +}; diff --git a/lib/newlib_tests/test17.c b/lib/newlib_tests/tst_print_result.c old mode 100644 new mode 100755 similarity index 80% rename from lib/newlib_tests/test17.c rename to lib/newlib_tests/tst_print_result.c index c0fc0bc301fdd18db7906f707b8e269b28b208f4..0a2ca5af1eac25295f2f6efd930d59cb24f5f024 --- a/lib/newlib_tests/test17.c +++ b/lib/newlib_tests/tst_print_result.c @@ -1,12 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2017 Richard Palethorpe + * Copyright (c) 2017 Veronika Kabatova */ -/* Basic functionality test for tst_fuzzy_sync.h similar to the atomic tests - * (test15.c). One thread writes to the odd indexes of an array while the - * other writes to the even. If the threads are not synchronised then they - * will probably write to the wrong indexes as they share an index variable - * which they should take it in turns to update. + +/* + * Test for cecbd0cb3 ("Fix buffer overflow in print_result() function") */ #include diff --git a/lib/newlib_tests/tst_res_hexd.c b/lib/newlib_tests/tst_res_hexd.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/tst_safe_fileops.c b/lib/newlib_tests/tst_safe_fileops.c old mode 100644 new mode 100755 diff --git a/lib/newlib_tests/tst_strstatus.c b/lib/newlib_tests/tst_strstatus.c old mode 100644 new mode 100755 index aeeeb77ed75df858c89bada73f764796aefb81d5..f8655fe820036e8e1412ec9e26b6c8c5fa8e742b --- a/lib/newlib_tests/tst_strstatus.c +++ b/lib/newlib_tests/tst_strstatus.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) 2019-2021 Petr Vorel */ /* @@ -18,7 +19,7 @@ static struct tcase { {0x0001, "killed by SIGHUP"}, {0x137f, "is stopped"}, {0xffff, "is resumed"}, - {0xff, "invalid status 0xff"}, + {0x1ff, "invalid status 0x1ff"}, }; static void do_test(unsigned int n) diff --git a/lib/newlib_tests/variant.c b/lib/newlib_tests/variant.c old mode 100644 new mode 100755 index fbab710f1e10afda6570e7a3ef1d94f71bbd34c5..0f5be46e3ea053c8db676f1a58608bba888a9152 --- a/lib/newlib_tests/variant.c +++ b/lib/newlib_tests/variant.c @@ -17,12 +17,12 @@ static void do_test(void) tst_res(TPASS, "Test passed"); break; case 2: - /* This exits the test immediatelly */ + /* This exits the test immediately */ tst_brk(TBROK, "Test broken"); break; } - tst_res(TINFO, "test() function exitting normaly"); + tst_res(TINFO, "test() function exiting normally"); } static void setup(void) diff --git a/lib/parse_opts.c b/lib/parse_opts.c old mode 100644 new mode 100755 diff --git a/lib/random_range.c b/lib/random_range.c old mode 100644 new mode 100755 diff --git a/lib/safe_file_ops.c b/lib/safe_file_ops.c old mode 100644 new mode 100755 index e06d399fa5f331c4a432e46f6435c8c7d63d9a08..f803691d8f3fea58dcfe6a0e1be8bc1b2143ec7b --- a/lib/safe_file_ops.c +++ b/lib/safe_file_ops.c @@ -34,15 +34,7 @@ #include "test.h" #include "safe_file_ops_fn.h" -/* - * Count number of expected assigned conversions. Any conversion starts with '%'. - * The '%%' matches % and no assignment is done. The %*x matches as x would do but - * the assignment is suppressed. - * - * NOTE: This is not 100% correct for complex scanf strings, but will do for - * all of our intended usage. - */ -static int count_scanf_conversions(const char *fmt) +int tst_count_scanf_conversions(const char *fmt) { unsigned int cnt = 0; int flag = 0; @@ -84,36 +76,33 @@ int file_scanf(const char *file, const int lineno, f = fopen(path, "r"); if (f == NULL) { - tst_resm(TWARN, - "Failed to open FILE '%s' at %s:%d", - path, file, lineno); + tst_resm_(file, lineno, TWARN, "Failed to open FILE '%s'", + path); return 1; } - exp_convs = count_scanf_conversions(fmt); + exp_convs = tst_count_scanf_conversions(fmt); va_start(va, fmt); ret = vfscanf(f, fmt, va); va_end(va); if (ret == EOF) { - tst_resm(TWARN, - "The FILE '%s' ended prematurely at %s:%d", - path, file, lineno); + tst_resm_(file, lineno, TWARN, + "The FILE '%s' ended prematurely", path); goto err; } if (ret != exp_convs) { - tst_resm(TWARN, - "Expected %i conversions got %i FILE '%s' at %s:%d", - exp_convs, ret, path, file, lineno); + tst_resm_(file, lineno, TWARN, + "Expected %i conversions got %i FILE '%s'", + exp_convs, ret, path); goto err; } if (fclose(f)) { - tst_resm(TWARN, - "Failed to close FILE '%s' at %s:%d", - path, file, lineno); + tst_resm_(file, lineno, TWARN, "Failed to close FILE '%s'", + path); return 1; } @@ -121,10 +110,10 @@ int file_scanf(const char *file, const int lineno, err: if (fclose(f)) { - tst_resm(TWARN, - "Failed to close FILE '%s' at %s:%d", - path, file, lineno); + tst_resm_(file, lineno, TWARN, "Failed to close FILE '%s'", + path); } + return 1; } @@ -139,36 +128,33 @@ void safe_file_scanf(const char *file, const int lineno, f = fopen(path, "r"); if (f == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to open FILE '%s' for reading at %s:%d", - path, file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to open FILE '%s' for reading", path); return; } - exp_convs = count_scanf_conversions(fmt); + exp_convs = tst_count_scanf_conversions(fmt); va_start(va, fmt); ret = vfscanf(f, fmt, va); va_end(va); if (ret == EOF) { - tst_brkm(TBROK, cleanup_fn, - "The FILE '%s' ended prematurely at %s:%d", - path, file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "The FILE '%s' ended prematurely", path); return; } if (ret != exp_convs) { - tst_brkm(TBROK, cleanup_fn, - "Expected %i conversions got %i FILE '%s' at %s:%d", - exp_convs, ret, path, file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Expected %i conversions got %i FILE '%s'", + exp_convs, ret, path); return; } if (fclose(f)) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to close FILE '%s' at %s:%d", - path, file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to close FILE '%s'", path); return; } } @@ -190,20 +176,18 @@ int file_lines_scanf(const char *file, const int lineno, va_list ap; if (!fmt) { - tst_brkm(TBROK, cleanup_fn, "pattern is NULL, %s:%d", - file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, "pattern is NULL"); return 1; } fp = fopen(path, "r"); if (fp == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to open FILE '%s' for reading at %s:%d", - path, file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to open FILE '%s' for reading", path); return 1; } - arg_count = count_scanf_conversions(fmt); + arg_count = tst_count_scanf_conversions(fmt); while (fgets(line, BUFSIZ, fp) != NULL) { va_start(ap, fmt); @@ -216,8 +200,9 @@ int file_lines_scanf(const char *file, const int lineno, fclose(fp); if (strict && ret != arg_count) { - tst_brkm(TBROK, cleanup_fn, "Expected %i conversions got %i" - " FILE '%s' at %s:%d", arg_count, ret, path, file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Expected %i conversions got %i FILE '%s'", + arg_count, ret, path); return 1; } @@ -233,27 +218,24 @@ int file_printf(const char *file, const int lineno, f = fopen(path, "w"); if (f == NULL) { - tst_resm(TWARN, - "Failed to open FILE '%s' at %s:%d", - path, file, lineno); + tst_resm_(file, lineno, TWARN, "Failed to open FILE '%s'", + path); return 1; } va_start(va, fmt); if (vfprintf(f, fmt, va) < 0) { - tst_resm(TWARN, - "Failed to print to FILE '%s' at %s:%d", - path, file, lineno); + tst_resm_(file, lineno, TWARN, "Failed to print to FILE '%s'", + path); goto err; } va_end(va); if (fclose(f)) { - tst_resm(TWARN, - "Failed to close FILE '%s' at %s:%d", - path, file, lineno); + tst_resm_(file, lineno, TWARN, "Failed to close FILE '%s'", + path); return 1; } @@ -261,50 +243,65 @@ int file_printf(const char *file, const int lineno, err: if (fclose(f)) { - tst_resm(TWARN, - "Failed to close FILE '%s' at %s:%d", - path, file, lineno); + tst_resm_(file, lineno, TWARN, "Failed to close FILE '%s'", + path); } + return 1; } -void safe_file_printf(const char *file, const int lineno, - void (*cleanup_fn) (void), - const char *path, const char *fmt, ...) +static void safe_file_vprintf(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *path, const char *fmt, + va_list va) { - va_list va; FILE *f; f = fopen(path, "w"); if (f == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to open FILE '%s' for writing at %s:%d", - path, file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to open FILE '%s' for writing", path); return; } - va_start(va, fmt); - if (vfprintf(f, fmt, va) < 0) { - tst_brkm(TBROK, cleanup_fn, - "Failed to print to FILE '%s' at %s:%d", - path, file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Failed to print to FILE '%s'", path); return; } - va_end(va); - if (fclose(f)) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to close FILE '%s' at %s:%d", - path, file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to close FILE '%s'", path); return; } } +void safe_file_printf(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *path, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + safe_file_vprintf(file, lineno, cleanup_fn, path, fmt, va); + va_end(va); +} + +void safe_try_file_printf(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *path, const char *fmt, ...) +{ + va_list va; + + if (access(path, F_OK)) + return; + + va_start(va, fmt); + safe_file_vprintf(file, lineno, cleanup_fn, path, fmt, va); + va_end(va); +} + //TODO: C implementation? better error condition reporting? -void safe_cp(const char *file, const int lineno, +int safe_cp(const char *file, const int lineno, void (*cleanup_fn) (void), const char *src, const char *dst) { size_t len = strlen(src) + strlen(dst) + 16; @@ -316,10 +313,12 @@ void safe_cp(const char *file, const int lineno, ret = system(buf); if (ret) { - tst_brkm(TBROK, cleanup_fn, - "Failed to copy '%s' to '%s' at %s:%d", - src, dst, file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Failed to copy '%s' to '%s'", src, dst); + return ret; } + + return 0; } #ifndef HAVE_UTIMENSAT @@ -342,7 +341,7 @@ static void set_time(struct timeval *res, const struct timespec *src, #endif -void safe_touch(const char *file, const int lineno, +int safe_touch(const char *file, const int lineno, void (*cleanup_fn)(void), const char *pathname, mode_t mode, const struct timespec times[2]) @@ -353,28 +352,41 @@ void safe_touch(const char *file, const int lineno, defmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; ret = open(pathname, O_CREAT | O_WRONLY, defmode); + if (ret == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to open file '%s' at %s:%d", - pathname, file, lineno); - return; + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to open file '%s'", pathname); + return ret; + } else if (ret < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid open(%s) return value %d", pathname, ret); + return ret; } ret = close(ret); + if (ret == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to close file '%s' at %s:%d", - pathname, file, lineno); - return; + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to close file '%s'", pathname); + return ret; + } else if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid close('%s') return value %d", pathname, ret); + return ret; } if (mode != 0) { ret = chmod(pathname, mode); + if (ret == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to chmod file '%s' at %s:%d", - pathname, file, lineno); - return; + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to chmod file '%s'", pathname); + return ret; + } else if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid chmod('%s') return value %d", + pathname, ret); + return ret; } } @@ -389,19 +401,28 @@ void safe_touch(const char *file, const int lineno, struct timeval cotimes[2]; ret = stat(pathname, &sb); + if (ret == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to stat file '%s' at %s:%d", - pathname, file, lineno); - return; + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to stat file '%s'", pathname); + return ret; + } else if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid stat('%s') return value %d", + pathname, ret); + return ret; } ret = gettimeofday(cotimes, NULL); + if (ret == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to gettimeofday() at %s:%d", - file, lineno); - return; + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to gettimeofday()"); + return ret; + } else if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid gettimeofday() return value %d", ret); + return ret; } cotimes[1] = cotimes[0]; @@ -415,8 +436,18 @@ void safe_touch(const char *file, const int lineno, } #endif if (ret == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "Failed to update the access/modification time on file" - " '%s' at %s:%d", pathname, file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to update the access/modification time on file '%s'", + pathname); + } else if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, +#ifdef HAVE_UTIMENSAT + "Invalid utimensat('%s') return value %d", +#else + "Invalid utimes('%s') return value %d", +#endif + pathname, ret); } + + return ret; } diff --git a/lib/safe_macros.c b/lib/safe_macros.c old mode 100644 new mode 100755 index dde9b7b5ef039138a91595ee1e61f7e8252cf04a..a5b6bc5047521334f79aa44e2370d8a8508992af --- a/lib/safe_macros.c +++ b/lib/safe_macros.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -29,10 +30,10 @@ char *safe_basename(const char *file, const int lineno, char *rval; rval = basename(path); + if (rval == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: basename(%s) failed", - file, lineno, path); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "basename(%s) failed", path); } return rval; @@ -45,10 +46,13 @@ safe_chdir(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = chdir(path); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: chdir(%s) failed", - file, lineno, path); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "chdir(%s) failed", path); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid chdir(%s) return value %d", path, rval); } return rval; @@ -61,10 +65,13 @@ safe_close(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = close(fildes); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: close(%d) failed", - file, lineno, fildes); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "close(%d) failed", fildes); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid close(%d) return value %d", fildes, rval); } return rval; @@ -77,10 +84,14 @@ safe_creat(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = creat(pathname, mode); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: creat(%s,0%o) failed", - file, lineno, pathname, mode); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "creat(%s,%04o) failed", pathname, mode); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid creat(%s,%04o) return value %d", pathname, + mode, rval); } return rval; @@ -92,10 +103,10 @@ char *safe_dirname(const char *file, const int lineno, char *rval; rval = dirname(path); + if (rval == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: dirname(%s) failed", - file, lineno, path); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "dirname(%s) failed", path); } return rval; @@ -107,10 +118,10 @@ char *safe_getcwd(const char *file, const int lineno, void (*cleanup_fn) (void), char *rval; rval = getcwd(buf, size); + if (rval == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: getcwd(%p,%zu) failed", - file, lineno, buf, size); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "getcwd(%p,%zu) failed", buf, size); } return rval; @@ -122,10 +133,10 @@ struct passwd *safe_getpwnam(const char *file, const int lineno, struct passwd *rval; rval = getpwnam(name); + if (rval == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: getpwnam(%s) failed", - file, lineno, name); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "getpwnam(%s) failed", name); } return rval; @@ -138,10 +149,14 @@ safe_getrusage(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = getrusage(who, usage); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: getrusage(%d,%p) failed", - file, lineno, who, usage); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "getrusage(%d,%p) failed", who, usage); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid getrusage(%d,%p) return value %d", who, + usage, rval); } return rval; @@ -153,10 +168,10 @@ void *safe_malloc(const char *file, const int lineno, void (*cleanup_fn) (void), void *rval; rval = malloc(size); + if (rval == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: malloc(%zu) failed", - file, lineno, size); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "malloc(%zu) failed", size); } return rval; @@ -168,10 +183,14 @@ int safe_mkdir(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = mkdir(pathname, mode); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: mkdir(%s,0%o) failed", - file, lineno, pathname, mode); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "mkdir(%s, %04o) failed", pathname, mode); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid mkdir(%s, %04o) return value %d", pathname, + mode, rval); } return (rval); @@ -183,10 +202,13 @@ int safe_rmdir(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = rmdir(pathname); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: rmdir(%s) failed", - file, lineno, pathname); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "rmdir(%s) failed", pathname); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid rmdir(%s) return value %d", pathname, rval); } return (rval); @@ -198,10 +220,14 @@ int safe_munmap(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = munmap(addr, length); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: munmap(%p,%zu) failed", - file, lineno, addr, length); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "munmap(%p,%zu) failed", addr, length); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid munmap(%p,%zu) return value %d", addr, + length, rval); } return rval; @@ -224,10 +250,14 @@ int safe_open(const char *file, const int lineno, void (*cleanup_fn) (void), va_end(ap); rval = open(pathname, oflags, mode); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: open(%s,%d,0%o) failed", - file, lineno, pathname, oflags, mode); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "open(%s,%d,%04o) failed", pathname, oflags, mode); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid open(%s,%d,%04o) return value %d", pathname, + oflags, mode, rval); } return rval; @@ -239,10 +269,14 @@ int safe_pipe(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = pipe(fildes); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: pipe({%d,%d}) failed", - file, lineno, fildes[0], fildes[1]); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "pipe({%d,%d}) failed", fildes[0], fildes[1]); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid pipe({%d,%d}) return value %d", fildes[0], + fildes[1], rval); } return rval; @@ -254,10 +288,15 @@ ssize_t safe_read(const char *file, const int lineno, void (*cleanup_fn) (void), ssize_t rval; rval = read(fildes, buf, nbyte); + if (rval == -1 || (len_strict && (size_t)rval != nbyte)) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: read(%d,%p,%zu) failed, returned %zd", - file, lineno, fildes, buf, nbyte, rval); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "read(%d,%p,%zu) failed, returned %zd", fildes, buf, + nbyte, rval); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid read(%d,%p,%zu) return value %zd", fildes, + buf, nbyte, rval); } return rval; @@ -269,10 +308,14 @@ int safe_setegid(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = setegid(egid); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: setegid(%u) failed", - file, lineno, (unsigned) egid); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "setegid(%u) failed", (unsigned int)egid); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid setegid(%u) return value %d", + (unsigned int)egid, rval); } return rval; @@ -284,10 +327,14 @@ int safe_seteuid(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = seteuid(euid); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: seteuid(%u) failed", - file, lineno, (unsigned) euid); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "seteuid(%u) failed", (unsigned int)euid); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid seteuid(%u) return value %d", + (unsigned int)euid, rval); } return rval; @@ -299,10 +346,14 @@ int safe_setgid(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = setgid(gid); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: setgid(%u) failed", - file, lineno, (unsigned) gid); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "setgid(%u) failed", (unsigned int)gid); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid setgid(%u) return value %d", + (unsigned int)gid, rval); } return rval; @@ -314,10 +365,14 @@ int safe_setuid(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = setuid(uid); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: setuid(%u) failed", - file, lineno, (unsigned) uid); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "setuid(%u) failed", (unsigned int)uid); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid setuid(%u) return value %d", + (unsigned int)uid, rval); } return rval; @@ -329,10 +384,14 @@ int safe_getresuid(const char *file, const int lineno, void (*cleanup_fn)(void), int rval; rval = getresuid(ruid, euid, suid); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: getresuid(%p, %p, %p) failed", - file, lineno, ruid, euid, suid); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "getresuid(%p, %p, %p) failed", ruid, euid, suid); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid getresuid(%p, %p, %p) return value %d", ruid, + euid, suid, rval); } return rval; @@ -344,10 +403,14 @@ int safe_getresgid(const char *file, const int lineno, void (*cleanup_fn)(void), int rval; rval = getresgid(rgid, egid, sgid); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: getresgid(%p, %p, %p) failed", - file, lineno, rgid, egid, sgid); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "getresgid(%p, %p, %p) failed", rgid, egid, sgid); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid getresgid(%p, %p, %p) return value %d", rgid, + egid, sgid, rval); } return rval; @@ -359,10 +422,13 @@ int safe_unlink(const char *file, const int lineno, void (*cleanup_fn) (void), int rval; rval = unlink(pathname); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: unlink(%s) failed", - file, lineno, pathname); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "unlink(%s) failed", pathname); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid unlink(%s) return value %d", pathname, rval); } return rval; @@ -378,9 +444,12 @@ int safe_link(const char *file, const int lineno, rval = link(oldpath, newpath); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: link(%s,%s) failed", - file, lineno, oldpath, newpath); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "link(%s,%s) failed", oldpath, newpath); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid link(%s,%s) return value %d", oldpath, + newpath, rval); } return rval; @@ -395,10 +464,13 @@ int safe_linkat(const char *file, const int lineno, rval = linkat(olddirfd, oldpath, newdirfd, newpath, flags); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: linkat(%d,%s,%d,%s,%d) failed", - file, lineno, olddirfd, oldpath, newdirfd, - newpath, flags); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "linkat(%d,%s,%d,%s,%d) failed", olddirfd, oldpath, + newdirfd, newpath, flags); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid linkat(%d,%s,%d,%s,%d) return value %d", + olddirfd, oldpath, newdirfd, newpath, flags, rval); } return rval; @@ -413,9 +485,12 @@ ssize_t safe_readlink(const char *file, const int lineno, rval = readlink(path, buf, bufsize); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: readlink(%s,%p,%zu) failed", - file, lineno, path, buf, bufsize); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "readlink(%s,%p,%zu) failed", path, buf, bufsize); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid readlink(%s,%p,%zu) return value %zd", path, + buf, bufsize, rval); } else { /* readlink does not append a NUL byte to the buffer. * Add it now. */ @@ -437,9 +512,12 @@ int safe_symlink(const char *file, const int lineno, rval = symlink(oldpath, newpath); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: symlink(%s,%s) failed", - file, lineno, oldpath, newpath); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "symlink(%s,%s) failed", oldpath, newpath); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid symlink(%s,%s) return value %d", oldpath, + newpath, rval); } return rval; @@ -451,10 +529,14 @@ ssize_t safe_write(const char *file, const int lineno, void (cleanup_fn) (void), ssize_t rval; rval = write(fildes, buf, nbyte); + if (rval == -1 || (len_strict && (size_t)rval != nbyte)) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: write(%d,%p,%zu) failed", - file, lineno, fildes, buf, rval); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "write(%d,%p,%zu) failed", fildes, buf, nbyte); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid write(%d,%p,%zu) return value %zd", fildes, + buf, nbyte, rval); } return rval; @@ -471,21 +553,21 @@ long safe_strtol(const char *file, const int lineno, if ((errno == ERANGE && (rval == LONG_MAX || rval == LONG_MIN)) || (errno != 0 && rval == 0)) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: strtol(%s) failed", file, lineno, str); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "strtol(%s) failed", str); return rval; } if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { - tst_brkm(TBROK, cleanup_fn, - "%s:%d: strtol(%s): Invalid value", file, lineno, str); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "strtol(%s): Invalid value", str); return 0; } if (rval > max || rval < min) { - tst_brkm(TBROK, cleanup_fn, - "%s:%d: strtol(%s): %ld is out of range %ld - %ld", - file, lineno, str, rval, min, max); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "strtol(%s): %ld is out of range %ld - %ld", + str, rval, min, max); return 0; } @@ -504,21 +586,21 @@ unsigned long safe_strtoul(const char *file, const int lineno, if ((errno == ERANGE && rval == ULONG_MAX) || (errno != 0 && rval == 0)) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: strtoul(%s) failed", file, lineno, str); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "strtoul(%s) failed", str); return rval; } if (rval > max || rval < min) { - tst_brkm(TBROK, cleanup_fn, - "%s:%d: strtoul(%s): %lu is out of range %lu - %lu", - file, lineno, str, rval, min, max); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "strtoul(%s): %lu is out of range %lu - %lu", + str, rval, min, max); return 0; } if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { - tst_brkm(TBROK, cleanup_fn, - "Invalid value: '%s' at %s:%d", str, file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Invalid value: '%s'", str); return 0; } @@ -529,20 +611,18 @@ long safe_sysconf(const char *file, const int lineno, void (cleanup_fn) (void), int name) { long rval; - errno = 0; + errno = 0; rval = sysconf(name); if (rval == -1) { if (errno) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: sysconf(%d) failed", - file, lineno, name); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "sysconf(%d) failed", name); } else { - tst_resm(TINFO, "%s:%d: sysconf(%d): " - "queried option is not available" - " or there is no definite limit", - file, lineno, name); + tst_resm_(file, lineno, TINFO, + "sysconf(%d): queried option is not available or there is no definite limit", + name); } } @@ -557,9 +637,12 @@ int safe_chmod(const char *file, const int lineno, rval = chmod(path, mode); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: chmod(%s,0%o) failed", - file, lineno, path, mode); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "chmod(%s,%04o) failed", path, mode); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid chmod(%s,%04o) return value %d", path, mode, + rval); } return rval; @@ -573,9 +656,12 @@ int safe_fchmod(const char *file, const int lineno, rval = fchmod(fd, mode); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: fchmod(%d,0%o) failed", - file, lineno, fd, mode); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "fchmod(%d,%04o) failed", fd, mode); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid fchmod(%d,%04o) return value %d", fd, mode, + rval); } return rval; @@ -589,9 +675,12 @@ int safe_chown(const char *file, const int lineno, void (cleanup_fn)(void), rval = chown(path, owner, group); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: chown(%s,%d,%d) failed", - file, lineno, path, owner, group); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "chown(%s,%d,%d) failed", path, owner, group); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid chown(%s,%d,%d) return value %d", path, + owner, group, rval); } return rval; @@ -605,9 +694,12 @@ int safe_fchown(const char *file, const int lineno, void (cleanup_fn)(void), rval = fchown(fd, owner, group); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: fchown(%d,%d,%d) failed", - file, lineno, fd, owner, group); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "fchown(%d,%d,%d) failed", fd, owner, group); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid fchown(%d,%d,%d) return value %d", fd, + owner, group, rval); } return rval; @@ -619,10 +711,13 @@ pid_t safe_wait(const char *file, const int lineno, void (cleanup_fn)(void), pid_t rval; rval = wait(status); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: wait(%p) failed", - file, lineno, status); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "wait(%p) failed", status); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid wait(%p) return value %d", status, rval); } return rval; @@ -634,10 +729,14 @@ pid_t safe_waitpid(const char *file, const int lineno, void (cleanup_fn)(void), pid_t rval; rval = waitpid(pid, status, opts); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: waitpid(%d,%p,%d) failed", - file, lineno, pid, status, opts); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "waitpid(%d,%p,%d) failed", pid, status, opts); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid waitpid(%d,%p,%d) return value %d", pid, + status, opts, rval); } return rval; @@ -649,9 +748,11 @@ void *safe_memalign(const char *file, const int lineno, void *rval; rval = memalign(alignment, size); - if (rval == NULL) - tst_brkm(TBROK | TERRNO, cleanup_fn, "memalign failed at %s:%d", - file, lineno); + + if (rval == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "memalign() failed"); + } return rval; } @@ -664,9 +765,12 @@ int safe_kill(const char *file, const int lineno, void (cleanup_fn)(void), rval = kill(pid, sig); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: kill(%d,%s) failed", - file, lineno, pid, tst_strsig(sig)); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "kill(%d,%s) failed", pid, tst_strsig(sig)); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid kill(%d,%s) return value %d", pid, + tst_strsig(sig), rval); } return rval; @@ -680,9 +784,12 @@ int safe_mkfifo(const char *file, const int lineno, rval = mkfifo(pathname, mode); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: mkfifo(%s, 0%o) failed", - file, lineno, pathname, mode); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "mkfifo(%s, %04o) failed", pathname, mode); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid mkfifo(%s, %04o) return value %d", pathname, + mode, rval); } return rval; @@ -696,9 +803,12 @@ int safe_rename(const char *file, const int lineno, void (*cleanup_fn)(void), rval = rename(oldpath, newpath); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: rename(%s, %s) failed", - file, lineno, oldpath, newpath); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "rename(%s, %s) failed", oldpath, newpath); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid rename(%s, %s) return value %d", oldpath, + newpath, rval); } return rval; @@ -729,7 +839,7 @@ int safe_mount(const char *file, const int lineno, void (*cleanup_fn)(void), const char *filesystemtype, unsigned long mountflags, const void *data) { - int rval; + int rval = -1; /* * Don't try using the kernel's NTFS driver when mounting NTFS, since @@ -751,25 +861,29 @@ int safe_mount(const char *file, const int lineno, void (*cleanup_fn)(void), if (possibly_fuse(filesystemtype)) { char buf[1024]; - tst_resm(TINFO, "Trying FUSE..."); + tst_resm_(file, lineno, TINFO, "Trying FUSE..."); snprintf(buf, sizeof(buf), "mount.%s '%s' '%s'", - filesystemtype, source, target); + filesystemtype, source, target); rval = tst_system(buf); if (WIFEXITED(rval) && WEXITSTATUS(rval) == 0) return 0; - tst_brkm(TBROK, cleanup_fn, "mount.%s failed with %i", - filesystemtype, rval); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "mount.%s failed with %i", filesystemtype, rval); return -1; + } else if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "mount(%s, %s, %s, %lu, %p) failed", source, target, + filesystemtype, mountflags, data); } else { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: mount(%s, %s, %s, %lu, %p) failed", - file, lineno, source, target, filesystemtype, - mountflags, data); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid mount(%s, %s, %s, %lu, %p) return value %d", + source, target, filesystemtype, mountflags, data, + rval); } - return -1; + return rval; } int safe_umount(const char *file, const int lineno, void (*cleanup_fn)(void), @@ -780,9 +894,11 @@ int safe_umount(const char *file, const int lineno, void (*cleanup_fn)(void), rval = tst_umount(target); if (rval == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: umount(%s) failed", - file, lineno, target); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "umount(%s) failed", target); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid umount(%s) return value %d", target, rval); } return rval; @@ -796,8 +912,8 @@ DIR* safe_opendir(const char *file, const int lineno, void (cleanup_fn)(void), rval = opendir(name); if (!rval) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: opendir(%s) failed", file, lineno, name); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "opendir(%s) failed", name); } return rval; @@ -810,9 +926,12 @@ int safe_closedir(const char *file, const int lineno, void (cleanup_fn)(void), rval = closedir(dirp); - if (rval) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: closedir(%p) failed", file, lineno, dirp); + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "closedir(%p) failed", dirp); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid closedir(%p) return value %d", dirp, rval); } return rval; @@ -828,8 +947,8 @@ struct dirent *safe_readdir(const char *file, const int lineno, void (cleanup_fn rval = readdir(dirp); if (!rval && errno) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: readdir(%p) failed", file, lineno, dirp); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "readdir(%p) failed", dirp); } errno = err; @@ -842,10 +961,14 @@ int safe_getpriority(const char *file, const int lineno, int which, id_t who) errno = 0; rval = getpriority(which, who); - if (errno) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d getpriority(%i, %i) failed", - file, lineno, which, who); + + if (rval == -1 && errno) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "getpriority(%i, %i) failed", which, who); + } else if (errno) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "getpriority(%i, %i) failed with return value %d", + which, who, rval); } errno = err; @@ -861,14 +984,18 @@ ssize_t safe_getxattr(const char *file, const int lineno, const char *path, if (rval == -1) { if (errno == ENOTSUP) { - tst_brkm(TCONF, NULL, - "%s:%d: no xattr support in fs or mounted " - "without user_xattr option", file, lineno); + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; } - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: getxattr(%s, %s, %p, %zu) failed", - file, lineno, path, name, value, size); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "getxattr(%s, %s, %p, %zu) failed", + path, name, value, size); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid getxattr(%s, %s, %p, %zu) return value %zd", + path, name, value, size, rval); } return rval; @@ -881,16 +1008,20 @@ int safe_setxattr(const char *file, const int lineno, const char *path, rval = setxattr(path, name, value, size, flags); - if (rval) { + if (rval == -1) { if (errno == ENOTSUP) { - tst_brkm(TCONF, NULL, - "%s:%d: no xattr support in fs or mounted " - "without user_xattr option", file, lineno); + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; } - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: setxattr(%s, %s, %p, %zu) failed", - file, lineno, path, name, value, size); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "setxattr(%s, %s, %p, %zu) failed", + path, name, value, size); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid setxattr(%s, %s, %p, %zu) return value %d", + path, name, value, size, rval); } return rval; @@ -903,16 +1034,20 @@ int safe_lsetxattr(const char *file, const int lineno, const char *path, rval = lsetxattr(path, name, value, size, flags); - if (rval) { + if (rval == -1) { if (errno == ENOTSUP) { - tst_brkm(TCONF, NULL, - "%s:%d: no xattr support in fs or mounted " - "without user_xattr option", file, lineno); + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; } - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: lsetxattr(%s, %s, %p, %zu, %i) failed", - file, lineno, path, name, value, size, flags); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "lsetxattr(%s, %s, %p, %zu, %i) failed", + path, name, value, size, flags); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid lsetxattr(%s, %s, %p, %zu, %i) return value %d", + path, name, value, size, flags, rval); } return rval; @@ -925,16 +1060,20 @@ int safe_fsetxattr(const char *file, const int lineno, int fd, const char *name, rval = fsetxattr(fd, name, value, size, flags); - if (rval) { + if (rval == -1) { if (errno == ENOTSUP) { - tst_brkm(TCONF, NULL, - "%s:%d: no xattr support in fs or mounted " - "without user_xattr option", file, lineno); + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; } - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: fsetxattr(%i, %s, %p, %zu, %i) failed", - file, lineno, fd, name, value, size, flags); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "fsetxattr(%i, %s, %p, %zu, %i) failed", + fd, name, value, size, flags); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid fsetxattr(%i, %s, %p, %zu, %i) return value %d", + fd, name, value, size, flags, rval); } return rval; @@ -947,16 +1086,19 @@ int safe_removexattr(const char *file, const int lineno, const char *path, rval = removexattr(path, name); - if (rval) { + if (rval == -1) { if (errno == ENOTSUP) { - tst_brkm(TCONF, NULL, - "%s:%d: no xattr support in fs or mounted " - "without user_xattr option", file, lineno); + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; } - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: removexattr(%s, %s) failed", - file, lineno, path, name); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "removexattr(%s, %s) failed", path, name); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid removexattr(%s, %s) return value %d", path, + name, rval); } return rval; @@ -969,16 +1111,19 @@ int safe_lremovexattr(const char *file, const int lineno, const char *path, rval = lremovexattr(path, name); - if (rval) { + if (rval == -1) { if (errno == ENOTSUP) { - tst_brkm(TCONF, NULL, - "%s:%d: no xattr support in fs or mounted " - "without user_xattr option", file, lineno); + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; } - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: lremovexattr(%s, %s) failed", - file, lineno, path, name); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "lremovexattr(%s, %s) failed", path, name); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid lremovexattr(%s, %s) return value %d", path, + name, rval); } return rval; @@ -991,16 +1136,19 @@ int safe_fremovexattr(const char *file, const int lineno, int fd, rval = fremovexattr(fd, name); - if (rval) { + if (rval == -1) { if (errno == ENOTSUP) { - tst_brkm(TCONF, NULL, - "%s:%d: no xattr support in fs or mounted " - "without user_xattr option", file, lineno); + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; } - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: fremovexattr(%i, %s) failed", - file, lineno, fd, name); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "fremovexattr(%i, %s) failed", fd, name); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid fremovexattr(%i, %s) return value %d", fd, + name, rval); } return rval; @@ -1012,9 +1160,12 @@ int safe_fsync(const char *file, const int lineno, int fd) rval = fsync(fd); - if (rval) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: fsync(%i) failed", file, lineno, fd); + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "fsync(%i) failed", fd); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid fsync(%i) return value %d", fd, rval); } return rval; @@ -1025,9 +1176,10 @@ pid_t safe_setsid(const char *file, const int lineno) pid_t rval; rval = setsid(); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: setsid() failed", file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "setsid() failed"); } return rval; @@ -1039,9 +1191,13 @@ int safe_mknod(const char *file, const int lineno, const char *pathname, int rval; rval = mknod(pathname, mode, dev); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: mknod() failed", file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "mknod() failed"); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid mknod() return value %d", rval); } return rval; @@ -1053,9 +1209,13 @@ int safe_mlock(const char *file, const int lineno, const void *addr, int rval; rval = mlock(addr, len); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: mlock() failed", file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "mlock() failed"); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid mlock() return value %d", rval); } return rval; @@ -1067,9 +1227,13 @@ int safe_munlock(const char *file, const int lineno, const void *addr, int rval; rval = munlock(addr, len); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: munlock() failed", file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "munlock() failed"); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid munlock() return value %d", rval); } return rval; @@ -1081,10 +1245,32 @@ int safe_mincore(const char *file, const int lineno, void *start, int rval; rval = mincore(start, length, vec); + if (rval == -1) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: mincore() failed", file, lineno); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "mincore() failed"); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid mincore() return value %d", rval); } return rval; } + +int safe_sysinfo(const char *file, const int lineno, struct sysinfo *info) +{ + int ret; + + errno = 0; + ret = sysinfo(info); + + if (ret == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "sysinfo() failed"); + } else if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid sysinfo() return value %d", ret); + } + + return ret; +} diff --git a/lib/safe_net.c b/lib/safe_net.c old mode 100644 new mode 100755 index 49936800750f59ba58c82ab45d841cb25c6e9e3c..1717f0745fbdb19ca23d8675c6e3c705ee9028a7 --- a/lib/safe_net.c +++ b/lib/safe_net.c @@ -18,6 +18,7 @@ #include #include "test.h" +#include "safe_macros_fn.h" #include "safe_net_fn.h" char *tst_sock_addr(const struct sockaddr *sa, socklen_t salen, char *res, @@ -111,7 +112,7 @@ int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void), rval = socket(domain, type, protocol); - if (rval < 0) { + if (rval == -1) { switch (errno) { case EPROTONOSUPPORT: case ESOCKTNOSUPPORT: @@ -124,9 +125,12 @@ int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void), ttype = TBROK; } - tst_brkm(ttype | TERRNO, cleanup_fn, - "%s:%d: socket(%d, %d, %d) failed", file, lineno, - domain, type, protocol); + tst_brkm_(file, lineno, ttype | TERRNO, cleanup_fn, + "socket(%d, %d, %d) failed", domain, type, protocol); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid socket(%d, %d, %d) return value %d", domain, + type, protocol, rval); } return rval; @@ -139,7 +143,7 @@ int safe_socketpair(const char *file, const int lineno, int domain, int type, rval = socketpair(domain, type, protocol, sv); - if (rval < 0) { + if (rval == -1) { switch (errno) { case EPROTONOSUPPORT: case EOPNOTSUPP: @@ -150,9 +154,13 @@ int safe_socketpair(const char *file, const int lineno, int domain, int type, ttype = TBROK; } - tst_brkm(ttype | TERRNO, NULL, - "%s:%d: socketpair(%d, %d, %d, %p) failed", - file, lineno, domain, type, protocol, sv); + tst_brkm_(file, lineno, ttype | TERRNO, NULL, + "socketpair(%d, %d, %d, %p) failed", domain, type, + protocol, sv); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid socketpair(%d, %d, %d, %p) return value %d", + domain, type, protocol, sv, rval); } return rval; @@ -163,12 +171,15 @@ int safe_getsockopt(const char *file, const int lineno, int sockfd, int level, { int rval = getsockopt(sockfd, level, optname, optval, optlen); - if (!rval) - return 0; - - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: getsockopt(%d, %d, %d, %p, %p) failed", - file, lineno, sockfd, level, optname, optval, optlen); + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "getsockopt(%d, %d, %d, %p, %p) failed", + sockfd, level, optname, optval, optlen); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid getsockopt(%d, %d, %d, %p, %p) return value %d", + sockfd, level, optname, optval, optlen, rval); + } return rval; } @@ -180,10 +191,14 @@ int safe_setsockopt(const char *file, const int lineno, int sockfd, int level, rval = setsockopt(sockfd, level, optname, optval, optlen); - if (rval) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: setsockopt(%d, %d, %d, %p, %d) failed", - file, lineno, sockfd, level, optname, optval, optlen); + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "setsockopt(%d, %d, %d, %p, %d) failed", + sockfd, level, optname, optval, optlen); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid setsockopt(%d, %d, %d, %p, %d) return value %d", + sockfd, level, optname, optval, optlen, rval); } return rval; @@ -197,9 +212,13 @@ ssize_t safe_send(const char *file, const int lineno, char len_strict, rval = send(sockfd, buf, len, flags); if (rval == -1 || (len_strict && (size_t)rval != len)) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: send(%d, %p, %zu, %d) failed", - file, lineno, sockfd, buf, len, flags); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "send(%d, %p, %zu, %d) failed", sockfd, buf, len, + flags); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid send(%d, %p, %zu, %d) return value %zd", + sockfd, buf, len, flags, rval); } return rval; @@ -215,11 +234,17 @@ ssize_t safe_sendto(const char *file, const int lineno, char len_strict, rval = sendto(sockfd, buf, len, flags, dest_addr, addrlen); if (rval == -1 || (len_strict && (size_t)rval != len)) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: sendto(%d, %p, %zu, %d, %s, %d) failed", - file, lineno, sockfd, buf, len, flags, - tst_sock_addr(dest_addr, addrlen, res, sizeof(res)), - addrlen); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "sendto(%d, %p, %zu, %d, %s, %d) failed", + sockfd, buf, len, flags, + tst_sock_addr(dest_addr, addrlen, res, sizeof(res)), + addrlen); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid sendto(%d, %p, %zu, %d, %s, %d) return value %zd", + sockfd, buf, len, flags, + tst_sock_addr(dest_addr, addrlen, res, sizeof(res)), + addrlen, rval); } return rval; @@ -233,18 +258,44 @@ ssize_t safe_sendmsg(const char *file, const int lineno, size_t len, rval = sendmsg(sockfd, msg, flags); if (rval == -1) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: sendmsg(%d, %p, %d) failed", - file, lineno, sockfd, msg, flags); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "sendmsg(%d, %p, %d) failed", sockfd, msg, flags); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid sendmsg(%d, %p, %d) return value %zd", + sockfd, msg, flags, rval); + } else if (len && (size_t)rval != len) { + tst_brkm_(file, lineno, TBROK, NULL, + "sendmsg(%d, %p, %d) ret(%zd) != len(%zu)", + sockfd, msg, flags, rval, len); } - if (len && (size_t)rval != len) { - tst_brkm(TBROK, NULL, - "%s:%d: sendmsg(%d, %p, %d) ret(%zd) != len(%zu)", - file, lineno, sockfd, msg, flags, rval, len); + return rval; +} + +ssize_t safe_recv(const char *file, const int lineno, size_t len, + int sockfd, void *buf, size_t size, int flags) +{ + ssize_t rval; + + rval = recv(sockfd, buf, size, flags); + + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "recv(%d, %p, %zu, %d) failed", sockfd, buf, size, + flags); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid recv(%d, %p, %zu, %d) return value %zd", + sockfd, buf, size, flags, rval); + } else if (len && (size_t)rval != len) { + tst_brkm_(file, lineno, TBROK, NULL, + "recv(%d, %p, %zu, %d) ret(%zd) != len(%zu)", + sockfd, buf, size, flags, rval, len); } return rval; + } ssize_t safe_recvmsg(const char *file, const int lineno, size_t len, @@ -255,15 +306,16 @@ ssize_t safe_recvmsg(const char *file, const int lineno, size_t len, rval = recvmsg(sockfd, msg, flags); if (rval == -1) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: recvmsg(%d, %p, %d) failed", - file, lineno, sockfd, msg, flags); - } - - if (len && (size_t)rval != len) { - tst_brkm(TBROK, NULL, - "%s:%d: recvmsg(%d, %p, %d) ret(%zd) != len(%zu)", - file, lineno, sockfd, msg, flags, rval, len); + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "recvmsg(%d, %p, %d) failed", sockfd, msg, flags); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid recvmsg(%d, %p, %d) return value %zd", + sockfd, msg, flags, rval); + } else if (len && (size_t)rval != len) { + tst_brkm_(file, lineno, TBROK, NULL, + "recvmsg(%d, %p, %d) ret(%zd) != len(%zu)", + sockfd, msg, flags, rval, len); } return rval; @@ -274,35 +326,41 @@ int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void), int socket, const struct sockaddr *address, socklen_t address_len) { - int i; + int i, ret; char buf[128]; for (i = 0; i < 120; i++) { - if (!bind(socket, address, address_len)) + ret = bind(socket, address, address_len); + + if (!ret) return 0; - if (errno != EADDRINUSE) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: bind(%d, %s, %d) failed", file, lineno, - socket, tst_sock_addr(address, address_len, - buf, sizeof(buf)), - address_len); - return -1; + if (ret != -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid bind(%d, %s, %d) return value %d", + socket, tst_sock_addr(address, address_len, + buf, sizeof(buf)), address_len, ret); + return ret; + } else if (errno != EADDRINUSE) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "bind(%d, %s, %d) failed", socket, + tst_sock_addr(address, address_len, buf, + sizeof(buf)), address_len); + return ret; } if ((i + 1) % 10 == 0) { - tst_resm(TINFO, "address is in use, waited %3i sec", - i + 1); + tst_resm_(file, lineno, TINFO, + "address is in use, waited %3i sec", i + 1); } sleep(1); } - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: Failed to bind(%d, %s, %d) after 120 retries", file, - lineno, socket, - tst_sock_addr(address, address_len, buf, sizeof(buf)), - address_len); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to bind(%d, %s, %d) after 120 retries", socket, + tst_sock_addr(address, address_len, buf, sizeof(buf)), + address_len); return -1; } @@ -310,13 +368,19 @@ int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void), int socket, int backlog) { int rval; + int res = TBROK; rval = listen(socket, backlog); - if (rval < 0) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: listen(%d, %d) failed", file, lineno, socket, - backlog); + if (rval == -1) { + if (errno == ENOSYS) + res = TCONF; + tst_brkm_(file, lineno, res | TERRNO, cleanup_fn, + "listen(%d, %d) failed", socket, backlog); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid listen(%d, %d) return value %d", socket, + backlog, rval); } return rval; @@ -329,10 +393,13 @@ int safe_accept(const char *file, const int lineno, void (cleanup_fn)(void), rval = accept(sockfd, addr, addrlen); - if (rval < 0) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: accept(%d, %p, %d) failed", file, lineno, - sockfd, addr, *addrlen); + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "accept(%d, %p, %d) failed", sockfd, addr, *addrlen); + } else if (rval < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid accept(%d, %p, %d) return value %d", sockfd, + addr, *addrlen, rval); } return rval; @@ -346,11 +413,16 @@ int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void), rval = connect(sockfd, addr, addrlen); - if (rval < 0) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: connect(%d, %s, %d) failed", file, lineno, - sockfd, tst_sock_addr(addr, addrlen, buf, - sizeof(buf)), addrlen); + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "connect(%d, %s, %d) failed", sockfd, + tst_sock_addr(addr, addrlen, buf, sizeof(buf)), + addrlen); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid connect(%d, %s, %d) return value %d", sockfd, + tst_sock_addr(addr, addrlen, buf, sizeof(buf)), + addrlen, rval); } return rval; @@ -365,11 +437,16 @@ int safe_getsockname(const char *file, const int lineno, rval = getsockname(sockfd, addr, addrlen); - if (rval < 0) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: getsockname(%d, %s, %d) failed", file, lineno, - sockfd, tst_sock_addr(addr, *addrlen, buf, - sizeof(buf)), *addrlen); + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "getsockname(%d, %s, %d) failed", sockfd, + tst_sock_addr(addr, *addrlen, buf, sizeof(buf)), + *addrlen); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid getsockname(%d, %s, %d) return value %d", + sockfd, tst_sock_addr(addr, *addrlen, buf, + sizeof(buf)), *addrlen, rval); } return rval; @@ -380,10 +457,13 @@ int safe_gethostname(const char *file, const int lineno, { int rval = gethostname(name, size); - if (rval < 0) { - tst_brkm(TBROK | TERRNO, NULL, - "%s:%d: gethostname(%p, %zu) failed", - file, lineno, name, size); + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "gethostname(%p, %zu) failed", name, size); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid gethostname(%p, %zu) return value %d", name, + size, rval); } return rval; @@ -395,7 +475,7 @@ int safe_gethostname(const char *file, const int lineno, unsigned short tst_get_unused_port(const char *file, const int lineno, void (cleanup_fn)(void), unsigned short family, int type) { - int sock; + int sock, ret; socklen_t slen; struct sockaddr_storage _addr; struct sockaddr *addr = (struct sockaddr *)&_addr; @@ -418,35 +498,31 @@ unsigned short tst_get_unused_port(const char *file, const int lineno, break; default: - tst_brkm(TBROK, cleanup_fn, - "%s:%d: unknown family", file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "%s(): Unsupported socket family %d", __func__, + family); return -1; } - sock = socket(addr->sa_family, type, 0); - if (sock < 0) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: socket failed", file, lineno); - return -1; - } + sock = safe_socket(file, lineno, cleanup_fn, addr->sa_family, type, 0); - if (bind(sock, addr, slen) < 0) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: bind failed", file, lineno); - return -1; - } + if (sock < 0) + return sock; - if (getsockname(sock, addr, &slen) == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: getsockname failed", file, lineno); - return -1; - } + ret = safe_bind(file, lineno, cleanup_fn, sock, addr, slen); - if (close(sock) == -1) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: close failed", file, lineno); - return -1; - } + if (ret) + return ret; + + ret = safe_getsockname(file, lineno, cleanup_fn, sock, addr, &slen); + + if (ret) + return ret; + + ret = safe_close(file, lineno, cleanup_fn, sock); + + if (ret) + return ret; switch (family) { case AF_INET: diff --git a/lib/safe_pthread.c b/lib/safe_pthread.c old mode 100644 new mode 100755 diff --git a/lib/safe_stdio.c b/lib/safe_stdio.c old mode 100644 new mode 100755 index 966a039a5c94e8e16c50c1acd486a6f7ecd084c4..ab23e43bb0835cdca5eaa015bc873fd23f9a8408 --- a/lib/safe_stdio.c +++ b/lib/safe_stdio.c @@ -29,9 +29,8 @@ FILE *safe_fopen(const char *file, const int lineno, void (cleanup_fn)(void), FILE *f = fopen(path, mode); if (f == NULL) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: fopen(%s,%s) failed", - file, lineno, path, mode); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "fopen(%s,%s) failed", path, mode); } return f; @@ -44,9 +43,12 @@ int safe_fclose(const char *file, const int lineno, void (cleanup_fn)(void), ret = fclose(f); - if (ret) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: fclose(%p) failed", file, lineno, f); + if (ret == EOF) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "fclose(%p) failed", f); + } else if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid fclose(%p) return value %d", f, ret); } return ret; @@ -62,9 +64,12 @@ int safe_asprintf(const char *file, const int lineno, void (cleanup_fn)(void), ret = vasprintf(strp, fmt, va); va_end(va); - if (ret < 0) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: asprintf(%s,...) failed", file, lineno, fmt); + if (ret == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "asprintf(%s,...) failed", fmt); + } else if (ret < 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid asprintf(%s,...) return value %d", fmt, ret); } return ret; @@ -81,13 +86,12 @@ FILE *safe_popen(const char *file, const int lineno, void (cleanup_fn)(void), if (stream == NULL) { if (errno != 0) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: popen(%s,%s) failed", - file, lineno, command, type); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "popen(%s,%s) failed", command, type); } else { - tst_brkm(TBROK, cleanup_fn, - "%s:%d: popen(%s,%s) failed: Out of memory", - file, lineno, command, type); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "popen(%s,%s) failed: Out of memory", + command, type); } } diff --git a/lib/self_exec.c b/lib/self_exec.c old mode 100644 new mode 100755 diff --git a/lib/signame.h b/lib/signame.h old mode 100644 new mode 100755 diff --git a/lib/tests/Makefile b/lib/tests/Makefile old mode 100644 new mode 100755 diff --git a/lib/tests/trerrno.c b/lib/tests/trerrno.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_checkpoint.c b/lib/tests/tst_checkpoint.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_checkpoint_wait_timeout.c b/lib/tests/tst_checkpoint_wait_timeout.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_checkpoint_wake_timeout.c b/lib/tests/tst_checkpoint_wake_timeout.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_cleanup_once.c b/lib/tests/tst_cleanup_once.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_dataroot01.c b/lib/tests/tst_dataroot01.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_dataroot02.c b/lib/tests/tst_dataroot02.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_dataroot03.c b/lib/tests/tst_dataroot03.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_device.c b/lib/tests/tst_device.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_fs_fill_hardlinks.c b/lib/tests/tst_fs_fill_hardlinks.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_fs_fill_subdirs.c b/lib/tests/tst_fs_fill_subdirs.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_process_state.c b/lib/tests/tst_process_state.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_record_childstatus.c b/lib/tests/tst_record_childstatus.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_safe_macros.c b/lib/tests/tst_safe_macros.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_strerrno.c b/lib/tests/tst_strerrno.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_strsig.c b/lib/tests/tst_strsig.c old mode 100644 new mode 100755 diff --git a/lib/tests/tst_tmpdir_test.c b/lib/tests/tst_tmpdir_test.c old mode 100644 new mode 100755 diff --git a/lib/tlibio.c b/lib/tlibio.c old mode 100644 new mode 100755 diff --git a/lib/tst_af_alg.c b/lib/tst_af_alg.c old mode 100644 new mode 100755 index 97be548b40c81074c6182c247664f442b80f1b32..f5437c5c50d0a9cd4b81474900ab8a6341cd073a --- a/lib/tst_af_alg.c +++ b/lib/tst_af_alg.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright 2019 Google LLC + * Copyright (c) Linux Test Project, 2019-2021 */ #include @@ -13,25 +14,36 @@ int tst_alg_create(void) { - TEST(socket(AF_ALG, SOCK_SEQPACKET, 0)); - if (TST_RET >= 0) - return TST_RET; - if (TST_ERR == EAFNOSUPPORT) + const long ret = socket(AF_ALG, SOCK_SEQPACKET, 0); + + if (ret >= 0) + return ret; + if (errno == EAFNOSUPPORT) tst_brk(TCONF, "kernel doesn't support AF_ALG"); - tst_brk(TBROK | TTERRNO, "unexpected error creating AF_ALG socket"); + tst_brk(TBROK | TERRNO, "unexpected error creating AF_ALG socket"); return -1; } void tst_alg_bind_addr(int algfd, const struct sockaddr_alg *addr) { - TEST(bind(algfd, (const struct sockaddr *)addr, sizeof(*addr))); - if (TST_RET == 0) + const long ret = bind(algfd, (const struct sockaddr *)addr, + sizeof(*addr)); + + if (ret == 0) return; - if (TST_ERR == ENOENT) { + + if (errno == ELIBBAD && tst_fips_enabled()) { + tst_brk(TCONF, + "FIPS enabled => %s algorithm '%s' disabled", + addr->salg_type, addr->salg_name); + } + + if (errno == ENOENT) { tst_brk(TCONF, "kernel doesn't support %s algorithm '%s'", addr->salg_type, addr->salg_name); } - tst_brk(TBROK | TTERRNO, + + tst_brk(TBROK | TERRNO, "unexpected error binding AF_ALG socket to %s algorithm '%s'", addr->salg_type, addr->salg_name); } @@ -61,28 +73,54 @@ void tst_alg_bind(int algfd, const char *algtype, const char *algname) tst_alg_bind_addr(algfd, &addr); } -bool tst_have_alg(const char *algtype, const char *algname) +int tst_try_alg(const char *algtype, const char *algname) { + long ret; + int retval = 0; int algfd; struct sockaddr_alg addr; - bool have_alg = true; algfd = tst_alg_create(); init_sockaddr_alg(&addr, algtype, algname); - TEST(bind(algfd, (const struct sockaddr *)&addr, sizeof(addr))); - if (TST_RET != 0) { - if (TST_ERR != ENOENT) { - tst_brk(TBROK | TTERRNO, - "unexpected error binding AF_ALG socket to %s algorithm '%s'", + ret = bind(algfd, (const struct sockaddr *)&addr, sizeof(addr)); + + if (ret != 0) + retval = errno; + + close(algfd); + return retval; +} + +bool tst_have_alg(const char *algtype, const char *algname) +{ + int ret; + + ret = tst_try_alg(algtype, algname); + + switch (ret) { + case 0: + return true; + case ENOENT: + tst_res(TCONF, "kernel doesn't have %s algorithm '%s'", + algtype, algname); + return false; + case ELIBBAD: + if (tst_fips_enabled()) { + tst_res(TCONF, + "FIPS enabled => %s algorithm '%s' disabled", algtype, algname); + return false; } - have_alg = false; + /* fallthrough */ + default: + errno = ret; + tst_brk(TBROK | TERRNO, + "unexpected error binding AF_ALG socket to %s algorithm '%s'", + algtype, algname); + return false; } - - close(algfd); - return have_alg; } void tst_require_alg(const char *algtype, const char *algname) @@ -96,6 +134,7 @@ void tst_require_alg(const char *algtype, const char *algname) void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen) { + long ret; uint8_t *keybuf = NULL; unsigned int i; @@ -106,9 +145,9 @@ void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen) keybuf[i] = rand(); key = keybuf; } - TEST(setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, keylen)); - if (TST_RET != 0) { - tst_brk(TBROK | TTERRNO, + ret = setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, keylen); + if (ret != 0) { + tst_brk(TBROK | TERRNO, "unexpected error setting key (len=%u)", keylen); } free(keybuf); @@ -116,12 +155,13 @@ void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen) int tst_alg_accept(int algfd) { - TEST(accept(algfd, NULL, NULL)); - if (TST_RET < 0) { - tst_brk(TBROK | TTERRNO, + const long ret = accept(algfd, NULL, NULL); + + if (ret < 0) { + tst_brk(TBROK | TERRNO, "unexpected error accept()ing AF_ALG request socket"); } - return TST_RET; + return ret; } int tst_alg_setup(const char *algtype, const char *algname, @@ -146,3 +186,67 @@ int tst_alg_setup_reqfd(const char *algtype, const char *algname, close(algfd); return reqfd; } + +void tst_alg_sendmsg(int reqfd, const void *data, size_t datalen, + const struct tst_alg_sendmsg_params *params) +{ + struct iovec iov = { + .iov_base = (void *)data, + .iov_len = datalen, + }; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_flags = params->msg_flags, + }; + size_t controllen; + uint8_t *control; + struct cmsghdr *cmsg; + struct af_alg_iv *alg_iv; + + if (params->encrypt && params->decrypt) + tst_brk(TBROK, "Both encrypt and decrypt are specified"); + + controllen = 0; + if (params->encrypt || params->decrypt) + controllen += CMSG_SPACE(sizeof(uint32_t)); + if (params->ivlen) + controllen += CMSG_SPACE(sizeof(struct af_alg_iv) + + params->ivlen); + if (params->assoclen) + controllen += CMSG_SPACE(sizeof(uint32_t)); + + control = SAFE_MALLOC(controllen); + memset(control, 0, controllen); + msg.msg_control = control; + msg.msg_controllen = controllen; + cmsg = CMSG_FIRSTHDR(&msg); + + if (params->encrypt || params->decrypt) { + cmsg->cmsg_level = SOL_ALG; + cmsg->cmsg_type = ALG_SET_OP; + cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t)); + *(uint32_t *)CMSG_DATA(cmsg) = + params->encrypt ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT; + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + if (params->ivlen) { + cmsg->cmsg_level = SOL_ALG; + cmsg->cmsg_type = ALG_SET_IV; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct af_alg_iv) + + params->ivlen); + alg_iv = (struct af_alg_iv *)CMSG_DATA(cmsg); + alg_iv->ivlen = params->ivlen; + memcpy(alg_iv->iv, params->iv, params->ivlen); + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + if (params->assoclen) { + cmsg->cmsg_level = SOL_ALG; + cmsg->cmsg_type = ALG_SET_AEAD_ASSOCLEN; + cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t)); + *(uint32_t *)CMSG_DATA(cmsg) = params->assoclen; + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + + SAFE_SENDMSG(datalen, reqfd, &msg, 0); +} diff --git a/lib/tst_ansi_color.c b/lib/tst_ansi_color.c old mode 100644 new mode 100755 diff --git a/lib/tst_arch.c b/lib/tst_arch.c new file mode 100755 index 0000000000000000000000000000000000000000..acae1c3faccb2bbc973097122b18d632b751fb42 --- /dev/null +++ b/lib/tst_arch.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2021 Li Wang + */ + +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_arch.h" +#include "tst_test.h" + +const struct tst_arch tst_arch = { +#if defined(__x86_64__) + .name = "x86_64", + .type = TST_X86_64, +#elif defined(__i386__) || defined(__i586__) || defined(__i686__) + .name = "x86", + .type = TST_X86, +#elif defined(__ia64__) + .name = "ia64", + .type = TST_IA64, +#elif defined(__powerpc64__) || defined(__ppc64__) + .name = "ppc64", + .type = TST_PPC64, +#elif defined(__powerpc__) || defined(__ppc__) + .name = "ppc", + .type = TST_PPC, +#elif defined(__s390x__) + .name = "s390x", + .type = TST_S390X, +#elif defined(__s390__) + .name = "s390", + .type = TST_S390, +#elif defined(__aarch64__) + .name = "aarch64", + .type = TST_AARCH64, +#elif defined(__arm__) + .name = "arm", + .type = TST_ARM, +#elif defined(__sparc__) + .name = "sparc", + .type = TST_SPARC, +#else + .name = "unknown", + .type = TST_UNKNOWN, +#endif +}; + +static const char *const arch_type_list[] = { + "x86", + "x86_64", + "ia64", + "ppc", + "ppc64", + "s390", + "s390x", + "arm", + "aarch64", + "sparc", + NULL +}; + +static int is_valid_arch_name(const char *name) +{ + unsigned int i; + + for (i = 0; arch_type_list[i]; i++) { + if (!strcmp(arch_type_list[i], name)) + return 1; + } + + return 0; +} + +int tst_is_on_arch(const char *const *archlist) +{ + unsigned int i; + + if (!archlist) + return 1; + + for (i = 0; archlist[i]; i++) { + if (!is_valid_arch_name(archlist[i])) + tst_brk(TBROK, "%s is invalid arch, please reset!", + archlist[i]); + } + + for (i = 0; archlist[i]; i++) { + if (!strcmp(tst_arch.name, archlist[i])) + return 1; + } + + return 0; +} diff --git a/lib/tst_assert.c b/lib/tst_assert.c old mode 100644 new mode 100755 index c7908f64f009cbc8fecf3449fe511be26a73b1c1..9b8ebc167e2dd2eaebd049140559886d66d465a1 --- a/lib/tst_assert.c +++ b/lib/tst_assert.c @@ -23,6 +23,20 @@ void tst_assert_int(const char *file, const int lineno, const char *path, int va tst_res_(file, lineno, TFAIL, "%s != %d got %d", path, val, sys_val); } +void tst_assert_ulong(const char *file, const int lineno, const char *path, unsigned long val) +{ + unsigned long sys_val; + + safe_file_scanf(file, lineno, NULL, path, "%lu", &sys_val); + + if (val == sys_val) { + tst_res_(file, lineno, TPASS, "%s = %lu", path, val); + return; + } + + tst_res_(file, lineno, TFAIL, "%s != %lu got %lu", path, val, sys_val); +} + void tst_assert_file_int(const char *file, const int lineno, const char *path, const char *prefix, int val) { int sys_val; diff --git a/lib/tst_bool_expr.c b/lib/tst_bool_expr.c new file mode 100755 index 0000000000000000000000000000000000000000..15825e3647a5f270d24941f469a54eaf7e1872cc --- /dev/null +++ b/lib/tst_bool_expr.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + */ +/* + * Boolean expression is evaluated in three steps. + * + * First of all the string containing the expression is tokenized. The + * tokenizer runs twice and we only count number of tokens in the first pass in + * order to simplify the memory allocation. + * + * Secondly the the expression is transformed to a postfix (RPN) notation by + * the shunting yard algorithm and the correctness of the expression is checked + * during the transformation as well. The fact that parenthesis are matched is + * asserted by the shunting yard algorithm itself while the rest is checked + * simply by checking if the preceding token is in a set of allowed tokens. + * This could be thought of as a simple open-coded state machine. + * + * An expression in the RPN form can be evaluated given a variable mapping + * function. The evaluation ignores most of errors because invalid expression + * will be rejected in the second step. + */ + +#include +#include +#include +#include "tst_bool_expr.h" + +static int char_to_op(char c) +{ + switch (c) { + case '(': + return TST_OP_LPAR; + case ')': + return TST_OP_RPAR; + case '&': + return TST_OP_AND; + case '|': + return TST_OP_OR; + case '!': + return TST_OP_NOT; + default: + return TST_OP_VAR; + } +} + +static int new_tok(struct tst_expr_tok **last, const char *tok, size_t tok_len) +{ + if (!tok_len) + return 0; + + if (!(*last)) + return 1; + + (*last)->tok = tok; + (*last)->tok_len = tok_len; + (*last)->op = char_to_op(tok[0]); + (*last)->priv = NULL; + (*last)++; + + return 1; +} + +static unsigned int tokenize(const char *expr, struct tst_expr_tok *last) +{ + size_t i, j; + unsigned int token_cnt = 0; + + for (j = i = 0; expr[i]; i++) { + switch (expr[i]) { + case '(': + case ')': + case '!': + case '&': + case '|': + token_cnt += new_tok(&last, &expr[j], i - j); + token_cnt += new_tok(&last, &expr[i], 1); + j = i+1; + break; + case '\t': + case ' ': + token_cnt += new_tok(&last, &expr[j], i - j); + j = i+1; + break; + case '"': + while (expr[i+1] != '"' && expr[i+1]) + i++; + + if (expr[i+1] == '"') + i++; + break; + default: + break; + } + } + + token_cnt += new_tok(&last, &expr[j], i - j); + + return token_cnt; +} + +void tst_bool_expr_print(FILE *f, struct tst_expr *expr) +{ + struct tst_expr_tok *i; + size_t j; + + for (i = expr->rpn; i; i = i->next) { + for (j = 0; j < i->tok_len; j++) + putc(i->tok[j], f); + + if (i->next) + putc(' ', f); + } +} + +static void print_spaces(FILE *f, unsigned int spaces) +{ + while (spaces--) + putc(' ', f); +} + +static void tst_bool_expr_err(FILE *f, struct tst_expr *expr, unsigned int cnt) +{ + unsigned int i, spaces, err_len; + const char *err; + + fprintf(f, "%s", expr->buf->tok); + fprintf(f, "\n"); + + for (i = 0; i < cnt; i++) { + if (expr->buf[i].priv) + break; + } + + spaces = expr->buf[i].tok - expr->buf[0].tok; + err = expr->buf[i].priv; + err_len = strlen(err); + + print_spaces(f, spaces); + + fprintf(f, "^\n"); + + if (err_len < spaces) + print_spaces(f, spaces - err_len + 1); + + fprintf(f, "%s\n", err); +} + +static inline void stack_push(struct tst_expr_tok *stack[], unsigned int *op_stack_pos, + struct tst_expr_tok *op) +{ + stack[(*op_stack_pos)++] = op; +} + +static inline int stack_empty(unsigned int op_stack_pos) +{ + return op_stack_pos == 0; +} + +static inline struct tst_expr_tok *stack_pop(struct tst_expr_tok *stack[], + unsigned int *op_stack_pos) +{ + if (stack_empty(*op_stack_pos)) + return NULL; + + return stack[--(*op_stack_pos)]; +} + +#define TST_OP_NONE -1 + +static inline int stack_peek_op(struct tst_expr_tok *stack[], + unsigned int op_stack_pos) +{ + if (stack_empty(op_stack_pos)) + return TST_OP_NONE; + + return stack[op_stack_pos - 1]->op; +} + +/* + * This is a complete list of which tokens can happen before any of: + * - variable + * - left parentesis + * - negation + * + * The -1 represents start of the expression. + */ +static inline int check_one(int op) +{ + switch (op) { + case TST_OP_AND: + case TST_OP_OR: + case TST_OP_NOT: + case TST_OP_NONE: + case TST_OP_LPAR: + return 0; + default: + return 1; + } +} + +/* + * And this checks for tokens that can happen before any of: + * - right parentesis + * - and + * - or + * + * This is also used to check that the last token in expression is correct one. + */ +static inline int check_two(int op) +{ + switch (op) { + case TST_OP_VAR: + case TST_OP_RPAR: + return 1; + default: + return 0; + } +} + +static int shunting_yard(struct tst_expr *expr, unsigned int cnt) +{ + struct tst_expr_tok *op_stack[cnt]; + unsigned int op_stack_pos = 0; + struct tst_expr_tok *out[cnt + 1]; + unsigned int out_pos = 0; + struct tst_expr_tok *i; + unsigned int j; + int prev_op = TST_OP_NONE; + + for (i = expr->buf; i < &(expr->buf[cnt]); i++) { + switch (i->op) { + case TST_OP_VAR: + if (check_one(prev_op)) { + i->priv = "Expected operation"; + goto err; + } + + stack_push(out, &out_pos, i); + + while (stack_peek_op(op_stack, op_stack_pos) == TST_OP_NOT) + stack_push(out, &out_pos, stack_pop(op_stack, &op_stack_pos)); + break; + case TST_OP_LPAR: + if (check_one(prev_op)) { + i->priv = "Expected operation"; + goto err; + } + + stack_push(op_stack, &op_stack_pos, i); + break; + case TST_OP_RPAR: + if (!check_two(prev_op)) { + i->priv = "Expected variable or )"; + goto err; + } + + /* pop everything till ( */ + for (;;) { + struct tst_expr_tok *op = stack_pop(op_stack, &op_stack_pos); + + if (!op) { + i->priv = "Missing ("; + goto err; + } + + if (op->op == TST_OP_LPAR) + break; + + stack_push(out, &out_pos, op); + } + + while (stack_peek_op(op_stack, op_stack_pos) == TST_OP_NOT) + stack_push(out, &out_pos, stack_pop(op_stack, &op_stack_pos)); + break; + case TST_OP_NOT: + if (check_one(prev_op)) { + i->priv = "Expected operation"; + goto err; + } + stack_push(op_stack, &op_stack_pos, i); + break; + case TST_OP_AND: + case TST_OP_OR: + if (!check_two(prev_op)) { + i->priv = "Expected variable or ("; + goto err; + } + + /* + * There can be at most one binary op on the stack + * since we pop the one present on the stack before we + * attempt to push new one they so never accumulate. + */ + switch (stack_peek_op(op_stack, op_stack_pos)) { + case TST_OP_AND: + case TST_OP_OR: + stack_push(out, &out_pos, stack_pop(op_stack, &op_stack_pos)); + break; + } + + stack_push(op_stack, &op_stack_pos, i); + break; + } + + prev_op = i->op; + } + + if (!check_two(expr->buf[cnt-1].op)) { + expr->buf[cnt-1].priv = "Unfinished expression"; + goto err; + } + + /* pop remaining operations */ + while ((i = stack_pop(op_stack, &op_stack_pos))) { + if (i->op == TST_OP_LPAR) { + i->priv = "Missing )"; + goto err; + } + + stack_push(out, &out_pos, i); + } + + /* construct the list */ + out[out_pos] = NULL; + + for (j = 0; j < out_pos; j++) + out[j]->next = out[j + 1]; + + expr->rpn = out[0]; + + return 0; +err: + return 1; +} + +struct tst_expr *tst_bool_expr_parse(const char *expr) +{ + struct tst_expr *ret; + unsigned int tok_cnt = tokenize(expr, NULL); + + if (!tok_cnt) + return NULL; + + ret = malloc(sizeof(struct tst_expr) + sizeof(struct tst_expr_tok) * tok_cnt); + if (!ret) + return NULL; + + tokenize(expr, ret->buf); + + if (shunting_yard(ret, tok_cnt)) { + tst_bool_expr_err(stderr, ret, tok_cnt); + tst_bool_expr_free(ret); + return NULL; + } + + return ret; +} + +#define MAX_STACK 16 + +int tst_bool_expr_eval(struct tst_expr *expr, + int (*map)(struct tst_expr_tok *var)) +{ + struct tst_expr_tok *i; + int stack[MAX_STACK]; + int pos = -1; + + for (i = expr->rpn; i; i = i->next) { + switch (i->op) { + case TST_OP_NOT: + stack[pos] = !stack[pos]; + break; + case TST_OP_OR: + stack[pos-1] = stack[pos] || stack[pos-1]; + pos--; + break; + case TST_OP_AND: + stack[pos-1] = stack[pos] && stack[pos-1]; + pos--; + break; + case TST_OP_VAR: + if (pos + 1 >= MAX_STACK) { + fprintf(stderr, "Eval out of stack!\n"); + return -1; + } + + stack[++pos] = map(i); + + /* map reported undefined variable -> abort */ + if (stack[pos] == -1) + return -1; + break; + /* does not happen */ + default: + break; + } + } + + return stack[0]; +} + +void tst_bool_expr_free(struct tst_expr *expr) +{ + free(expr); +} diff --git a/lib/tst_buffers.c b/lib/tst_buffers.c old mode 100644 new mode 100755 diff --git a/lib/tst_capability.c b/lib/tst_capability.c old mode 100644 new mode 100755 index 1fa0e49c574be7db4266b00798f1bf10e4f380bc..cb0502e2ec4dcb7cfb9a643c0af0aeaaab9a9031 --- a/lib/tst_capability.c +++ b/lib/tst_capability.c @@ -57,7 +57,7 @@ void tst_cap_action(struct tst_cap *cap) uint32_t mask = CAP_TO_MASK(cap->id); if (tst_capget(&hdr, cur)) - tst_brk(TBROK | TTERRNO, "tst_capget()"); + tst_brk(TBROK | TERRNO, "tst_capget()"); memcpy(new, cur, sizeof(new)); diff --git a/lib/tst_cgroup.c b/lib/tst_cgroup.c new file mode 100755 index 0000000000000000000000000000000000000000..2ef599d9ef189e6fa2c6945a5e12edb38936f174 --- /dev/null +++ b/lib/tst_cgroup.c @@ -0,0 +1,1208 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Red Hat, Inc. + * Copyright (c) 2020 Li Wang + * Copyright (c) 2020-2021 SUSE LLC + */ + +#define TST_NO_DEFAULT_MAIN + +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "lapi/fcntl.h" +#include "lapi/mount.h" +#include "lapi/mkdirat.h" +#include "tst_safe_file_at.h" +#include "tst_cgroup.h" + +struct cgroup_root; + +/* A node in a single CGroup hierarchy. It exists mainly for + * convenience so that we do not have to traverse the CGroup structure + * for frequent operations. + * + * This is actually a single-linked list not a tree. We only need to + * traverse from leaf towards root. + */ +struct cgroup_dir { + const char *dir_name; + const struct cgroup_dir *dir_parent; + + /* Shortcut to root */ + const struct cgroup_root *dir_root; + + /* Subsystems (controllers) bit field. Only controllers which + * were required and configured for this node are added to + * this field. So it may be different from root->css_field. + */ + uint32_t ctrl_field; + + /* In general we avoid having sprintfs everywhere and use + * openat, linkat, etc. + */ + int dir_fd; + + int we_created_it:1; +}; + +/* The root of a CGroup hierarchy/tree */ +struct cgroup_root { + enum tst_cgroup_ver ver; + /* A mount path */ + char mnt_path[PATH_MAX]; + /* Subsystems (controllers) bit field. Includes all + * controllers found while scanning this root. + */ + uint32_t ctrl_field; + + /* CGroup hierarchy: mnt -> ltp -> {drain, test -> ??? } We + * keep a flat reference to ltp, drain and test for + * convenience. + */ + + /* Mount directory */ + struct cgroup_dir mnt_dir; + /* LTP CGroup directory, contains drain and test dirs */ + struct cgroup_dir ltp_dir; + /* Drain CGroup, see cgroup_cleanup */ + struct cgroup_dir drain_dir; + /* CGroup for current test. Which may have children. */ + struct cgroup_dir test_dir; + + int we_mounted_it:1; + /* cpuset is in compatability mode */ + int no_cpuset_prefix:1; +}; + +/* Controller sub-systems */ +enum cgroup_ctrl_indx { + CTRL_MEMORY = 1, + CTRL_CPU, + CTRL_CPUSET, +}; +#define CTRLS_MAX CTRL_CPUSET + +/* At most we can have one cgroup V1 tree for each controller and one + * (empty) v2 tree. + */ +#define ROOTS_MAX (CTRLS_MAX + 1) + +/* Describes a controller file or knob + * + * The primary purpose of this is to map V2 names to V1 + * names. + */ +struct cgroup_file { + /* Canonical name. Is the V2 name unless an item is V1 only */ + const char *const file_name; + /* V1 name or NULL if item is V2 only */ + const char *const file_name_v1; + + /* The controller this item belongs to or zero for + * 'cgroup.'. + */ + const enum cgroup_ctrl_indx ctrl_indx; +}; + +/* Describes a Controller or subsystem + * + * Internally the kernel seems to call controllers subsystems and uses + * the abbreviations subsys and css. + */ +struct cgroup_ctrl { + /* Userland name of the controller (e.g. 'memory' not 'memcg') */ + const char *const ctrl_name; + /* List of files belonging to this controller */ + const struct cgroup_file *const files; + /* Our index for the controller */ + const enum cgroup_ctrl_indx ctrl_indx; + + /* Runtime; hierarchy the controller is attached to */ + struct cgroup_root *ctrl_root; + /* Runtime; whether we required the controller */ + int we_require_it:1; +}; + +struct tst_cgroup_group { + char group_name[NAME_MAX + 1]; + /* Maps controller ID to the tree which contains it. The V2 + * tree is at zero even if it contains no controllers. + */ + struct cgroup_dir *dirs_by_ctrl[ROOTS_MAX]; + /* NULL terminated list of trees */ + struct cgroup_dir *dirs[ROOTS_MAX + 1]; +}; + +/* Always use first item for unified hierarchy */ +static struct cgroup_root roots[ROOTS_MAX + 1]; + +static const struct cgroup_file cgroup_ctrl_files[] = { + /* procs exists on V1, however it was read-only until kernel v3.0. */ + { "cgroup.procs", "tasks", 0 }, + { "cgroup.controllers", NULL, 0 }, + { "cgroup.subtree_control", NULL, 0 }, + { "cgroup.clone_children", "cgroup.clone_children", 0 }, + { } +}; + +static const struct cgroup_file memory_ctrl_files[] = { + { "memory.current", "memory.usage_in_bytes", CTRL_MEMORY }, + { "memory.max", "memory.limit_in_bytes", CTRL_MEMORY }, + { "memory.stat", "memory.stat", CTRL_MEMORY }, + { "memory.swappiness", "memory.swappiness", CTRL_MEMORY }, + { "memory.swap.current", "memory.memsw.usage_in_bytes", CTRL_MEMORY }, + { "memory.swap.max", "memory.memsw.limit_in_bytes", CTRL_MEMORY }, + { "memory.kmem.usage_in_bytes", "memory.kmem.usage_in_bytes", CTRL_MEMORY }, + { "memory.kmem.limit_in_bytes", "memory.kmem.limit_in_bytes", CTRL_MEMORY }, + { } +}; + +static const struct cgroup_file cpu_ctrl_files[] = { + /* The V1 quota and period files were combined in the V2 max + * file. The quota is in the first column and if we just print + * a single value to the file, it will be treated as the + * quota. To get or set the period we need to branch on the + * API version. + */ + { "cpu.max", "cpu.cfs_quota_us", CTRL_CPU }, + { "cpu.cfs_period_us", "cpu.cfs_period_us", CTRL_CPU }, + { } +}; + +static const struct cgroup_file cpuset_ctrl_files[] = { + { "cpuset.cpus", "cpuset.cpus", CTRL_CPUSET }, + { "cpuset.mems", "cpuset.mems", CTRL_CPUSET }, + { "cpuset.memory_migrate", "cpuset.memory_migrate", CTRL_CPUSET }, + { } +}; + +/* Lookup tree for item names. */ +static struct cgroup_ctrl controllers[] = { + [0] = { "cgroup", cgroup_ctrl_files, 0, NULL, 0 }, + [CTRL_MEMORY] = { + "memory", memory_ctrl_files, CTRL_MEMORY, NULL, 0 + }, + [CTRL_CPU] = { + "cpu", cpu_ctrl_files, CTRL_CPU, NULL, 0 + }, + [CTRL_CPUSET] = { + "cpuset", cpuset_ctrl_files, CTRL_CPUSET, NULL, 0 + }, + { } +}; + +static const struct tst_cgroup_opts default_opts = { 0 }; + +/* We should probably allow these to be set in environment + * variables + */ +static const char *cgroup_ltp_dir = "ltp"; +static const char *cgroup_ltp_drain_dir = "drain"; +static char cgroup_test_dir[NAME_MAX + 1]; +static const char *cgroup_mount_ltp_prefix = "/tmp/cgroup_"; +static const char *cgroup_v2_ltp_mount = "unified"; + +#define first_root \ + (roots[0].ver ? roots : roots + 1) +#define for_each_root(r) \ + for ((r) = first_root; (r)->ver; (r)++) +#define for_each_v1_root(r) \ + for ((r) = roots + 1; (r)->ver; (r)++) +#define for_each_ctrl(ctrl) \ + for ((ctrl) = controllers + 1; (ctrl)->ctrl_name; (ctrl)++) + +/* In all cases except one, this only loops once. + * + * If (ctrl) == 0 and multiple V1 (and a V2) hierarchies are mounted, + * then we need to loop over multiple directories. For example if we + * need to write to "tasks"/"cgroup.procs" which exists for each + * hierarchy. + */ +#define for_each_dir(cg, ctrl, t) \ + for ((t) = (ctrl) ? (cg)->dirs_by_ctrl + (ctrl) : (cg)->dirs; \ + *(t); \ + (t) = (ctrl) ? (cg)->dirs + ROOTS_MAX : (t) + 1) + +__attribute__ ((nonnull)) +static int has_ctrl(const uint32_t ctrl_field, + const struct cgroup_ctrl *const ctrl) +{ + return !!(ctrl_field & (1 << ctrl->ctrl_indx)); +} + +__attribute__ ((nonnull)) +static void add_ctrl(uint32_t *const ctrl_field, + const struct cgroup_ctrl *const ctrl) +{ + *ctrl_field |= 1 << ctrl->ctrl_indx; +} + +static int cgroup_v2_mounted(void) +{ + return !!roots[0].ver; +} + +static int cgroup_v1_mounted(void) +{ + return !!roots[1].ver; +} + +static int cgroup_mounted(void) +{ + return cgroup_v2_mounted() || cgroup_v1_mounted(); +} + +__attribute__ ((nonnull, warn_unused_result)) +static int cgroup_ctrl_on_v2(const struct cgroup_ctrl *const ctrl) +{ + return ctrl->ctrl_root && ctrl->ctrl_root->ver == TST_CGROUP_V2; +} + +__attribute__ ((nonnull)) +static void cgroup_dir_mk(const struct cgroup_dir *const parent, + const char *const dir_name, + struct cgroup_dir *const new) +{ + const char *dpath; + + new->dir_root = parent->dir_root; + new->dir_name = dir_name; + new->dir_parent = parent; + new->ctrl_field = parent->ctrl_field; + new->we_created_it = 0; + + if (!mkdirat(parent->dir_fd, dir_name, 0777)) { + new->we_created_it = 1; + goto opendir; + } + + if (errno == EEXIST) + goto opendir; + + dpath = tst_decode_fd(parent->dir_fd); + + if (errno == EACCES) { + tst_brk(TCONF | TERRNO, + "Lack permission to make '%s/%s'; premake it or run as root", + dpath, dir_name); + } else { + tst_brk(TBROK | TERRNO, + "mkdirat(%d<%s>, '%s', 0777)", + parent->dir_fd, dpath, dir_name); + } + +opendir: + new->dir_fd = SAFE_OPENAT(parent->dir_fd, dir_name, + O_PATH | O_DIRECTORY); +} + +void tst_cgroup_print_config(void) +{ + struct cgroup_root *root; + const struct cgroup_ctrl *ctrl; + + tst_res(TINFO, "Detected Controllers:"); + + for_each_ctrl(ctrl) { + root = ctrl->ctrl_root; + + if (!root) + continue; + + tst_res(TINFO, "\t%.10s %s @ %s:%s", + ctrl->ctrl_name, + root->no_cpuset_prefix ? "[noprefix]" : "", + root->ver == TST_CGROUP_V1 ? "V1" : "V2", + root->mnt_path); + } +} + +__attribute__ ((nonnull, warn_unused_result)) +static struct cgroup_ctrl *cgroup_find_ctrl(const char *const ctrl_name) +{ + struct cgroup_ctrl *ctrl = controllers; + + while (ctrl->ctrl_name && strcmp(ctrl_name, ctrl->ctrl_name)) + ctrl++; + + if (!ctrl->ctrl_name) + ctrl = NULL; + + return ctrl; +} + +/* Determine if a mounted cgroup hierarchy is unique and record it if so. + * + * For CGroups V2 this is very simple as there is only one + * hierarchy. We just record which controllers are available and check + * if this matches what we read from any previous mount points. + * + * For V1 the set of controllers S is partitioned into sets {P_1, P_2, + * ..., P_n} with one or more controllers in each partion. Each + * partition P_n can be mounted multiple times, but the same + * controller can not appear in more than one partition. Usually each + * partition contains a single controller, but, for example, cpu and + * cpuacct are often mounted together in the same partiion. + * + * Each controller partition has its own hierarchy (root) which we + * must track and update independently. + */ +__attribute__ ((nonnull)) +static void cgroup_root_scan(const char *const mnt_type, + const char *const mnt_dir, + char *const mnt_opts) +{ + struct cgroup_root *root = roots; + const struct cgroup_ctrl *const_ctrl; + struct cgroup_ctrl *ctrl; + uint32_t ctrl_field = 0; + int no_prefix = 0; + char buf[BUFSIZ]; + char *tok; + const int mnt_dfd = SAFE_OPEN(mnt_dir, O_PATH | O_DIRECTORY); + + if (!strcmp(mnt_type, "cgroup")) + goto v1; + + SAFE_FILE_READAT(mnt_dfd, "cgroup.controllers", buf, sizeof(buf)); + + for (tok = strtok(buf, " "); tok; tok = strtok(NULL, " ")) { + const_ctrl = cgroup_find_ctrl(tok); + if (const_ctrl) + add_ctrl(&ctrl_field, const_ctrl); + } + + if (root->ver && ctrl_field == root->ctrl_field) + goto discard; + + if (root->ctrl_field) + tst_brk(TBROK, "Available V2 controllers are changing between scans?"); + + root->ver = TST_CGROUP_V2; + + goto backref; + +v1: + for (tok = strtok(mnt_opts, ","); tok; tok = strtok(NULL, ",")) { + const_ctrl = cgroup_find_ctrl(tok); + if (const_ctrl) + add_ctrl(&ctrl_field, const_ctrl); + + no_prefix |= !strcmp("noprefix", tok); + } + + if (!ctrl_field) + goto discard; + + for_each_v1_root(root) { + if (!(ctrl_field & root->ctrl_field)) + continue; + + if (ctrl_field == root->ctrl_field) + goto discard; + + tst_brk(TBROK, + "The intersection of two distinct sets of mounted controllers should be null? " + "Check '%s' and '%s'", root->mnt_path, mnt_dir); + } + + if (root >= roots + ROOTS_MAX) { + tst_brk(TBROK, + "Unique controller mounts have exceeded our limit %d?", + ROOTS_MAX); + } + + root->ver = TST_CGROUP_V1; + +backref: + strcpy(root->mnt_path, mnt_dir); + root->mnt_dir.dir_root = root; + root->mnt_dir.dir_name = root->mnt_path; + root->mnt_dir.dir_fd = mnt_dfd; + root->ctrl_field = ctrl_field; + root->no_cpuset_prefix = no_prefix; + + for_each_ctrl(ctrl) { + if (has_ctrl(root->ctrl_field, ctrl)) + ctrl->ctrl_root = root; + } + + return; + +discard: + close(mnt_dfd); +} + +void tst_cgroup_scan(void) +{ + struct mntent *mnt; + FILE *f = setmntent("/proc/self/mounts", "r"); + + if (!f) { + tst_brk(TBROK | TERRNO, "Can't open /proc/self/mounts"); + return; + } + + mnt = getmntent(f); + if (!mnt) { + tst_brk(TBROK | TERRNO, "Can't read mounts or no mounts?"); + return; + } + + do { + if (strncmp(mnt->mnt_type, "cgroup", 6)) + continue; + + cgroup_root_scan(mnt->mnt_type, mnt->mnt_dir, mnt->mnt_opts); + } while ((mnt = getmntent(f))); +} + +static void cgroup_mount_v2(void) +{ + char mnt_path[PATH_MAX]; + + sprintf(mnt_path, "%s%s", cgroup_mount_ltp_prefix, cgroup_v2_ltp_mount); + + if (!mkdir(mnt_path, 0777)) { + roots[0].mnt_dir.we_created_it = 1; + goto mount; + } + + if (errno == EEXIST) + goto mount; + + if (errno == EACCES) { + tst_res(TINFO | TERRNO, + "Lack permission to make %s, premake it or run as root", + mnt_path); + return; + } + + tst_brk(TBROK | TERRNO, "mkdir(%s, 0777)", mnt_path); + return; + +mount: + if (!mount("cgroup2", mnt_path, "cgroup2", 0, NULL)) { + tst_res(TINFO, "Mounted V2 CGroups on %s", mnt_path); + tst_cgroup_scan(); + roots[0].we_mounted_it = 1; + return; + } + + tst_res(TINFO | TERRNO, "Could not mount V2 CGroups on %s", mnt_path); + + if (roots[0].mnt_dir.we_created_it) { + roots[0].mnt_dir.we_created_it = 0; + SAFE_RMDIR(mnt_path); + } +} + +__attribute__ ((nonnull)) +static void cgroup_mount_v1(struct cgroup_ctrl *const ctrl) +{ + char mnt_path[PATH_MAX]; + int made_dir = 0; + + sprintf(mnt_path, "%s%s", cgroup_mount_ltp_prefix, ctrl->ctrl_name); + + if (!mkdir(mnt_path, 0777)) { + made_dir = 1; + goto mount; + } + + if (errno == EEXIST) + goto mount; + + if (errno == EACCES) { + tst_res(TINFO | TERRNO, + "Lack permission to make %s, premake it or run as root", + mnt_path); + return; + } + + tst_brk(TBROK | TERRNO, "mkdir(%s, 0777)", mnt_path); + return; + +mount: + if (mount(ctrl->ctrl_name, mnt_path, "cgroup", 0, ctrl->ctrl_name)) { + tst_res(TINFO | TERRNO, + "Could not mount V1 CGroup on %s", mnt_path); + + if (made_dir) + SAFE_RMDIR(mnt_path); + return; + } + + tst_res(TINFO, "Mounted V1 %s CGroup on %s", ctrl->ctrl_name, mnt_path); + tst_cgroup_scan(); + if (!ctrl->ctrl_root) + return; + + ctrl->ctrl_root->we_mounted_it = 1; + ctrl->ctrl_root->mnt_dir.we_created_it = made_dir; + + if (ctrl->ctrl_indx == CTRL_MEMORY) { + SAFE_FILE_PRINTFAT(ctrl->ctrl_root->mnt_dir.dir_fd, + "memory.use_hierarchy", "%d", 1); + } +} + +__attribute__ ((nonnull)) +static void cgroup_copy_cpuset(const struct cgroup_root *const root) +{ + char knob_val[BUFSIZ]; + int i; + const char *const n0[] = {"mems", "cpus"}; + const char *const n1[] = {"cpuset.mems", "cpuset.cpus"}; + const char *const *const fname = root->no_cpuset_prefix ? n0 : n1; + + for (i = 0; i < 2; i++) { + SAFE_FILE_READAT(root->mnt_dir.dir_fd, + fname[i], knob_val, sizeof(knob_val)); + SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd, + fname[i], "%s", knob_val); + } +} + +/* Ensure the specified controller is available. + * + * First we check if the specified controller has a known mount point, + * if not then we scan the system. If we find it then we goto ensuring + * the LTP group exists in the hierarchy the controller is using. + * + * If we can't find the controller, then we try to create it. First we + * check if the V2 hierarchy/tree is mounted. If it isn't then we try + * mounting it and look for the controller. If it is already mounted + * then we know the controller is not available on V2 on this system. + * + * If we can't mount V2 or the controller is not on V2, then we try + * mounting it on its own V1 tree. + * + * Once we have mounted the controller somehow, we create a hierarchy + * of cgroups. If we are on V2 we first need to enable the controller + * for all children of root. Then we create hierarchy described in + * tst_cgroup.h. + * + * If we are using V1 cpuset then we copy the available mems and cpus + * from root to the ltp group and set clone_children on the ltp group + * to distribute these settings to the test cgroups. This means the + * test author does not have to copy these settings before using the + * cpuset. + * + */ +void tst_cgroup_require(const char *const ctrl_name, + const struct tst_cgroup_opts *options) +{ + const char *const cgsc = "cgroup.subtree_control"; + struct cgroup_ctrl *const ctrl = cgroup_find_ctrl(ctrl_name); + struct cgroup_root *root; + + if (!ctrl) { + tst_brk(TBROK, "'%s' controller is unknown to LTP", ctrl_name); + tst_brk(TBROK, "Calling %s in cleanup?", __func__); + return; + } + + if (!options) + options = &default_opts; + + if (ctrl->we_require_it) + tst_res(TWARN, "Duplicate %s(%s, )", __func__, ctrl->ctrl_name); + + ctrl->we_require_it = 1; + + if (ctrl->ctrl_root) + goto mkdirs; + + tst_cgroup_scan(); + + if (ctrl->ctrl_root) + goto mkdirs; + + if (!cgroup_v2_mounted() && !options->only_mount_v1) + cgroup_mount_v2(); + + if (ctrl->ctrl_root) + goto mkdirs; + + cgroup_mount_v1(ctrl); + + if (!ctrl->ctrl_root) { + tst_brk(TCONF, + "'%s' controller required, but not available", + ctrl->ctrl_name); + return; + } + +mkdirs: + root = ctrl->ctrl_root; + add_ctrl(&root->mnt_dir.ctrl_field, ctrl); + + if (cgroup_ctrl_on_v2(ctrl)) { + if (root->we_mounted_it) { + SAFE_FILE_PRINTFAT(root->mnt_dir.dir_fd, + cgsc, "+%s", ctrl->ctrl_name); + } else { + tst_file_printfat(root->mnt_dir.dir_fd, + cgsc, "+%s", ctrl->ctrl_name); + } + } + + if (!root->ltp_dir.dir_fd) + cgroup_dir_mk(&root->mnt_dir, cgroup_ltp_dir, &root->ltp_dir); + else + root->ltp_dir.ctrl_field |= root->mnt_dir.ctrl_field; + + if (cgroup_ctrl_on_v2(ctrl)) { + SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd, + cgsc, "+%s", ctrl->ctrl_name); + } else { + SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd, + "cgroup.clone_children", "%d", 1); + + if (ctrl->ctrl_indx == CTRL_CPUSET) + cgroup_copy_cpuset(root); + } + + cgroup_dir_mk(&root->ltp_dir, cgroup_ltp_drain_dir, &root->drain_dir); + + sprintf(cgroup_test_dir, "test-%d", getpid()); + cgroup_dir_mk(&root->ltp_dir, cgroup_test_dir, &root->test_dir); +} + +static void cgroup_drain(const enum tst_cgroup_ver ver, + const int source_dfd, const int dest_dfd) +{ + char pid_list[BUFSIZ]; + char *tok; + const char *const file_name = + ver == TST_CGROUP_V1 ? "tasks" : "cgroup.procs"; + int fd; + ssize_t ret; + + ret = SAFE_FILE_READAT(source_dfd, file_name, + pid_list, sizeof(pid_list)); + if (ret < 0) + return; + + fd = SAFE_OPENAT(dest_dfd, file_name, O_WRONLY); + if (fd < 0) + return; + + for (tok = strtok(pid_list, "\n"); tok; tok = strtok(NULL, "\n")) { + ret = dprintf(fd, "%s", tok); + + if (ret < (ssize_t)strlen(tok)) + tst_brk(TBROK | TERRNO, "Failed to drain %s", tok); + } + SAFE_CLOSE(fd); +} + +__attribute__ ((nonnull)) +static void close_path_fds(struct cgroup_root *const root) +{ + if (root->test_dir.dir_fd > 0) + SAFE_CLOSE(root->test_dir.dir_fd); + if (root->ltp_dir.dir_fd > 0) + SAFE_CLOSE(root->ltp_dir.dir_fd); + if (root->drain_dir.dir_fd > 0) + SAFE_CLOSE(root->drain_dir.dir_fd); + if (root->mnt_dir.dir_fd > 0) + SAFE_CLOSE(root->mnt_dir.dir_fd); +} + +/* Maybe remove CGroups used during testing and clear our data + * + * This will never remove CGroups we did not create to allow tests to + * be run in parallel. + * + * Each test process is given its own unique CGroup. Unless we want to + * stress test the CGroup system. We should at least remove these + * unique per test CGroups. + * + * We probably also want to remove the LTP parent CGroup, although + * this may have been created by the system manager or another test + * (see notes on parallel testing). + * + * On systems with no initial CGroup setup we may try to destroy the + * CGroup roots we mounted so that they can be recreated by another + * test. Note that successfully unmounting a CGroup root does not + * necessarily indicate that it was destroyed. + * + * The ltp/drain CGroup is required for cleaning up test CGroups when + * we can not move them to the root CGroup. CGroups can only be + * removed when they have no members and only leaf or root CGroups may + * have processes within them. As test processes create and destroy + * their own CGroups they must move themselves either to root or + * another leaf CGroup. So we move them to drain while destroying the + * unique test CGroup. + * + * If we have access to root and created the LTP CGroup we then move + * the test process to root and destroy the drain and LTP + * CGroups. Otherwise we just leave the test process to die in the + * drain, much like many a unwanted terrapin. + * + * Finally we clear any data we have collected on CGroups. This will + * happen regardless of whether anything was removed. + */ +void tst_cgroup_cleanup(void) +{ + struct cgroup_root *root; + struct cgroup_ctrl *ctrl; + + if (!cgroup_mounted()) + goto clear_data; + + for_each_root(root) { + if (!root->test_dir.dir_name) + continue; + + cgroup_drain(root->ver, + root->test_dir.dir_fd, root->drain_dir.dir_fd); + SAFE_UNLINKAT(root->ltp_dir.dir_fd, root->test_dir.dir_name, + AT_REMOVEDIR); + } + + for_each_root(root) { + if (!root->ltp_dir.we_created_it) + continue; + + cgroup_drain(root->ver, + root->drain_dir.dir_fd, root->mnt_dir.dir_fd); + + if (root->drain_dir.dir_name) { + SAFE_UNLINKAT(root->ltp_dir.dir_fd, + root->drain_dir.dir_name, AT_REMOVEDIR); + } + + if (root->ltp_dir.dir_name) { + SAFE_UNLINKAT(root->mnt_dir.dir_fd, + root->ltp_dir.dir_name, AT_REMOVEDIR); + } + } + + for_each_ctrl(ctrl) { + if (!cgroup_ctrl_on_v2(ctrl) || !ctrl->ctrl_root->we_mounted_it) + continue; + + SAFE_FILE_PRINTFAT(ctrl->ctrl_root->mnt_dir.dir_fd, + "cgroup.subtree_control", + "-%s", ctrl->ctrl_name); + } + + for_each_root(root) { + if (!root->we_mounted_it) + continue; + + /* This probably does not result in the CGroup root + * being destroyed + */ + if (umount2(root->mnt_path, MNT_DETACH)) + continue; + + SAFE_RMDIR(root->mnt_path); + } + +clear_data: + for_each_ctrl(ctrl) { + ctrl->ctrl_root = NULL; + ctrl->we_require_it = 0; + } + + for_each_root(root) + close_path_fds(root); + + memset(roots, 0, sizeof(roots)); +} + +__attribute__((nonnull(1))) +static void cgroup_group_init(struct tst_cgroup_group *const cg, + const char *const group_name) +{ + memset(cg, 0, sizeof(*cg)); + + if (!group_name) + return; + + if (strlen(group_name) > NAME_MAX) + tst_brk(TBROK, "Group name is too long"); + + strcpy(cg->group_name, group_name); +} + +__attribute__((nonnull(2, 3))) +static void cgroup_group_add_dir(const struct tst_cgroup_group *const parent, + struct tst_cgroup_group *const cg, + struct cgroup_dir *const dir) +{ + const struct cgroup_ctrl *ctrl; + int i; + + if (dir->dir_root->ver != TST_CGROUP_V1) + cg->dirs_by_ctrl[0] = dir; + + for_each_ctrl(ctrl) { + if (!has_ctrl(dir->ctrl_field, ctrl)) + continue; + + cg->dirs_by_ctrl[ctrl->ctrl_indx] = dir; + + if (!parent || dir->dir_root->ver == TST_CGROUP_V1) + continue; + + SAFE_CGROUP_PRINTF(parent, "cgroup.subtree_control", + "+%s", ctrl->ctrl_name); + } + + for (i = 0; cg->dirs[i]; i++) + ; + cg->dirs[i] = dir; +} + +struct tst_cgroup_group * +tst_cgroup_group_mk(const struct tst_cgroup_group *const parent, + const char *const group_name) +{ + struct tst_cgroup_group *cg; + struct cgroup_dir *const *dir; + struct cgroup_dir *new_dir; + + cg = SAFE_MALLOC(sizeof(*cg)); + cgroup_group_init(cg, group_name); + + for_each_dir(parent, 0, dir) { + new_dir = SAFE_MALLOC(sizeof(*new_dir)); + cgroup_dir_mk(*dir, group_name, new_dir); + cgroup_group_add_dir(parent, cg, new_dir); + } + + return cg; +} + +const char *tst_cgroup_group_name(const struct tst_cgroup_group *const cg) +{ + return cg->group_name; +} + +struct tst_cgroup_group *tst_cgroup_group_rm(struct tst_cgroup_group *const cg) +{ + struct cgroup_dir **dir; + + for_each_dir(cg, 0, dir) { + close((*dir)->dir_fd); + SAFE_UNLINKAT((*dir)->dir_parent->dir_fd, + (*dir)->dir_name, + AT_REMOVEDIR); + free(*dir); + } + + free(cg); + return NULL; +} + +__attribute__ ((nonnull, warn_unused_result)) +static const struct cgroup_file *cgroup_file_find(const char *const file, + const int lineno, + const char *const file_name) +{ + const struct cgroup_file *cfile; + const struct cgroup_ctrl *ctrl; + char ctrl_name[32]; + const char *const sep = strchr(file_name, '.'); + size_t len; + + if (!sep) { + tst_brk_(file, lineno, TBROK, + "Invalid file name '%s'; did not find controller separator '.'", + file_name); + return NULL; + } + + len = sep - file_name; + memcpy(ctrl_name, file_name, len); + ctrl_name[len] = '\0'; + + ctrl = cgroup_find_ctrl(ctrl_name); + + if (!ctrl) { + tst_brk_(file, lineno, TBROK, + "Did not find controller '%s'\n", ctrl_name); + return NULL; + } + + for (cfile = ctrl->files; cfile->file_name; cfile++) { + if (!strcmp(file_name, cfile->file_name)) + break; + } + + if (!cfile->file_name) { + tst_brk_(file, lineno, TBROK, + "Did not find '%s' in '%s'\n", + file_name, ctrl->ctrl_name); + return NULL; + } + + return cfile; +} + +enum tst_cgroup_ver tst_cgroup_ver(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const ctrl_name) +{ + const struct cgroup_ctrl *const ctrl = cgroup_find_ctrl(ctrl_name); + const struct cgroup_dir *dir; + + if (!strcmp(ctrl_name, "cgroup")) { + tst_brk_(file, lineno, + TBROK, + "cgroup may be present on both V1 and V2 hierarchies"); + return 0; + } + + if (!ctrl) { + tst_brk_(file, lineno, + TBROK, "Unknown controller '%s'", ctrl_name); + return 0; + } + + dir = cg->dirs_by_ctrl[ctrl->ctrl_indx]; + + if (!dir) { + tst_brk_(file, lineno, + TBROK, "%s controller not attached to CGroup %s", + ctrl_name, cg->group_name); + return 0; + } + + return dir->dir_root->ver; +} + +__attribute__ ((nonnull, warn_unused_result)) +static const char *cgroup_file_alias(const struct cgroup_file *const cfile, + const struct cgroup_dir *const dir) +{ + if (dir->dir_root->ver != TST_CGROUP_V1) + return cfile->file_name; + + if (cfile->ctrl_indx == CTRL_CPUSET && + dir->dir_root->no_cpuset_prefix && + cfile->file_name_v1) { + return strchr(cfile->file_name_v1, '.') + 1; + } + + return cfile->file_name_v1; +} + +int safe_cgroup_has(const char *const file, const int lineno, + const struct tst_cgroup_group *cg, + const char *const file_name) +{ + const struct cgroup_file *const cfile = + cgroup_file_find(file, lineno, file_name); + struct cgroup_dir *const *dir; + const char *alias; + + if (!cfile) + return 0; + + for_each_dir(cg, cfile->ctrl_indx, dir) { + alias = cgroup_file_alias(cfile, *dir); + if (!alias) + continue; + + if (!faccessat((*dir)->dir_fd, alias, F_OK, 0)) + return 1; + + if (errno == ENOENT) + continue; + + tst_brk_(file, lineno, TBROK | TERRNO, + "faccessat(%d<%s>, %s, F_OK, 0)", + (*dir)->dir_fd, tst_decode_fd((*dir)->dir_fd), alias); + } + + return 0; +} + +__attribute__ ((warn_unused_result)) +static struct tst_cgroup_group *cgroup_group_from_roots(const size_t tree_off) +{ + struct cgroup_root *root; + struct cgroup_dir *dir; + struct tst_cgroup_group *cg; + + cg = tst_alloc(sizeof(*cg)); + cgroup_group_init(cg, NULL); + + for_each_root(root) { + dir = (typeof(dir))(((char *)root) + tree_off); + + if (dir->ctrl_field) + cgroup_group_add_dir(NULL, cg, dir); + } + + if (cg->dirs[0]) { + strncpy(cg->group_name, cg->dirs[0]->dir_name, NAME_MAX); + return cg; + } + + tst_brk(TBROK, + "No CGroups found; maybe you forgot to call tst_cgroup_require?"); + + return cg; +} + +const struct tst_cgroup_group *tst_cgroup_get_test_group(void) +{ + return cgroup_group_from_roots(offsetof(struct cgroup_root, test_dir)); +} + +const struct tst_cgroup_group *tst_cgroup_get_drain_group(void) +{ + return cgroup_group_from_roots(offsetof(struct cgroup_root, drain_dir)); +} + +ssize_t safe_cgroup_read(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + char *const out, const size_t len) +{ + const struct cgroup_file *const cfile = + cgroup_file_find(file, lineno, file_name); + struct cgroup_dir *const *dir; + const char *alias; + size_t prev_len = 0; + char prev_buf[BUFSIZ]; + ssize_t read_ret = 0; + + for_each_dir(cg, cfile->ctrl_indx, dir) { + alias = cgroup_file_alias(cfile, *dir); + if (!alias) + continue; + + if (prev_len) + memcpy(prev_buf, out, prev_len); + + read_ret = safe_file_readat(file, lineno, + (*dir)->dir_fd, alias, out, len); + if (read_ret < 0) + continue; + + if (prev_len && memcmp(out, prev_buf, prev_len)) { + tst_brk_(file, lineno, TBROK, + "%s has different value across roots", + file_name); + break; + } + + prev_len = MIN(sizeof(prev_buf), (size_t)read_ret); + } + + out[MAX(read_ret, 0)] = '\0'; + + return read_ret; +} + +void safe_cgroup_printf(const char *const file, const int lineno, + const struct tst_cgroup_group *cg, + const char *const file_name, + const char *const fmt, ...) +{ + const struct cgroup_file *const cfile = + cgroup_file_find(file, lineno, file_name); + struct cgroup_dir *const *dir; + const char *alias; + va_list va; + + for_each_dir(cg, cfile->ctrl_indx, dir) { + alias = cgroup_file_alias(cfile, *dir); + if (!alias) + continue; + + va_start(va, fmt); + safe_file_vprintfat(file, lineno, + (*dir)->dir_fd, alias, fmt, va); + va_end(va); + } +} + +void safe_cgroup_scanf(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + const char *const fmt, ...) +{ + va_list va; + char buf[BUFSIZ]; + ssize_t len = safe_cgroup_read(file, lineno, + cg, file_name, buf, sizeof(buf)); + const int conv_cnt = tst_count_scanf_conversions(fmt); + int ret; + + if (len < 1) + return; + + va_start(va, fmt); + ret = vsscanf(buf, fmt, va); + if (ret < 1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "'%s': vsscanf('%s', '%s', ...)", file_name, buf, fmt); + } + va_end(va); + + if (conv_cnt == ret) + return; + + tst_brk_(file, lineno, TBROK, + "'%s': vsscanf('%s', '%s', ..): Less conversions than expected: %d != %d", + file_name, buf, fmt, ret, conv_cnt); +} + +void safe_cgroup_lines_scanf(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + const char *const fmt, ...) +{ + va_list va; + char buf[BUFSIZ]; + ssize_t len = safe_cgroup_read(file, lineno, + cg, file_name, buf, sizeof(buf)); + const int conv_cnt = tst_count_scanf_conversions(fmt); + int ret = 0; + char *line, *buf_ptr; + + if (len < 1) + return; + + line = strtok_r(buf, "\n", &buf_ptr); + while (line && ret != conv_cnt) { + va_start(va, fmt); + ret = vsscanf(line, fmt, va); + va_end(va); + + line = strtok_r(NULL, "\n", &buf_ptr); + } + + if (conv_cnt == ret) + return; + + tst_brk_(file, lineno, TBROK, + "'%s': vsscanf('%s', '%s', ..): Less conversions than expected: %d != %d", + file_name, buf, fmt, ret, conv_cnt); +} + +int safe_cgroup_occursin(const char *const file, const int lineno, + const struct tst_cgroup_group *const cg, + const char *const file_name, + const char *const needle) +{ + char buf[BUFSIZ]; + + safe_cgroup_read(file, lineno, cg, file_name, buf, sizeof(buf)); + + return !!strstr(buf, needle); +} diff --git a/lib/tst_checkpoint.c b/lib/tst_checkpoint.c old mode 100644 new mode 100755 index 5e5b11496cbddaaa5a06a53be3416d391631b065..b41986f0c2d01c273140bfa364ab4d92919dfb91 --- a/lib/tst_checkpoint.c +++ b/lib/tst_checkpoint.c @@ -43,9 +43,8 @@ void tst_checkpoint_init(const char *file, const int lineno, unsigned int page_size; if (tst_futexes) { - tst_brkm(TBROK, cleanup_fn, - "%s: %d checkpoints already initialized", - file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "checkpoints already initialized"); return; } @@ -61,9 +60,9 @@ void tst_checkpoint_init(const char *file, const int lineno, * the init as a first function with NULL as cleanup function. */ if (cleanup_fn && !tst_tmpdir_created()) { - tst_brkm(TBROK, cleanup_fn, - "%s:%d You have to create test temporary directory " - "first (call tst_tmpdir())", file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "You have to create test temporary directory " + "first (call tst_tmpdir())"); return; } @@ -87,6 +86,9 @@ int tst_checkpoint_wait(unsigned int id, unsigned int msec_timeout) struct timespec timeout; int ret; + if (!tst_max_futexes) + tst_brkm(TBROK, NULL, "Set test.needs_checkpoints = 1"); + if (id >= tst_max_futexes) { errno = EOVERFLOW; return -1; @@ -108,6 +110,9 @@ int tst_checkpoint_wake(unsigned int id, unsigned int nr_wake, { unsigned int msecs = 0, waked = 0; + if (!tst_max_futexes) + tst_brkm(TBROK, NULL, "Set test.needs_checkpoints = 1"); + if (id >= tst_max_futexes) { errno = EOVERFLOW; return -1; @@ -144,9 +149,9 @@ void tst_safe_checkpoint_wait(const char *file, const int lineno, ret = tst_checkpoint_wait(id, msec_timeout); if (ret) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: tst_checkpoint_wait(%u, %i)", - file, lineno, id, msec_timeout); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "tst_checkpoint_wait(%u, %i) failed", id, + msec_timeout); } } @@ -157,8 +162,8 @@ void tst_safe_checkpoint_wake(const char *file, const int lineno, int ret = tst_checkpoint_wake(id, nr_wake, DEFAULT_MSEC_TIMEOUT); if (ret) { - tst_brkm(TBROK | TERRNO, cleanup_fn, - "%s:%d: tst_checkpoint_wake(%u, %u, %i)", - file, lineno, id, nr_wake, DEFAULT_MSEC_TIMEOUT); + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "tst_checkpoint_wake(%u, %u, %i) failed", id, nr_wake, + DEFAULT_MSEC_TIMEOUT); } } diff --git a/lib/tst_checksum.c b/lib/tst_checksum.c old mode 100644 new mode 100755 diff --git a/lib/tst_clocks.c b/lib/tst_clocks.c old mode 100644 new mode 100755 index 2eaa73b11abeed9a9bd4de3b139a9e232ab1a556..0417802fc80866106c983f88776577400e55f3eb --- a/lib/tst_clocks.c +++ b/lib/tst_clocks.c @@ -7,23 +7,110 @@ #define TST_NO_DEFAULT_MAIN #include "tst_test.h" +#include "tst_timer.h" #include "tst_clocks.h" #include "lapi/syscalls.h" #include "lapi/posix_clocks.h" +typedef int (*mysyscall)(clockid_t clk_id, void *ts); + +int syscall_supported_by_kernel(long sysnr) +{ + int ret; + + ret = syscall(sysnr, 0, NULL); + if (ret == -1 && errno == ENOSYS) + return 0; + + return 1; +} + int tst_clock_getres(clockid_t clk_id, struct timespec *res) { - return tst_syscall(__NR_clock_getres, clk_id, res); + static struct tst_ts tts = { 0, }; + static mysyscall func; + int ret; + +#if (__NR_clock_getres_time64 != __LTP__NR_INVALID_SYSCALL) + if (!func && syscall_supported_by_kernel(__NR_clock_getres_time64)) { + func = sys_clock_getres64; + tts.type = TST_KERN_TIMESPEC; + } +#endif + + if (!func && syscall_supported_by_kernel(__NR_clock_getres)) { + func = sys_clock_getres; + tts.type = TST_KERN_OLD_TIMESPEC; + } + + if (!func) { + tst_res(TCONF, "clock_getres() not available"); + errno = ENOSYS; + return -1; + } + + ret = func(clk_id, tst_ts_get(&tts)); + res->tv_sec = tst_ts_get_sec(tts); + res->tv_nsec = tst_ts_get_nsec(tts); + return ret; } int tst_clock_gettime(clockid_t clk_id, struct timespec *ts) { - return tst_syscall(__NR_clock_gettime, clk_id, ts); + static struct tst_ts tts = { 0, }; + static mysyscall func; + int ret; + +#if (__NR_clock_gettime64 != __LTP__NR_INVALID_SYSCALL) + if (!func && syscall_supported_by_kernel(__NR_clock_gettime64)) { + func = sys_clock_gettime64; + tts.type = TST_KERN_TIMESPEC; + } +#endif + + if (!func && syscall_supported_by_kernel(__NR_clock_gettime)) { + func = sys_clock_gettime; + tts.type = TST_KERN_OLD_TIMESPEC; + } + + if (!func) { + tst_res(TCONF, "clock_gettime() not available"); + errno = ENOSYS; + return -1; + } + + ret = func(clk_id, tst_ts_get(&tts)); + ts->tv_sec = tst_ts_get_sec(tts); + ts->tv_nsec = tst_ts_get_nsec(tts); + return ret; } int tst_clock_settime(clockid_t clk_id, struct timespec *ts) { - return tst_syscall(__NR_clock_settime, clk_id, ts); + static struct tst_ts tts = { 0, }; + static mysyscall func; + +#if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL) + if (!func && syscall_supported_by_kernel(__NR_clock_settime64)) { + func = sys_clock_settime64; + tts.type = TST_KERN_TIMESPEC; + } +#endif + + if (!func && syscall_supported_by_kernel(__NR_clock_settime)) { + func = sys_clock_settime; + tts.type = TST_KERN_OLD_TIMESPEC; + } + + if (!func) { + tst_res(TCONF, "clock_settime() not available"); + errno = ENOSYS; + return -1; + } + + tst_ts_set_sec(&tts, ts->tv_sec); + tst_ts_set_nsec(&tts, ts->tv_nsec); + return func(clk_id, tst_ts_get(&tts)); } const char *tst_clock_name(clockid_t clk_id) @@ -55,3 +142,16 @@ const char *tst_clock_name(clockid_t clk_id) return "INVALID/UNKNOWN CLOCK"; } } + +time_t tst_get_fs_timestamp(void) +{ + struct timespec ts; + int ret; + + ret = tst_clock_gettime(CLOCK_REALTIME_COARSE, &ts); + + if (ret < 0) + tst_brk(TBROK | TERRNO, "clock_gettime(CLOCK_REALTIME_COARSE)"); + + return ts.tv_sec; +} diff --git a/lib/tst_clone.c b/lib/tst_clone.c new file mode 100755 index 0000000000000000000000000000000000000000..07e7f0767d4168f2ac41d13a40b589773e74b172 --- /dev/null +++ b/lib/tst_clone.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2021 SUSE LLC + * Richard Palethorpe + */ + +#define TST_NO_DEFAULT_MAIN + +#include + +#include "tst_test.h" +#include "lapi/clone.h" + +pid_t tst_clone(const struct tst_clone_args *tst_args) +{ + struct clone_args args = { + .flags = tst_args->flags, + .exit_signal = tst_args->exit_signal, + }; + int flags; + pid_t pid = -1; + + tst_flush(); + + errno = ENOSYS; + if (__NR_clone3 != __LTP__NR_INVALID_SYSCALL) + pid = syscall(__NR_clone3, &args, sizeof(args)); + + if (pid == -1 && errno != ENOSYS) + return -1; + + if (pid != -1) + return pid; + + flags = args.exit_signal | args.flags; + +#ifdef __s390x__ + pid = syscall(__NR_clone, NULL, flags); +#else + pid = syscall(__NR_clone, flags, NULL); +#endif + + if (pid == -1) + return -2; + + return pid; +} diff --git a/lib/tst_cmd.c b/lib/tst_cmd.c old mode 100644 new mode 100755 index 7446249f9d0778934d3667954f377e9dd78bab36..b3f8a95abf39987fa809a4d644a43a47eed7b79a --- a/lib/tst_cmd.c +++ b/lib/tst_cmd.c @@ -19,6 +19,7 @@ * Author: Alexey Kodanev */ +#include #include #include #include @@ -28,10 +29,21 @@ #include #include "test.h" #include "tst_cmd.h" +#include "tst_private.h" #define OPEN_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) #define OPEN_FLAGS (O_WRONLY | O_APPEND | O_CREAT) +enum cmd_op { + OP_GE, /* >= */ + OP_GT, /* > */ + OP_LE, /* <= */ + OP_LT, /* < */ + OP_EQ, /* == */ + OP_NE, /* != */ +}; + + int tst_cmd_fds_(void (cleanup_fn)(void), const char *const argv[], int stdout_fd, @@ -176,3 +188,160 @@ int tst_system(const char *command) signal(SIGCHLD, old_handler); return ret; } + +static int mkfs_ext4_version_parser(void) +{ + FILE *f; + int rc, major, minor, patch; + + f = popen("mkfs.ext4 -V 2>&1", "r"); + if (!f) { + tst_resm(TWARN, "Could not run mkfs.ext4 -V 2>&1 cmd"); + return -1; + } + + rc = fscanf(f, "mke2fs %d.%d.%d", &major, &minor, &patch); + pclose(f); + if (rc != 3) { + tst_resm(TWARN, "Unable to parse mkfs.ext4 version"); + return -1; + } + + return major * 10000 + minor * 100 + patch; +} + +static int mkfs_ext4_version_table_get(char *version) +{ + int major, minor, patch; + int len; + + if (sscanf(version, "%u.%u.%u %n", &major, &minor, &patch, &len) != 3) { + tst_resm(TWARN, "Illegal version(%s), should use format like 1.43.0", version); + return -1; + } + + if (len != (int)strlen(version)) { + tst_resm(TWARN, "Grabage after version"); + return -1; + } + + return major * 10000 + minor * 100 + patch; +} + +static struct version_parser { + const char *cmd; + int (*parser)(void); + int (*table_get)(char *version); +} version_parsers[] = { + {"mkfs.ext4", mkfs_ext4_version_parser, mkfs_ext4_version_table_get}, + {}, +}; + +void tst_check_cmd(const char *cmd) +{ + struct version_parser *p; + char *cmd_token, *op_token, *version_token, *next, *str; + char path[PATH_MAX]; + char parser_cmd[100]; + int ver_parser, ver_get; + int op_flag = 0; + + strcpy(parser_cmd, cmd); + + cmd_token = strtok_r(parser_cmd, " ", &next); + op_token = strtok_r(NULL, " ", &next); + version_token = strtok_r(NULL, " ", &next); + str = strtok_r(NULL, " ", &next); + + if (tst_get_path(cmd_token, path, sizeof(path))) + tst_brkm(TCONF, NULL, "Couldn't find '%s' in $PATH", cmd_token); + + if (!op_token) + return; + + if (!strcmp(op_token, ">=")) + op_flag = OP_GE; + else if (!strcmp(op_token, ">")) + op_flag = OP_GT; + else if (!strcmp(op_token, "<=")) + op_flag = OP_LE; + else if (!strcmp(op_token, "<")) + op_flag = OP_LT; + else if (!strcmp(op_token, "==")) + op_flag = OP_EQ; + else if (!strcmp(op_token, "!=")) + op_flag = OP_NE; + else + tst_brkm(TCONF, NULL, "Invalid op(%s)", op_token); + + if (!version_token || str) { + tst_brkm(TCONF, NULL, + "Illegal format(%s), should use format like mkfs.ext4 >= 1.43.0", + cmd); + } + + for (p = &version_parsers[0]; p->cmd; p++) { + if (!strcmp(p->cmd, cmd_token)) { + tst_resm(TINFO, "Parsing %s version", p->cmd); + break; + } + } + + if (!p->cmd) { + tst_brkm(TBROK, NULL, "No version parser for %s implemented!", + cmd_token); + } + + ver_parser = p->parser(); + if (ver_parser < 0) + tst_brkm(TBROK, NULL, "Failed to parse %s version", p->cmd); + + ver_get = p->table_get(version_token); + if (ver_get < 0) + tst_brkm(TBROK, NULL, "Failed to get %s version", p->cmd); + + switch (op_flag) { + case OP_GE: + if (ver_parser < ver_get) { + tst_brkm(TCONF, NULL, "%s required >= %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_GT: + if (ver_parser <= ver_get) { + tst_brkm(TCONF, NULL, "%s required > %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_LE: + if (ver_parser > ver_get) { + tst_brkm(TCONF, NULL, "%s required <= %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_LT: + if (ver_parser >= ver_get) { + tst_brkm(TCONF, NULL, "%s required < %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_EQ: + if (ver_parser != ver_get) { + tst_brkm(TCONF, NULL, "%s required == %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_NE: + if (ver_parser == ver_get) { + tst_brkm(TCONF, NULL, "%s required != %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + } +} diff --git a/lib/tst_coredump.c b/lib/tst_coredump.c old mode 100644 new mode 100755 diff --git a/lib/tst_cpu.c b/lib/tst_cpu.c old mode 100644 new mode 100755 index 033155e47ec631f7ba76956e2745f1fcbcb93a9a..b4c7c2f815ccdf43dd8f13da39e7e5915e03ed6c --- a/lib/tst_cpu.c +++ b/lib/tst_cpu.c @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "lapi/cpuset.h" + #include #include #include "test.h" @@ -71,3 +73,27 @@ long tst_ncpus_max(void) } return ncpus_max; } + +long tst_ncpus_available(void) +{ +#ifdef CPU_COUNT_S + long ncpus = tst_ncpus_max(); + size_t cpusz = CPU_ALLOC_SIZE(ncpus); + cpu_set_t *cpus = CPU_ALLOC(ncpus); + + if (!cpus) + tst_brkm(TBROK | TERRNO, NULL, "CPU_ALLOC(%zu)", cpusz); + + if (sched_getaffinity(0, cpusz, cpus)) { + tst_resm(TWARN | TERRNO, "sched_getaffinity(0, %zu, %zx)", + cpusz, (size_t)cpus); + } else { + ncpus = CPU_COUNT_S(cpusz, cpus); + } + CPU_FREE(cpus); + + return ncpus; +#else + return tst_ncpus(); +#endif +} diff --git a/lib/tst_crypto.c b/lib/tst_crypto.c old mode 100644 new mode 100755 index 685e0871ebd5b2e7060094ba40234a473e188cd2..c01632c2a4be8a989449bf26ea5d575534b1bc6d --- a/lib/tst_crypto.c +++ b/lib/tst_crypto.c @@ -14,16 +14,17 @@ void tst_crypto_open(struct tst_crypto_session *ses) { - TEST(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CRYPTO)); - if (TST_RET < 0 && TST_ERR == EPROTONOSUPPORT) - tst_brk(TCONF | TTERRNO, "NETLINK_CRYPTO is probably disabled"); + const long ret = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CRYPTO); - if (TST_RET < 0) { - tst_brk(TBROK | TTERRNO, + if (ret < 0 && errno == EPROTONOSUPPORT) + tst_brk(TCONF | TERRNO, "NETLINK_CRYPTO is probably disabled"); + + if (ret < 0) { + tst_brk(TBROK | TERRNO, "socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CRYPTO)"); } - ses->fd = TST_RET; + ses->fd = ret; ses->seq_num = 0; } @@ -83,6 +84,7 @@ int tst_crypto_add_alg(struct tst_crypto_session *ses, int tst_crypto_del_alg(struct tst_crypto_session *ses, const struct crypto_user_alg *alg) { + long ret; unsigned int i = 0; struct nlmsghdr nh = { .nlmsg_len = sizeof(struct nlmsghdr) + sizeof(*alg), @@ -96,8 +98,8 @@ int tst_crypto_del_alg(struct tst_crypto_session *ses, SAFE_NETLINK_SEND(ses->fd, &nh, alg); - TEST(tst_crypto_recv_ack(ses)); - if (TST_RET != -EBUSY || i >= ses->retries) + ret = tst_crypto_recv_ack(ses); + if (ret != -EBUSY || i >= ses->retries) break; if (usleep(1) && errno != EINTR) @@ -106,5 +108,5 @@ int tst_crypto_del_alg(struct tst_crypto_session *ses, ++i; } - return TST_RET; + return ret; } diff --git a/lib/tst_device.c b/lib/tst_device.c old mode 100644 new mode 100755 index 67fe90ed6a8e5c0ae9c0f8708b10414ef767dfd8..73e70d26e83a73aca3f75dcdc6b5ee45cd93db58 --- a/lib/tst_device.c +++ b/lib/tst_device.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "lapi/syscalls.h" #include "test.h" #include "safe_macros.h" @@ -186,43 +187,90 @@ int tst_attach_device(const char *dev, const char *file) return 0; } -int tst_detach_device(const char *dev) +uint64_t tst_get_device_size(const char *dev_path) { - int dev_fd, ret, i; + int fd; + uint64_t size; + struct stat st; - dev_fd = open(dev, O_RDONLY); - if (dev_fd < 0) { - tst_resm(TWARN | TERRNO, "open(%s) failed", dev); - return 1; + if (!dev_path) + tst_brkm(TBROK, NULL, "No block device path"); + + if (stat(dev_path, &st)) { + tst_resm(TWARN | TERRNO, "stat() failed"); + return -1; + } + + if (!S_ISBLK(st.st_mode)) { + tst_resm(TWARN, "%s is not a block device", dev_path); + return -1; + } + + fd = open(dev_path, O_RDONLY); + if (fd < 0) { + tst_resm(TWARN | TERRNO, + "open(%s, O_RDONLY) failed", dev_path); + return -1; + } + + if (ioctl(fd, BLKGETSIZE64, &size)) { + tst_resm(TWARN | TERRNO, + "ioctl(fd, BLKGETSIZE64, ...) failed"); + close(fd); + return -1; + } + + if (close(fd)) { + tst_resm(TWARN | TERRNO, + "close(fd) failed"); + return -1; } + return size/1024/1024; +} + +int tst_detach_device_by_fd(const char *dev, int dev_fd) +{ + int ret, i; + /* keep trying to clear LOOPDEV until we get ENXIO, a quick succession * of attach/detach might not give udev enough time to complete */ for (i = 0; i < 40; i++) { ret = ioctl(dev_fd, LOOP_CLR_FD, 0); - if (ret && (errno == ENXIO)) { - close(dev_fd); + if (ret && (errno == ENXIO)) return 0; - } if (ret && (errno != EBUSY)) { tst_resm(TWARN, "ioctl(%s, LOOP_CLR_FD, 0) unexpectedly failed with: %s", dev, tst_strerrno(errno)); - close(dev_fd); return 1; } usleep(50000); } - close(dev_fd); tst_resm(TWARN, "ioctl(%s, LOOP_CLR_FD, 0) no ENXIO for too long", dev); return 1; } +int tst_detach_device(const char *dev) +{ + int dev_fd, ret; + + dev_fd = open(dev, O_RDONLY); + if (dev_fd < 0) { + tst_resm(TWARN | TERRNO, "open(%s) failed", dev); + return 1; + } + + ret = tst_detach_device_by_fd(dev, dev_fd); + close(dev_fd); + return ret; +} + int tst_dev_sync(int fd) { return syscall(__NR_syncfs, fd); @@ -230,9 +278,9 @@ int tst_dev_sync(int fd) const char *tst_acquire_loop_device(unsigned int size, const char *filename) { - unsigned int acq_dev_size = MAX(size, DEV_SIZE_MB); + unsigned int acq_dev_size = size ? size : DEV_SIZE_MB; - if (tst_fill_file(filename, 0, 1024 * 1024, acq_dev_size)) { + if (tst_prealloc_file(filename, 1024 * 1024, acq_dev_size)) { tst_resm(TWARN | TERRNO, "Failed to create %s", filename); return NULL; } @@ -248,50 +296,18 @@ const char *tst_acquire_loop_device(unsigned int size, const char *filename) const char *tst_acquire_device__(unsigned int size) { - int fd; const char *dev; - struct stat st; unsigned int acq_dev_size; uint64_t ltp_dev_size; - acq_dev_size = MAX(size, DEV_SIZE_MB); + acq_dev_size = size ? size : DEV_SIZE_MB; dev = getenv("LTP_DEV"); if (dev) { tst_resm(TINFO, "Using test device LTP_DEV='%s'", dev); - if (stat(dev, &st)) { - tst_resm(TWARN | TERRNO, "stat() failed"); - return NULL; - } - - if (!S_ISBLK(st.st_mode)) { - tst_resm(TWARN, "%s is not a block device", dev); - return NULL; - } - - fd = open(dev, O_RDONLY); - if (fd < 0) { - tst_resm(TWARN | TERRNO, - "open(%s, O_RDONLY) failed", dev); - return NULL; - } - - if (ioctl(fd, BLKGETSIZE64, <p_dev_size)) { - tst_resm(TWARN | TERRNO, - "ioctl(fd, BLKGETSIZE64, ...) failed"); - close(fd); - return NULL; - } - - if (close(fd)) { - tst_resm(TWARN | TERRNO, - "close(fd) failed"); - return NULL; - } - - ltp_dev_size = ltp_dev_size/1024/1024; + ltp_dev_size = tst_get_device_size(dev); if (acq_dev_size <= ltp_dev_size) return dev; @@ -488,3 +504,46 @@ unsigned long tst_dev_bytes_written(const char *dev) return dev_bytes_written; } + +void tst_find_backing_dev(const char *path, char *dev) +{ + struct stat buf; + FILE *file; + char line[PATH_MAX]; + char *pre = NULL; + char *next = NULL; + unsigned int dev_major, dev_minor, line_mjr, line_mnr; + + if (stat(path, &buf) < 0) + tst_brkm(TWARN | TERRNO, NULL, "stat() failed"); + + dev_major = major(buf.st_dev); + dev_minor = minor(buf.st_dev); + file = SAFE_FOPEN(NULL, "/proc/self/mountinfo", "r"); + *dev = '\0'; + + while (fgets(line, sizeof(line), file)) { + if (sscanf(line, "%*d %*d %d:%d", &line_mjr, &line_mnr) != 2) + continue; + + if (line_mjr == dev_major && line_mnr == dev_minor) { + pre = strstr(line, " - "); + pre = strtok_r(pre, " ", &next); + pre = strtok_r(NULL, " ", &next); + pre = strtok_r(NULL, " ", &next); + strcpy(dev, pre); + break; + } + } + + SAFE_FCLOSE(NULL, file); + + if (!*dev) + tst_brkm(TBROK, NULL, "Cannot find block device for %s", path); + + if (stat(dev, &buf) < 0) + tst_brkm(TWARN | TERRNO, NULL, "stat(%s) failed", dev); + + if (S_ISBLK(buf.st_mode) != 1) + tst_brkm(TCONF, NULL, "dev(%s) isn't a block dev", dev); +} diff --git a/lib/tst_dir_is_empty.c b/lib/tst_dir_is_empty.c old mode 100644 new mode 100755 diff --git a/lib/tst_fill_file.c b/lib/tst_fill_file.c old mode 100644 new mode 100755 index f2bc52d42e709800b19a73ddc6950f96df7680fc..80472007f466fdcfde31c28c863a1fdbc1ef0362 --- a/lib/tst_fill_file.c +++ b/lib/tst_fill_file.c @@ -19,12 +19,14 @@ * */ +#define _GNU_SOURCE #include #include #include #include #include #include +#include "lapi/fallocate.h" #include "test.h" @@ -54,6 +56,22 @@ int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount) return 0; } +int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount) +{ + int ret; + + errno = 0; + ret = fallocate(fd, 0, 0, bs * bcount); + + if (ret && errno == ENOSPC) + return ret; + + if (ret) + ret = tst_fill_fd(fd, 0, bs, bcount); + + return ret; +} + int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount) { int fd; @@ -76,3 +94,25 @@ int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount) return 0; } + +int tst_prealloc_file(const char *path, size_t bs, size_t bcount) +{ + int fd; + + fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR); + if (fd < 0) + return -1; + + if (tst_prealloc_size_fd(fd, bs, bcount)) { + close(fd); + unlink(path); + return -1; + } + + if (close(fd) < 0) { + unlink(path); + return -1; + } + + return 0; +} diff --git a/lib/tst_fill_fs.c b/lib/tst_fill_fs.c old mode 100644 new mode 100755 diff --git a/lib/tst_fips.c b/lib/tst_fips.c new file mode 100755 index 0000000000000000000000000000000000000000..82dafef7ad32e1d404d0482533b048270acf31af --- /dev/null +++ b/lib/tst_fips.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Petr Vorel + */ + +#define TST_NO_DEFAULT_MAIN + +#define PATH_FIPS "/proc/sys/crypto/fips_enabled" + +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "tst_fips.h" + +int tst_fips_enabled(void) +{ + int fips = 0; + + if (access(PATH_FIPS, R_OK) == 0) { + SAFE_FILE_SCANF(PATH_FIPS, "%d", &fips); + } + + tst_res(TINFO, "FIPS: %s", fips ? "on" : "off"); + return fips; +} diff --git a/lib/tst_fs_has_free.c b/lib/tst_fs_has_free.c old mode 100644 new mode 100755 diff --git a/lib/tst_fs_link_count.c b/lib/tst_fs_link_count.c old mode 100644 new mode 100755 index 860510d7581aa9d90a839ce5d07844f85bfa4447..b8807236de0bf57a83a36acdcad08539f9daeb1a --- a/lib/tst_fs_link_count.c +++ b/lib/tst_fs_link_count.c @@ -147,9 +147,8 @@ int tst_fs_fill_subdirs_(void (*cleanup) (void), const char *dir) * created directory (the '.' and link from parent dir) */ if (s.st_nlink != (i + 2)) { - tst_brkm(TBROK, cleanup, "%s link counts have" - "%d, should be %d", dir, - (int)s.st_nlink, i + 2); + tst_brkm(TBROK, cleanup, "%s link counts have %d, should be %d", + dir, (int)s.st_nlink, i + 2); return 0; } else { tst_resm(TINFO, "the maximum subdirectories in " diff --git a/lib/tst_fs_setup.c b/lib/tst_fs_setup.c old mode 100644 new mode 100755 index 54ea37077b001dd70b2929621aa7c4a93456d6dd..6b93483dea7ba4f3375353b931494d0c9202da2b --- a/lib/tst_fs_setup.c +++ b/lib/tst_fs_setup.c @@ -36,14 +36,15 @@ int mount_overlay(const char *file, const int lineno, int skip) if (errno == ENODEV) { if (skip) { - tst_brk(TCONF, "%s:%d: " TST_FS_SETUP_OVERLAYFS_MSG, - file, lineno); + tst_brk_(file, lineno, TCONF, + TST_FS_SETUP_OVERLAYFS_MSG); } else { - tst_res(TINFO, "%s:%d: " TST_FS_SETUP_OVERLAYFS_MSG, - file, lineno); + tst_res_(file, lineno, TINFO, + TST_FS_SETUP_OVERLAYFS_MSG); } } else { - tst_brk(TBROK | TERRNO, "overlayfs mount failed"); + tst_brk_(file, lineno, TBROK | TERRNO, + "overlayfs mount failed"); } return ret; } diff --git a/lib/tst_fs_type.c b/lib/tst_fs_type.c old mode 100644 new mode 100755 index 1d0ac9669237138f55335ad90c5c53a34d787d23..9de80224bb6706999e27c7e0c32fc5427b3f9f88 --- a/lib/tst_fs_type.c +++ b/lib/tst_fs_type.c @@ -47,44 +47,48 @@ const char *tst_fs_type_name(long f_type) { switch (f_type) { case TST_TMPFS_MAGIC: - return "TMPFS"; + return "tmpfs"; case TST_NFS_MAGIC: - return "NFS"; + return "nfs"; case TST_V9FS_MAGIC: - return "9P"; + return "9p"; case TST_RAMFS_MAGIC: - return "RAMFS"; + return "ramfs"; case TST_BTRFS_MAGIC: - return "BTRFS"; + return "btrfs"; case TST_XFS_MAGIC: - return "XFS"; + return "xfs"; case TST_EXT2_OLD_MAGIC: - return "EXT2"; + return "ext2"; case TST_EXT234_MAGIC: - return "EXT2/EXT3/EXT4"; + return "ext2/ext3/ext4"; case TST_MINIX_MAGIC: case TST_MINIX_MAGIC2: case TST_MINIX2_MAGIC: case TST_MINIX2_MAGIC2: case TST_MINIX3_MAGIC: - return "MINIX"; + return "minix"; case TST_UDF_MAGIC: - return "UDF"; + return "udf"; case TST_SYSV2_MAGIC: case TST_SYSV4_MAGIC: - return "SYSV"; + return "sysv"; case TST_UFS_MAGIC: case TST_UFS2_MAGIC: - return "UFS"; + return "ufs"; case TST_F2FS_MAGIC: - return "F2FS"; + return "f2fs"; case TST_NILFS_MAGIC: - return "NILFS"; + return "nilfs"; case TST_EXOFS_MAGIC: - return "EXOFS"; + return "exofs"; case TST_OVERLAYFS_MAGIC: - return "OVERLAYFS"; + return "overlayfs"; + case TST_FUSE_MAGIC: + return "fuse"; + case TST_EXFAT_MAGIC: + return "exfat"; default: - return "Unknown"; + return "unknown"; } } diff --git a/lib/tst_get_bad_addr.c b/lib/tst_get_bad_addr.c old mode 100644 new mode 100755 diff --git a/lib/tst_hugepage.c b/lib/tst_hugepage.c old mode 100644 new mode 100755 index 52667a14e8ff6019ad23cd85334e6a4f28a5d0b1..a7585bc3d5576fb2ea1dae254119a7f1c4905402 --- a/lib/tst_hugepage.c +++ b/lib/tst_hugepage.c @@ -12,6 +12,14 @@ unsigned long tst_hugepages; char *nr_opt; char *Hopt; +size_t tst_get_hugepage_size(void) +{ + if (access(PATH_HUGEPAGES, F_OK)) + return 0; + + return SAFE_READ_MEMINFO("Hugepagesize:") * 1024; +} + unsigned long tst_request_hugepages(unsigned long hpages) { unsigned long val, max_hpages; @@ -26,6 +34,11 @@ unsigned long tst_request_hugepages(unsigned long hpages) else tst_hugepages = hpages; + if (hpages == TST_NO_HUGEPAGES) { + tst_hugepages = 0; + goto set_hugepages; + } + SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3"); max_hpages = SAFE_READ_MEMINFO("MemFree:") / SAFE_READ_MEMINFO("Hugepagesize:"); @@ -39,11 +52,14 @@ unsigned long tst_request_hugepages(unsigned long hpages) goto out; } +set_hugepages: tst_sys_conf_save("?/proc/sys/vm/nr_hugepages"); SAFE_FILE_PRINTF(PATH_NR_HPAGES, "%lu", tst_hugepages); SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val); if (val != tst_hugepages) - tst_brk(TBROK, "nr_hugepages = %lu, but expect %lu", val, tst_hugepages); + tst_brk(TCONF, "nr_hugepages = %lu, but expect %lu. " + "Not enough hugepages for testing.", + val, tst_hugepages); tst_res(TINFO, "%lu hugepage(s) reserved", tst_hugepages); out: diff --git a/lib/tst_ioctl.c b/lib/tst_ioctl.c old mode 100644 new mode 100755 diff --git a/lib/tst_kconfig.c b/lib/tst_kconfig.c old mode 100644 new mode 100755 index d49187b6f4371a025ec8cbfa50571c38d64a4c83..ac13866e826f730799c8f064068786339233eae5 --- a/lib/tst_kconfig.c +++ b/lib/tst_kconfig.c @@ -11,7 +11,21 @@ #define TST_NO_DEFAULT_MAIN #include "tst_test.h" +#include "tst_private.h" #include "tst_kconfig.h" +#include "tst_bool_expr.h" + +static int kconfig_skip_check(void) +{ + char *skipped = getenv("KCONFIG_SKIP_CHECK"); + + if (skipped) { + tst_res(TINFO, "Skipping kernel config check as requested"); + return 1; + } + + return 0; +} static const char *kconfig_path(char *path_buf, size_t path_buf_len) { @@ -30,6 +44,12 @@ static const char *kconfig_path(char *path_buf, size_t path_buf_len) uname(&un); + /* Common install module path */ + snprintf(path_buf, path_buf_len, "/lib/modules/%s/build/.config", un.release); + + if (!access(path_buf, F_OK)) + return path_buf; + /* Debian and derivatives */ snprintf(path_buf, path_buf_len, "/boot/config-%s", un.release); @@ -84,126 +104,108 @@ static void close_kconfig(FILE *fp) fclose(fp); } -struct match { - /* match len, string length up to \0 or = */ - size_t len; - /* if set part of conf string after = */ - const char *val; - /* if set the config option was matched already */ - int match; -}; - -static int is_set(const char *str, const char *val) +static inline int kconfig_parse_line(const char *line, + struct tst_kconfig_var *vars, + unsigned int vars_len) { - size_t vlen = strlen(val); + unsigned int i, var_len = 0; + const char *var; + int is_not_set = 0; - while (isspace(*str)) - str++; + while (isspace(*line)) + line++; - if (strncmp(str, val, vlen)) - return 0; + if (*line == '#') { + if (!strstr(line, "is not set")) + return 0; - switch (str[vlen]) { - case ' ': - case '\n': - case '\0': - return 1; - break; - default: - return 0; + is_not_set = 1; } -} -static inline int match(struct match *match, const char *conf, - struct tst_kconfig_res *result, const char *line) -{ - if (match->match) - return 0; - - const char *cfg = strstr(line, "CONFIG_"); + var = strstr(line, "CONFIG_"); - if (!cfg) + if (!var) return 0; - if (strncmp(cfg, conf, match->len)) - return 0; - - const char *val = &cfg[match->len]; - - switch (cfg[match->len]) { - case '=': + for (;;) { + switch (var[var_len]) { + case 'A' ... 'Z': + case '0' ... '9': + case '_': + var_len++; + break; + default: + goto out; break; - case ' ': - if (is_set(val, "is not set")) { - result->match = 'n'; - goto match; } - /* fall through */ - default: - return 0; } - if (is_set(val, "=y")) { - result->match = 'y'; - goto match; - } +out: - if (is_set(val, "=m")) { - result->match = 'm'; - goto match; - } + for (i = 0; i < vars_len; i++) { + const char *val; + unsigned int val_len = 0; - result->match = 'v'; - result->value = strndup(val+1, strlen(val)-2); + if (vars[i].id_len != var_len) + continue; -match: - match->match = 1; - return 1; -} + if (strncmp(vars[i].id, var, var_len)) + continue; -void tst_kconfig_read(const char *const *kconfigs, - struct tst_kconfig_res results[], size_t cnt) -{ - struct match matches[cnt]; - FILE *fp; - unsigned int i, j; - char buf[1024]; + if (is_not_set) { + vars[i].choice = 'n'; + return 1; + } + + val = var + var_len; - for (i = 0; i < cnt; i++) { - const char *val = strchr(kconfigs[i], '='); + while (isspace(*val)) + val++; + + if (*val != '=') + return 0; - if (strncmp("CONFIG_", kconfigs[i], 7)) - tst_brk(TBROK, "Invalid config string '%s'", kconfigs[i]); + val++; - matches[i].match = 0; - matches[i].len = strlen(kconfigs[i]); + while (isspace(*val)) + val++; - if (val) { - matches[i].val = val + 1; - matches[i].len -= strlen(val); + while (!isspace(val[val_len])) + val_len++; + + if (val_len == 1) { + switch (val[0]) { + case 'y': + vars[i].choice = 'y'; + return 1; + case 'm': + vars[i].choice = 'm'; + return 1; + } } - results[i].match = 0; - results[i].value = NULL; + vars[i].choice = 'v'; + vars[i].val = strndup(val, val_len); } - fp = open_kconfig(); + return 0; +} + +void tst_kconfig_read(struct tst_kconfig_var vars[], size_t vars_len) +{ + char line[128]; + unsigned int vars_found = 0; + + FILE *fp = open_kconfig(); if (!fp) tst_brk(TBROK, "Cannot parse kernel .config"); - while (fgets(buf, sizeof(buf), fp)) { - for (i = 0; i < cnt; i++) { - if (match(&matches[i], kconfigs[i], &results[i], buf)) { - for (j = 0; j < cnt; j++) { - if (matches[j].match) - break; - } - - if (j == cnt) - goto exit; - } - } + while (fgets(line, sizeof(line), fp)) { + if (kconfig_parse_line(line, vars, vars_len)) + vars_found++; + if (vars_found == vars_len) + goto exit; } exit: @@ -219,67 +221,342 @@ static size_t array_len(const char *const kconfigs[]) return i; } -static int compare_res(struct tst_kconfig_res *res, const char *kconfig, - char match, const char *val) +static const char *strnchr(const char *s, int c, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + if (s[i] == c) + return s + i; + } + + return NULL; +} + +static inline unsigned int get_len(const char* kconfig, unsigned int len) { - if (res->match != match) { - tst_res(TINFO, "Needs kernel %s, have %c", kconfig, res->match); + const char *sep = strnchr(kconfig, '=', len); + + if (!sep) + return len; + + return sep - kconfig; +} + +static void print_err(FILE *f, const struct tst_expr_tok *var, + size_t spaces, const char *err) +{ + size_t i; + + for (i = 0; i < var->tok_len; i++) + fputc(var->tok[i], f); + + fputc('\n', f); + + while (spaces--) + fputc(' ', f); + + fprintf(f, "^\n%s\n\n", err); +} + +static int validate_var(const struct tst_expr_tok *var) +{ + size_t i = 7; + + if (var->tok_len < 7 || strncmp(var->tok, "CONFIG_", 7)) { + print_err(stderr, var, 0, "Expected CONFIG_ prefix"); return 1; } - if (match != 'v') + while (var->tok[i]) { + char c; + + if (i >= var->tok_len) + return 0; + + c = var->tok[i]; + + if ((c >= 'A' && c <= 'Z') || c == '_') { + i++; + continue; + } + + if (c >= '0' && c <= '9') { + i++; + continue; + } + + if (c == '=') { + i++; + break; + } + + print_err(stderr, var, i, "Unexpected character in variable name"); + return 1; + } + + if (i >= var->tok_len) { + + if (var->tok[i-1] == '=') { + print_err(stderr, var, i, "Missing value"); + return -1; + } + return 0; + } + + if (var->tok[i] == '"') { + do { + i++; + } while (i < var->tok_len && var->tok[i] != '"'); + + if (i < var->tok_len - 1) { + print_err(stderr, var, i, "Garbage after a string"); + return 1; + } + + if (var->tok[i] != '"') { + print_err(stderr, var, i, "Untermianted string"); + return 1; + } - if (strcmp(res->value, val)) { - tst_res(TINFO, "Needs kernel %s, have %s", kconfig, res->value); + return 0; + } + + do { + i++; + } while (i < var->tok_len && isalnum(var->tok[i])); + + if (i < var->tok_len) { + print_err(stderr, var, i, "Invalid character in variable value"); return 1; } return 0; } -void tst_kconfig_check(const char *const kconfigs[]) +static int validate_vars(struct tst_expr *const exprs[], unsigned int expr_cnt) { - size_t cnt = array_len(kconfigs); - struct tst_kconfig_res results[cnt]; unsigned int i; - int abort_test = 0; + const struct tst_expr_tok *j; + unsigned int ret = 0; + + for (i = 0; i < expr_cnt; i++) { + for (j = exprs[i]->rpn; j; j = j->next) { + if (j->op == TST_OP_VAR) + ret |= validate_var(j); + } + } + + return ret; +} + + +static inline unsigned int get_var_cnt(struct tst_expr *const exprs[], + unsigned int expr_cnt) +{ + unsigned int i; + const struct tst_expr_tok *j; + unsigned int cnt = 0; + + for (i = 0; i < expr_cnt; i++) { + for (j = exprs[i]->rpn; j; j = j->next) { + if (j->op == TST_OP_VAR) + cnt++; + } + } + + return cnt; +} + +static const struct tst_kconfig_var *find_var(const struct tst_kconfig_var vars[], + unsigned int var_cnt, + const char *var) +{ + unsigned int i; + + for (i = 0; i < var_cnt; i++) { + if (!strcmp(vars[i].id, var)) + return &vars[i]; + } - tst_kconfig_read(kconfigs, results, cnt); + return NULL; +} + +/* + * Fill in the kconfig variables array from the expressions. Also makes sure + * that each variable is copied to the array exaclty once. + */ +static inline unsigned int populate_vars(struct tst_expr *exprs[], + unsigned int expr_cnt, + struct tst_kconfig_var vars[]) +{ + unsigned int i; + struct tst_expr_tok *j; + unsigned int cnt = 0; + + for (i = 0; i < expr_cnt; i++) { + for (j = exprs[i]->rpn; j; j = j->next) { + const struct tst_kconfig_var *var; + + if (j->op != TST_OP_VAR) + continue; + + vars[cnt].id_len = get_len(j->tok, j->tok_len); + + if (vars[cnt].id_len + 1 >= sizeof(vars[cnt].id)) + tst_brk(TBROK, "kconfig var id too long!"); + + strncpy(vars[cnt].id, j->tok, vars[cnt].id_len); + vars[cnt].id[vars[cnt].id_len] = 0; + vars[cnt].choice = 0; + vars[cnt].val = NULL; + + var = find_var(vars, cnt, vars[cnt].id); + + if (var) + j->priv = var; + else + j->priv = &vars[cnt++]; + } + } + + return cnt; +} + +static int map(struct tst_expr_tok *expr) +{ + const struct tst_kconfig_var *var = expr->priv; + + if (var->choice == 0) + return 0; - for (i = 0; i < cnt; i++) { - if (results[i].match == 0) { - tst_res(TINFO, "Missing kernel %s", kconfigs[i]); - abort_test = 1; + const char *val = strnchr(expr->tok, '=', expr->tok_len); + + /* CONFIG_FOO evaluates to true if y or m */ + if (!val) + return var->choice == 'y' || var->choice == 'm'; + + val++; + + unsigned int len = expr->tok_len - (val - expr->tok); + char choice = 'v'; + + if (!strncmp(val, "n", len)) + choice = 'n'; + + if (!strncmp(val, "y", len)) + choice = 'y'; + + if (!strncmp(val, "m", len)) + choice = 'm'; + + if (choice != 'v') + return var->choice == choice; + + if (var->choice != 'v') + return 0; + + if (strlen(var->val) != len) + return 0; + + return !strncmp(val, var->val, len); +} + +static void dump_vars(const struct tst_expr *expr) +{ + const struct tst_expr_tok *i; + const struct tst_kconfig_var *var; + + tst_res(TINFO, "Variables:"); + + for (i = expr->rpn; i; i = i->next) { + if (i->op != TST_OP_VAR) + continue; + + var = i->priv; + + if (!var->choice) { + tst_res(TINFO, " %s Undefined", var->id); continue; } - if (results[i].match == 'n') { - tst_res(TINFO, "Kernel %s is not set", kconfigs[i]); - abort_test = 1; + if (var->choice == 'v') { + tst_res(TINFO, " %s=%s", var->id, var->val); continue; } - const char *val = strchr(kconfigs[i], '='); + tst_res(TINFO, " %s=%c", var->id, var->choice); + } +} + +int tst_kconfig_check(const char *const kconfigs[]) +{ + size_t expr_cnt = array_len(kconfigs); + struct tst_expr *exprs[expr_cnt]; + unsigned int i, var_cnt; + int ret = 0; - if (val) { - char match = 'v'; - val++; + if (kconfig_skip_check()) + return 0; + + for (i = 0; i < expr_cnt; i++) { + exprs[i] = tst_bool_expr_parse(kconfigs[i]); - if (!strcmp(val, "y")) - match = 'y'; + if (!exprs[i]) + tst_brk(TBROK, "Invalid kconfig expression!"); + } - if (!strcmp(val, "m")) - match = 'm'; + if (validate_vars(exprs, expr_cnt)) + tst_brk(TBROK, "Invalid kconfig variables!"); - if (compare_res(&results[i], kconfigs[i], match, val)) - abort_test = 1; + var_cnt = get_var_cnt(exprs, expr_cnt); + struct tst_kconfig_var vars[var_cnt]; + var_cnt = populate_vars(exprs, expr_cnt, vars); + + tst_kconfig_read(vars, var_cnt); + + for (i = 0; i < expr_cnt; i++) { + int val = tst_bool_expr_eval(exprs[i], map); + + if (val != 1) { + ret = 1; + tst_res(TINFO, "Constraint '%s' not satisfied!", kconfigs[i]); + dump_vars(exprs[i]); } - free(results[i].value); + tst_bool_expr_free(exprs[i]); + } + + for (i = 0; i < var_cnt; i++) { + if (vars[i].choice == 'v') + free(vars[i].val); } - if (abort_test) - tst_brk(TCONF, "Aborting due to unsuitable kernel config, see above!"); + return ret; +} + +char tst_kconfig_get(const char *confname) +{ + struct tst_kconfig_var var; + + if (kconfig_skip_check()) + return 0; + + var.id_len = strlen(confname); + + if (var.id_len >= sizeof(var.id)) + tst_brk(TBROK, "Kconfig var name \"%s\" too long", confname); + + strcpy(var.id, confname); + var.choice = 0; + var.val = NULL; + + tst_kconfig_read(&var, 1); + + if (var.choice == 'v') + free(var.val); + + return var.choice; } diff --git a/lib/tst_kernel.c b/lib/tst_kernel.c old mode 100644 new mode 100755 index 57fa4b2bed89ccb9886bddc3afcc567895787e1c..6db85bff0e5cec176f71738e362abc1a81b1a6d8 --- a/lib/tst_kernel.c +++ b/lib/tst_kernel.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) 2020-2021 Petr Vorel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,8 +18,11 @@ #include #include +#include + #include "test.h" #include "tst_kernel.h" +#include "old_safe_stdio.h" static int get_kernel_bits_from_uname(struct utsname *buf) { @@ -33,7 +37,12 @@ static int get_kernel_bits_from_uname(struct utsname *buf) int tst_kernel_bits(void) { struct utsname buf; - int kernel_bits = get_kernel_bits_from_uname(&buf); + static int kernel_bits; + + if (kernel_bits) + return kernel_bits; + + kernel_bits = get_kernel_bits_from_uname(&buf); if (kernel_bits == -1) return -1; @@ -81,20 +90,97 @@ int tst_kernel_bits(void) return kernel_bits; } -int tst_check_driver(const char *name) +static int tst_search_driver(const char *driver, const char *file) { -#ifndef __ANDROID__ - const char * const argv[] = { "modprobe", "-n", name, NULL }; - int res = tst_cmd_(NULL, argv, "/dev/null", "/dev/null", - TST_CMD_PASS_RETVAL); - - /* 255 - it looks like modprobe not available */ - return (res == 255) ? 0 : res; -#else - /* Android modprobe may not have '-n', or properly installed - * module.*.bin files to determine built-in drivers. Assume - * all drivers are available. + struct stat st; + char buf[PATH_MAX]; + char *path = NULL, *search = NULL, *sep = NULL; + FILE *f; + int ret = -1; + + struct utsname uts; + + if (uname(&uts)) { + tst_brkm(TBROK | TERRNO, NULL, "uname() failed"); + return -1; + } + SAFE_ASPRINTF(NULL, &path, "/lib/modules/%s/%s", uts.release, file); + + if (stat(path, &st) || !(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) { + tst_resm(TWARN, "expected file %s does not exist or not a file", path); + return -1; + } + + if (access(path, R_OK)) { + tst_resm(TWARN, "file %s cannot be read", path); + return -1; + } + + SAFE_ASPRINTF(NULL, &search, "/%s.ko", driver); + + f = SAFE_FOPEN(NULL, path, "r"); + + while (fgets(buf, sizeof(buf), f)) { + /* cut dependencies after : */ + if ((sep = strchr(buf, ':'))) + *sep = 0; + + /* driver found */ + if (strstr(buf, search) != NULL) { + ret = 0; + break; + } + } + + SAFE_FCLOSE(NULL, f); + free(search); + free(path); + + return ret; +} + +static int tst_check_driver_(const char *driver) +{ + if (!tst_search_driver(driver, "modules.dep") || + !tst_search_driver(driver, "modules.builtin")) + return 0; + + return -1; +} + +int tst_check_driver(const char *driver) +{ +#ifdef __ANDROID__ + /* + * Android may not have properly installed modules.* files. We could + * search modules in /system/lib/modules, but to to determine built-in + * drivers we need modules.builtin. Therefore assume all drivers are + * available. */ return 0; #endif + + if (!tst_check_driver_(driver)) + return 0; + + int ret = -1; + + if (strrchr(driver, '-') || strrchr(driver, '_')) { + char *driver2 = strdup(driver); + char *ix = driver2; + char find = '-', replace = '_'; + + if (strrchr(driver, '_')) { + find = '_'; + replace = '-'; + } + + while ((ix = strchr(ix, find))) + *ix++ = replace; + + ret = tst_check_driver_(driver2); + free(driver2); + } + + return ret; } diff --git a/lib/tst_kvercmp.c b/lib/tst_kvercmp.c old mode 100644 new mode 100755 index dc3bb669b554ba98e24ce640a2ae990a46a49bf8..dc0daa74665c18ab0dd3702ef853c43e75d6bd4d --- a/lib/tst_kvercmp.c +++ b/lib/tst_kvercmp.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include @@ -25,6 +26,8 @@ #include #include "test.h" +#define OSRELEASE_PATH "/etc/os-release" + static char *parse_digit(const char *str, int *d) { unsigned long v; @@ -62,7 +65,7 @@ int tst_parse_kver(const char *str_kver, int *v1, int *v2, int *v3) /* * Check for a short version e.g '2.4' */ - if (*str == ' ' || *str == '\0') + if (*str == ' ' || *str == '\0' || *str == '-') return 0; if (*(str++) != '.') @@ -127,6 +130,10 @@ int tst_kvexcmp(const char *tst_exv, const char *cur_ver) const char *tst_kvcmp_distname(const char *kver) { + static char distname[64]; + char *ret = distname; + char *p = distname; + if (strstr(kver, ".el5uek")) return "OL5UEK"; @@ -139,6 +146,32 @@ const char *tst_kvcmp_distname(const char *kver) if (strstr(kver, ".el6")) return "RHEL6"; + if (strstr(kver, ".el7")) + return "RHEL7"; + + if (strstr(kver, ".el8")) + return "RHEL8"; + + if (access(OSRELEASE_PATH, F_OK) != -1) { + SAFE_FILE_LINES_SCANF(NULL, OSRELEASE_PATH, "ID=%s", distname); + + if (p[0] == '"') { + ret = distname + 1; + p = ret; + } + + while (*p) { + if (*p == '"') { + *p = 0; + break; + } + *p = toupper((unsigned char)*p); + p++; + } + + return ret; + } + return NULL; } diff --git a/lib/tst_lockdown.c b/lib/tst_lockdown.c new file mode 100755 index 0000000000000000000000000000000000000000..26a57b6a14ce18df98c29017b8b1a0dbae6ac30a --- /dev/null +++ b/lib/tst_lockdown.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#define TST_NO_DEFAULT_MAIN + +#define PATH_LOCKDOWN "/sys/kernel/security/lockdown" + +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "tst_safe_stdio.h" +#include "tst_lockdown.h" +#include "tst_private.h" + +#define EFIVAR_SECUREBOOT "/sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c" + +int tst_secureboot_enabled(void) +{ + int fd; + char data[5]; + + if (access(EFIVAR_SECUREBOOT, F_OK)) { + tst_res(TINFO, "Efivar FS not available"); + return -1; + } + + fd = open(EFIVAR_SECUREBOOT, O_RDONLY); + + if (fd == -1) { + tst_res(TINFO | TERRNO, + "Cannot open SecureBoot Efivar sysfile"); + return -1; + } else if (fd < 0) { + tst_brk(TBROK | TERRNO, "Invalid open() return value %d", fd); + return -1; + } + + SAFE_READ(1, fd, data, 5); + SAFE_CLOSE(fd); + tst_res(TINFO, "SecureBoot: %s", data[4] ? "on" : "off"); + return data[4]; +} + +int tst_lockdown_enabled(void) +{ + char line[BUFSIZ]; + FILE *file; + + if (access(PATH_LOCKDOWN, F_OK) != 0) { + char flag; + + flag = tst_kconfig_get("CONFIG_EFI_SECURE_BOOT_LOCK_DOWN"); + + /* SecureBoot enabled could mean integrity lockdown */ + if (flag == 'y' && tst_secureboot_enabled() > 0) + return 1; + + tst_res(TINFO, "Unable to determine system lockdown state"); + return 0; + } + + file = SAFE_FOPEN(PATH_LOCKDOWN, "r"); + if (!fgets(line, sizeof(line), file)) + tst_brk(TBROK | TERRNO, "fgets %s", PATH_LOCKDOWN); + SAFE_FCLOSE(file); + + return (strstr(line, "[none]") == NULL); +} diff --git a/lib/tst_memutils.c b/lib/tst_memutils.c new file mode 100755 index 0000000000000000000000000000000000000000..4a49747613e32323c583900d7a9f25c137ff82b9 --- /dev/null +++ b/lib/tst_memutils.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 SUSE LLC + */ + +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_capability.h" +#include "lapi/syscalls.h" + +#define BLOCKSIZE (16 * 1024 * 1024) + +void tst_pollute_memory(size_t maxsize, int fillchar) +{ + size_t i, map_count = 0, safety = 0, blocksize = BLOCKSIZE; + unsigned long long freeram; + unsigned long min_free; + void **map_blocks; + struct sysinfo info; + + SAFE_FILE_SCANF("/proc/sys/vm/min_free_kbytes", "%lu", &min_free); + min_free *= 1024; + /* Apply a margin because we cannot get below "min" watermark */ + min_free += min_free / 10; + + SAFE_SYSINFO(&info); + safety = MAX(4096 * SAFE_SYSCONF(_SC_PAGESIZE), 128 * 1024 * 1024); + safety = MAX(safety, min_free); + safety /= info.mem_unit; + + if (info.freeswap > safety) + safety = 0; + + /* + * MemFree usually is lower than MemAvailable, although when setting + * sysctl vm.lowmem_reserve_ratio, this could reverse. + * + * Use the lower value of both for pollutable memory. Usually this + * means we will not evict any caches. + */ + freeram = MIN(info.freeram, (tst_available_mem() * 1024)); + + /* Not enough free memory to avoid invoking OOM killer */ + if (freeram <= safety) + return; + + if (!maxsize) + maxsize = SIZE_MAX; + + if (freeram - safety < maxsize / info.mem_unit) + maxsize = (freeram - safety) * info.mem_unit; + + blocksize = MIN(maxsize, blocksize); + map_count = maxsize / blocksize; + map_blocks = SAFE_MALLOC(map_count * sizeof(void *)); + + /* + * Keep allocating until the first failure. The address space may be + * too fragmented or just smaller than maxsize. + */ + for (i = 0; i < map_count; i++) { + map_blocks[i] = mmap(NULL, blocksize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (map_blocks[i] == MAP_FAILED) { + map_count = i; + break; + } + + memset(map_blocks[i], fillchar, blocksize); + } + + for (i = 0; i < map_count; i++) + SAFE_MUNMAP(map_blocks[i], blocksize); + + free(map_blocks); +} + +long long tst_available_mem(void) +{ + unsigned long long mem_available = 0; + + if (FILE_LINES_SCANF("/proc/meminfo", "MemAvailable: %llu", + &mem_available)) { + mem_available = SAFE_READ_MEMINFO("MemFree:") + + SAFE_READ_MEMINFO("Cached:"); + } + + return mem_available; +} + +static int has_caps(void) +{ + struct tst_cap_user_header hdr = { + .version = 0x20080522, + .pid = tst_syscall(__NR_gettid), + }; + + struct tst_cap_user_data caps[2]; + + if (tst_capget(&hdr, caps)) + tst_brk(TBROK | TERRNO, "tst_capget()"); + + if (caps[0].effective & (1U << CAP_SYS_RESOURCE)) + return 1; + + return 0; +} + +static int write_score(const char *path, int score) +{ + FILE *f; + + f = fopen(path, "w"); + if (!f) + return 1; + + if (fprintf(f, "%d", score) <= 0) + return 1; + + if (fclose(f)) + return 1; + + return 0; +} + +static void set_oom_score_adj(pid_t pid, int value) +{ + int val; + char score_path[64]; + + if (access("/proc/self/oom_score_adj", F_OK) == -1) { + tst_res(TINFO, "oom_score_adj does not exist, skipping the adjustment"); + return; + } + + if (pid == 0) { + sprintf(score_path, "/proc/self/oom_score_adj"); + } else { + sprintf(score_path, "/proc/%d/oom_score_adj", pid); + if (access(score_path, F_OK) == -1) + tst_brk(TBROK, "%s does not exist, please check if PID is valid", score_path); + } + + if (write_score(score_path, value)) { + if (!has_caps()) + return; + + tst_res(TWARN, "Can't adjust score, even with capabilities!?"); + return; + } + + FILE_SCANF(score_path, "%d", &val); + + if (val != value) + tst_brk(TBROK, "oom_score_adj = %d, but expect %d.", val, value); +} + +void tst_enable_oom_protection(pid_t pid) +{ + set_oom_score_adj(pid, -1000); +} + +void tst_disable_oom_protection(pid_t pid) +{ + set_oom_score_adj(pid, 0); +} diff --git a/lib/tst_mkfs.c b/lib/tst_mkfs.c old mode 100644 new mode 100755 index 38b2e715130f0c077c7393d27886801bca0d1cc3..736324f042e375a8eddabebb535502a3d85186f7 --- a/lib/tst_mkfs.c +++ b/lib/tst_mkfs.c @@ -33,14 +33,20 @@ void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), char extra_opts_str[1024] = ""; if (!dev) { - tst_brkm(TBROK, cleanup_fn, - "%s:%d: No device specified", file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "No device specified"); return; } if (!fs_type) { - tst_brkm(TBROK, cleanup_fn, - "%s:%d: No fs_type specified", file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "No fs_type specified"); + return; + } + + if (!strcmp(fs_type, "tmpfs")) { + tst_resm_(file, lineno, TINFO, + "Skipping mkfs for TMPFS filesystem"); return; } @@ -51,9 +57,8 @@ void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), argv[pos++] = fs_opts[i]; if (pos + 2 > OPTS_MAX) { - tst_brkm(TBROK, cleanup_fn, - "%s:%d: Too much mkfs options", - file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Too many mkfs options"); return; } @@ -70,8 +75,8 @@ void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), argv[pos++] = extra_opts[i]; if (pos + 1 > OPTS_MAX) { - tst_brkm(TBROK, cleanup_fn, - "%s:%d: Too much mkfs options", file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Too many mkfs options"); return; } @@ -83,11 +88,14 @@ void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), argv[pos] = NULL; - if (tst_clear_device(dev)) - tst_brkm(TBROK, cleanup_fn, "tst_clear_device() failed"); + if (tst_clear_device(dev)) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "tst_clear_device() failed"); + } - tst_resm(TINFO, "Formatting %s with %s opts='%s' extra opts='%s'", - dev, fs_type, fs_opts_str, extra_opts_str); + tst_resm_(file, lineno, TINFO, + "Formatting %s with %s opts='%s' extra opts='%s'", + dev, fs_type, fs_opts_str, extra_opts_str); ret = tst_cmd(cleanup_fn, argv, "/dev/null", NULL, TST_CMD_PASS_RETVAL | TST_CMD_TCONF_ON_MISSING); @@ -95,12 +103,12 @@ void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), case 0: break; case 255: - tst_brkm(TCONF, cleanup_fn, - "%s:%d: %s not found in $PATH", file, lineno, mkfs); + tst_brkm_(file, lineno, TCONF, cleanup_fn, + "%s not found in $PATH", mkfs); break; default: - tst_brkm(TBROK, cleanup_fn, - "%s:%d: %s failed with %i", file, lineno, mkfs, ret); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "%s failed with exit code %i", mkfs, ret); } } diff --git a/lib/tst_module.c b/lib/tst_module.c old mode 100644 new mode 100755 index eda61872fe016168439311d754ecd863fe8f9528..9bd44362361651a5577ccc9a1b08c9a6165cbff6 --- a/lib/tst_module.c +++ b/lib/tst_module.c @@ -28,7 +28,7 @@ #include "ltp_priv.h" #include "old_module.h" -void tst_module_exists(void (cleanup_fn)(void), +void tst_module_exists_(void (cleanup_fn)(void), const char *mod_name, char **mod_path) { /* check current working directory */ @@ -77,11 +77,11 @@ void tst_module_exists(void (cleanup_fn)(void), free(buf); } -void tst_module_load(void (cleanup_fn)(void), +void tst_module_load_(void (cleanup_fn)(void), const char *mod_name, char *const argv[]) { char *mod_path = NULL; - tst_module_exists(cleanup_fn, mod_name, &mod_path); + tst_module_exists_(cleanup_fn, mod_name, &mod_path); const int offset = 2; /* command name & module path */ int size = 0; @@ -101,7 +101,7 @@ void tst_module_load(void (cleanup_fn)(void), free(mod_path); } -void tst_module_unload(void (cleanup_fn)(void), const char *mod_name) +void tst_module_unload_(void (cleanup_fn)(void), const char *mod_name) { int i, rc; diff --git a/lib/tst_net.c b/lib/tst_net.c old mode 100644 new mode 100755 index 8a589b0ad9d1f158c6ba1c74071823123742f7b8..de343bb394a90d36da5f181d0580aeb554ac274b --- a/lib/tst_net.c +++ b/lib/tst_net.c @@ -212,10 +212,11 @@ void safe_getaddrinfo(const char *file, const int lineno, const char *src_addr, { int err = getaddrinfo(src_addr, port, hints, addr_info); - if (err) - tst_brk(TBROK, "%s:%d: getaddrinfo failed, %s", file, lineno, - gai_strerror(err)); + if (err) { + tst_brk_(file, lineno, TBROK, "getaddrinfo failed, %s", + gai_strerror(err)); + } if (!*addr_info) - tst_brk(TBROK, "%s:%d: failed to get the address", file, lineno); + tst_brk_(file, lineno, TBROK, "failed to get the address"); } diff --git a/lib/tst_netdevice.c b/lib/tst_netdevice.c new file mode 100755 index 0000000000000000000000000000000000000000..4a04429327e2e5e50140183049df13b98abe1aab --- /dev/null +++ b/lib/tst_netdevice.c @@ -0,0 +1,514 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Linux Test Project + */ + +#include +#include +#include +#include +#include "lapi/rtnetlink.h" + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_rtnetlink.h" +#include "tst_netdevice.h" + +static struct tst_rtnl_context *create_request(const char *file, + const int lineno, unsigned int type, unsigned int flags, + const void *payload, size_t psize) +{ + struct tst_rtnl_context *ctx; + struct nlmsghdr header = { + .nlmsg_type = type, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags, + }; + + ctx = tst_rtnl_create_context(file, lineno); + + if (!ctx) + return NULL; + + if (!tst_rtnl_add_message(file, lineno, ctx, &header, payload, psize)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return NULL; + } + + return ctx; +} + +int tst_netdev_index_by_name(const char *file, const int lineno, + const char *ifname) +{ + struct ifreq ifr; + int sock, ret; + + if (strlen(ifname) >= IFNAMSIZ) { + tst_brk_(file, lineno, TBROK, + "Network device name \"%s\" too long", ifname); + return -1; + } + + sock = safe_socket(file, lineno, NULL, AF_INET, SOCK_DGRAM, 0); + + if (sock < 0) + return -1; + + strcpy(ifr.ifr_name, ifname); + ret = SAFE_IOCTL_(file, lineno, sock, SIOCGIFINDEX, &ifr); + safe_close(file, lineno, NULL, sock); + + return ret ? -1 : ifr.ifr_ifindex; +} + +int tst_netdev_set_state(const char *file, const int lineno, + const char *ifname, int up) +{ + struct ifreq ifr; + int sock, ret; + + if (strlen(ifname) >= IFNAMSIZ) { + tst_brk_(file, lineno, TBROK, + "Network device name \"%s\" too long", ifname); + return -1; + } + + sock = safe_socket(file, lineno, NULL, AF_INET, SOCK_DGRAM, 0); + + if (sock < 0) + return -1; + + strcpy(ifr.ifr_name, ifname); + ret = SAFE_IOCTL_(file, lineno, sock, SIOCGIFFLAGS, &ifr); + + if (ret) { + safe_close(file, lineno, NULL, sock); + return ret; + } + + if (up) + ifr.ifr_flags |= IFF_UP; + else + ifr.ifr_flags &= ~IFF_UP; + + ret = SAFE_IOCTL_(file, lineno, sock, SIOCSIFFLAGS, &ifr); + safe_close(file, lineno, NULL, sock); + + return ret; +} + +int tst_create_veth_pair(const char *file, const int lineno, + const char *ifname1, const char *ifname2) +{ + int ret; + struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; + struct tst_rtnl_context *ctx; + struct tst_rtnl_attr_list peerinfo[] = { + {IFLA_IFNAME, ifname2, strlen(ifname2) + 1, NULL}, + {0, NULL, -1, NULL} + }; + struct tst_rtnl_attr_list peerdata[] = { + {VETH_INFO_PEER, &info, sizeof(info), peerinfo}, + {0, NULL, -1, NULL} + }; + struct tst_rtnl_attr_list attrs[] = { + {IFLA_IFNAME, ifname1, strlen(ifname1) + 1, NULL}, + {IFLA_LINKINFO, NULL, 0, (const struct tst_rtnl_attr_list[]){ + {IFLA_INFO_KIND, "veth", 4, NULL}, + {IFLA_INFO_DATA, NULL, 0, peerdata}, + {0, NULL, -1, NULL} + }}, + {0, NULL, -1, NULL} + }; + + if (strlen(ifname1) >= IFNAMSIZ) { + tst_brk_(file, lineno, TBROK, + "Network device name \"%s\" too long", ifname1); + return 0; + } + + if (strlen(ifname2) >= IFNAMSIZ) { + tst_brk_(file, lineno, TBROK, + "Network device name \"%s\" too long", ifname2); + return 0; + } + + ctx = create_request(file, lineno, RTM_NEWLINK, + NLM_F_CREATE | NLM_F_EXCL, &info, sizeof(info)); + + if (!ctx) + return 0; + + if (tst_rtnl_add_attr_list(file, lineno, ctx, attrs) != 2) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_rtnl_send_validate(file, lineno, ctx); + tst_rtnl_destroy_context(file, lineno, ctx); + + if (!ret) { + tst_brk_(file, lineno, TBROK, + "Failed to create veth interfaces %s+%s: %s", ifname1, + ifname2, tst_strerrno(tst_rtnl_errno)); + } + + return ret; +} + +int tst_netdev_add_device(const char *file, const int lineno, + const char *ifname, const char *devtype) +{ + int ret; + struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; + struct tst_rtnl_context *ctx; + struct tst_rtnl_attr_list attrs[] = { + {IFLA_IFNAME, ifname, strlen(ifname) + 1, NULL}, + {IFLA_LINKINFO, NULL, 0, (const struct tst_rtnl_attr_list[]){ + {IFLA_INFO_KIND, devtype, strlen(devtype), NULL}, + {0, NULL, -1, NULL} + }}, + {0, NULL, -1, NULL} + }; + + if (strlen(ifname) >= IFNAMSIZ) { + tst_brk_(file, lineno, TBROK, + "Network device name \"%s\" too long", ifname); + return 0; + } + + ctx = create_request(file, lineno, RTM_NEWLINK, + NLM_F_CREATE | NLM_F_EXCL, &info, sizeof(info)); + + if (!ctx) + return 0; + + if (tst_rtnl_add_attr_list(file, lineno, ctx, attrs) != 2) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_rtnl_send_validate(file, lineno, ctx); + tst_rtnl_destroy_context(file, lineno, ctx); + + if (!ret) { + tst_brk_(file, lineno, TBROK, + "Failed to create %s device %s: %s", devtype, ifname, + tst_strerrno(tst_rtnl_errno)); + } + + return ret; +} + +int tst_netdev_remove_device(const char *file, const int lineno, + const char *ifname) +{ + struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; + struct tst_rtnl_context *ctx; + int ret; + + if (strlen(ifname) >= IFNAMSIZ) { + tst_brk_(file, lineno, TBROK, + "Network device name \"%s\" too long", ifname); + return 0; + } + + ctx = create_request(file, lineno, RTM_DELLINK, 0, &info, sizeof(info)); + + if (!ctx) + return 0; + + if (!tst_rtnl_add_attr_string(file, lineno, ctx, IFLA_IFNAME, ifname)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_rtnl_send_validate(file, lineno, ctx); + tst_rtnl_destroy_context(file, lineno, ctx); + + if (!ret) { + tst_brk_(file, lineno, TBROK, + "Failed to remove netdevice %s: %s", ifname, + tst_strerrno(tst_rtnl_errno)); + } + + return ret; +} + +static int modify_address(const char *file, const int lineno, + unsigned int action, unsigned int nl_flags, const char *ifname, + unsigned int family, const void *address, unsigned int prefix, + size_t addrlen, uint32_t addr_flags) +{ + struct tst_rtnl_context *ctx; + int index, ret; + struct ifaddrmsg info = { + .ifa_family = family, + .ifa_prefixlen = prefix + }; + + index = tst_netdev_index_by_name(file, lineno, ifname); + + if (index < 0) { + tst_brk_(file, lineno, TBROK, "Interface %s not found", ifname); + return 0; + } + + info.ifa_index = index; + ctx = create_request(file, lineno, action, nl_flags, &info, + sizeof(info)); + + if (!ctx) + return 0; + + if (!tst_rtnl_add_attr(file, lineno, ctx, IFA_FLAGS, &addr_flags, + sizeof(uint32_t))) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + if (!tst_rtnl_add_attr(file, lineno, ctx, IFA_LOCAL, address, + addrlen)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_rtnl_send_validate(file, lineno, ctx); + tst_rtnl_destroy_context(file, lineno, ctx); + + if (!ret) { + tst_brk_(file, lineno, TBROK, + "Failed to modify %s network address: %s", ifname, + tst_strerrno(tst_rtnl_errno)); + } + + return ret; +} + +int tst_netdev_add_address(const char *file, const int lineno, + const char *ifname, unsigned int family, const void *address, + unsigned int prefix, size_t addrlen, unsigned int flags) +{ + return modify_address(file, lineno, RTM_NEWADDR, + NLM_F_CREATE | NLM_F_EXCL, ifname, family, address, prefix, + addrlen, flags); +} + +int tst_netdev_add_address_inet(const char *file, const int lineno, + const char *ifname, in_addr_t address, unsigned int prefix, + unsigned int flags) +{ + return tst_netdev_add_address(file, lineno, ifname, AF_INET, + &address, prefix, sizeof(address), flags); +} + +int tst_netdev_remove_address(const char *file, const int lineno, + const char *ifname, unsigned int family, const void *address, + size_t addrlen) +{ + return modify_address(file, lineno, RTM_DELADDR, 0, ifname, family, + address, 0, addrlen, 0); +} + +int tst_netdev_remove_address_inet(const char *file, const int lineno, + const char *ifname, in_addr_t address) +{ + return tst_netdev_remove_address(file, lineno, ifname, AF_INET, + &address, sizeof(address)); +} + +static int change_ns(const char *file, const int lineno, const char *ifname, + unsigned short attr, uint32_t value) +{ + struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; + struct tst_rtnl_context *ctx; + int ret; + + if (strlen(ifname) >= IFNAMSIZ) { + tst_brk_(file, lineno, TBROK, + "Network device name \"%s\" too long", ifname); + return 0; + } + + ctx = create_request(file, lineno, RTM_NEWLINK, 0, &info, sizeof(info)); + + if (!tst_rtnl_add_attr_string(file, lineno, ctx, IFLA_IFNAME, ifname)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + if (!tst_rtnl_add_attr(file, lineno, ctx, attr, &value, + sizeof(uint32_t))) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_rtnl_send_validate(file, lineno, ctx); + tst_rtnl_destroy_context(file, lineno, ctx); + + if (!ret) { + tst_brk_(file, lineno, TBROK, + "Failed to move %s to another namespace: %s", ifname, + tst_strerrno(tst_rtnl_errno)); + } + + return ret; +} + +int tst_netdev_change_ns_fd(const char *file, const int lineno, + const char *ifname, int nsfd) +{ + return change_ns(file, lineno, ifname, IFLA_NET_NS_FD, nsfd); +} + +int tst_netdev_change_ns_pid(const char *file, const int lineno, + const char *ifname, pid_t nspid) +{ + return change_ns(file, lineno, ifname, IFLA_NET_NS_PID, nspid); +} + +static int modify_route(const char *file, const int lineno, unsigned int action, + unsigned int flags, const char *ifname, unsigned int family, + const void *srcaddr, unsigned int srcprefix, size_t srclen, + const void *dstaddr, unsigned int dstprefix, size_t dstlen, + const void *gateway, size_t gatewaylen) +{ + struct tst_rtnl_context *ctx; + int ret; + int32_t index; + struct rtmsg info = { + .rtm_family = family, + .rtm_dst_len = dstprefix, + .rtm_src_len = srcprefix, + .rtm_table = RT_TABLE_MAIN, + .rtm_protocol = RTPROT_STATIC, + .rtm_type = RTN_UNICAST + }; + + if (!ifname && !gateway) { + tst_brk_(file, lineno, TBROK, + "Interface name or gateway address required"); + return 0; + } + + if (ifname && strlen(ifname) >= IFNAMSIZ) { + tst_brk_(file, lineno, TBROK, + "Network device name \"%s\" too long", ifname); + return 0; + } + + if (ifname) { + index = tst_netdev_index_by_name(file, lineno, ifname); + + if (index < 0) + return 0; + } + + if (action == RTM_DELROUTE) + info.rtm_scope = RT_SCOPE_NOWHERE; + else + info.rtm_scope = RT_SCOPE_UNIVERSE; + + ctx = create_request(file, lineno, action, flags, &info, sizeof(info)); + + if (srcaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_SRC, srcaddr, + srclen)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + if (dstaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_DST, dstaddr, + dstlen)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + if (gateway && !tst_rtnl_add_attr(file, lineno, ctx, RTA_GATEWAY, + gateway, gatewaylen)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + if (ifname && !tst_rtnl_add_attr(file, lineno, ctx, RTA_OIF, &index, + sizeof(index))) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_rtnl_send_validate(file, lineno, ctx); + tst_rtnl_destroy_context(file, lineno, ctx); + + if (!ret) { + tst_brk_(file, lineno, TBROK, + "Failed to modify network route: %s", + tst_strerrno(tst_rtnl_errno)); + } + + return ret; +} + +static int modify_route_inet(const char *file, const int lineno, + unsigned int action, unsigned int flags, const char *ifname, + in_addr_t srcaddr, unsigned int srcprefix, in_addr_t dstaddr, + unsigned int dstprefix, in_addr_t gateway) +{ + void *src = NULL, *dst = NULL, *gw = NULL; + size_t srclen = 0, dstlen = 0, gwlen = 0; + + if (srcprefix) { + src = &srcaddr; + srclen = sizeof(srcaddr); + } + + if (dstprefix) { + dst = &dstaddr; + dstlen = sizeof(dstaddr); + } + + if (gateway) { + gw = &gateway; + gwlen = sizeof(gateway); + } + + return modify_route(file, lineno, action, flags, ifname, AF_INET, src, + srcprefix, srclen, dst, dstprefix, dstlen, gw, gwlen); +} + +int tst_netdev_add_route(const char *file, const int lineno, + const char *ifname, unsigned int family, const void *srcaddr, + unsigned int srcprefix, size_t srclen, const void *dstaddr, + unsigned int dstprefix, size_t dstlen, const void *gateway, + size_t gatewaylen) +{ + return modify_route(file, lineno, RTM_NEWROUTE, + NLM_F_CREATE | NLM_F_EXCL, ifname, family, srcaddr, srcprefix, + srclen, dstaddr, dstprefix, dstlen, gateway, gatewaylen); +} + +int tst_netdev_add_route_inet(const char *file, const int lineno, + const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, + in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway) +{ + return modify_route_inet(file, lineno, RTM_NEWROUTE, + NLM_F_CREATE | NLM_F_EXCL, ifname, srcaddr, srcprefix, dstaddr, + dstprefix, gateway); +} + +int tst_netdev_remove_route(const char *file, const int lineno, + const char *ifname, unsigned int family, const void *srcaddr, + unsigned int srcprefix, size_t srclen, const void *dstaddr, + unsigned int dstprefix, size_t dstlen, const void *gateway, + size_t gatewaylen) +{ + return modify_route(file, lineno, RTM_DELROUTE, 0, ifname, family, + srcaddr, srcprefix, srclen, dstaddr, dstprefix, dstlen, + gateway, gatewaylen); +} + +int tst_netdev_remove_route_inet(const char *file, const int lineno, + const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, + in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway) +{ + return modify_route_inet(file, lineno, RTM_DELROUTE, 0, ifname, + srcaddr, srcprefix, dstaddr, dstprefix, gateway); +} diff --git a/lib/tst_parse_opts.c b/lib/tst_parse_opts.c old mode 100644 new mode 100755 diff --git a/lib/tst_path_has_mnt_flags.c b/lib/tst_path_has_mnt_flags.c old mode 100644 new mode 100755 diff --git a/lib/tst_pid.c b/lib/tst_pid.c old mode 100644 new mode 100755 index 9568cc9e91d2bc4d3fcb801734fef74671915cb4..21cadef2a782fd6c1f0352084d0b3200fb2f8db2 --- a/lib/tst_pid.c +++ b/lib/tst_pid.c @@ -18,14 +18,23 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include +#include +#include #include +#include #include "test.h" #include "tst_pid.h" #include "old_safe_file_ops.h" +#include "tst_safe_macros.h" #define PID_MAX_PATH "/proc/sys/kernel/pid_max" +#define CGROUPS_V1_SLICE_FMT "/sys/fs/cgroup/pids/user.slice/user-%d.slice/pids.max" +#define CGROUPS_V2_SLICE_FMT "/sys/fs/cgroup/user.slice/user-%d.slice/pids.max" +/* Leave some available processes for the OS */ +#define PIDS_RESERVE 50 pid_t tst_get_unused_pid_(void (*cleanup_fn) (void)) { @@ -36,29 +45,106 @@ pid_t tst_get_unused_pid_(void (*cleanup_fn) (void)) return pid; } +/* + * Get the effective session UID - either one invoking current test via sudo + * or the real UID. + */ +static unsigned int get_session_uid(void) +{ + const char *sudo_uid; + + sudo_uid = getenv("SUDO_UID"); + if (sudo_uid) { + unsigned int real_uid; + int ret; + + ret = sscanf(sudo_uid, "%u", &real_uid); + if (ret == 1) + return real_uid; + } + + return getuid(); +} + +static int read_session_pids_limit(const char *path_fmt, int uid, + void (*cleanup_fn) (void)) +{ + int max_pids, ret; + char max_pid_value[100]; + char path[PATH_MAX]; + + ret = snprintf(path, sizeof(path), path_fmt, uid); + if (ret < 0 || (size_t)ret >= sizeof(path)) + return -1; + + if (access(path, R_OK) != 0) { + tst_resm(TINFO, "Cannot read session user limits from '%s'", path); + return -1; + } + + SAFE_FILE_SCANF(cleanup_fn, path, "%s", max_pid_value); + if (!strcmp(max_pid_value, "max")) { + SAFE_FILE_SCANF(cleanup_fn, PID_MAX_PATH, "%d", &max_pids); + tst_resm(TINFO, "Found limit of processes %d (from %s=max)", max_pids, path); + } else { + max_pids = SAFE_STRTOL(max_pid_value, 0, INT_MAX); + tst_resm(TINFO, "Found limit of processes %d (from %s)", max_pids, path); + } + + return max_pids; +} + +static int get_session_pids_limit(void (*cleanup_fn) (void)) +{ + int max_pids, uid; + + uid = get_session_uid(); + max_pids = read_session_pids_limit(CGROUPS_V2_SLICE_FMT, uid, cleanup_fn); + if (max_pids < 0) + max_pids = read_session_pids_limit(CGROUPS_V1_SLICE_FMT, uid, + cleanup_fn); + + if (max_pids < 0) + return -1; + + return max_pids; +} + int tst_get_free_pids_(void (*cleanup_fn) (void)) { FILE *f; - int rc, used_pids, max_pids; + int rc, used_pids, max_pids, max_session_pids; f = popen("ps -eT | wc -l", "r"); if (!f) { - tst_resm(TBROK, "Could not run 'ps' to calculate used " "pids"); + tst_brkm(TBROK, cleanup_fn, "Could not run 'ps' to calculate used pids"); return -1; } rc = fscanf(f, "%i", &used_pids); pclose(f); if (rc != 1 || used_pids < 0) { - tst_resm(TBROK, "Could not read output of 'ps' to " - "calculate used pids"); + tst_brkm(TBROK, cleanup_fn, "Could not read output of 'ps' to calculate used pids"); return -1; } SAFE_FILE_SCANF(cleanup_fn, PID_MAX_PATH, "%d", &max_pids); + max_session_pids = get_session_pids_limit(cleanup_fn); + if ((max_session_pids > 0) && (max_session_pids < max_pids)) + max_pids = max_session_pids; + + if (max_pids > PIDS_RESERVE) + max_pids -= PIDS_RESERVE; + else + max_pids = 0; + /* max_pids contains the maximum PID + 1, * used_pids contains used PIDs + 1, * so this additional '1' is eliminated by the substraction */ + if (used_pids >= max_pids) { + tst_brkm(TBROK, cleanup_fn, "No free pids"); + return 0; + } return max_pids - used_pids; } diff --git a/lib/tst_process_state.c b/lib/tst_process_state.c old mode 100644 new mode 100755 index 11790c9473aa992ba837fff56803d84c4e67126c..08a9d096650283e5fc2bf692102efb68c641fe49 --- a/lib/tst_process_state.c +++ b/lib/tst_process_state.c @@ -1,24 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2012-2014 Cyril Hrubis chrubis@suse.cz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (c) 2021 Xie Ziyao */ #include @@ -29,8 +12,8 @@ #include "tst_process_state.h" int tst_process_state_wait(const char *file, const int lineno, - void (*cleanup_fn)(void), pid_t pid, - const char state, unsigned int msec_timeout) + void (*cleanup_fn)(void), pid_t pid, + const char state, unsigned int msec_timeout) { char proc_path[128], cur_state; unsigned int msecs = 0; @@ -39,7 +22,7 @@ int tst_process_state_wait(const char *file, const int lineno, for (;;) { safe_file_scanf(file, lineno, cleanup_fn, proc_path, - "%*i %*s %c", &cur_state); + "%*i %*s %c", &cur_state); if (state == cur_state) break; @@ -64,16 +47,17 @@ int tst_process_state_wait2(pid_t pid, const char state) for (;;) { FILE *f = fopen(proc_path, "r"); + if (!f) { fprintf(stderr, "Failed to open '%s': %s\n", - proc_path, strerror(errno)); + proc_path, strerror(errno)); return 1; } if (fscanf(f, "%*i %*s %c", &cur_state) != 1) { fclose(f); fprintf(stderr, "Failed to read '%s': %s\n", - proc_path, strerror(errno)); + proc_path, strerror(errno)); return 1; } fclose(f); @@ -84,3 +68,23 @@ int tst_process_state_wait2(pid_t pid, const char state) usleep(10000); } } + +int tst_process_exit_wait(pid_t pid, unsigned int msec_timeout) +{ + unsigned int msecs = 0; + + for (;;) { + if (kill(pid, 0) && errno == ESRCH) + break; + + usleep(1000); + msecs += 1; + + if (msec_timeout && msecs >= msec_timeout) { + errno = ETIMEDOUT; + return 0; + } + } + + return 1; +} diff --git a/lib/tst_res.c b/lib/tst_res.c old mode 100644 new mode 100755 index c35f41b74c553adda053e227ee7acd90f1788f8a..8d86b48a42c0f2bce1e2312f7d5075b9c0b2358e --- a/lib/tst_res.c +++ b/lib/tst_res.c @@ -575,7 +575,7 @@ void tst_resm_hexd_(const char *file, const int lineno, int ttype, } } -void tst_brkm_(const char *file, const int lineno, int ttype, +void tst_brkm__(const char *file, const int lineno, int ttype, void (*func)(void), const char *arg_fmt, ...) { char tmesg[USERMESG]; @@ -589,10 +589,10 @@ void tst_brkm_(const char *file, const int lineno, int ttype, } tst_brk_(file, lineno, ttype, "%s", tmesg); - } else { - tst_brk__(file, lineno, ttype, func, "%s", tmesg); } + tst_brk__(file, lineno, ttype, func, "%s", tmesg); + /* Shouldn't be reached, but fixes build time warnings about noreturn. */ abort(); } diff --git a/lib/tst_resource.c b/lib/tst_resource.c old mode 100644 new mode 100755 index 0b9b381f12a9296c505120ab327a3571f1f23333..c35d05a25bc8c552811c1e95924dd752fd524e8e --- a/lib/tst_resource.c +++ b/lib/tst_resource.c @@ -102,9 +102,8 @@ void tst_resource_copy(const char *file, const int lineno, const char *filename, const char *dest) { if (!tst_tmpdir_created()) { - tst_brkm(TBROK, cleanup_fn, - "Temporary directory doesn't exist at %s:%d", - file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Temporary directory doesn't exist"); return; } @@ -133,6 +132,6 @@ void tst_resource_copy(const char *file, const int lineno, if (file_copy(file, lineno, cleanup_fn, startwd, filename, dest)) return; - tst_brkm(TBROK, cleanup_fn, "Failed to copy resource '%s' at %s:%d", - filename, file, lineno); + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Failed to copy resource '%s'", filename); } diff --git a/lib/tst_rtctime.c b/lib/tst_rtctime.c new file mode 100755 index 0000000000000000000000000000000000000000..c62ac731d1510b9be924f1fa395b9b66ec7c76fe --- /dev/null +++ b/lib/tst_rtctime.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Unisoc Communications Inc. + * + * This file is a implementation for rtc set read,covert to tm functions + */ + +#include +#include +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_rtctime.h" + +#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) + +static const unsigned char rtc_days_in_month[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static inline bool is_leap_year(unsigned int year) +{ + return (!(year % 4) && (year % 100)) || !(year % 400); +} + +static long long tst_mktime(const unsigned int year0, const unsigned int mon0, + const unsigned int day, const unsigned int hour, + const unsigned int min, const unsigned int sec) +{ + unsigned int mon = mon0, year = year0; + + /* 1..12 -> 11,12,1..10 */ + mon -= 2; + if (0 >= (int) (mon)) { + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + + return ((((long long) + (year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours - midnight tomorrow handled here */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +/* + * The number of days in the month. + */ +static int rtc_month_days(unsigned int month, unsigned int year) +{ + return rtc_days_in_month[month] + (is_leap_year(year) && month == 1); +} + +/* + * tst_rtc_time_to_tm - Converts time_t to rtc_time. + * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. + */ +void tst_rtc_time_to_tm(long long time, struct rtc_time *tm) +{ + unsigned int month, year, secs; + int days; + + /* time must be positive */ + days = time / 86400; + secs = time % 86400; + + /* day of the week, 1970-01-01 was a Thursday */ + tm->tm_wday = (days + 4) % 7; + + year = 1970 + days / 365; + days -= (year - 1970) * 365 + + LEAPS_THRU_END_OF(year - 1) + - LEAPS_THRU_END_OF(1970 - 1); + while (days < 0) { + year -= 1; + days += 365 + is_leap_year(year); + } + tm->tm_year = year - 1900; + tm->tm_yday = days + 1; + + for (month = 0; month < 11; month++) { + int newdays; + + newdays = days - rtc_month_days(month, year); + if (newdays < 0) + break; + days = newdays; + } + tm->tm_mon = month; + tm->tm_mday = days + 1; + + tm->tm_hour = secs / 3600; + secs -= tm->tm_hour * 3600; + tm->tm_min = secs / 60; + tm->tm_sec = secs - tm->tm_min * 60; + + tm->tm_isdst = 0; +} + +/* + * tst_rtc_tm_to_time - Converts rtc_time to time_t. + * Convert Gregorian date to seconds since 01-01-1970 00:00:00. + */ +long long tst_rtc_tm_to_time(struct rtc_time *tm) +{ + return tst_mktime(((unsigned int)tm->tm_year + 1900), tm->tm_mon + 1, + tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); +} + +int tst_rtc_ioctl(const char *rtc_dev, unsigned long request, + struct rtc_time *rtc_tm) +{ + int ret; + int rtc_fd = -1; + + rtc_fd = SAFE_OPEN(rtc_dev, O_RDONLY); + + ret = ioctl(rtc_fd, request, rtc_tm); + + if (ret != 0) + return -1; + + if (rtc_fd > 0) + SAFE_CLOSE(rtc_fd); + + return 0; +} diff --git a/lib/tst_rtnetlink.c b/lib/tst_rtnetlink.c new file mode 100755 index 0000000000000000000000000000000000000000..a2411dfdea57446da4b8a70114b50f5caf312e38 --- /dev/null +++ b/lib/tst_rtnetlink.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Linux Test Project + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_rtnetlink.h" + +struct tst_rtnl_context { + int socket; + pid_t pid; + uint32_t seq; + size_t bufsize, datalen; + char *buffer; + struct nlmsghdr *curmsg; +}; + +int tst_rtnl_errno; + +static int tst_rtnl_grow_buffer(const char *file, const int lineno, + struct tst_rtnl_context *ctx, size_t size) +{ + size_t needed, offset, curlen = NLMSG_ALIGN(ctx->datalen); + char *buf; + + if (ctx->bufsize - curlen >= size) + return 1; + + needed = size - (ctx->bufsize - curlen); + size = ctx->bufsize + (ctx->bufsize > needed ? ctx->bufsize : needed); + size = NLMSG_ALIGN(size); + buf = safe_realloc(file, lineno, ctx->buffer, size); + + if (!buf) + return 0; + + memset(buf + ctx->bufsize, 0, size - ctx->bufsize); + offset = ((char *)ctx->curmsg) - ctx->buffer; + ctx->buffer = buf; + ctx->curmsg = (struct nlmsghdr *)(buf + offset); + ctx->bufsize = size; + + return 1; +} + +void tst_rtnl_destroy_context(const char *file, const int lineno, + struct tst_rtnl_context *ctx) +{ + safe_close(file, lineno, NULL, ctx->socket); + free(ctx->buffer); + free(ctx); +} + +struct tst_rtnl_context *tst_rtnl_create_context(const char *file, + const int lineno) +{ + struct tst_rtnl_context *ctx; + struct sockaddr_nl addr = { .nl_family = AF_NETLINK }; + + ctx = safe_malloc(file, lineno, NULL, sizeof(struct tst_rtnl_context)); + + if (!ctx) + return NULL; + + ctx->pid = 0; + ctx->seq = 0; + ctx->buffer = NULL; + ctx->bufsize = 1024; + ctx->datalen = 0; + ctx->curmsg = NULL; + ctx->socket = safe_socket(file, lineno, NULL, AF_NETLINK, + SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE); + + if (ctx->socket < 0) { + free(ctx); + return NULL; + } + + if (safe_bind(file, lineno, NULL, ctx->socket, (struct sockaddr *)&addr, + sizeof(addr))) { + tst_rtnl_destroy_context(file, lineno, ctx); + return NULL; + } + + ctx->buffer = safe_malloc(file, lineno, NULL, ctx->bufsize); + + if (!ctx->buffer) { + tst_rtnl_destroy_context(file, lineno, ctx); + return NULL; + } + + memset(ctx->buffer, 0, ctx->bufsize); + + return ctx; +} + +void tst_rtnl_free_message(struct tst_rtnl_message *msg) +{ + if (!msg) + return; + + // all ptr->header and ptr->info pointers point to the same buffer + // msg->header is the start of the buffer + free(msg->header); + free(msg); +} + +int tst_rtnl_send(const char *file, const int lineno, + struct tst_rtnl_context *ctx) +{ + int ret; + struct sockaddr_nl addr = { .nl_family = AF_NETLINK }; + struct iovec iov; + struct msghdr msg = { + .msg_name = &addr, + .msg_namelen = sizeof(addr), + .msg_iov = &iov, + .msg_iovlen = 1 + }; + + if (!ctx->curmsg) { + tst_brk_(file, lineno, TBROK, "%s(): No message to send", + __func__); + return 0; + } + + if (ctx->curmsg->nlmsg_flags & NLM_F_MULTI) { + struct nlmsghdr eom = { .nlmsg_type = NLMSG_DONE }; + + if (!tst_rtnl_add_message(file, lineno, ctx, &eom, NULL, 0)) + return 0; + + /* NLMSG_DONE message must not have NLM_F_MULTI flag */ + ctx->curmsg->nlmsg_flags = 0; + } + + iov.iov_base = ctx->buffer; + iov.iov_len = ctx->datalen; + ret = safe_sendmsg(file, lineno, ctx->datalen, ctx->socket, &msg, 0); + + if (ret > 0) + ctx->curmsg = NULL; + + return ret; +} + +int tst_rtnl_wait(struct tst_rtnl_context *ctx) +{ + struct pollfd fdinfo = { + .fd = ctx->socket, + .events = POLLIN + }; + + return poll(&fdinfo, 1, 1000); +} + +struct tst_rtnl_message *tst_rtnl_recv(const char *file, const int lineno, + struct tst_rtnl_context *ctx) +{ + char tmp, *tmpbuf, *buffer = NULL; + struct tst_rtnl_message *ret; + struct nlmsghdr *ptr; + size_t retsize, bufsize = 0; + ssize_t size; + int i, size_left, msgcount; + + /* Each recv() call returns one message, read all pending messages */ + while (1) { + errno = 0; + size = recv(ctx->socket, &tmp, 1, + MSG_DONTWAIT | MSG_PEEK | MSG_TRUNC); + + if (size < 0) { + if (errno != EAGAIN) { + tst_brk_(file, lineno, TBROK | TERRNO, + "recv() failed"); + } + + break; + } + + tmpbuf = safe_realloc(file, lineno, buffer, bufsize + size); + + if (!tmpbuf) + break; + + buffer = tmpbuf; + size = safe_recv(file, lineno, size, ctx->socket, + buffer + bufsize, size, 0); + + if (size < 0) + break; + + bufsize += size; + } + + if (!bufsize) { + free(buffer); + return NULL; + } + + ptr = (struct nlmsghdr *)buffer; + size_left = bufsize; + msgcount = 0; + + for (; size_left > 0 && NLMSG_OK(ptr, size_left); msgcount++) + ptr = NLMSG_NEXT(ptr, size_left); + + retsize = (msgcount + 1) * sizeof(struct tst_rtnl_message); + ret = safe_malloc(file, lineno, NULL, retsize); + + if (!ret) { + free(buffer); + return NULL; + } + + memset(ret, 0, retsize); + ptr = (struct nlmsghdr *)buffer; + size_left = bufsize; + + for (i = 0; i < msgcount; i++, ptr = NLMSG_NEXT(ptr, size_left)) { + ret[i].header = ptr; + ret[i].payload = NLMSG_DATA(ptr); + ret[i].payload_size = NLMSG_PAYLOAD(ptr, 0); + + if (ptr->nlmsg_type == NLMSG_ERROR) + ret[i].err = NLMSG_DATA(ptr); + } + + return ret; +} + +int tst_rtnl_add_message(const char *file, const int lineno, + struct tst_rtnl_context *ctx, const struct nlmsghdr *header, + const void *payload, size_t payload_size) +{ + size_t size; + unsigned int extra_flags = 0; + + if (!tst_rtnl_grow_buffer(file, lineno, ctx, NLMSG_SPACE(payload_size))) + return 0; + + if (!ctx->curmsg) { + /* + * datalen may hold the size of last sent message for ACK + * checking, reset it back to 0 here + */ + ctx->datalen = 0; + ctx->curmsg = (struct nlmsghdr *)ctx->buffer; + } else { + size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len); + + extra_flags = NLM_F_MULTI; + ctx->curmsg->nlmsg_flags |= extra_flags; + ctx->curmsg = NLMSG_NEXT(ctx->curmsg, size); + ctx->datalen = NLMSG_ALIGN(ctx->datalen); + } + + *ctx->curmsg = *header; + ctx->curmsg->nlmsg_len = NLMSG_LENGTH(payload_size); + ctx->curmsg->nlmsg_flags |= extra_flags; + ctx->curmsg->nlmsg_seq = ctx->seq++; + ctx->curmsg->nlmsg_pid = ctx->pid; + + if (payload_size) + memcpy(NLMSG_DATA(ctx->curmsg), payload, payload_size); + + ctx->datalen += ctx->curmsg->nlmsg_len; + + return 1; +} + +int tst_rtnl_add_attr(const char *file, const int lineno, + struct tst_rtnl_context *ctx, unsigned short type, + const void *data, unsigned short len) +{ + size_t size; + struct rtattr *attr; + + if (!ctx->curmsg) { + tst_brk_(file, lineno, TBROK, + "%s(): No message to add attributes to", __func__); + return 0; + } + + if (!tst_rtnl_grow_buffer(file, lineno, ctx, RTA_SPACE(len))) + return 0; + + size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len); + attr = (struct rtattr *)(((char *)ctx->curmsg) + size); + attr->rta_type = type; + attr->rta_len = RTA_LENGTH(len); + memcpy(RTA_DATA(attr), data, len); + ctx->curmsg->nlmsg_len = size + attr->rta_len; + ctx->datalen = NLMSG_ALIGN(ctx->datalen) + attr->rta_len; + + return 1; +} + +int tst_rtnl_add_attr_string(const char *file, const int lineno, + struct tst_rtnl_context *ctx, unsigned short type, + const char *data) +{ + return tst_rtnl_add_attr(file, lineno, ctx, type, data, + strlen(data) + 1); +} + +int tst_rtnl_add_attr_list(const char *file, const int lineno, + struct tst_rtnl_context *ctx, + const struct tst_rtnl_attr_list *list) +{ + int i, ret; + size_t offset; + + for (i = 0; list[i].len >= 0; i++) { + if (list[i].len > USHRT_MAX) { + tst_brk_(file, lineno, TBROK, + "%s(): Attribute value too long", __func__); + return -1; + } + + offset = NLMSG_ALIGN(ctx->datalen); + ret = tst_rtnl_add_attr(file, lineno, ctx, list[i].type, + list[i].data, list[i].len); + + if (!ret) + return -1; + + if (list[i].sublist) { + struct rtattr *attr; + + ret = tst_rtnl_add_attr_list(file, lineno, ctx, + list[i].sublist); + + if (ret < 0) + return ret; + + attr = (struct rtattr *)(ctx->buffer + offset); + + if (ctx->datalen - offset > USHRT_MAX) { + tst_brk_(file, lineno, TBROK, + "%s(): Sublist too long", __func__); + return -1; + } + + attr->rta_len = ctx->datalen - offset; + } + } + + return i; +} + +int tst_rtnl_check_acks(const char *file, const int lineno, + struct tst_rtnl_context *ctx, struct tst_rtnl_message *res) +{ + struct nlmsghdr *msg = (struct nlmsghdr *)ctx->buffer; + int size_left = ctx->datalen; + + for (; size_left > 0 && NLMSG_OK(msg, size_left); + msg = NLMSG_NEXT(msg, size_left)) { + + if (!(msg->nlmsg_flags & NLM_F_ACK)) + continue; + + while (res->header && res->header->nlmsg_seq != msg->nlmsg_seq) + res++; + + if (!res->err || res->header->nlmsg_seq != msg->nlmsg_seq) { + tst_brk_(file, lineno, TBROK, + "No ACK found for Netlink message %u", + msg->nlmsg_seq); + return 0; + } + + if (res->err->error) { + tst_rtnl_errno = -res->err->error; + return 0; + } + } + + return 1; +} + +int tst_rtnl_send_validate(const char *file, const int lineno, + struct tst_rtnl_context *ctx) +{ + struct tst_rtnl_message *response; + int ret; + + tst_rtnl_errno = 0; + + if (tst_rtnl_send(file, lineno, ctx) <= 0) + return 0; + + tst_rtnl_wait(ctx); + response = tst_rtnl_recv(file, lineno, ctx); + + if (!response) + return 0; + + ret = tst_rtnl_check_acks(file, lineno, ctx, response); + tst_rtnl_free_message(response); + + return ret; +} diff --git a/lib/tst_safe_file_at.c b/lib/tst_safe_file_at.c new file mode 100755 index 0000000000000000000000000000000000000000..ca8ef2f687c5b1c735021c758c84059fda0e0c0f --- /dev/null +++ b/lib/tst_safe_file_at.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 SUSE LLC + */ + +#define _GNU_SOURCE +#include +#include "lapi/fcntl.h" +#include "tst_safe_file_at.h" + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +static char fd_path[PATH_MAX]; + +const char *tst_decode_fd(const int fd) +{ + ssize_t ret; + char proc_path[32]; + + if (fd < 0) + return "!"; + + sprintf(proc_path, "/proc/self/fd/%d", fd); + ret = readlink(proc_path, fd_path, sizeof(fd_path)); + + if (ret < 0) + return "?"; + + fd_path[ret] = '\0'; + + return fd_path; +} + +int safe_openat(const char *const file, const int lineno, + const int dirfd, const char *const path, const int oflags, ...) +{ + va_list ap; + int fd; + mode_t mode; + + va_start(ap, oflags); + mode = va_arg(ap, int); + va_end(ap); + + fd = openat(dirfd, path, oflags, mode); + if (fd > -1) + return fd; + + tst_brk_(file, lineno, TBROK | TERRNO, + "openat(%d<%s>, '%s', %o, %o)", + dirfd, tst_decode_fd(dirfd), path, oflags, mode); + + return fd; +} + +ssize_t safe_file_readat(const char *const file, const int lineno, + const int dirfd, const char *const path, + char *const buf, const size_t nbyte) +{ + int fd = safe_openat(file, lineno, dirfd, path, O_RDONLY); + ssize_t rval; + + if (fd < 0) + return -1; + + rval = safe_read(file, lineno, NULL, 0, fd, buf, nbyte - 1); + if (rval < 0) + return -1; + + close(fd); + buf[rval] = '\0'; + + if (rval >= (ssize_t)nbyte - 1) { + tst_brk_(file, lineno, TBROK, + "Buffer length %zu too small to read %d<%s>/%s", + nbyte, dirfd, tst_decode_fd(dirfd), path); + } + + return rval; +} + +int tst_file_vprintfat(const int dirfd, const char *const path, + const char *const fmt, va_list va) +{ + const int fd = openat(dirfd, path, O_WRONLY); + int ret, errno_cpy; + + if (fd < 0) + return -1; + + ret = vdprintf(fd, fmt, va); + errno_cpy = errno; + close(fd); + + if (ret < 0) { + errno = errno_cpy; + return -2; + } + + return ret; +} + +int tst_file_printfat(const int dirfd, const char *const path, + const char *const fmt, ...) +{ + va_list va; + int rval; + + va_start(va, fmt); + rval = tst_file_vprintfat(dirfd, path, fmt, va); + va_end(va); + + return rval; +} + +int safe_file_vprintfat(const char *const file, const int lineno, + const int dirfd, const char *const path, + const char *const fmt, va_list va) +{ + char buf[16]; + va_list vac; + int rval, errno_cpy; + + va_copy(vac, va); + + rval = tst_file_vprintfat(dirfd, path, fmt, va); + + if (rval == -2) { + errno_cpy = errno; + rval = vsnprintf(buf, sizeof(buf), fmt, vac); + va_end(vac); + + if (rval >= (ssize_t)sizeof(buf)) + strcpy(buf + sizeof(buf) - 5, "..."); + else if (rval < 0) + buf[0] = '\0'; + + errno = errno_cpy; + tst_brk_(file, lineno, TBROK | TERRNO, + "vdprintf(%d<%s>, '%s', '%s'<%s>)", + dirfd, tst_decode_fd(dirfd), path, fmt, buf); + return -1; + } + + va_end(vac); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "openat(%d<%s>, '%s', O_WRONLY)", + dirfd, tst_decode_fd(dirfd), path); + } + + return rval; +} + +int safe_file_printfat(const char *const file, const int lineno, + const int dirfd, const char *const path, + const char *const fmt, ...) +{ + va_list va; + int rval; + + va_start(va, fmt); + rval = safe_file_vprintfat(file, lineno, dirfd, path, fmt, va); + va_end(va); + + return rval; +} + +int safe_unlinkat(const char *const file, const int lineno, + const int dirfd, const char *const path, const int flags) +{ + const int rval = unlinkat(dirfd, path, flags); + const char *flags_sym; + + if (!rval) + return rval; + + switch(flags) { + case AT_REMOVEDIR: + flags_sym = "AT_REMOVEDIR"; + break; + case 0: + flags_sym = "0"; + break; + default: + flags_sym = "?"; + break; + } + + tst_brk_(file, lineno, TBROK | TERRNO, + "unlinkat(%d<%s>, '%s', %s)", + dirfd, tst_decode_fd(dirfd), path, flags_sym); + + return rval; +} diff --git a/lib/tst_safe_io_uring.c b/lib/tst_safe_io_uring.c new file mode 100755 index 0000000000000000000000000000000000000000..f300fd38c10144607ddd2b3439a676b9a82892a9 --- /dev/null +++ b/lib/tst_safe_io_uring.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 SUSE LLC + */ + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_safe_io_uring.h" + +int safe_io_uring_init(const char *file, const int lineno, + unsigned int entries, struct io_uring_params *params, + struct tst_io_uring *uring) +{ + errno = 0; + uring->fd = io_uring_setup(entries, params); + + if (uring->fd == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "io_uring_setup() failed"); + return uring->fd; + } else if (uring->fd < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "io_uring_setup() returned invalid value %d", + uring->fd); + return uring->fd; + } + + uring->sqr_size = params->sq_entries; + uring->cqr_size = params->cq_entries; + uring->sqr_mapsize = params->sq_off.array + + params->sq_entries * sizeof(__u32); + uring->cqr_mapsize = params->cq_off.cqes + + params->cq_entries * sizeof(struct io_uring_cqe); + + uring->sqr_base = safe_mmap(file, lineno, NULL, uring->sqr_mapsize, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, uring->fd, + IORING_OFF_SQ_RING); + + if (uring->sqr_base == MAP_FAILED) + return -1; + + uring->sqr_entries = safe_mmap(file, lineno, NULL, + params->sq_entries * sizeof(struct io_uring_sqe), + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, uring->fd, + IORING_OFF_SQES); + + if (uring->sqr_entries == MAP_FAILED) + return -1; + + uring->cqr_base = safe_mmap(file, lineno, NULL, uring->cqr_mapsize, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, uring->fd, + IORING_OFF_CQ_RING); + + if (uring->cqr_base == MAP_FAILED) + return -1; + + uring->sqr_head = uring->sqr_base + params->sq_off.head; + uring->sqr_tail = uring->sqr_base + params->sq_off.tail; + uring->sqr_mask = uring->sqr_base + params->sq_off.ring_mask; + uring->sqr_flags = uring->sqr_base + params->sq_off.flags; + uring->sqr_dropped = uring->sqr_base + params->sq_off.dropped; + uring->sqr_array = uring->sqr_base + params->sq_off.array; + + uring->cqr_head = uring->cqr_base + params->cq_off.head; + uring->cqr_tail = uring->cqr_base + params->cq_off.tail; + uring->cqr_mask = uring->cqr_base + params->cq_off.ring_mask; + uring->cqr_overflow = uring->cqr_base + params->cq_off.overflow; + uring->cqr_entries = uring->cqr_base + params->cq_off.cqes; + return uring->fd; +} + +int safe_io_uring_close(const char *file, const int lineno, + struct tst_io_uring *uring) +{ + int ret; + + safe_munmap(file, lineno, NULL, uring->cqr_base, uring->cqr_mapsize); + safe_munmap(file, lineno, NULL, uring->sqr_entries, + uring->sqr_size * sizeof(struct io_uring_sqe)); + safe_munmap(file, lineno, NULL, uring->sqr_base, uring->sqr_mapsize); + ret = safe_close(file, lineno, NULL, uring->fd); + uring->fd = -1; + return ret; +} + +int safe_io_uring_enter(const char *file, const int lineno, int strict, + int fd, unsigned int to_submit, unsigned int min_complete, + unsigned int flags, sigset_t *sig) +{ + int ret; + + errno = 0; + ret = io_uring_enter(fd, to_submit, min_complete, flags, sig); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "io_uring_enter() failed"); + } else if (ret < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid io_uring_enter() return value %d", ret); + } else if (strict && to_submit != (unsigned int)ret) { + tst_brk_(file, lineno, TBROK, + "io_uring_enter() submitted %d items (expected %d)", + ret, to_submit); + } + + return ret; +} diff --git a/lib/tst_safe_macros.c b/lib/tst_safe_macros.c old mode 100644 new mode 100755 index dbdfcc5be9803f225025b2970d0b66230058e1c0..36b5da66f4375146cae65ee7138c4d2e2c148547 --- a/lib/tst_safe_macros.c +++ b/lib/tst_safe_macros.c @@ -5,6 +5,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -23,10 +24,14 @@ int safe_setpgid(const char *file, const int lineno, pid_t pid, pid_t pgid) int rval; rval = setpgid(pid, pgid); - if (rval) { - tst_brk(TBROK | TERRNO, - "%s:%d: setpgid(%i, %i) failed", - file, lineno, pid, pgid); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "setpgid(%i, %i) failed", pid, pgid); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid setpgid(%i, %i) return value %d", pid, pgid, + rval); } return rval; @@ -37,33 +42,50 @@ pid_t safe_getpgid(const char *file, const int lineno, pid_t pid) pid_t pgid; pgid = getpgid(pid); + if (pgid == -1) { - tst_brk(TBROK | TERRNO, - "%s:%d: getpgid(%i) failed", file, lineno, pid); + tst_brk_(file, lineno, TBROK | TERRNO, "getpgid(%i) failed", + pid); + } else if (pgid < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid getpgid(%i) return value %d", pid, pgid); } return pgid; } -int safe_fanotify_init(const char *file, const int lineno, - unsigned int flags, unsigned int event_f_flags) +int safe_setgroups(const char *file, const int lineno, size_t size, const gid_t *list) { int rval; -#ifdef HAVE_SYS_FANOTIFY_H - rval = fanotify_init(flags, event_f_flags); + rval = setgroups(size, list); if (rval == -1) { - if (errno == ENOSYS) { - tst_brk(TCONF, - "fanotify is not configured in this kernel."); - } - tst_brk(TBROK | TERRNO, - "%s:%d: fanotify_init() failed", file, lineno); + tst_brk_(file, lineno, TBROK | TERRNO, + "setgroups(%zu, %p) failed", size, list); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid setgroups(%zu, %p) return value %d", size, + list, rval); + } + + return rval; +} + +int safe_getgroups(const char *file, const int lineno, int size, gid_t list[]) +{ + int rval; + + rval = getgroups(size, list); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "getgroups(%i, %p)", size, list); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid getgroups(%i, %p) return value %d", size, + list, rval); } -#else - tst_brk(TCONF, "Header is not present"); -#endif /* HAVE_SYS_FANOTIFY_H */ return rval; } @@ -73,9 +95,13 @@ int safe_personality(const char *filename, unsigned int lineno, { int prev_persona = personality(persona); - if (prev_persona < 0) { + if (prev_persona == -1) { tst_brk_(filename, lineno, TBROK | TERRNO, "persona(%ld) failed", persona); + } else if (prev_persona < 0) { + tst_brk_(filename, lineno, TBROK | TERRNO, + "Invalid persona(%ld) return value %d", persona, + prev_persona); } return prev_persona; @@ -87,31 +113,77 @@ int safe_setregid(const char *file, const int lineno, int rval; rval = setregid(rgid, egid); + if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "setregid(%li, %li) failed", - (long)rgid, (long)egid); + "setregid(%li, %li) failed", (long)rgid, (long)egid); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid setregid(%li, %li) return value %d", + (long)rgid, (long)egid, rval); } return rval; } - int safe_setreuid(const char *file, const int lineno, uid_t ruid, uid_t euid) { int rval; rval = setreuid(ruid, euid); + if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "setreuid(%li, %li) failed", - (long)ruid, (long)euid); + "setreuid(%li, %li) failed", (long)ruid, (long)euid); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid setreuid(%li, %li) return value %d", + (long)ruid, (long)euid, rval); } return rval; } +int safe_setresgid(const char *file, const int lineno, + gid_t rgid, gid_t egid, gid_t sgid) +{ + int ret; + + ret = setresgid(rgid, egid, sgid); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "setregid(%li, %li, %li) failed", (long)rgid, + (long)egid, (long)sgid); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid setregid(%li, %li, %li) return value %d", + (long)rgid, (long)egid, (long)sgid, ret); + } + + return ret; +} + +int safe_setresuid(const char *file, const int lineno, + uid_t ruid, uid_t euid, uid_t suid) +{ + int ret; + + ret = setresuid(ruid, euid, suid); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "setreuid(%li, %li, %li) failed", (long)ruid, + (long)euid, (long)suid); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid setreuid(%li, %li, %li) return value %d", + (long)ruid, (long)euid, (long)suid, ret); + } + + return ret; +} int safe_sigaction(const char *file, const int lineno, int signum, const struct sigaction *act, @@ -125,6 +197,138 @@ int safe_sigaction(const char *file, const int lineno, tst_brk_(file, lineno, TBROK | TERRNO, "sigaction(%s (%d), %p, %p) failed", tst_strsig(signum), signum, act, oldact); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid sigaction(%s (%d), %p, %p) return value %d", + tst_strsig(signum), signum, act, oldact, rval); + } + + return rval; +} + +int safe_sigaddset(const char *file, const int lineno, + sigset_t *sigs, int signo) +{ + int rval; + + rval = sigaddset(sigs, signo); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "sigaddset() %s (%i) failed", tst_strsig(signo), + signo); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid sigaddset() %s (%i) return value %d", + tst_strsig(signo), signo, rval); + } + + return rval; +} + +int safe_sigdelset(const char *file, const int lineno, + sigset_t *sigs, int signo) +{ + int rval; + + rval = sigdelset(sigs, signo); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "sigdelset() %s (%i) failed", tst_strsig(signo), + signo); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid sigdelset() %s (%i) return value %d", + tst_strsig(signo), signo, rval); + } + + return rval; +} + +int safe_sigemptyset(const char *file, const int lineno, + sigset_t *sigs) +{ + int rval; + + rval = sigemptyset(sigs); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, "sigemptyset() failed"); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid sigemptyset() return value %d", rval); + } + + return rval; +} + +int safe_sigfillset(const char *file, const int lineno, + sigset_t *sigs) +{ + int rval; + + rval = sigfillset(sigs); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, "sigfillset() failed"); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid sigfillset() return value %d", rval); + } + + return rval; +} + +static const char *strhow(int how) +{ + switch (how) { + case SIG_BLOCK: + return "SIG_BLOCK"; + case SIG_UNBLOCK: + return "SIG_UNBLOCK"; + case SIG_SETMASK: + return "SIG_SETMASK"; + default: + return "???"; + } +} + +int safe_sigprocmask(const char *file, const int lineno, + int how, sigset_t *set, sigset_t *oldset) +{ + int rval; + + rval = sigprocmask(how, set, oldset); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "sigprocmask(%s, %p, %p) failed", strhow(how), set, + oldset); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid sigprocmask(%s, %p, %p) return value %d", + strhow(how), set, oldset, rval); + } + + return rval; +} + +int safe_sigwait(const char *file, const int lineno, + sigset_t *set, int *sig) +{ + int rval; + + rval = sigwait(set, sig); + + if (rval > 0) { + errno = rval; + tst_brk_(file, lineno, TBROK | TERRNO, + "sigwait(%p, %p) failed", set, sig); + } else if (rval) { + tst_brk_(file, lineno, TBROK, + "Invalid sigwait(%p, %p) return value %d", set, sig, + rval); } return rval; @@ -181,19 +385,24 @@ int safe_chroot(const char *file, const int lineno, const char *path) int rval; rval = chroot(path); + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, "chroot(%s) failed", + path); + } else if (rval) { tst_brk_(file, lineno, TBROK | TERRNO, - "chroot(%s) failed", path); + "Invalid chroot(%s) return value %d", path, rval); } return rval; } -void safe_unshare(const char *file, const int lineno, int flags) +int safe_unshare(const char *file, const int lineno, int flags) { int res; res = unshare(flags); + if (res == -1) { if (errno == EINVAL) { tst_brk_(file, lineno, TCONF | TERRNO, @@ -202,18 +411,30 @@ void safe_unshare(const char *file, const int lineno, int flags) tst_brk_(file, lineno, TBROK | TERRNO, "unshare(%d) failed", flags); } + } else if (res) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid unshare(%d) return value %d", flags, res); } + + return res; } -void safe_setns(const char *file, const int lineno, int fd, int nstype) +int safe_setns(const char *file, const int lineno, int fd, int nstype) { int ret; ret = setns(fd, nstype); + if (ret == -1) { tst_brk_(file, lineno, TBROK | TERRNO, "setns(%i, %i) failed", - fd, nstype); + fd, nstype); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid setns(%i, %i) return value %d", fd, nstype, + ret); } + + return ret; } long tst_safe_ptrace(const char *file, const int lineno, int req, pid_t pid, @@ -239,11 +460,95 @@ int safe_pipe2(const char *file, const int lineno, int fildes[2], int flags) int ret; ret = pipe2(fildes, flags); + if (ret == -1) { tst_brk_(file, lineno, TBROK | TERRNO, - "pipe2({%d,%d}) failed with flag(%d)", - fildes[0], fildes[1], flags); + "pipe2({%d,%d}) failed with flag(%d)", fildes[0], + fildes[1], flags); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid pipe2({%d,%d}, %d) return value %d", + fildes[0], fildes[1], flags, ret); } return ret; } + +int safe_dup(const char *file, const int lineno, int oldfd) +{ + int rval; + + rval = dup(oldfd); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "dup(%i) failed", oldfd); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid dup(%i) return value %d", oldfd, rval); + } + + return rval; +} + +int safe_dup2(const char *file, const int lineno, int oldfd, int newfd) +{ + int rval; + + rval = dup2(oldfd, newfd); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "dup2(%i, %i) failed", oldfd, newfd); + } else if (rval != newfd) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid dup2(%i, %i) return value %d", + oldfd, newfd, rval); + } + + return rval; +} + +void *safe_realloc(const char *file, const int lineno, void *ptr, size_t size) +{ + void *ret; + + ret = realloc(ptr, size); + + if (!ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "realloc(%p, %zu) failed", ptr, size); + } + + return ret; +} + +sighandler_t safe_signal(const char *file, const int lineno, + int signum, sighandler_t handler) +{ + sighandler_t rval; + + rval = signal(signum, handler); + + if (rval == SIG_ERR) { + tst_brk_(file, lineno, TBROK | TERRNO, + "signal(%d,%p) failed", + signum, handler); + } + + return rval; +} + +void safe_cmd(const char *file, const int lineno, const char *const argv[], + const char *stdout_path, const char *stderr_path) +{ + int rval; + + switch ((rval = tst_cmd(argv, stdout_path, stderr_path, + TST_CMD_PASS_RETVAL | TST_CMD_TCONF_ON_MISSING))) { + case 0: + break; + default: + tst_brk_(file, lineno, TBROK, "%s failed (%d)", argv[0], rval); + } +} diff --git a/lib/tst_safe_sysv_ipc.c b/lib/tst_safe_sysv_ipc.c old mode 100644 new mode 100755 index 30b5f6ec7ff5101a114a7830bd3c19210ef86db2..5eaa82539b56daded462092310e6c3d211e0046e --- a/lib/tst_safe_sysv_ipc.c +++ b/lib/tst_safe_sysv_ipc.c @@ -10,14 +10,12 @@ #define TST_NO_DEFAULT_MAIN #include "tst_test.h" #include "tst_safe_sysv_ipc.h" +#include "lapi/sem.h" /* - * The IPC_STAT, IPC_SET and IPC_RMID can return either 0 or -1. - * - * Linux specific cmds either returns -1 on failure or positive integer - * either index into an kernel array or shared primitive indentifier. + * The IPC_STAT, IPC_SET, IPC_RMID can return either 0 or -1. */ -static int ret_check(int cmd, int ret) +static int msg_ret_check(int cmd, int ret) { switch (cmd) { case IPC_STAT: @@ -25,7 +23,41 @@ static int ret_check(int cmd, int ret) case IPC_RMID: return ret != 0; default: - return ret == -1; + return ret < 0; + } +} + +/* + * The IPC_STAT, IPC_SET, IPC_RMID, SHM_LOCK, SHM_UNLOCK can return either 0 or -1. + */ +static int shm_ret_check(int cmd, int ret) +{ + switch (cmd) { + case IPC_STAT: + case IPC_SET: + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + return ret != 0; + default: + return ret < 0; + } +} + +/* + * The IPC_STAT, IPC_SET, IPC_RMID, SETALL, SETVAL can return either 0 or -1. + */ +static int sem_ret_check(int cmd, int ret) +{ + switch (cmd) { + case IPC_STAT: + case IPC_SET: + case IPC_RMID: + case SETALL: + case SETVAL: + return ret != 0; + default: + return ret < 0; } } @@ -34,9 +66,14 @@ int safe_msgget(const char *file, const int lineno, key_t key, int msgflg) int rval; rval = msgget(key, msgflg); + if (rval == -1) { - tst_brk(TBROK | TERRNO, "%s:%d: msgget(%i, %x) failed", - file, lineno, (int)key, msgflg); + tst_brk_(file, lineno, TBROK | TERRNO, "msgget(%i, %x) failed", + (int)key, msgflg); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid msgget(%i, %x) return value %d", (int)key, + msgflg, rval); } return rval; @@ -48,10 +85,15 @@ int safe_msgsnd(const char *file, const int lineno, int msqid, const void *msgp, int rval; rval = msgsnd(msqid, msgp, msgsz, msgflg); + if (rval == -1) { - tst_brk(TBROK | TERRNO, - "%s:%d: msgsnd(%i, %p, %zu, %x) failed", - file, lineno, msqid, msgp, msgsz, msgflg); + tst_brk_(file, lineno, TBROK | TERRNO, + "msgsnd(%i, %p, %zu, %x) failed", msqid, msgp, msgsz, + msgflg); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid msgsnd(%i, %p, %zu, %x) return value %d", + msqid, msgp, msgsz, msgflg, rval); } return rval; @@ -63,10 +105,15 @@ ssize_t safe_msgrcv(const char *file, const int lineno, int msqid, void *msgp, ssize_t rval; rval = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); + if (rval == -1) { - tst_brk(TBROK | TERRNO, - "%s:%d: msgrcv(%i, %p, %zu, %li, %x) failed", - file, lineno, msqid, msgp, msgsz, msgtyp, msgflg); + tst_brk_(file, lineno, TBROK | TERRNO, + "msgrcv(%i, %p, %zu, %li, %x) failed", + msqid, msgp, msgsz, msgtyp, msgflg); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid msgrcv(%i, %p, %zu, %li, %x) return value %ld", + msqid, msgp, msgsz, msgtyp, msgflg, rval); } return rval; @@ -78,12 +125,15 @@ int safe_msgctl(const char *file, const int lineno, int msqid, int cmd, int rval; rval = msgctl(msqid, cmd, buf); - if (ret_check(cmd, rval)) { - tst_brk(TBROK | TERRNO, - "%s:%d: msgctl(%i, %i, %p) = %i failed", - file, lineno, msqid, cmd, buf, rval); - } + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "msgctl(%i, %i, %p) failed", msqid, cmd, buf); + } else if (msg_ret_check(cmd, rval)) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid msgctl(%i, %i, %p) return value %d", msqid, + cmd, buf, rval); + } return rval; } @@ -94,9 +144,14 @@ int safe_shmget(const char *file, const int lineno, key_t key, size_t size, int rval; rval = shmget(key, size, shmflg); + if (rval == -1) { - tst_brk(TBROK | TERRNO, "%s:%d: shmget(%i, %zu, %x) failed", - file, lineno, (int)key, size, shmflg); + tst_brk_(file, lineno, TBROK | TERRNO, + "shmget(%i, %zu, %x) failed", (int)key, size, shmflg); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid shmget(%i, %zu, %x) return value %d", + (int)key, size, shmflg, rval); } return rval; @@ -108,9 +163,10 @@ void *safe_shmat(const char *file, const int lineno, int shmid, void *rval; rval = shmat(shmid, shmaddr, shmflg); + if (rval == (void *)-1) { - tst_brk(TBROK | TERRNO, "%s:%d: shmat(%i, %p, %x) failed", - file, lineno, shmid, shmaddr, shmflg); + tst_brk_(file, lineno, TBROK | TERRNO, + "shmat(%i, %p, %x) failed", shmid, shmaddr, shmflg); } return rval; @@ -121,9 +177,13 @@ int safe_shmdt(const char *file, const int lineno, const void *shmaddr) int rval; rval = shmdt(shmaddr); + if (rval == -1) { - tst_brk(TBROK | TERRNO, "%s:%d: shmdt(%p) failed", - file, lineno, shmaddr); + tst_brk_(file, lineno, TBROK | TERRNO, "shmdt(%p) failed", + shmaddr); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid shmdt(%p) return value %d", shmaddr, rval); } return rval; @@ -135,10 +195,78 @@ int safe_shmctl(const char *file, const int lineno, int shmid, int cmd, int rval; rval = shmctl(shmid, cmd, buf); - if (ret_check(cmd, rval)) { - tst_brk(TBROK | TERRNO, - "%s:%d: shmctl(%i, %i, %p) = %i failed", - file, lineno, shmid, cmd, buf, rval); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "shmctl(%i, %i, %p) failed", shmid, cmd, buf); + } else if (shm_ret_check(cmd, rval)) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid shmctl(%i, %i, %p) return value %d", shmid, + cmd, buf, rval); + } + + return rval; +} + +int safe_semget(const char *file, const int lineno, key_t key, int nsems, + int semflg) +{ + int rval; + + rval = semget(key, nsems, semflg); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "semget(%i, %i, %x) failed", (int)key, nsems, semflg); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid semget(%i, %i, %x) return value %d", + (int)key, nsems, semflg, rval); + } + + return rval; +} + +int safe_semctl(const char *file, const int lineno, int semid, int semnum, + int cmd, ...) +{ + int rval; + va_list va; + union semun un; + + va_start(va, cmd); + + un = va_arg(va, union semun); + + va_end(va); + + rval = semctl(semid, semnum, cmd, un); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "semctl(%i, %i, %i,...) failed", semid, semnum, cmd); + } else if (sem_ret_check(cmd, rval)) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid semctl(%i, %i, %i,...) return value %d", semid, + semnum, cmd, rval); + } + + return rval; +} + +int safe_semop(const char *file, const int lineno, int semid, struct sembuf *sops, + size_t nsops) +{ + int rval; + + rval = semop(semid, sops, nsops); + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "semop(%d, %p, %zu) failed", semid, sops, nsops); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid semop(%d, %p, %zu) return value %d", + semid, sops, nsops, rval); } return rval; diff --git a/lib/tst_safe_timerfd.c b/lib/tst_safe_timerfd.c old mode 100644 new mode 100755 index ffe7b2ef70a5b3477b4b69cad1d4cd227b24be3f..d31f6e35e5d7511140e5fcf0d085626fad1f00a4 --- a/lib/tst_safe_timerfd.c +++ b/lib/tst_safe_timerfd.c @@ -17,9 +17,14 @@ int safe_timerfd_create(const char *file, const int lineno, int fd; fd = timerfd_create(clockid, flags); - if (fd < 0) { - tst_brk(TTYPE | TERRNO, "%s:%d timerfd_create(%s) failed", - file, lineno, tst_clock_name(clockid)); + + if (fd == -1) { + tst_brk_(file, lineno, TTYPE | TERRNO, + "timerfd_create(%s) failed", tst_clock_name(clockid)); + } else if (fd < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid timerfd_create(%s) return value %d", + tst_clock_name(clockid), fd); } return fd; @@ -31,9 +36,13 @@ int safe_timerfd_gettime(const char *file, const int lineno, int rval; rval = timerfd_gettime(fd, curr_value); - if (rval != 0) { - tst_brk(TTYPE | TERRNO, "%s:%d timerfd_gettime() failed", - file, lineno); + + if (rval == -1) { + tst_brk_(file, lineno, TTYPE | TERRNO, + "timerfd_gettime() failed"); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid timerfd_gettime() return value %d", rval); } return rval; @@ -47,9 +56,13 @@ int safe_timerfd_settime(const char *file, const int lineno, int rval; rval = timerfd_settime(fd, flags, new_value, old_value); - if (rval != 0) { - tst_brk(TTYPE | TERRNO, "%s:%d timerfd_settime() failed", - file, lineno); + + if (rval == -1) { + tst_brk_(file, lineno, TTYPE | TERRNO, + "timerfd_settime() failed"); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid timerfd_settime() return value %d", rval); } return rval; diff --git a/lib/tst_sig.c b/lib/tst_sig.c old mode 100644 new mode 100755 diff --git a/lib/tst_sig_proc.c b/lib/tst_sig_proc.c old mode 100644 new mode 100755 diff --git a/lib/tst_status.c b/lib/tst_status.c old mode 100644 new mode 100755 index f1affeac501688e5f3014abd06f74b7e9d9ef206..9124faaa3b1ff535d1bafe8958edb813443bf180 --- a/lib/tst_status.c +++ b/lib/tst_status.c @@ -20,7 +20,8 @@ const char *exited(int status) const char *signaled(int status) { - snprintf(buf, sizeof(buf), "killed by %s", tst_strsig(status)); + snprintf(buf, sizeof(buf), "killed by %s", + tst_strsig(WTERMSIG(status))); return buf; } diff --git a/lib/tst_supported_fs_types.c b/lib/tst_supported_fs_types.c old mode 100644 new mode 100755 index 00ede549ddb452c70c1901a7051c1dc105b11311..23e5ce8775b8e3c40c3bfc9a0a79428d20d58857 --- a/lib/tst_supported_fs_types.c +++ b/lib/tst_supported_fs_types.c @@ -8,6 +8,7 @@ #include #include #include +#include #define TST_NO_DEFAULT_MAIN #include "tst_test.h" @@ -22,6 +23,7 @@ static const char *const fs_type_whitelist[] = { "vfat", "exfat", "ntfs", + "tmpfs", NULL }; @@ -32,6 +34,11 @@ static int has_mkfs(const char *fs_type) char buf[128]; int ret; + if (strstr(fs_type, "tmpfs")) { + tst_res(TINFO, "mkfs is not needed for tmpfs"); + return 1; + } + sprintf(buf, "mkfs.%s >/dev/null 2>&1", fs_type); ret = tst_system(buf); @@ -45,22 +52,47 @@ static int has_mkfs(const char *fs_type) return 1; } -static int has_kernel_support(const char *fs_type, int flags) +int tst_fs_in_skiplist(const char *fs_type, const char *const *skiplist) +{ + unsigned int i; + + if (!skiplist) + return 0; + + for (i = 0; skiplist[i]; i++) { + if (!strcmp(fs_type, skiplist[i])) + return 1; + } + + return 0; +} + +static enum tst_fs_impl has_kernel_support(const char *fs_type) { static int fuse_supported = -1; const char *tmpdir = getenv("TMPDIR"); char buf[128]; + char template[PATH_MAX]; int ret; if (!tmpdir) tmpdir = "/tmp"; - mount("/dev/zero", tmpdir, fs_type, 0, NULL); - if (errno != ENODEV) { + snprintf(template, sizeof(template), "%s/mountXXXXXX", tmpdir); + if (!mkdtemp(template)) + tst_brk(TBROK | TERRNO, "mkdtemp(%s) failed", template); + + ret = mount("/dev/zero", template, fs_type, 0, NULL); + if ((ret && errno != ENODEV) || !ret) { + if (!ret) + tst_umount(template); tst_res(TINFO, "Kernel supports %s", fs_type); - return 1; + SAFE_RMDIR(template); + return TST_FS_KERNEL; } + SAFE_RMDIR(template); + /* Is FUSE supported by kernel? */ if (fuse_supported == -1) { ret = open("/dev/fuse", O_RDWR); @@ -73,7 +105,7 @@ static int has_kernel_support(const char *fs_type, int flags) } if (!fuse_supported) - return 0; + return TST_FS_UNSUPPORTED; /* Is FUSE implementation installed? */ sprintf(buf, "mount.%s >/dev/null 2>&1", fs_type); @@ -81,31 +113,95 @@ static int has_kernel_support(const char *fs_type, int flags) ret = tst_system(buf); if (WEXITSTATUS(ret) == 127) { tst_res(TINFO, "Filesystem %s is not supported", fs_type); - return 0; - } - - if (flags & TST_FS_SKIP_FUSE) { - tst_res(TINFO, "Skipping FUSE as requested by the test"); - return 0; + return TST_FS_UNSUPPORTED; } tst_res(TINFO, "FUSE does support %s", fs_type); - return 1; + return TST_FS_FUSE; } -int tst_fs_is_supported(const char *fs_type, int flags) +enum tst_fs_impl tst_fs_is_supported(const char *fs_type) { - return has_kernel_support(fs_type, flags) && has_mkfs(fs_type); + enum tst_fs_impl ret; + + ret = has_kernel_support(fs_type); + if (!ret) + return TST_FS_UNSUPPORTED; + + if (has_mkfs(fs_type)) + return ret; + + return TST_FS_UNSUPPORTED; } -const char **tst_get_supported_fs_types(int flags) +const char **tst_get_supported_fs_types(const char *const *skiplist) { unsigned int i, j = 0; + int skip_fuse; + enum tst_fs_impl sup; + const char *only_fs; + + skip_fuse = tst_fs_in_skiplist("fuse", skiplist); + only_fs = getenv("LTP_SINGLE_FS_TYPE"); + + if (only_fs) { + tst_res(TINFO, "WARNING: testing only %s", only_fs); + if (tst_fs_is_supported(only_fs)) + fs_types[0] = only_fs; + return fs_types; + } for (i = 0; fs_type_whitelist[i]; i++) { - if (tst_fs_is_supported(fs_type_whitelist[i], flags)) + if (tst_fs_in_skiplist(fs_type_whitelist[i], skiplist)) { + tst_res(TINFO, "Skipping %s as requested by the test", + fs_type_whitelist[i]); + continue; + } + + sup = tst_fs_is_supported(fs_type_whitelist[i]); + + if (skip_fuse && sup == TST_FS_FUSE) { + tst_res(TINFO, + "Skipping FUSE based %s as requested by the test", + fs_type_whitelist[i]); + continue; + } + + if (sup) fs_types[j++] = fs_type_whitelist[i]; } return fs_types; } + +int tst_check_quota_support(const char *device, int format, char *quotafile) +{ + const long ret = quotactl(QCMD(Q_QUOTAON, USRQUOTA), device, format, + quotafile); + + /* Not supported */ + + if (ret == -1 && errno == ESRCH) + return 0; + + /* Broken */ + if (ret) + return -1; + + quotactl(QCMD(Q_QUOTAOFF, USRQUOTA), device, 0, 0); + return 1; +} + +void tst_require_quota_support_(const char *file, const int lineno, + const char *device, int format, char *quotafile) +{ + int status = tst_check_quota_support(device, format, quotafile); + + if (!status) { + tst_brk_(file, lineno, TCONF, + "Kernel or device does not support FS quotas"); + } + + if (status < 0) + tst_brk_(file, lineno, TBROK|TERRNO, "FS quotas are broken"); +} diff --git a/lib/tst_sys_conf.c b/lib/tst_sys_conf.c old mode 100644 new mode 100755 diff --git a/lib/tst_taint.c b/lib/tst_taint.c old mode 100644 new mode 100755 index 49146aacbbe93bfed0ab7b16401491b455290b15..5015db4d51dcfa663fd2499d1b58972a642d0150 --- a/lib/tst_taint.c +++ b/lib/tst_taint.c @@ -1,3 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Michael Moese + * Copyright (c) Linux Test Project, 2020 + */ + #define TST_NO_DEFAULT_MAIN #include "tst_test.h" diff --git a/lib/tst_test.c b/lib/tst_test.c old mode 100644 new mode 100755 index 0e58060e0159b9f6a580684c34d2e349a46c796c..844756fbd7e3091d7997dedd8f047a1ec561a7e0 --- a/lib/tst_test.c +++ b/lib/tst_test.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015-2016 Cyril Hrubis + * Copyright (c) Linux Test Project, 2016-2021 */ #include @@ -17,6 +18,7 @@ #define TST_NO_DEFAULT_MAIN #include "tst_test.h" #include "tst_device.h" +#include "lapi/abisize.h" #include "lapi/futex.h" #include "lapi/syscalls.h" #include "tst_ansi_color.h" @@ -27,7 +29,7 @@ #include "tst_wallclock.h" #include "tst_sys_conf.h" #include "tst_kconfig.h" - +#include "tst_private.h" #include "old_resource.h" #include "old_device.h" #include "old_tmpdir.h" @@ -37,7 +39,10 @@ */ const char *TCID __attribute__((weak)); +/* update also docparse/testinfo.pl */ #define LINUX_GIT_URL "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=" +#define LINUX_STABLE_GIT_URL "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=" +#define GLIBC_GIT_URL "https://sourceware.org/git/?p=glibc.git;a=commit;h=" #define CVE_DB_URL "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-" struct tst_test *tst_test; @@ -56,6 +61,7 @@ struct results { int skipped; int failed; int warnings; + int broken; unsigned int timeout; }; @@ -66,14 +72,13 @@ static int ipc_fd; extern void *tst_futexes; extern unsigned int tst_max_futexes; -#define IPC_ENV_VAR "LTP_IPC_PATH" - static char ipc_path[1064]; const char *tst_ipc_path = ipc_path; static char shm_path[1024]; int TST_ERR; +int TST_PASS; long TST_RET; static void do_cleanup(void); @@ -179,6 +184,9 @@ static void update_results(int ttype) case TFAIL: tst_atomic_inc(&results->failed); break; + case TBROK: + tst_atomic_inc(&results->broken); + break; } } @@ -193,22 +201,22 @@ static void print_result(const char *file, const int lineno, int ttype, switch (TTYPE_RESULT(ttype)) { case TPASS: - res = "PASS"; + res = "TPASS"; break; case TFAIL: - res = "FAIL"; + res = "TFAIL"; break; case TBROK: - res = "BROK"; + res = "TBROK"; break; case TCONF: - res = "CONF"; + res = "TCONF"; break; case TWARN: - res = "WARN"; + res = "TWARN"; break; case TINFO: - res = "INFO"; + res = "TINFO"; break; default: tst_brk(TBROK, "Invalid ttype value %i", ttype); @@ -316,6 +324,7 @@ void tst_vbrk_(const char *file, const int lineno, int ttype, const char *fmt, va_list va) { print_result(file, lineno, ttype, fmt, va); + update_results(TTYPE_RESULT(ttype)); /* * The getpid implementation in some C library versions may cause cloned @@ -352,6 +361,15 @@ void tst_brk_(const char *file, const int lineno, int ttype, va_end(va); } +void tst_printf(const char *const fmt, ...) +{ + va_list va; + + va_start(va, fmt); + vdprintf(STDERR_FILENO, fmt, va); + va_end(va); +} + static void check_child_status(pid_t pid, int status) { int ret; @@ -362,15 +380,13 @@ static void check_child_status(pid_t pid, int status) } if (!(WIFEXITED(status))) - tst_brk(TBROK, "Child (%i) exited abnormaly", pid); + tst_brk(TBROK, "Child (%i) exited abnormally", pid); ret = WEXITSTATUS(status); switch (ret) { case TPASS: - break; case TBROK: case TCONF: - tst_brk(ret, "Reported by child (%i)", pid); break; default: tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret); @@ -420,6 +436,31 @@ pid_t safe_fork(const char *filename, unsigned int lineno) return pid; } +pid_t safe_clone(const char *file, const int lineno, + const struct tst_clone_args *args) +{ + pid_t pid; + + if (!tst_test->forks_child) + tst_brk(TBROK, "test.forks_child must be set!"); + + pid = tst_clone(args); + + switch (pid) { + case -1: + tst_brk_(file, lineno, TBROK | TERRNO, "clone3 failed"); + break; + case -2: + tst_brk_(file, lineno, TBROK | TERRNO, "clone failed"); + return -1; + } + + if (!pid) + atexit(tst_free_all); + + return pid; +} + static struct option { char *optstr; char *help; @@ -434,6 +475,21 @@ static void print_help(void) { unsigned int i; + /* see doc/user-guide.txt, which lists also shell API variables */ + fprintf(stderr, "Environment Variables\n"); + fprintf(stderr, "---------------------\n"); + fprintf(stderr, "KCONFIG_PATH Specify kernel config file\n"); + fprintf(stderr, "KCONFIG_SKIP_CHECK Skip kernel config check if variable set (not set by default)\n"); + fprintf(stderr, "LTPROOT Prefix for installed LTP (default: /opt/ltp)\n"); + fprintf(stderr, "LTP_COLORIZE_OUTPUT Force colorized output behaviour (y/1 always, n/0: never)\n"); + fprintf(stderr, "LTP_DEV Path to the block device to be used (for .needs_device)\n"); + fprintf(stderr, "LTP_DEV_FS_TYPE Filesystem used for testing (default: %s)\n", DEFAULT_FS_TYPE); + fprintf(stderr, "LTP_SINGLE_FS_TYPE Testing only - specifies filesystem instead all supported (for .all_filesystems)\n"); + fprintf(stderr, "LTP_TIMEOUT_MUL Timeout multiplier (must be a number >=1)\n"); + fprintf(stderr, "LTP_VIRT_OVERRIDE Overrides virtual machine detection (values: \"\"|kvm|microsoft|xen|zvm)\n"); + fprintf(stderr, "TMPDIR Base directory for template directory (for .needs_tmpdir, default: %s)\n", TEMPDIR); + fprintf(stderr, "\n"); + fprintf(stderr, "Options\n"); fprintf(stderr, "-------\n"); @@ -443,8 +499,11 @@ static void print_help(void) if (!tst_test->options) return; - for (i = 0; tst_test->options[i].optstr; i++) - fprintf(stderr, "%s\n", tst_test->options[i].help); + for (i = 0; tst_test->options[i].optstr; i++) { + fprintf(stderr, "-%c\t %s\n", + tst_test->options[i].optstr[0], + tst_test->options[i].help); + } } static void print_test_tags(void) @@ -455,19 +514,23 @@ static void print_test_tags(void) if (!tags) return; - printf("\nTags\n"); - printf("----\n"); + fprintf(stderr, "\nTags\n"); + fprintf(stderr, "----\n"); for (i = 0; tags[i].name; i++) { if (!strcmp(tags[i].name, "CVE")) - printf(CVE_DB_URL "%s\n", tags[i].value); + fprintf(stderr, CVE_DB_URL "%s\n", tags[i].value); else if (!strcmp(tags[i].name, "linux-git")) - printf(LINUX_GIT_URL "%s\n", tags[i].value); + fprintf(stderr, LINUX_GIT_URL "%s\n", tags[i].value); + else if (!strcmp(tags[i].name, "linux-stable-git")) + fprintf(stderr, LINUX_STABLE_GIT_URL "%s\n", tags[i].value); + else if (!strcmp(tags[i].name, "glibc-git")) + fprintf(stderr, GLIBC_GIT_URL "%s\n", tags[i].value); else - printf("%s: %s\n", tags[i].name, tags[i].value); + fprintf(stderr, "%s: %s\n", tags[i].name, tags[i].value); } - printf("\n"); + fprintf(stderr, "\n"); } static void check_option_collision(void) @@ -634,52 +697,94 @@ int tst_parse_float(const char *str, float *val, float min, float max) return 0; } +int tst_parse_filesize(const char *str, long long *val, long long min, long long max) +{ + long long rval; + char *end; + + if (!str) + return 0; + + errno = 0; + rval = strtoll(str, &end, 0); + + if (str == end || (end[0] && end[1])) + return EINVAL; + + if (errno) + return errno; + + switch (*end) { + case 'g': + case 'G': + rval *= (1024 * 1024 * 1024); + break; + case 'm': + case 'M': + rval *= (1024 * 1024); + break; + case 'k': + case 'K': + rval *= 1024; + break; + default: + break; + } + + if (rval > max || rval < min) + return ERANGE; + + *val = rval; + return 0; +} + static void print_colored(const char *str) { if (tst_color_enabled(STDOUT_FILENO)) - printf("%s%s%s", ANSI_COLOR_YELLOW, str, ANSI_COLOR_RESET); + fprintf(stderr, "%s%s%s", ANSI_COLOR_YELLOW, str, ANSI_COLOR_RESET); else - printf("%s", str); + fprintf(stderr, "%s", str); } -static void print_failure_hints(void) +static void print_failure_hint(const char *tag, const char *hint, + const char *url) { - unsigned int i; const struct tst_tag *tags = tst_test->tags; if (!tags) return; + unsigned int i; int hint_printed = 0; - for (i = 0; tags[i].name; i++) { - if (!strcmp(tags[i].name, "linux-git")) { - if (!hint_printed) { - hint_printed = 1; - printf("\n"); - print_colored("HINT: "); - printf("You _MAY_ be missing kernel fixes, see:\n\n"); - } - - printf(LINUX_GIT_URL "%s\n", tags[i].value); - } - - } - hint_printed = 0; for (i = 0; tags[i].name; i++) { - if (!strcmp(tags[i].name, "CVE")) { + if (!strcmp(tags[i].name, tag)) { if (!hint_printed) { hint_printed = 1; - printf("\n"); + fprintf(stderr, "\n"); print_colored("HINT: "); - printf("You _MAY_ be vunerable to CVE(s), see:\n\n"); + fprintf(stderr, "You _MAY_ be %s:\n\n", hint); } - printf(CVE_DB_URL "%s\n", tags[i].value); + if (url) + fprintf(stderr, "%s%s\n", url, tags[i].value); + else + fprintf(stderr, "%s\n", tags[i].value); } } } +/* update also docparse/testinfo.pl */ +static void print_failure_hints(void) +{ + print_failure_hint("linux-git", "missing kernel fixes", LINUX_GIT_URL); + print_failure_hint("linux-stable-git", "missing stable kernel fixes", + LINUX_STABLE_GIT_URL); + print_failure_hint("glibc-git", "missing glibc fixes", GLIBC_GIT_URL); + print_failure_hint("CVE", "vulnerable to CVE(s)", CVE_DB_URL); + print_failure_hint("known-fail", "hit by known kernel failures", NULL); +} + static void do_exit(int ret) { if (results) { @@ -697,11 +802,15 @@ static void do_exit(int ret) if (results->warnings) ret |= TWARN; - printf("\nSummary:\n"); - printf("passed %d\n", results->passed); - printf("failed %d\n", results->failed); - printf("skipped %d\n", results->skipped); - printf("warnings %d\n", results->warnings); + if (results->broken) + ret |= TBROK; + + fprintf(stderr, "\nSummary:\n"); + fprintf(stderr, "passed %d\n", results->passed); + fprintf(stderr, "failed %d\n", results->failed); + fprintf(stderr, "broken %d\n", results->broken); + fprintf(stderr, "skipped %d\n", results->skipped); + fprintf(stderr, "warnings %d\n", results->warnings); } do_cleanup(); @@ -736,6 +845,9 @@ static int results_equal(struct results *a, struct results *b) if (a->skipped != b->skipped) return 0; + if (a->broken != b->broken) + return 0; + return 1; } @@ -789,7 +901,7 @@ static void assert_test_fn(void) cnt++; if (!cnt) - tst_brk(TBROK, "No test function speficied"); + tst_brk(TBROK, "No test function specified"); if (cnt != 1) tst_brk(TBROK, "You can define only one test function"); @@ -841,8 +953,45 @@ static void prepare_and_mount_dev_fs(const char *mntpoint) } } +static const char *limit_tmpfs_mount_size(const char *mnt_data, + char *buf, size_t buf_size, const char *fs_type) +{ + unsigned int tmpfs_size; + + if (strcmp(fs_type, "tmpfs")) + return mnt_data; + + if (!tst_test->dev_min_size) + tmpfs_size = 32; + else + tmpfs_size = tdev.size; + + if ((tst_available_mem() / 1024) < (tmpfs_size * 2)) + tst_brk(TCONF, "No enough memory for tmpfs use"); + + if (mnt_data) + snprintf(buf, buf_size, "%s,size=%uM", mnt_data, tmpfs_size); + else + snprintf(buf, buf_size, "size=%uM", tmpfs_size); + + tst_res(TINFO, "Limiting tmpfs size to %uMB", tmpfs_size); + + return buf; +} + +static const char *get_device_name(const char *fs_type) +{ + if (!strcmp(fs_type, "tmpfs")) + return "ltp-tmpfs"; + else + return tdev.dev; +} + static void prepare_device(void) { + const char *mnt_data; + char buf[1024]; + if (tst_test->format_device) { SAFE_MKFS(tdev.dev, tdev.fs_type, tst_test->dev_fs_opts, tst_test->dev_extra_opts); @@ -855,8 +1004,11 @@ static void prepare_device(void) } if (tst_test->mount_device) { - SAFE_MOUNT(tdev.dev, tst_test->mntpoint, tdev.fs_type, - tst_test->mnt_flags, tst_test->mnt_data); + mnt_data = limit_tmpfs_mount_size(tst_test->mnt_data, + buf, sizeof(buf), tdev.fs_type); + + SAFE_MOUNT(get_device_name(tdev.fs_type), tst_test->mntpoint, + tdev.fs_type, tst_test->mnt_flags, mnt_data); mntpoint_mounted = 1; } } @@ -869,32 +1021,39 @@ static void do_setup(int argc, char *argv[]) if (tst_test->tconf_msg) tst_brk(TCONF, "%s", tst_test->tconf_msg); - if (tst_test->needs_kconfigs) - tst_kconfig_check(tst_test->needs_kconfigs); - assert_test_fn(); - tid = get_tid(argv); + TCID = tid = get_tid(argv); if (tst_test->sample) tst_test = tst_timer_test_setup(tst_test); parse_opts(argc, argv); + if (tst_test->needs_kconfigs && tst_kconfig_check(tst_test->needs_kconfigs)) + tst_brk(TCONF, "Aborting due to unsuitable kernel config, see above!"); + if (tst_test->needs_root && geteuid() != 0) tst_brk(TCONF, "Test needs to be run as root"); if (tst_test->min_kver) check_kver(); + if (tst_test->supported_archs && !tst_is_on_arch(tst_test->supported_archs)) + tst_brk(TCONF, "This arch '%s' is not supported for test!", tst_arch.name); + + if (tst_test->skip_in_lockdown && tst_lockdown_enabled()) + tst_brk(TCONF, "Kernel is locked down, skipping test"); + + if (tst_test->skip_in_compat && TST_ABI != tst_kernel_bits()) + tst_brk(TCONF, "Not supported in 32-bit compat mode"); + if (tst_test->needs_cmds) { const char *cmd; - char path[PATH_MAX]; int i; for (i = 0; (cmd = tst_test->needs_cmds[i]); ++i) - if (tst_get_path(cmd, path, sizeof(path))) - tst_brk(TCONF, "Couldn't find '%s' in $PATH", cmd); + tst_check_cmd(cmd); } if (tst_test->needs_drivers) { @@ -906,17 +1065,18 @@ static void do_setup(int argc, char *argv[]) tst_brk(TCONF, "%s driver not available", name); } - if (tst_test->format_device) - tst_test->needs_device = 1; + if (tst_test->mount_device) + tst_test->format_device = 1; - if (tst_test->mount_device) { + if (tst_test->format_device) tst_test->needs_device = 1; - tst_test->format_device = 1; - } if (tst_test->all_filesystems) tst_test->needs_device = 1; + if (tst_test->min_cpus > (unsigned long)tst_ncpus()) + tst_brk(TCONF, "Test needs at least %lu CPUs online", tst_test->min_cpus); + if (tst_test->request_hugepages) tst_request_hugepages(tst_test->request_hugepages); @@ -973,6 +1133,8 @@ static void do_setup(int argc, char *argv[]) if (!tdev.dev) tst_brk(TCONF, "Failed to acquire device"); + tdev.size = tst_get_device_size(tdev.dev); + tst_device = &tdev; if (tst_test->dev_fs_type) @@ -1000,12 +1162,27 @@ static void do_setup(int argc, char *argv[]) if (tst_test->restore_wallclock) tst_wallclock_save(); + + if (tst_test->taint_check) + tst_taint_init(tst_test->taint_check); } static void do_test_setup(void) { main_pid = getpid(); + if (!tst_test->all_filesystems && tst_test->skip_filesystems) { + long fs_type = tst_fs_type("."); + const char *fs_name = tst_fs_type_name(fs_type); + + if (tst_fs_in_skiplist(fs_name, tst_test->skip_filesystems)) { + tst_brk(TCONF, "%s is not supported by the test", + fs_name); + } + + tst_res(TINFO, "%s is supported by the test", fs_name); + } + if (tst_test->caps) tst_cap_setup(tst_test->caps, TST_CAP_REQ); @@ -1111,6 +1288,16 @@ static void heartbeat(void) if (tst_clock_gettime(CLOCK_MONOTONIC, &tst_start_time)) tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); + if (getppid() == 1) { + tst_res(TFAIL, "Main test process might have exit!"); + /* + * We need kill the task group immediately since the + * main process has exit. + */ + kill(0, SIGKILL); + exit(TBROK); + } + kill(getppid(), SIGUSR1); } @@ -1169,7 +1356,7 @@ static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED) if (++sigkill_retries > 10) { WRITE_MSG("Cannot kill test processes!\n"); WRITE_MSG("Congratulation, likely test hit a kernel bug.\n"); - WRITE_MSG("Exitting uncleanly...\n"); + WRITE_MSG("Exiting uncleanly...\n"); _exit(TFAIL); } } @@ -1267,6 +1454,7 @@ static int fork_testrun(void) tst_brk(TBROK | TERRNO, "fork()"); if (!test_pid) { + tst_disable_oom_protection(0); SAFE_SIGNAL(SIGALRM, SIG_DFL); SAFE_SIGNAL(SIGUSR1, SIG_DFL); SAFE_SIGNAL(SIGINT, SIG_DFL); @@ -1278,6 +1466,11 @@ static int fork_testrun(void) alarm(0); SAFE_SIGNAL(SIGINT, SIG_DFL); + if (tst_test->taint_check && tst_taint_check()) { + tst_res(TFAIL, "Kernel is now tainted."); + return TFAIL; + } + if (WIFEXITED(status) && WEXITSTATUS(status)) return WEXITSTATUS(status); @@ -1297,7 +1490,7 @@ static int run_tcases_per_fs(void) { int ret = 0; unsigned int i; - const char *const *filesystems = tst_get_supported_fs_types(tst_test->dev_fs_flags); + const char *const *filesystems = tst_get_supported_fs_types(tst_test->skip_filesystems); if (!filesystems[0]) tst_brk(TCONF, "There are no supported filesystems"); @@ -1316,10 +1509,8 @@ static int run_tcases_per_fs(void) mntpoint_mounted = 0; } - if (ret == TCONF) { - update_results(ret); + if (ret == TCONF) continue; - } if (ret == 0) continue; @@ -1341,8 +1532,7 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) tst_test = self; do_setup(argc, argv); - - TCID = tid; + tst_enable_oom_protection(lib_pid); SAFE_SIGNAL(SIGALRM, alarm_handler); SAFE_SIGNAL(SIGUSR1, heartbeat_handler); @@ -1373,7 +1563,7 @@ void tst_flush(void) if (rval != 0) tst_brk(TBROK | TERRNO, "fflush(stderr) failed"); - rval = fflush(stderr); + rval = fflush(stdout); if (rval != 0) tst_brk(TBROK | TERRNO, "fflush(stdout) failed"); diff --git a/lib/tst_timer.c b/lib/tst_timer.c old mode 100644 new mode 100755 diff --git a/lib/tst_timer_test.c b/lib/tst_timer_test.c old mode 100644 new mode 100755 index 196c51272d344240e53758e6127404a4ef8ebf70..3cd52fc9db1bc21135d26e5991a63cf6513a4281 --- a/lib/tst_timer_test.c +++ b/lib/tst_timer_test.c @@ -267,7 +267,7 @@ void do_timer_test(long long usec, unsigned int nsamples) cur_sample = 0; for (i = 0; i < (int)nsamples; i++) { if (sample(CLOCK_MONOTONIC, usec)) { - tst_res(TINFO, "sampling function failed, exitting"); + tst_res(TINFO, "sampling function failed, exiting"); return; } } diff --git a/lib/tst_tmpdir.c b/lib/tst_tmpdir.c old mode 100644 new mode 100755 index 0c39eb89fc75666e8de0004047f96c92fcbe287f..6e38ae97761cc1f38c67f685ed7390b1119a0f14 --- a/lib/tst_tmpdir.c +++ b/lib/tst_tmpdir.c @@ -108,12 +108,18 @@ int tst_tmpdir_created(void) char *tst_get_tmpdir(void) { + char *ret = NULL; + if (TESTDIR == NULL) { tst_brkm(TBROK, NULL, "you must call tst_tmpdir() first"); return NULL; } - return strdup(TESTDIR); + ret = strdup(TESTDIR); + if (!ret) + tst_brkm(TBROK, NULL, "strdup() failed"); + + return ret; } const char *tst_get_startwd(void) diff --git a/lib/tst_uid.c b/lib/tst_uid.c new file mode 100755 index 0000000000000000000000000000000000000000..af4ef8cf72d507c0ca91eac40b06ac0a1aa6f583 --- /dev/null +++ b/lib/tst_uid.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Linux Test Project + */ + +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_uid.h" + +#define MAX_GID 32767 + +gid_t tst_get_free_gid_(const char *file, const int lineno, gid_t skip) +{ + gid_t ret; + + errno = 0; + + for (ret = 1; ret < MAX_GID; ret++) { + if (ret == skip || getgrgid(ret)) + continue; + + if (errno == 0 || errno == ENOENT || errno == ESRCH) { + tst_res_(file, lineno, TINFO | TERRNO, + "Found unused GID %d", (int)ret); + return ret; + } + + tst_brk_(file, lineno, TBROK|TERRNO, "Group ID lookup failed"); + return (gid_t)-1; + } + + tst_brk_(file, lineno, TBROK, "No free group ID found"); + return (gid_t)-1; +} + +void tst_get_uids(uid_t *buf, unsigned int start, unsigned int count) +{ + unsigned int i, j; + uid_t id; + + for (i = start, id = 1; i < count; id++) { + for (j = 0; j < start; j++) { + if (buf[j] == id) + break; + } + + if (j >= start) + buf[i++] = id; + } +} + +void tst_get_gids(gid_t *buf, unsigned int start, unsigned int count) +{ + unsigned int i, j; + gid_t id; + + for (i = start, id = 1; i < count; id++) { + for (j = 0; j < start; j++) { + if (buf[j] == id) + break; + } + + if (j >= start) + buf[i++] = id; + } +} + +int tst_check_resuid_(const char *file, const int lineno, const char *callstr, + uid_t exp_ruid, uid_t exp_euid, uid_t exp_suid) +{ + uid_t ruid, euid, suid; + + SAFE_GETRESUID(&ruid, &euid, &suid); + + if (ruid == exp_ruid && euid == exp_euid && suid == exp_suid) + return 1; + + if (callstr) { + tst_res_(file, lineno, TFAIL, "Unexpected process UID after %s", + callstr); + } else { + tst_res_(file, lineno, TFAIL, "Unexpected process UID"); + } + + tst_res_(file, lineno, TINFO, "Got: ruid = %d, euid = %d, suid = %d", + (int)ruid, (int)euid, (int)suid); + tst_res_(file, lineno, TINFO, + "Expected: ruid = %d, euid = %d, suid = %d", + (int)exp_ruid, (int)exp_euid, (int)exp_suid); + return 0; +} + +int tst_check_resgid_(const char *file, const int lineno, const char *callstr, + gid_t exp_rgid, gid_t exp_egid, gid_t exp_sgid) +{ + gid_t rgid, egid, sgid; + + SAFE_GETRESGID(&rgid, &egid, &sgid); + + if (rgid == exp_rgid && egid == exp_egid && sgid == exp_sgid) + return 1; + + if (callstr) { + tst_res_(file, lineno, TFAIL, "Unexpected process GID after %s", + callstr); + } else { + tst_res_(file, lineno, TFAIL, "Unexpected process GID"); + } + + tst_res_(file, lineno, TINFO, "Got: rgid = %d, egid = %d, sgid = %d", + (int)rgid, (int)egid, (int)sgid); + tst_res_(file, lineno, TINFO, + "Expected: rgid = %d, egid = %d, sgid = %d", + (int)exp_rgid, (int)exp_egid, (int)exp_sgid); + return 0; +} diff --git a/lib/tst_virt.c b/lib/tst_virt.c old mode 100644 new mode 100755 index 53d33e69c254e80c59dd31776a94a855efb80c31..0fda20a17c2a9db07d4d880ec9ea408651c4cdbd --- a/lib/tst_virt.c +++ b/lib/tst_virt.c @@ -64,11 +64,54 @@ static int is_xen(void) return 0; } +static int is_ibmz(int virt_type) +{ + FILE *sysinfo; + char line[64]; + int found_lpar, found_zvm; + + if (access("/proc/sysinfo", F_OK) != 0) + return 0; + + sysinfo = SAFE_FOPEN(NULL, "/proc/sysinfo", "r"); + found_lpar = 0; + found_zvm = 0; + while (fgets(line, sizeof(line), sysinfo) != NULL) { + if (strstr(line, "LPAR")) + found_lpar = 1; + else if (strstr(line, "z/VM")) + found_zvm = 1; + } + + SAFE_FCLOSE(NULL, sysinfo); + + switch (virt_type) { + case VIRT_IBMZ: + return found_lpar; + case VIRT_IBMZ_LPAR: + return found_lpar && !found_zvm; + case VIRT_IBMZ_ZVM: + return found_lpar && found_zvm; + default: + return 0; + } +} + static int try_systemd_detect_virt(void) { FILE *f; - char virt_type[64]; + char virt_buf[64]; int ret; + char *virt_type = getenv("LTP_VIRT_OVERRIDE"); + + if (virt_type) { + if (!strcmp("", virt_type)) + return 0; + + goto cmp; + } + + virt_type = virt_buf; /* See tst_cmd.c */ void *old_handler = signal(SIGCHLD, SIG_DFL); @@ -96,12 +139,19 @@ static int try_systemd_detect_virt(void) if (ret) return 0; +cmp: if (!strncmp("kvm", virt_type, 3)) return VIRT_KVM; if (!strncmp("xen", virt_type, 3)) return VIRT_XEN; + if (!strncmp("zvm", virt_type, 3)) + return VIRT_IBMZ_ZVM; + + if (!strncmp("microsoft", virt_type, 9)) + return VIRT_HYPERV; + return VIRT_OTHER; } @@ -109,20 +159,25 @@ int tst_is_virt(int virt_type) { int ret = try_systemd_detect_virt(); - if (ret >= 0) { + if (ret > 0) { if (virt_type == VIRT_ANY) - return ret != 0; + return 1; else return ret == virt_type; } switch (virt_type) { case VIRT_ANY: - return is_xen() || is_kvm(); + return is_xen() || is_kvm() || is_ibmz(VIRT_IBMZ); case VIRT_XEN: return is_xen(); case VIRT_KVM: return is_kvm(); + case VIRT_IBMZ: + case VIRT_IBMZ_LPAR: + case VIRT_IBMZ_ZVM: + return is_ibmz(virt_type); + case VIRT_HYPERV: case VIRT_OTHER: return 0; } diff --git a/lib/tst_wallclock.c b/lib/tst_wallclock.c old mode 100644 new mode 100755 index 282d6ada3008268b358932453817e89998248b6e..ee53e2b7f3790278cade9e35b48ad12f91acb80a --- a/lib/tst_wallclock.c +++ b/lib/tst_wallclock.c @@ -11,11 +11,14 @@ #include "tst_test.h" #include "tst_timer.h" #include "tst_clocks.h" +#include "tst_rtctime.h" #include "tst_wallclock.h" #include "lapi/posix_clocks.h" static struct timespec real_begin, mono_begin; +static struct rtc_time rtc_begin; + static int clock_saved; void tst_wallclock_save(void) @@ -39,7 +42,9 @@ void tst_wallclock_save(void) void tst_wallclock_restore(void) { + static const char *localtime = "/etc/localtime"; static struct timespec mono_end, elapsed, adjust; + int ret; if (!clock_saved) return; @@ -57,4 +62,57 @@ void tst_wallclock_restore(void) if (tst_clock_settime(CLOCK_REALTIME, &adjust)) tst_brk(TBROK | TERRNO, "tst_clock_settime() realtime failed"); + + /* + * Fix access time of /etc/localtime because adjusting the wallclock + * might have changed it to a time value which lies far ahead + * in the future. + * The access time of a file only changes if the new one is past + * the current one, therefore, just opening a file and reading it + * might not be enough because the current access time might be far + * in the future. + */ + ret = access(localtime, F_OK | W_OK); + if (!ret) + SAFE_TOUCH(localtime, 0, NULL); +} + +void tst_rtc_clock_save(const char *rtc_dev) +{ + /* save initial monotonic time to restore it when needed */ + if (tst_rtc_gettime(rtc_dev, &rtc_begin)) + tst_brk(TBROK | TERRNO, "tst_rtc_gettime() realtime failed"); + + if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_begin)) + tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed"); + + clock_saved = 1; +} + +void tst_rtc_clock_restore(const char *rtc_dev) +{ + static struct timespec mono_end, elapsed; + static struct timespec rtc_begin_tm, rtc_adjust; + static struct rtc_time rtc_restore; + + if (!clock_saved) + return; + + clock_saved = 0; + + if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_end)) + tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed"); + + elapsed = tst_timespec_diff(mono_end, mono_begin); + + rtc_begin_tm.tv_nsec = 0; + rtc_begin_tm.tv_sec = tst_rtc_tm_to_time(&rtc_begin); + + rtc_adjust = tst_timespec_add(rtc_begin_tm, elapsed); + + tst_rtc_time_to_tm(rtc_adjust.tv_sec, &rtc_restore); + + /* restore realtime clock based on monotonic delta */ + if (tst_rtc_settime(rtc_dev, &rtc_restore)) + tst_brk(TBROK | TERRNO, "tst_rtc_settime() realtime failed"); } diff --git a/libs/Makefile b/libs/Makefile old mode 100644 new mode 100755 diff --git a/testcases/kernel/syscalls/ipc/lib/Makefile b/libs/libltpipc/Makefile old mode 100644 new mode 100755 similarity index 64% rename from testcases/kernel/syscalls/ipc/lib/Makefile rename to libs/libltpipc/Makefile index 19916fa050030db7c8cae7b27b9985f7e82af49d..ad8f5a23b0c0e2f8949fc193cc78d4de8a0c61ee --- a/testcases/kernel/syscalls/ipc/lib/Makefile +++ b/libs/libltpipc/Makefile @@ -1,10 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) International Business Machines Corp., 2001 -top_srcdir ?= ../../../../.. +top_srcdir ?= ../.. include $(top_srcdir)/include/mk/env_pre.mk -LIB := libipc.a libmsgctl.a +INTERNAL_LIB := libltpipc.a include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/lib/libipc.c b/libs/libltpipc/libipc.c old mode 100644 new mode 100755 similarity index 98% rename from testcases/kernel/syscalls/ipc/lib/libipc.c rename to libs/libltpipc/libipc.c index d94880f54b648ae78552f6ec3ec08d04e4ade209..c2ecbf02d926808ca295aaafb2a57191c8e8d5b6 --- a/testcases/kernel/syscalls/ipc/lib/libipc.c +++ b/libs/libltpipc/libipc.c @@ -122,13 +122,11 @@ void init_buf(MSGBUF * m_buf, int type, int size) */ void rm_sema(int sem_id) { - union semun arr; - if (sem_id == -1) { /* no semaphore to remove */ return; } - if (semctl(sem_id, 0, IPC_RMID, arr) == -1) { + if (semctl(sem_id, 0, IPC_RMID) == -1) { tst_resm(TINFO, "WARNING: semaphore deletion failed."); tst_resm(TINFO, "This could lead to IPC resource problems."); tst_resm(TINFO, "id = %d", sem_id); diff --git a/testcases/kernel/syscalls/ipc/lib/libmsgctl.c b/libs/libltpipc/libmsgctl.c old mode 100644 new mode 100755 similarity index 100% rename from testcases/kernel/syscalls/ipc/lib/libmsgctl.c rename to libs/libltpipc/libmsgctl.c diff --git a/testcases/kernel/syscalls/ipc/libnewipc/Makefile b/libs/libltpnewipc/Makefile old mode 100644 new mode 100755 similarity index 63% rename from testcases/kernel/syscalls/ipc/libnewipc/Makefile rename to libs/libltpnewipc/Makefile index d150fb70f6e8b964c798e400bf5451eed02cf437..741c78f81c89b7f3bbc69da04f252b312a26d5a8 --- a/testcases/kernel/syscalls/ipc/libnewipc/Makefile +++ b/libs/libltpnewipc/Makefile @@ -1,10 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2016 Xiao Yang -top_srcdir ?= ../../../../.. +top_srcdir ?= ../.. include $(top_srcdir)/include/mk/env_pre.mk -INTERNAL_LIB := libnewipc.a +INTERNAL_LIB := libltpnewipc.a include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/libnewipc/libnewipc.c b/libs/libltpnewipc/libnewipc.c old mode 100644 new mode 100755 similarity index 54% rename from testcases/kernel/syscalls/ipc/libnewipc/libnewipc.c rename to libs/libltpnewipc/libnewipc.c index b909cb7e6c388a79ff096cf2ff492a2ca3234055..331f1b1f503ccf476dba49b9f7bdd22a53337410 --- a/testcases/kernel/syscalls/ipc/libnewipc/libnewipc.c +++ b/libs/libltpnewipc/libnewipc.c @@ -21,6 +21,8 @@ #include "tst_test.h" #include "libnewipc.h" +#include "tst_safe_stdio.h" +#include "tst_safe_sysv_ipc.h" #define BUFSIZE 1024 @@ -31,7 +33,7 @@ key_t getipckey(const char *file, const int lineno) int id; static int count; - SAFE_GETCWD(buf, BUFSIZE); + safe_getcwd(file, lineno, NULL, buf, BUFSIZE); id = count % 26 + (int) 'a'; count++; @@ -45,29 +47,25 @@ key_t getipckey(const char *file, const int lineno) return key; } -int get_used_queues(const char *file, const int lineno) +int get_used_sysvipc(const char *file, const int lineno, const char *sysvipc_file) { FILE *fp; - int used_queues = -1; + int used = -1; char buf[BUFSIZE]; - fp = fopen("/proc/sysvipc/msg", "r"); - if (fp == NULL) { - tst_brk(TBROK | TERRNO, - "fopen() failed at %s:%d", file, lineno); - } + fp = safe_fopen(file, lineno, NULL, sysvipc_file, "r"); while (fgets(buf, BUFSIZE, fp) != NULL) - used_queues++; + used++; fclose(fp); - if (used_queues < 0) { - tst_brk(TBROK, "can't read /proc/sysvipc/msg to get " - "used message queues at %s:%d", file, lineno); + if (used < 0) { + tst_brk(TBROK, "can't read %s to get used sysvipc resource total at " + "%s:%d", sysvipc_file, file, lineno); } - return used_queues; + return used; } void *probe_free_addr(const char *file, const int lineno) @@ -78,19 +76,11 @@ void *probe_free_addr(const char *file, const int lineno) probe_key = GETIPCKEY(); - shm_id = shmget(probe_key, SHMLBA * 2, SHM_RW | IPC_CREAT | IPC_EXCL); - if (shm_id == -1) - tst_brk(TBROK, "probe: shmget() failed at %s:%d", file, lineno); - - addr = shmat(shm_id, NULL, 0); - if (addr == (void *) -1) - tst_brk(TBROK, "probe: shmat() failed at %s:%d", file, lineno); - - if (shmdt(addr) == -1) - tst_brk(TBROK, "probe: shmdt() failed at %s:%d", file, lineno); - - if (shmctl(shm_id, IPC_RMID, NULL) == -1) - tst_brk(TBROK, "probe: shmctl() failed at %s:%d", file, lineno); + shm_id = safe_shmget(file, lineno, probe_key, SHMLBA * 2, + SHM_RW | IPC_CREAT | IPC_EXCL); + addr = safe_shmat(file, lineno, shm_id, NULL, 0); + safe_shmdt(file, lineno, addr); + safe_shmctl(file, lineno, shm_id, IPC_RMID, NULL); addr = (void *)(((unsigned long)(addr) + (SHMLBA - 1)) & ~(SHMLBA - 1)); diff --git a/libs/libltpnuma/Makefile b/libs/libltpnuma/Makefile old mode 100644 new mode 100755 index 56d6b7762581b42d32f0b100be4eee4a162566dc..a6856758d511d0f2073dc8220678a1d3ad6fcbac --- a/libs/libltpnuma/Makefile +++ b/libs/libltpnuma/Makefile @@ -6,7 +6,7 @@ top_srcdir ?= ../.. include $(top_srcdir)/include/mk/env_pre.mk -LIB := libltpnuma.a +INTERNAL_LIB := libltpnuma.a include $(top_srcdir)/include/mk/lib.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/libs/libltpnuma/tst_numa.c b/libs/libltpnuma/tst_numa.c old mode 100644 new mode 100755 index 56c8640ff58d90986ad4901a09ded92d81873edb..417d98cedd57de41896d1c7f9a81df68a499454e --- a/libs/libltpnuma/tst_numa.c +++ b/libs/libltpnuma/tst_numa.c @@ -1,6 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * SPDX-License-Identifier: GPL-2.0-or-later - * * Copyright (c) 2018 Cyril Hrubis */ @@ -16,6 +15,7 @@ #define TST_NO_DEFAULT_MAIN #include "tst_test.h" #include "tst_numa.h" +#include "lapi/numaif.h" void tst_nodemap_print_counters(struct tst_nodemap *nodes) { @@ -45,17 +45,19 @@ void tst_nodemap_free(struct tst_nodemap *nodes) #ifdef HAVE_NUMA_V2 -const char *tst_numa_mode_name(int mode) +const char *tst_mempolicy_mode_name(int mode) { switch (mode) { case MPOL_DEFAULT: return "MPOL_DEFAULT"; - case MPOL_BIND: - return "MPOL_BIND"; case MPOL_PREFERRED: return "MPOL_PREFERRED"; + case MPOL_BIND: + return "MPOL_BIND"; case MPOL_INTERLEAVE: return "MPOL_INTERLEAVE"; + case MPOL_LOCAL: + return "MPOL_LOCAL"; default: return "???"; } diff --git a/libs/libltpsigwait/Makefile b/libs/libltpsigwait/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..e0ea025ade2b3f0c02cb18d5dd4cc2e15eef6f64 --- /dev/null +++ b/libs/libltpsigwait/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2020 Viresh Kumar + +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := libltpsigwait.a + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/libs/libltpsigwait/sigwait.c b/libs/libltpsigwait/sigwait.c new file mode 100755 index 0000000000000000000000000000000000000000..2be949929fb1a259986010e7301d6ddfe5a7de9e --- /dev/null +++ b/libs/libltpsigwait/sigwait.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) Jiri Palecek, 2009 */ + +#define TST_NO_DEFAULT_MAIN +#include +#include +#include +#include "lapi/syscalls.h" +#include "libsigwait.h" +#include "tst_sig_proc.h" + +void test_empty_set(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + sigset_t sigs; + siginfo_t si; + pid_t child; + + SAFE_SIGEMPTYSET(&sigs); + + /* Run a child that will wake us up */ + child = create_sig_proc(signo, INT_MAX, 100000); + + TEST(sigwaitinfo(&sigs, &si, NULL)); + if (TST_RET == -1) { + if (TST_ERR == EINTR) + tst_res(TPASS, "Wait interrupted by expected signal"); + else + tst_res(TFAIL | TTERRNO, "Expected error number EINTR, got"); + } else { + tst_res(TFAIL, "Expected return value -1, got: %ld", TST_RET); + } + + SAFE_KILL(child, SIGTERM); + SAFE_WAIT(NULL); +} + +void test_timeout(swi_func sigwaitinfo, int signo, enum tst_ts_type type) +{ + sigset_t sigs; + siginfo_t si; + pid_t child; + struct tst_ts ts; + + ts.type = type; + tst_ts_set_sec(&ts, 1); + tst_ts_set_nsec(&ts, 0); + + SAFE_SIGEMPTYSET(&sigs); + + /* Run a child that will wake us up */ + child = create_sig_proc(signo, INT_MAX, 100000); + + TEST(sigwaitinfo(&sigs, &si, tst_ts_get(&ts))); + if (TST_RET == -1) { + if (TST_ERR == EAGAIN) + tst_res(TPASS, "Wait interrupted by timeout"); + else + tst_res(TFAIL | TTERRNO, "Expected error number EAGAIN, got"); + } else { + tst_res(TFAIL, "Expected return value -1, got: %ld", TST_RET); + } + + SAFE_KILL(child, SIGTERM); + SAFE_WAIT(NULL); +} + +/* Note: sigwait-ing for a signal that is not blocked is unspecified + * by POSIX; but works for non-ignored signals under Linux + */ +void test_unmasked_matching(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + sigset_t sigs; + siginfo_t si; + pid_t child; + + SAFE_SIGEMPTYSET(&sigs); + SAFE_SIGADDSET(&sigs, signo); + + /* Run a child that will wake us up */ + child = create_sig_proc(signo, INT_MAX, 100000); + + TEST(sigwaitinfo(&sigs, &si, NULL)); + if (TST_RET == signo) { + if (si.si_pid == child && si.si_code == SI_USER && + si.si_signo == signo) + tst_res(TPASS, "struct siginfo is correct"); + else + tst_res(TFAIL, "struct siginfo mismatch"); + } else { + tst_res(TFAIL | TTERRNO, "sigwaitinfo() failed"); + } + + SAFE_KILL(child, SIGTERM); + SAFE_WAIT(NULL); +} + +void test_unmasked_matching_noinfo(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + sigset_t sigs; + pid_t child; + + SAFE_SIGEMPTYSET(&sigs); + SAFE_SIGADDSET(&sigs, signo); + + /* Run a child that will wake us up */ + child = create_sig_proc(signo, INT_MAX, 100000); + + TEST(sigwaitinfo(&sigs, NULL, NULL)); + if (TST_RET == signo) + tst_res(TPASS, "Wait interrupted by expected signal"); + else + tst_res(TFAIL | TTERRNO, "sigwaitinfo() failed"); + + SAFE_KILL(child, SIGTERM); + SAFE_WAIT(NULL); +} + +void test_masked_matching(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + sigset_t sigs, oldmask; + siginfo_t si; + pid_t child; + + SAFE_SIGEMPTYSET(&sigs); + SAFE_SIGADDSET(&sigs, signo); + + /* let's not get interrupted by our dying child */ + SAFE_SIGADDSET(&sigs, SIGCHLD); + + TEST(sigprocmask(SIG_SETMASK, &sigs, &oldmask)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "sigprocmask() failed"); + + /* don't wait on a SIGCHLD */ + SAFE_SIGDELSET(&sigs, SIGCHLD); + + /* Run a child that will wake us up */ + child = create_sig_proc(signo, 1, 0); + + TEST(sigwaitinfo(&sigs, &si, NULL)); + if (TST_RET == signo) { + if (si.si_pid == child && si.si_code == SI_USER && + si.si_signo == signo) + tst_res(TPASS, "struct siginfo is correct"); + else + tst_res(TFAIL, "struct siginfo mismatch"); + } else { + tst_res(TFAIL | TTERRNO, "sigwaitinfo() failed"); + } + + TEST(sigprocmask(SIG_SETMASK, &oldmask, &sigs)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "restoring original signal mask failed"); + + if (sigismember(&sigs, signo)) + tst_res(TPASS, "sigwaitinfo restored the original mask"); + else + tst_res(TFAIL, + "sigwaitinfo failed to restore the original mask"); + + SAFE_KILL(child, SIGTERM); + SAFE_WAIT(NULL); +} + +void test_masked_matching_rt(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + sigset_t sigs, oldmask; + siginfo_t si; + pid_t child[2]; + int status; + + signo = SIGRTMIN + 1; + + SAFE_SIGEMPTYSET(&sigs); + SAFE_SIGADDSET(&sigs, signo); + SAFE_SIGADDSET(&sigs, signo + 1); + + /* let's not get interrupted by our dying child */ + SAFE_SIGADDSET(&sigs, SIGCHLD); + + TEST(sigprocmask(SIG_SETMASK, &sigs, &oldmask)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "sigprocmask() failed"); + + /* don't wait on a SIGCHLD */ + SAFE_SIGDELSET(&sigs, SIGCHLD); + + /* Run a child that will wake us up */ + child[0] = create_sig_proc(signo, 1, 0); + child[1] = create_sig_proc(signo + 1, 1, 0); + + /* Ensure that the signals have been sent */ + SAFE_WAITPID(child[0], &status, 0); + SAFE_WAITPID(child[1], &status, 0); + + TEST(sigwaitinfo(&sigs, &si, NULL)); + if (TST_RET == signo) { + if (si.si_pid == child[0] && si.si_code == SI_USER && + si.si_signo == signo) + tst_res(TPASS, "struct siginfo is correct"); + else + tst_res(TFAIL, "struct siginfo mismatch"); + } else { + tst_res(TFAIL | TTERRNO, "sigwaitinfo() failed"); + } + + /* eat the other signal */ + TEST(sigwaitinfo(&sigs, &si, NULL)); + if (TST_RET == signo + 1) { + if (si.si_pid == child[1] && si.si_code == SI_USER && + si.si_signo == signo + 1) + tst_res(TPASS, "struct siginfo is correct"); + else + tst_res(TFAIL, "struct siginfo mismatch"); + } else { + tst_res(TFAIL | TTERRNO, "sigwaitinfo() failed"); + } + + TEST(sigprocmask(SIG_SETMASK, &oldmask, &sigs)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "restoring original signal mask failed"); + + if (sigismember(&sigs, signo)) + tst_res(TPASS, "sigwaitinfo restored the original mask"); + else + tst_res(TFAIL, + "sigwaitinfo failed to restore the original mask"); +} + +void test_masked_matching_noinfo(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + sigset_t sigs, oldmask; + pid_t child; + + SAFE_SIGEMPTYSET(&sigs); + SAFE_SIGADDSET(&sigs, signo); + + /* let's not get interrupted by our dying child */ + SAFE_SIGADDSET(&sigs, SIGCHLD); + + TEST(sigprocmask(SIG_SETMASK, &sigs, &oldmask)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "sigprocmask() failed"); + + /* don't wait on a SIGCHLD */ + SAFE_SIGDELSET(&sigs, SIGCHLD); + + /* Run a child that will wake us up */ + child = create_sig_proc(signo, 1, 0); + + TEST(sigwaitinfo(&sigs, NULL, NULL)); + if (TST_RET == signo) + tst_res(TPASS, "Wait interrupted by expected signal"); + else + tst_res(TFAIL | TTERRNO, "sigwaitinfo() failed"); + + TEST(sigprocmask(SIG_SETMASK, &oldmask, &sigs)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "restoring original signal mask failed"); + + if (sigismember(&sigs, signo)) + tst_res(TPASS, "sigwaitinfo restored the original mask"); + else + tst_res(TFAIL, + "sigwaitinfo failed to restore the original mask"); + + SAFE_KILL(child, SIGTERM); + SAFE_WAIT(NULL); +} + +void test_bad_address(swi_func sigwaitinfo, int signo, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + sigset_t sigs, oldmask; + pid_t child; + + SAFE_SIGEMPTYSET(&sigs); + SAFE_SIGADDSET(&sigs, signo); + + /* let's not get interrupted by our dying child */ + SAFE_SIGADDSET(&sigs, SIGCHLD); + + TEST(sigprocmask(SIG_SETMASK, &sigs, &oldmask)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "sigprocmask() failed"); + + /* don't wait on a SIGCHLD */ + SAFE_SIGDELSET(&sigs, SIGCHLD); + + /* Run a child that will wake us up */ + child = create_sig_proc(signo, 1, 0); + + TEST(sigwaitinfo(&sigs, (void *)1, NULL)); + if (TST_RET == -1) { + if (TST_ERR == EFAULT) + tst_res(TPASS, "Fault occurred while accessing the buffers"); + else + tst_res(TFAIL | TTERRNO, "Expected error number EFAULT, got"); + } else { + tst_res(TFAIL, "Expected return value -1, got: %ld", TST_RET); + } + + TEST(sigprocmask(SIG_SETMASK, &oldmask, NULL)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "restoring original signal mask failed"); + + SAFE_KILL(child, SIGTERM); + SAFE_WAIT(NULL); +} + +void test_bad_address2(swi_func sigwaitinfo, int signo LTP_ATTRIBUTE_UNUSED, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + pid_t pid; + int status; + + pid = SAFE_FORK(); + if (pid == 0) { + signal(SIGSEGV, SIG_DFL); + + /* + * depending on glibc implementation we should + * either crash or get EFAULT + */ + TEST(sigwaitinfo((void *)1, NULL, NULL)); + + if (TST_RET == -1 && TST_ERR == EFAULT) + _exit(0); + + tst_res(TINFO | TTERRNO, "swi_func returned: %ld", TST_RET); + _exit(1); + } + + SAFE_WAITPID(pid, &status, 0); + + if ((WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) + || (WIFEXITED(status) && WEXITSTATUS(status) == 0)) { + tst_res(TPASS, "Child exited with expected code"); + return; + } + + if (WIFEXITED(status)) { + tst_res(TFAIL, "Unrecognised child exit code: %d", + WEXITSTATUS(status)); + } + if (WIFSIGNALED(status)) { + tst_res(TFAIL, "Unrecognised child termsig: %d", + WTERMSIG(status)); + } +} + +void test_bad_address3(swi_func sigwaitinfo, int signo LTP_ATTRIBUTE_UNUSED, + enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) +{ + sigset_t sigs; + + SAFE_SIGEMPTYSET(&sigs); + TEST(sigwaitinfo(&sigs, NULL, (void *)1)); + if (TST_RET == -1) { + if (TST_ERR == EFAULT) + tst_res(TPASS, "Fault occurred while accessing the buffers"); + else + tst_res(TFAIL | TTERRNO, "Expected error number EFAULT, got"); + } else { + tst_res(TFAIL, "Expected return value -1, got: %ld", TST_RET); + } +} + +static void empty_handler(int sig LTP_ATTRIBUTE_UNUSED) +{ +} + +void sigwait_setup(void) +{ + signal(SIGUSR1, empty_handler); + signal(SIGALRM, empty_handler); + signal(SIGUSR2, SIG_IGN); +} diff --git a/libs/libltpswap/Makefile b/libs/libltpswap/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..d8e692d17cc4abe798f5c3337f986c58ceba1343 --- /dev/null +++ b/libs/libltpswap/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) Richard Purdie + +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := libltpswap.a + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/libs/libltpswap/libswap.c b/libs/libltpswap/libswap.c new file mode 100755 index 0000000000000000000000000000000000000000..796ac0334eaab8e9a1fb62cd8f764ed08b238e4e --- /dev/null +++ b/libs/libltpswap/libswap.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Author: Stanislav Kholmanskikh + */ + +#include + +#define TST_NO_DEFAULT_MAIN + +#include "lapi/syscalls.h" +#include "tst_test.h" +#include "libswap.h" + +/* + * Make a swap file + */ +int make_swapfile(const char *swapfile, int safe) +{ + if (!tst_fs_has_free(".", sysconf(_SC_PAGESIZE) * 10, TST_BYTES)) + tst_brk(TBROK, "Insufficient disk space to create swap file"); + + /* create file */ + if (tst_fill_file(swapfile, 0, sysconf(_SC_PAGESIZE), 10) != 0) + tst_brk(TBROK, "Failed to create swapfile"); + + /* make the file swapfile */ + const char *argv[2 + 1]; + argv[0] = "mkswap"; + argv[1] = swapfile; + argv[2] = NULL; + + return tst_cmd(argv, "/dev/null", "/dev/null", safe); +} + +/* + * Check swapon/swapoff support status of filesystems or files + * we are testing on. + */ +void is_swap_supported(const char *filename) +{ + int fibmap = tst_fibmap(filename); + long fs_type = tst_fs_type(filename); + const char *fstype = tst_fs_type_name(fs_type); + + int ret = make_swapfile(filename, 1); + if (ret != 0) { + if (fibmap == 1) + tst_brk(TCONF, "mkswap on %s not supported", fstype); + else + tst_brk(TFAIL, "mkswap on %s failed", fstype); + } + + TEST(tst_syscall(__NR_swapon, filename, 0)); + if (TST_RET == -1) { + if (fibmap == 1 && errno == EINVAL) + tst_brk(TCONF, "Swapfile on %s not implemented", fstype); + else + tst_brk(TFAIL | TTERRNO, "swapon on %s failed", fstype); + } + + TEST(tst_syscall(__NR_swapoff, filename, 0)); + if (TST_RET == -1) + tst_brk(TFAIL | TTERRNO, "swapoff on %s failed", fstype); +} diff --git a/libs/libltpuinput/Makefile b/libs/libltpuinput/Makefile old mode 100644 new mode 100755 index dd2a6c09645f422e58a848a37961f124eec57ff7..c72dd2e1e6953f689d1055037f6a84f172a611bc --- a/libs/libltpuinput/Makefile +++ b/libs/libltpuinput/Makefile @@ -6,7 +6,7 @@ top_srcdir ?= ../.. include $(top_srcdir)/include/mk/env_pre.mk -LIB := libltpuinput.a +INTERNAL_LIB := libltpuinput.a include $(top_srcdir)/include/mk/lib.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/libs/libltpuinput/tst_uinput.c b/libs/libltpuinput/tst_uinput.c old mode 100644 new mode 100755 diff --git a/libs/libltpvdso/Makefile b/libs/libltpvdso/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..6b35bdf877b0ef0b925fd72c47f221a4e22902ed --- /dev/null +++ b/libs/libltpvdso/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2020 + +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +LIB := libltpvdso.a + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/libs/libltpvdso/README b/libs/libltpvdso/README new file mode 100755 index 0000000000000000000000000000000000000000..e208f7ef395e97771176906c83379a30e25cfcf6 --- /dev/null +++ b/libs/libltpvdso/README @@ -0,0 +1 @@ +Copied from kernel tree: tools/testing/selftests/vDSO/parse_vdso.c diff --git a/libs/libltpvdso/parse_vdso.c b/libs/libltpvdso/parse_vdso.c new file mode 100755 index 0000000000000000000000000000000000000000..cd75a89453bb1820f19100cd6c6fa9268e17f73a --- /dev/null +++ b/libs/libltpvdso/parse_vdso.c @@ -0,0 +1,278 @@ +/* + * parse_vdso.c: Linux reference vDSO parser + * Written by Andrew Lutomirski, 2011-2014. + * + * This code is meant to be linked in to various programs that run on Linux. + * As such, it is available with as few restrictions as possible. This file + * is licensed under the Creative Commons Zero License, version 1.0, + * available at http://creativecommons.org/publicdomain/zero/1.0/legalcode + * + * The vDSO is a regular ELF DSO that the kernel maps into user space when + * it starts a program. It works equally well in statically and dynamically + * linked binaries. + * + * This code is tested on x86. In principle it should work on any + * architecture that has a vDSO. + */ + +#include +#include +#include +#include +#include + +/* And here's the code. */ +#ifndef ELF_BITS +# if ULONG_MAX > 0xffffffffUL +# define ELF_BITS 64 +# else +# define ELF_BITS 32 +# endif +#endif + +#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x +#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x) +#define ELF(x) ELF_BITS_XFORM(ELF_BITS, x) + +static struct vdso_info +{ + bool valid; + + /* Load information */ + uintptr_t load_addr; + uintptr_t load_offset; /* load_addr - recorded vaddr */ + + /* Symbol table */ + ELF(Sym) *symtab; + const char *symstrings; + void *bucket, *chain; + ELF(Word) nbucket, nchain; + bool hash_ent_is_dword; + + /* Version table */ + ELF(Versym) *versym; + ELF(Verdef) *verdef; +} vdso_info; + +/* Straight from the ELF specification. */ +static unsigned long elf_hash(const unsigned char *name) +{ + unsigned long h = 0, g; + while (*name) + { + h = (h << 4) + *name++; + if ((g = h & 0xf0000000)) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +/* return value of hash table entry */ +ELF(Word) get_hash_val(void *ptr, ELF(Word) idx) +{ + if (vdso_info.hash_ent_is_dword) { + ELF(Xword) *table = ptr; + /* for vdso assume all values fit in Elf Word */ + return (ELF(Word)) table[idx]; + } + + ELF(Word) *table = ptr; + return table[idx]; +} + +/* return pointer to hash table entry */ +void *get_hash_ptr(void *ptr, ELF(Word) idx) +{ + if (vdso_info.hash_ent_is_dword) + return &((ELF(Xword) *) ptr)[idx]; + + return &((ELF(Word) *) ptr)[idx]; +} + +void vdso_init_from_sysinfo_ehdr(uintptr_t base) +{ + size_t i; + bool found_vaddr = false; + + vdso_info.valid = false; + + vdso_info.load_addr = base; + + ELF(Ehdr) *hdr = (ELF(Ehdr)*)base; + if (hdr->e_ident[EI_CLASS] != + (ELF_BITS == 32 ? ELFCLASS32 : ELFCLASS64)) { + return; /* Wrong ELF class -- check ELF_BITS */ + } + + /* 64bit s390 and alpha have hash entry size of 8 bytes */ + if ((hdr->e_machine == EM_ALPHA + || hdr->e_machine == EM_S390) + && hdr->e_ident[EI_CLASS] == ELFCLASS64) + vdso_info.hash_ent_is_dword = true; + else + vdso_info.hash_ent_is_dword = false; + + ELF(Phdr) *pt = (ELF(Phdr)*)(vdso_info.load_addr + hdr->e_phoff); + ELF(Dyn) *dyn = 0; + + /* + * We need two things from the segment table: the load offset + * and the dynamic table. + */ + for (i = 0; i < hdr->e_phnum; i++) + { + if (pt[i].p_type == PT_LOAD && !found_vaddr) { + found_vaddr = true; + vdso_info.load_offset = base + + (uintptr_t)pt[i].p_offset + - (uintptr_t)pt[i].p_vaddr; + } else if (pt[i].p_type == PT_DYNAMIC) { + dyn = (ELF(Dyn)*)(base + pt[i].p_offset); + } + } + + if (!found_vaddr || !dyn) + return; /* Failed */ + + /* + * Fish out the useful bits of the dynamic table. + */ + ELF(Word) *hash = 0; + vdso_info.symstrings = 0; + vdso_info.symtab = 0; + vdso_info.versym = 0; + vdso_info.verdef = 0; + for (i = 0; dyn[i].d_tag != DT_NULL; i++) { + switch (dyn[i].d_tag) { + case DT_STRTAB: + vdso_info.symstrings = (const char *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + case DT_SYMTAB: + vdso_info.symtab = (ELF(Sym) *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + case DT_HASH: + hash = (ELF(Word) *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + case DT_VERSYM: + vdso_info.versym = (ELF(Versym) *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + case DT_VERDEF: + vdso_info.verdef = (ELF(Verdef) *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + } + } + if (!vdso_info.symstrings || !vdso_info.symtab || !hash) + return; /* Failed */ + + if (!vdso_info.verdef) + vdso_info.versym = 0; + + + vdso_info.nbucket = get_hash_val(hash, 0); + vdso_info.nchain = get_hash_val(hash, 1); + vdso_info.bucket = get_hash_ptr(hash, 2); + vdso_info.chain = get_hash_ptr(hash, vdso_info.nbucket + 2); + + /* That's all we need. */ + vdso_info.valid = true; +} + +static bool vdso_match_version(ELF(Versym) ver, + const char *name, ELF(Word) hash) +{ + /* + * This is a helper function to check if the version indexed by + * ver matches name (which hashes to hash). + * + * The version definition table is a mess, and I don't know how + * to do this in better than linear time without allocating memory + * to build an index. I also don't know why the table has + * variable size entries in the first place. + * + * For added fun, I can't find a comprehensible specification of how + * to parse all the weird flags in the table. + * + * So I just parse the whole table every time. + */ + + /* First step: find the version definition */ + ver &= 0x7fff; /* Apparently bit 15 means "hidden" */ + ELF(Verdef) *def = vdso_info.verdef; + while(true) { + if ((def->vd_flags & VER_FLG_BASE) == 0 + && (def->vd_ndx & 0x7fff) == ver) + break; + + if (def->vd_next == 0) + return false; /* No definition. */ + + def = (ELF(Verdef) *)((char *)def + def->vd_next); + } + + /* Now figure out whether it matches. */ + ELF(Verdaux) *aux = (ELF(Verdaux)*)((char *)def + def->vd_aux); + return def->vd_hash == hash + && !strcmp(name, vdso_info.symstrings + aux->vda_name); +} + +void *vdso_sym(const char *version, const char *name) +{ + unsigned long ver_hash; + if (!vdso_info.valid) + return 0; + + ver_hash = elf_hash((const void*)version); + ELF(Word) chain = get_hash_val(vdso_info.bucket, + elf_hash((const void*)name) % vdso_info.nbucket); + + for (; chain != STN_UNDEF; chain = get_hash_val(vdso_info.chain, chain)) { + ELF(Sym) *sym = &vdso_info.symtab[chain]; + + /* Check for a defined global or weak function w/ right name. */ + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) + continue; + if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && + ELF64_ST_BIND(sym->st_info) != STB_WEAK) + continue; + if (sym->st_shndx == SHN_UNDEF) + continue; + if (strcmp(name, vdso_info.symstrings + sym->st_name)) + continue; + + /* Check symbol version. */ + if (vdso_info.versym + && !vdso_match_version(vdso_info.versym[chain], + version, ver_hash)) + continue; + + return (void *)(vdso_info.load_offset + sym->st_value); + } + + return 0; +} + +void vdso_init_from_auxv(void *auxv) +{ + int i; + + ELF(auxv_t) *elf_auxv = auxv; + for (i = 0; elf_auxv[i].a_type != AT_NULL; i++) { + if (elf_auxv[i].a_type == AT_SYSINFO_EHDR) { + vdso_init_from_sysinfo_ehdr(elf_auxv[i].a_un.a_val); + return; + } + } + + vdso_info.valid = false; +} diff --git a/libs/libltpvdso/vdso_helpers.c b/libs/libltpvdso/vdso_helpers.c new file mode 100755 index 0000000000000000000000000000000000000000..208c12f658c5b06296180d9e225e4c088726d139 --- /dev/null +++ b/libs/libltpvdso/vdso_helpers.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +#include "parse_vdso.h" +#include "config.h" + +#ifdef HAVE_GETAUXVAL +# include +#endif /* HAVE_GETAUXVAL */ + +static unsigned long sysinfo_ehdr; + +static void vdso_init(void) +{ +#ifdef HAVE_GETAUXVAL + if (sysinfo_ehdr) + return; + + sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); + if (!sysinfo_ehdr) { + tst_res(TINFO, "Couldn't find AT_SYSINFO_EHDR"); + return; + } + + vdso_init_from_sysinfo_ehdr(sysinfo_ehdr); +#else + tst_res(TINFO, "getauxval() not supported"); +#endif /* HAVE_GETAUXVAL */ +} + +void find_clock_gettime_vdso(gettime_t *ptr_vdso_gettime, + gettime_t *ptr_vdso_gettime64) +{ + /* + * Some vDSO exports its clock_gettime() implementation with a different + * name and version from other architectures, so we need to handle it as + * a special case. + */ +#if defined(__powerpc__) || defined(__powerpc64__) + const char *version = "LINUX_2.6.15"; + const char *name = "__kernel_clock_gettime"; +#elif defined(__aarch64__) + const char *version = "LINUX_2.6.39"; + const char *name = "__kernel_clock_gettime"; +#elif defined(__s390__) + const char *version = "LINUX_2.6.29"; + const char *name = "__kernel_clock_gettime"; +#elif defined(__nds32__) + const char *version = "LINUX_4"; + const char *name = "__vdso_clock_gettime"; +#elif defined(__riscv) + const char *version = "LINUX_4.15"; + const char *name = "__vdso_clock_gettime"; +#else + const char *version = "LINUX_2.6"; + const char *name = "__vdso_clock_gettime"; +#endif + + const char *version64 = "LINUX_2.6"; + const char *name64 = "__vdso_clock_gettime64"; + + vdso_init(); + + *ptr_vdso_gettime = vdso_sym(version, name); + if (!*ptr_vdso_gettime) + tst_res(TINFO, "Couldn't find vdso_gettime()"); + + *ptr_vdso_gettime64 = vdso_sym(version64, name64); + if (!*ptr_vdso_gettime64) + tst_res(TINFO, "Couldn't find vdso_gettime64()"); +} diff --git a/m4/GNUmakefile b/m4/GNUmakefile old mode 100644 new mode 100755 diff --git a/m4/Makefile.am b/m4/Makefile.am old mode 100644 new mode 100755 diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4 new file mode 100755 index 0000000000000000000000000000000000000000..ffb4997e8b146e1e40f5da58fee4f4150290f4a4 --- /dev/null +++ b/m4/ax_compare_version.m4 @@ -0,0 +1,177 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compare_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# This macro compares two version strings. Due to the various number of +# minor-version numbers that can exist, and the fact that string +# comparisons are not compatible with numeric comparisons, this is not +# necessarily trivial to do in a autoconf script. This macro makes doing +# these comparisons easy. +# +# The six basic comparisons are available, as well as checking equality +# limited to a certain number of minor-version levels. +# +# The operator OP determines what type of comparison to do, and can be one +# of: +# +# eq - equal (test A == B) +# ne - not equal (test A != B) +# le - less than or equal (test A <= B) +# ge - greater than or equal (test A >= B) +# lt - less than (test A < B) +# gt - greater than (test A > B) +# +# Additionally, the eq and ne operator can have a number after it to limit +# the test to that number of minor versions. +# +# eq0 - equal up to the length of the shorter version +# ne0 - not equal up to the length of the shorter version +# eqN - equal up to N sub-version levels +# neN - not equal up to N sub-version levels +# +# When the condition is true, shell commands ACTION-IF-TRUE are run, +# otherwise shell commands ACTION-IF-FALSE are run. The environment +# variable 'ax_compare_version' is always set to either 'true' or 'false' +# as well. +# +# Examples: +# +# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) +# +# would both be true. +# +# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) +# +# would both be false. +# +# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) +# +# would be true because it is only comparing two minor versions. +# +# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) +# +# would be true because it is only comparing the lesser number of minor +# versions of the two values. +# +# Note: The characters that separate the version numbers do not matter. An +# empty string is the same as version 0. OP is evaluated by autoconf, not +# configure, so must be a string, not a variable. +# +# The author would like to acknowledge Guido Draheim whose advice about +# the m4_case and m4_ifvaln functions make this macro only include the +# portions necessary to perform the specific comparison specified by the +# OP argument in the final configure script. +# +# LICENSE +# +# Copyright (c) 2008 Tim Toolan +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + +dnl ######################################################################### +AC_DEFUN([AX_COMPARE_VERSION], [ + AC_REQUIRE([AC_PROG_AWK]) + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + AS_VAR_PUSHDEF([A],[ax_compare_version_A]) + A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + AS_VAR_PUSHDEF([B],[ax_compare_version_B]) + B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary + dnl # then the first line is used to determine if the condition is true. + dnl # The sed right after the echo is to remove any indented white space. + m4_case(m4_tolower($2), + [lt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [gt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [le],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ], + [ge],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ],[ + dnl Split the operator from the subversion count if present. + m4_bmatch(m4_substr($2,2), + [0],[ + # A count of zero means use the length of the shorter version. + # Determine the number of characters in A and B. + ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` + ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` + + # Set A to no more than B's length and B to no more than A's length. + A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` + B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` + ], + [[0-9]+],[ + # A count greater than zero means use only that many subversions + A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + ], + [.+],[ + AC_WARNING( + [invalid OP numeric parameter: $2]) + ],[]) + + # Pad zeros at end of numbers to make same length. + ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" + B="$B`echo $A | sed 's/./0/g'`" + A="$ax_compare_version_tmp_A" + + # Check for equality or inequality as necessary. + m4_case(m4_tolower(m4_substr($2,0,2)), + [eq],[ + test "x$A" = "x$B" && ax_compare_version=true + ], + [ne],[ + test "x$A" != "x$B" && ax_compare_version=true + ],[ + AC_WARNING([invalid OP parameter: $2]) + ]) + ]) + + AS_VAR_POPDEF([A])dnl + AS_VAR_POPDEF([B])dnl + + dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. + if test "$ax_compare_version" = "true" ; then + m4_ifvaln([$4],[$4],[:])dnl + m4_ifvaln([$5],[else $5])dnl + fi +]) dnl AX_COMPARE_VERSION diff --git a/m4/ax_prog_perl_modules.m4 b/m4/ax_prog_perl_modules.m4 new file mode 100755 index 0000000000000000000000000000000000000000..70b3230ebdd3191d8cfe27c6061fc4bfe0ecc512 --- /dev/null +++ b/m4/ax_prog_perl_modules.m4 @@ -0,0 +1,77 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_prog_perl_modules.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_PERL_MODULES([MODULES], [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# Checks to see if the given perl modules are available. If true the shell +# commands in ACTION-IF-TRUE are executed. If not the shell commands in +# ACTION-IF-FALSE are run. Note if $PERL is not set (for example by +# calling AC_CHECK_PROG, or AC_PATH_PROG), AC_CHECK_PROG(PERL, perl, perl) +# will be run. +# +# MODULES is a space separated list of module names. To check for a +# minimum version of a module, append the version number to the module +# name, separated by an equals sign. +# +# Example: +# +# AX_PROG_PERL_MODULES( Text::Wrap Net::LDAP=1.0.3, , +# AC_MSG_WARN(Need some Perl modules) +# +# LICENSE +# +# Copyright (c) 2009 Dean Povey +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_PERL_MODULES], [AX_PROG_PERL_MODULES]) +AC_DEFUN([AX_PROG_PERL_MODULES],[dnl + +m4_define([ax_perl_modules]) +m4_foreach([ax_perl_module], m4_split(m4_normalize([$1])), + [ + m4_append([ax_perl_modules], + [']m4_bpatsubst(ax_perl_module,=,[ ])[' ]) + ]) + +# Make sure we have perl +if test -z "$PERL"; then +AC_CHECK_PROG(PERL,perl,perl) +fi + +if test "x$PERL" != x; then + ax_perl_modules_failed=0 + for ax_perl_module in ax_perl_modules; do + AC_MSG_CHECKING(for perl module $ax_perl_module) + + # Would be nice to log result here, but can't rely on autoconf internals + $PERL -e "use $ax_perl_module; exit" > /dev/null 2>&1 + if test $? -ne 0; then + AC_MSG_RESULT(no); + ax_perl_modules_failed=1 + else + AC_MSG_RESULT(ok); + fi + done + + # Run optional shell commands + if test "$ax_perl_modules_failed" = 0; then + : + $2 + else + : + $3 + fi +else + AC_MSG_WARN(could not find perl) +fi])dnl diff --git a/m4/ltp-acl.m4 b/m4/ltp-acl.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-atomic.m4 b/m4/ltp-atomic.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-builtin_clear_cache.m4 b/m4/ltp-builtin_clear_cache.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-cap.m4 b/m4/ltp-cap.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-clone7args.m4 b/m4/ltp-clone7args.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-crypto.m4 b/m4/ltp-crypto.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-docparse.m4 b/m4/ltp-docparse.m4 new file mode 100755 index 0000000000000000000000000000000000000000..88d2e08e46db8eebb4534f6c9a643e320000fa3c --- /dev/null +++ b/m4/ltp-docparse.m4 @@ -0,0 +1,112 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2020 Petr Vorel + +AC_DEFUN([LTP_CHECK_METADATA_GENERATOR_ASCIIDOCTOR], [ + AC_MSG_NOTICE(checking asciidoctor as metadata generator) + AC_PATH_TOOL(asciidoctor, "asciidoctor") + metadata_generator_html=$asciidoctor + # pdf requires both asciidoctor and asciidoctor-pdf + if test "x$metadata_generator_html" != x; then + AC_PATH_TOOL(asciidoctor_pdf, "asciidoctor-pdf") + metadata_generator_pdf=$asciidoctor_pdf + fi +]) + +AC_DEFUN([LTP_CHECK_METADATA_GENERATOR_ASCIIDOC], [ + AC_MSG_NOTICE(checking asciidoc as metadata generator) + AC_PATH_TOOL(a2x, "a2x") + if test "x$a2x" != x; then + version="`$a2x --version | cut -d ' ' -f2 `" + AX_COMPARE_VERSION([$version], lt, 9, [ + AC_MSG_WARN([a2x unsupported version: $version. Use a2x >= 9]) + a2x= + ]) + fi + metadata_generator_html=$a2x + # pdf requires both asciidoc and dblatex + if test "x$metadata_generator_html" != x; then + AC_PATH_TOOL(dblatex, "dblatex") + metadata_generator_pdf=$dblatex + fi +]) + +AC_DEFUN([LTP_DOCPARSE], [ +with_metadata=no +with_metadata_html=no +with_metadata_pdf=no + +if test "x$enable_metadata" = xyes && test "x$enable_metadata_html" = xyes -o "x$enable_metadata_pdf" = xyes; then + AX_PROG_PERL_MODULES(Cwd File::Basename JSON LWP::Simple) +fi + +if test "x$ax_perl_modules_failed" = x0; then + if test "x$with_metadata_generator" = xasciidoctor -o "x$with_metadata_generator" = xdetect; then + LTP_CHECK_METADATA_GENERATOR_ASCIIDOCTOR + elif test "x$with_metadata_generator" = xasciidoc; then + LTP_CHECK_METADATA_GENERATOR_ASCIIDOC + else + AC_MSG_ERROR([invalid metadata generator '$with_metadata_generator', use --with-metadata-generator=asciidoc|asciidoctor]) + fi + + # autodetection: check also Asciidoc + if test "x$with_metadata_generator" = xdetect; then + with_metadata_generator='asciidoctor' + # problems with Asciidoctor: (html enabled && not found) || (pdf enabled && not found) => try Asciidoc + if test "x$enable_metadata_html" = xyes -a "x$metadata_generator_html" = x || + test "x$enable_metadata_pdf" = xyes -a "x$metadata_generator_pdf" = x; then + backup_html="$metadata_generator_html" + backup_pdf="$metadata_generator_pdf" + AC_MSG_NOTICE(missing some dependencies for Asciidoctor => trying Asciidoc) + with_metadata_generator='asciidoc' + LTP_CHECK_METADATA_GENERATOR_ASCIIDOC + # prefer Asciidoctor if it's not worse than Asciidoc + # (html not enabled || asciidoctor html found || asciidoc html not found) && (pdf ...) + if test "x$enable_metadata_html" != xyes -o "x$backup_html" != x -o "x$metadata_generator_html" = x && + test "x$enable_metadata_pdf" != xyes -o "x$backup_pdf" != x -o "x$metadata_generator_pdf" = x; then + with_metadata_generator='asciidoctor' + metadata_generator_html="$backup_html" + metadata_generator_pdf="$backup_pdf" + fi + fi + if test "x$metadata_generator_html" != x -o "x$metadata_generator_pdf" != x; then + AC_MSG_NOTICE(choosing $with_metadata_generator for metadata generation) + fi + fi + + if test "x$enable_metadata_html" = xno; then + AC_MSG_NOTICE(HTML metadata generation disabled) + elif test "x$metadata_generator_html" != x; then + with_metadata_html=yes + fi + + if test "x$enable_metadata_pdf" = xno; then + AC_MSG_NOTICE(PDF metadata generation disabled) + elif test "x$metadata_generator_pdf" != x; then + with_metadata_pdf=yes + fi +fi + +reason="metadata generation skipped due missing suitable generator" +hint="specify correct generator with --with-metadata-generator=asciidoc|asciidoctor or use --disable-metadata|--disable-metadata-html|--disable-metadata-pdf" + +if test -z "$ax_perl_modules_failed"; then + AC_MSG_NOTICE(metadata generation disabled) +elif test "x$ax_perl_modules_failed" = x1; then + AC_MSG_WARN(metadata generation skipped due missing required Perl modules) +elif test "x$with_metadata_html" = xno -a "x$with_metadata_pdf" = xno; then + AC_MSG_WARN([$reason, $hint]) +else + with_metadata=yes + AC_SUBST(METADATA_GENERATOR, $with_metadata_generator) + if test "x$with_metadata_html" = xno -a "x$enable_metadata_html" = xyes; then + AC_MSG_WARN([HTML $reason, $hint]) + fi + if test "x$with_metadata_pdf" = xno -a "x$enable_metadata_pdf" = xyes; then + AC_MSG_WARN([PDF $reason, $hint]) + fi +fi + +AC_SUBST(WITH_METADATA, $with_metadata) +AC_SUBST(WITH_METADATA_HTML, $with_metadata_html) +AC_SUBST(WITH_METADATA_PDF, $with_metadata_pdf) +]) diff --git a/m4/ltp-eventfd.m4 b/m4/ltp-eventfd.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-fcntl.m4 b/m4/ltp-fcntl.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-fortify_source.m4 b/m4/ltp-fortify_source.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-host-cpu.m4 b/m4/ltp-host-cpu.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-kernel_devel.m4 b/m4/ltp-kernel_devel.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-keyutils.m4 b/m4/ltp-keyutils.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-libmnl.m4 b/m4/ltp-libmnl.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-linuxrandom.m4 b/m4/ltp-linuxrandom.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-mremap_fixed.m4 b/m4/ltp-mremap_fixed.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-nommu-linux.m4 b/m4/ltp-nommu-linux.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-numa.m4 b/m4/ltp-numa.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-perf_event_open.m4 b/m4/ltp-perf_event_open.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-ptrace.m4 b/m4/ltp-ptrace.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-selinux.m4 b/m4/ltp-selinux.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-signalfd.m4 b/m4/ltp-signalfd.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-sync_add_and_fetch.m4 b/m4/ltp-sync_add_and_fetch.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-taskstats.m4 b/m4/ltp-taskstats.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-tirpc.m4 b/m4/ltp-tirpc.m4 old mode 100644 new mode 100755 index 4d9701469c6627ccc733bf51b03e6b333f4eff9e..0fa706771776cc7f4dd32b10e28a18c74f6aa7c7 --- a/m4/ltp-tirpc.m4 +++ b/m4/ltp-tirpc.m4 @@ -6,8 +6,6 @@ AC_DEFUN([LTP_CHECK_TIRPC], [ dnl libtirpc library and headers PKG_CHECK_MODULES([LIBTIRPC], [libtirpc >= 0.2.4], [ have_libtirpc=yes - TIRPC_CFLAGS=$LIBTIRPC_CFLAGS - TIRPC_LIBS=$LIBTIRPC_LIBS ], [have_libtirpc=no]) dnl TI-RPC headers (in glibc, since 2.26 installed only when configured @@ -22,9 +20,4 @@ AC_DEFUN([LTP_CHECK_TIRPC], [ if test "x$have_libtirpc" = "xyes" -o "x$have_rpc_glibc" = "xyes"; then AC_SUBST(HAVE_RPC, 1) fi - - dnl fix for old pkg-config (< 0.24) - dnl https://autotools.io/pkgconfig/pkg_check_modules.html - AC_SUBST(TIRPC_CFLAGS) - AC_SUBST(TIRPC_LIBS) ]) diff --git a/m4/ltp-utimensat.m4 b/m4/ltp-utimensat.m4 old mode 100644 new mode 100755 diff --git a/m4/ltp-warn_oldstyle.m4 b/m4/ltp-warn_oldstyle.m4 old mode 100644 new mode 100755 diff --git a/metadata/.gitignore b/metadata/.gitignore new file mode 100755 index 0000000000000000000000000000000000000000..07d2fd6ffc6fc9a2d5947780b1294ec580e7e23f --- /dev/null +++ b/metadata/.gitignore @@ -0,0 +1,2 @@ +metaparse +ltp.json diff --git a/metadata/Makefile b/metadata/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..522af42705e6a951897b0f6e08bc7132b4a3d9a5 --- /dev/null +++ b/metadata/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2020 Cyril Hrubis + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/functions.mk + +MAKE_TARGETS := ltp.json +HOST_MAKE_TARGETS := metaparse +INSTALL_DIR = metadata + +.PHONY: ltp.json + +ltp.json: metaparse + $(abs_srcdir)/parse.sh > ltp.json +ifeq ($(WITH_METADATA),yes) + mkdir -p $(abs_top_builddir)/docparse + $(MAKE) -C $(abs_top_builddir)/docparse/ -f $(abs_top_srcdir)/docparse/Makefile +endif + +ifeq ($(WITH_METADATA),yes) +install: + $(MAKE) -C $(abs_top_builddir)/docparse/ -f $(abs_top_srcdir)/docparse/Makefile install +endif + +test: + $(MAKE) -C $(abs_srcdir)/tests/ test + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/metadata/data_storage.h b/metadata/data_storage.h new file mode 100755 index 0000000000000000000000000000000000000000..91ea70a02e2636c8a4eab5786f2cd3251182d610 --- /dev/null +++ b/metadata/data_storage.h @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Cyril Hrubis + */ + +#ifndef DATA_STORAGE_H__ +#define DATA_STORAGE_H__ + +#include +#include +#include +#include + +enum data_type { + DATA_ARRAY, + DATA_HASH, + DATA_STRING, + DATA_INT, +}; + +struct data_node_array { + enum data_type type; + unsigned int array_len; + unsigned int array_used; + struct data_node *array[]; +}; + +struct data_hash_elem { + struct data_node *node; + char *id; +}; + +struct data_node_hash { + enum data_type type; + unsigned int elems_len; + unsigned int elems_used; + struct data_hash_elem elems[]; +}; + +struct data_node_string { + enum data_type type; + char val[]; +}; + +struct data_node_int { + enum data_type type; + long val; +}; + +struct data_node { + union { + enum data_type type; + struct data_node_hash hash; + struct data_node_array array; + struct data_node_string string; + struct data_node_int i; + }; +}; + +static inline const char* data_type_name(enum data_type type) +{ + switch (type) { + case DATA_ARRAY: + return "array"; + case DATA_HASH: + return "hash"; + case DATA_STRING: + return "string"; + case DATA_INT: + return "int"; + default: + return "???"; + } +} + +static inline struct data_node *data_node_string(const char *string) +{ + size_t size = sizeof(struct data_node_string) + strlen(string) + 1; + struct data_node *node = malloc(size); + + if (!node) + return NULL; + + node->type = DATA_STRING; + strcpy(node->string.val, string); + + return node; +} + +static inline struct data_node *data_node_int(long i) +{ + struct data_node *node = malloc(sizeof(struct data_node_int)); + + if (!node) + return NULL; + + node->type = DATA_INT; + node->i.val = i; + + return node; +} + +#define MAX_ELEMS 100 + +static inline struct data_node *data_node_hash(void) +{ + size_t size = sizeof(struct data_node_hash) + + MAX_ELEMS * sizeof(struct data_hash_elem); + struct data_node *node = malloc(size); + + if (!node) + return NULL; + + node->type = DATA_HASH; + node->hash.elems_len = MAX_ELEMS; + node->hash.elems_used = 0; + + return node; +} + +static inline struct data_node *data_node_array(void) +{ + size_t size = sizeof(struct data_node_array) + + + MAX_ELEMS * sizeof(struct data_node*); + struct data_node *node = malloc(size); + + if (!node) + return NULL; + + node->type = DATA_ARRAY; + node->array.array_len = MAX_ELEMS; + node->array.array_used = 0; + + return node; +} + +static inline int data_node_hash_add(struct data_node *self, const char *id, struct data_node *payload) +{ + if (self->type != DATA_HASH) + return 1; + + struct data_node_hash *hash = &self->hash; + + if (hash->elems_used == hash->elems_len) + return 1; + + struct data_hash_elem *elem = &hash->elems[hash->elems_used++]; + + elem->node = payload; + elem->id = strdup(id); + + return 0; +} + +static inline void data_node_free(struct data_node *self) +{ + unsigned int i; + + switch (self->type) { + case DATA_STRING: + case DATA_INT: + break; + case DATA_HASH: + for (i = 0; i < self->hash.elems_used; i++) { + data_node_free(self->hash.elems[i].node); + free(self->hash.elems[i].id); + } + break; + case DATA_ARRAY: + for (i = 0; i < self->array.array_used; i++) + data_node_free(self->array.array[i]); + break; + } + + free(self); +} + +static inline int data_node_hash_del(struct data_node *self, const char *id) +{ + unsigned int i; + struct data_node_hash *hash = &self->hash; + + for (i = 0; i < hash->elems_used; i++) { + if (!strcmp(hash->elems[i].id, id)) + break; + } + + if (i >= hash->elems_used) + return 0; + + data_node_free(hash->elems[i].node); + free(hash->elems[i].id); + + hash->elems[i] = hash->elems[--hash->elems_used]; + + return 1; +} + +static struct data_node *data_node_hash_get(struct data_node *self, const char *id) +{ + unsigned int i; + struct data_node_hash *hash = &self->hash; + + for (i = 0; i < hash->elems_used; i++) { + if (!strcmp(hash->elems[i].id, id)) + break; + } + + if (i >= hash->elems_used) + return NULL; + + return hash->elems[i].node; +} + +static inline int data_node_array_add(struct data_node *self, struct data_node *payload) +{ + if (self->type != DATA_ARRAY) + return 1; + + struct data_node_array *array = &self->array; + + if (array->array_used == array->array_len) + return 1; + + array->array[array->array_used++] = payload; + + return 0; +} + +static inline unsigned int data_node_array_len(struct data_node *self) +{ + if (self->type != DATA_ARRAY) + return 0; + + return self->array.array_used; +} + +static inline void data_print_padd(unsigned int i) +{ + while (i-- > 0) + putchar(' '); +} + +static inline void data_node_print_(struct data_node *self, unsigned int padd) +{ + unsigned int i; + + switch (self->type) { + case DATA_INT: + data_print_padd(padd); + printf("%li\n", self->i.val); + break; + case DATA_STRING: + data_print_padd(padd); + printf("'%s'\n", self->string.val); + break; + case DATA_HASH: + for (i = 0; i < self->hash.elems_used; i++) { + data_print_padd(padd); + printf("%s = {\n", self->hash.elems[i].id); + data_node_print_(self->hash.elems[i].node, padd+1); + data_print_padd(padd); + printf("},\n"); + } + break; + case DATA_ARRAY: + for (i = 0; i < self->array.array_used; i++) { + data_print_padd(padd); + printf("{\n"); + data_node_print_(self->array.array[i], padd+1); + data_print_padd(padd); + printf("},\n"); + } + break; + } +} + +static inline void data_node_print(struct data_node *self) +{ + printf("{\n"); + data_node_print_(self, 1); + printf("}\n"); +} + +static inline void data_fprintf(FILE *f, unsigned int padd, const char *fmt, ...) + __attribute__((format (printf, 3, 4))); + +static inline void data_fprintf(FILE *f, unsigned int padd, const char *fmt, ...) +{ + va_list va; + + while (padd-- > 0) + putc(' ', f); + + va_start(va, fmt); + vfprintf(f, fmt, va); + va_end(va); +} + + +static inline void data_fprintf_esc(FILE *f, unsigned int padd, const char *str) +{ + while (padd-- > 0) + fputc(' ', f); + + fputc('"', f); + + while (*str) { + switch (*str) { + case '\\': + fputs("\\\\", f); + break; + case '"': + fputs("\\\"", f); + break; + case '\t': + fputs(" ", f); + break; + default: + /* RFC 8259 specify chars before 0x20 as invalid */ + if (*str >= 0x20) + putc(*str, f); + else + fprintf(stderr, "%s:%d: WARNING: invalid character for JSON: %x\n", + __FILE__, __LINE__, *str); + break; + } + str++; + } + + fputc('"', f); +} + +static inline void data_to_json_(struct data_node *self, FILE *f, unsigned int padd, int do_padd) +{ + unsigned int i; + + switch (self->type) { + case DATA_INT: + padd = do_padd ? padd : 0; + data_fprintf(f, padd, "%li", self->i.val); + break; + case DATA_STRING: + padd = do_padd ? padd : 0; + data_fprintf_esc(f, padd, self->string.val); + break; + case DATA_HASH: + for (i = 0; i < self->hash.elems_used; i++) { + data_fprintf(f, padd, "\"%s\": ", self->hash.elems[i].id); + data_to_json_(self->hash.elems[i].node, f, padd+1, 0); + if (i < self->hash.elems_used - 1) + fprintf(f, ",\n"); + else + fprintf(f, "\n"); + } + break; + case DATA_ARRAY: + data_fprintf(f, do_padd ? padd : 0, "[\n"); + for (i = 0; i < self->array.array_used; i++) { + data_to_json_(self->array.array[i], f, padd+1, 1); + if (i < self->array.array_used - 1) + fprintf(f, ",\n"); + else + fprintf(f, "\n"); + } + data_fprintf(f, padd, "]"); + break; + } +} + +static inline void data_to_json(struct data_node *self, FILE *f, unsigned int padd) +{ + fprintf(f, "{\n"); + data_to_json_(self, f, padd + 1, 1); + data_fprintf(f, padd, "}"); +} + +#endif /* DATA_STORAGE_H__ */ diff --git a/metadata/metaparse.c b/metadata/metaparse.c new file mode 100755 index 0000000000000000000000000000000000000000..f71d8628d536ab29dae56bd562a924e48cdcaae1 --- /dev/null +++ b/metadata/metaparse.c @@ -0,0 +1,903 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019-2021 Cyril Hrubis + * Copyright (c) 2020 Petr Vorel + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include "data_storage.h" + +#define INCLUDE_PATH_MAX 5 + +static int verbose; +static char *cmdline_includepath[INCLUDE_PATH_MAX]; +static unsigned int cmdline_includepaths; +static char *includepath; + +#define WARN(str) fprintf(stderr, "WARNING: " str "\n") + +static void oneline_comment(FILE *f) +{ + int c; + + do { + c = getc(f); + } while (c != '\n'); +} + +static const char *eat_asterisk_space(const char *c) +{ + unsigned int i = 0; + + while (isspace(c[i])) + i++; + + if (c[i] == '*') { + if (isspace(c[i+1])) + i++; + return &c[i+1]; + } + + return c; +} + +static void multiline_comment(FILE *f, struct data_node *doc) +{ + int c; + int state = 0; + char buf[4096]; + unsigned int bufp = 0; + + for (;;) { + c = getc(f); + + if (doc) { + if (c == '\n') { + struct data_node *line; + buf[bufp] = 0; + line = data_node_string(eat_asterisk_space(buf)); + if (data_node_array_add(doc, line)) + WARN("doc string comment truncated"); + bufp = 0; + continue; + } + + if (bufp + 1 >= sizeof(buf)) + continue; + + buf[bufp++] = c; + } + + switch (state) { + case 0: + if (c == '*') + state = 1; + break; + case 1: + switch (c) { + case '/': + return; + case '*': + continue; + default: + state = 0; + break; + } + break; + } + } + +} + +static const char doc_prefix[] = "\\\n"; + +static void maybe_doc_comment(FILE *f, struct data_node *doc) +{ + int c, i; + + for (i = 0; doc_prefix[i]; i++) { + c = getc(f); + + if (c == doc_prefix[i]) + continue; + + if (c == '*') + ungetc(c, f); + + multiline_comment(f, NULL); + return; + } + + multiline_comment(f, doc); +} + +static void maybe_comment(FILE *f, struct data_node *doc) +{ + int c = getc(f); + + switch (c) { + case '/': + oneline_comment(f); + break; + case '*': + maybe_doc_comment(f, doc); + break; + default: + ungetc(c, f); + break; + } +} + +static char *next_token2(FILE *f, char *buf, size_t buf_len, struct data_node *doc) +{ + size_t i = 0; + int c; + int in_str = 0; + + buf_len--; + + for (;;) { + c = fgetc(f); + + if (c == EOF) + goto exit; + + if (in_str) { + if (c == '"') { + if (i == 0 || buf[i-1] != '\\') + goto exit; + } + + if (i < buf_len) + buf[i++] = c; + continue; + } + + switch (c) { + case '{': + case '}': + case ';': + case '(': + case ')': + case '=': + case ',': + case '[': + case ']': + case '#': + if (i) { + ungetc(c, f); + goto exit; + } + + if (i < buf_len) + buf[i++] = c; + goto exit; + case '0' ... '9': + case 'a' ... 'z': + case 'A' ... 'Z': + case '.': + case '_': + case '-': + buf[i++] = c; + break; + case '/': + maybe_comment(f, doc); + break; + case '"': + in_str = 1; + break; + case ' ': + case '\n': + case '\t': + if (i) + goto exit; + break; + } + } + +exit: + if (i == 0 && !in_str) + return NULL; + + buf[i] = 0; + return buf; +} + +static char *next_token(FILE *f, struct data_node *doc) +{ + static char buf[4096]; + + return next_token2(f, buf, sizeof(buf), doc); +} + +static FILE *open_file(const char *dir, const char *fname) +{ + FILE *f; + char *path; + + if (asprintf(&path, "%s/%s", dir, fname) < 0) + return NULL; + + f = fopen(path, "r"); + + free(path); + + return f; +} + +static FILE *open_include(FILE *f) +{ + char buf[256], *fname; + FILE *inc; + unsigned int i; + + if (!fscanf(f, "%s\n", buf)) + return NULL; + + if (buf[0] != '"') + return NULL; + + fname = buf + 1; + + if (!buf[0]) + return NULL; + + fname[strlen(fname)-1] = 0; + + inc = open_file(includepath, fname); + if (inc) { + if (verbose) + fprintf(stderr, "INCLUDE %s/%s\n", includepath, fname); + + return inc; + } + + for (i = 0; i < cmdline_includepaths; i++) { + inc = open_file(cmdline_includepath[i], fname); + + if (!inc) + continue; + + if (verbose) { + fprintf(stderr, "INCLUDE %s/%s\n", + cmdline_includepath[i], fname); + } + + return inc; + } + + return NULL; +} + +static void close_include(FILE *inc) +{ + if (verbose) + fprintf(stderr, "INCLUDE END\n"); + + fclose(inc); +} + +static int parse_array(FILE *f, struct data_node *node) +{ + const char *token; + + for (;;) { + if (!(token = next_token(f, NULL))) + return 1; + + if (!strcmp(token, "{")) { + struct data_node *ret = data_node_array(); + parse_array(f, ret); + + if (data_node_array_len(ret)) + data_node_array_add(node, ret); + else + data_node_free(ret); + + continue; + } + + if (!strcmp(token, "}")) + return 0; + + if (!strcmp(token, ",")) + continue; + + if (!strcmp(token, "NULL")) + continue; + + struct data_node *str = data_node_string(token); + + data_node_array_add(node, str); + } + + return 0; +} + +static void try_apply_macro(char **res) +{ + ENTRY macro = { + .key = *res, + }; + + ENTRY *ret; + + ret = hsearch(macro, FIND); + + if (!ret) + return; + + if (verbose) + fprintf(stderr, "APPLYING MACRO %s=%s\n", ret->key, (char*)ret->data); + + *res = ret->data; +} + +static int parse_get_array_len(FILE *f) +{ + const char *token; + int cnt = 0, depth = 0, prev_comma = 0; + + if (!(token = next_token(f, NULL))) + return 0; + + if (strcmp(token, "{")) + return 0; + + for (;;) { + if (!(token = next_token(f, NULL))) + return 0; + + if (!strcmp(token, "{")) + depth++; + + if (!strcmp(token, "}")) + depth--; + else + prev_comma = 0; + + if (!strcmp(token, ",") && !depth) { + prev_comma = 1; + cnt++; + } + + if (depth < 0) + return cnt + !prev_comma; + } +} + +static void look_for_array_size(FILE *f, const char *arr_id, struct data_node **res) +{ + const char *token; + char buf[2][2048] = {}; + int cur_buf = 0; + int prev_buf = 1; + + for (;;) { + if (!(token = next_token2(f, buf[cur_buf], sizeof(buf[cur_buf]), NULL))) + break; + + if (!strcmp(token, "=") && !strcmp(buf[prev_buf], arr_id)) { + int arr_len = parse_get_array_len(f); + + if (verbose) + fprintf(stderr, "ARRAY %s LENGTH = %i\n", arr_id, arr_len); + + *res = data_node_int(arr_len); + + break; + } + + if (strcmp(buf[cur_buf], "]") && strcmp(buf[cur_buf], "[")) { + cur_buf = !cur_buf; + prev_buf = !prev_buf; + } + } +} + +static int parse_array_size(FILE *f, struct data_node **res) +{ + const char *token; + char *arr_id; + long pos; + int hash = 0; + + *res = NULL; + + if (!(token = next_token(f, NULL))) + return 1; + + if (strcmp(token, "(")) + return 1; + + if (!(token = next_token(f, NULL))) + return 1; + + arr_id = strdup(token); + + if (verbose) + fprintf(stderr, "COMPUTING ARRAY '%s' LENGHT\n", arr_id); + + pos = ftell(f); + + rewind(f); + + look_for_array_size(f, arr_id, res); + + if (!*res) { + FILE *inc; + + rewind(f); + + for (;;) { + if (!(token = next_token(f, NULL))) + break; + + if (token[0] == '#') { + hash = 1; + continue; + } + + if (!hash) + continue; + + if (!strcmp(token, "include")) { + inc = open_include(f); + + if (inc) { + look_for_array_size(inc, arr_id, res); + close_include(inc); + } + } + + if (*res) + break; + } + } + + free(arr_id); + + if (fseek(f, pos, SEEK_SET)) + return 1; + + return 0; +} + +static int parse_test_struct(FILE *f, struct data_node *doc, struct data_node *node) +{ + char *token; + char *id = NULL; + int state = 0; + struct data_node *ret; + + for (;;) { + if (!(token = next_token(f, doc))) + return 1; + + if (!strcmp(token, "}")) + return 0; + + switch (state) { + case 0: + id = strdup(token); + state = 1; + continue; + case 1: + if (!strcmp(token, "=")) + state = 2; + else + WARN("Expected '='"); + continue; + case 2: + if (!strcmp(token, "(")) { + state = 3; + continue; + } + break; + case 3: + if (!strcmp(token, ")")) + state = 2; + continue; + + case 4: + if (!strcmp(token, ",")) + state = 0; + continue; + } + + if (!strcmp(token, "{")) { + ret = data_node_array(); + parse_array(f, ret); + } else if (!strcmp(token, "ARRAY_SIZE")) { + if (parse_array_size(f, &ret)) + return 1; + } else { + try_apply_macro(&token); + ret = data_node_string(token); + } + + if (!ret) + continue; + + const char *key = id; + if (key[0] == '.') + key++; + + data_node_hash_add(node, key, ret); + free(id); + state = 4; + } +} + +static const char *tokens[] = { + "static", + "struct", + "tst_test", + "test", + "=", + "{", +}; + +static void macro_get_string(FILE *f, char *buf, char *buf_end) +{ + int c; + char *buf_start = buf; + + for (;;) { + c = fgetc(f); + + switch (c) { + case EOF: + *buf = 0; + return; + case '"': + if (buf == buf_start || buf[-1] != '\\') { + *buf = 0; + return; + } + buf[-1] = '"'; + break; + default: + if (buf < buf_end) + *(buf++) = c; + } + } +} + +static void macro_get_val(FILE *f, char *buf, size_t buf_len) +{ + int c, prev = 0; + char *buf_end = buf + buf_len - 1; + + while (isspace(c = fgetc(f))); + + if (c == '"') { + macro_get_string(f, buf, buf_end); + return; + } + + for (;;) { + switch (c) { + case '\n': + if (prev == '\\') { + buf--; + } else { + *buf = 0; + return; + } + break; + case EOF: + *buf = 0; + return; + case ' ': + case '\t': + break; + default: + if (buf < buf_end) + *(buf++) = c; + } + + prev = c; + c = fgetc(f); + } +} + +static void parse_macro(FILE *f) +{ + char name[128]; + char val[256]; + + if (!fscanf(f, "%s[^\n]", name)) + return; + + if (fgetc(f) == '\n') + return; + + macro_get_val(f, val, sizeof(val)); + + if (name[0] == '_') + return; + + ENTRY e = { + .key = strdup(name), + .data = strdup(val), + }; + + if (verbose) + fprintf(stderr, " MACRO %s=%s\n", e.key, (char*)e.data); + + hsearch(e, ENTER); +} + +static void parse_include_macros(FILE *f) +{ + FILE *inc; + const char *token; + int hash = 0; + + inc = open_include(f); + if (!inc) + return; + + while ((token = next_token(inc, NULL))) { + if (token[0] == '#') { + hash = 1; + continue; + } + + if (!hash) + continue; + + if (!strcmp(token, "define")) + parse_macro(inc); + + hash = 0; + } + + close_include(inc); +} + +static struct data_node *parse_file(const char *fname) +{ + int state = 0, found = 0; + const char *token; + + if (access(fname, F_OK)) { + fprintf(stderr, "file %s does not exist\n", fname); + return NULL; + } + + FILE *f = fopen(fname, "r"); + + includepath = dirname(strdup(fname)); + + struct data_node *res = data_node_hash(); + struct data_node *doc = data_node_array(); + + while ((token = next_token(f, doc))) { + if (state < 6 && !strcmp(tokens[state], token)) { + state++; + } else { + if (token[0] == '#') { + token = next_token(f, doc); + if (token) { + if (!strcmp(token, "define")) + parse_macro(f); + + if (!strcmp(token, "include")) + parse_include_macros(f); + } + } + + state = 0; + } + + if (state < 6) + continue; + + found = 1; + parse_test_struct(f, doc, res); + } + + if (data_node_array_len(doc)) { + data_node_hash_add(res, "doc", doc); + found = 1; + } else { + data_node_free(doc); + } + + fclose(f); + + if (!found) { + data_node_free(res); + return NULL; + } + + return res; +} + +static struct typemap { + const char *id; + enum data_type type; +} tst_test_typemap[] = { + {.id = "test_variants", .type = DATA_INT}, + {} +}; + +static void convert_str2int(struct data_node *res, const char *id, const char *str_val) +{ + long val; + char *endptr; + + errno = 0; + val = strtol(str_val, &endptr, 10); + + if (errno || *endptr) { + fprintf(stderr, "Cannot convert %s value %s to int!\n", id, str_val); + exit(1); + } + + if (verbose) + fprintf(stderr, "NORMALIZING %s TO INT %li\n", id, val); + + data_node_hash_del(res, id); + data_node_hash_add(res, id, data_node_int(val)); +} + +static void check_normalize_types(struct data_node *res) +{ + unsigned int i; + + for (i = 0; tst_test_typemap[i].id; i++) { + struct data_node *n; + struct typemap *typemap = &tst_test_typemap[i]; + + n = data_node_hash_get(res, typemap->id); + if (!n) + continue; + + if (n->type == typemap->type) + continue; + + if (n->type == DATA_STRING && typemap->type == DATA_INT) { + convert_str2int(res, typemap->id, n->string.val); + continue; + } + + fprintf(stderr, "Cannot convert %s from %s to %s!\n", + typemap->id, data_type_name(n->type), + data_type_name(typemap->type)); + exit(1); + } +} + +static const char *filter_out[] = { + "bufs", + "cleanup", + "mntpoint", + "setup", + "tcnt", + "test", + "test_all", + NULL +}; + +static struct implies { + const char *flag; + const char **implies; +} implies[] = { + {"mount_device", (const char *[]) {"format_device", "needs_device", + "needs_tmpdir", NULL}}, + {"format_device", (const char *[]) {"needs_device", "needs_tmpdir", + NULL}}, + {"all_filesystems", (const char *[]) {"needs_device", "needs_tmpdir", + NULL}}, + {"needs_device", (const char *[]) {"needs_tmpdir", NULL}}, + {"needs_checkpoints", (const char *[]) {"needs_tmpdir", NULL}}, + {"resource_files", (const char *[]) {"needs_tmpdir", NULL}}, + {NULL, (const char *[]) {NULL}} +}; + +const char *strip_name(char *path) +{ + char *name = basename(path); + size_t len = strlen(name); + + if (len > 2 && name[len-1] == 'c' && name[len-2] == '.') + name[len-2] = '\0'; + + return name; +} + +static void print_help(const char *prgname) +{ + printf("usage: %s [-vh] input.c\n\n", prgname); + printf("-v sets verbose mode\n"); + printf("-I add include path\n"); + printf("-h prints this help\n\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + unsigned int i, j; + struct data_node *res; + int opt; + + while ((opt = getopt(argc, argv, "hI:v")) != -1) { + switch (opt) { + case 'h': + print_help(argv[0]); + break; + case 'I': + if (cmdline_includepaths >= INCLUDE_PATH_MAX) { + fprintf(stderr, "Too much include paths!"); + exit(1); + } + + cmdline_includepath[cmdline_includepaths++] = optarg; + break; + case 'v': + verbose = 1; + break; + } + } + + if (optind >= argc) { + fprintf(stderr, "No input filename.c\n"); + return 1; + } + + if (!hcreate(128)) { + fprintf(stderr, "Failed to initialize hash table\n"); + return 1; + } + + res = parse_file(argv[optind]); + if (!res) + return 0; + + /* Filter out useless data */ + for (i = 0; filter_out[i]; i++) + data_node_hash_del(res, filter_out[i]); + + /* Normalize the result */ + for (i = 0; implies[i].flag; i++) { + if (data_node_hash_get(res, implies[i].flag)) { + for (j = 0; implies[i].implies[j]; j++) { + if (data_node_hash_get(res, implies[i].implies[j])) + fprintf(stderr, "%s: useless tag: %s\n", + argv[1], implies[i].implies[j]); + } + } + } + + /* Normalize types */ + check_normalize_types(res); + + for (i = 0; implies[i].flag; i++) { + if (data_node_hash_get(res, implies[i].flag)) { + for (j = 0; implies[i].implies[j]; j++) { + if (!data_node_hash_get(res, implies[i].implies[j])) + data_node_hash_add(res, implies[i].implies[j], + data_node_string("1")); + } + } + } + + data_node_hash_add(res, "fname", data_node_string(argv[optind])); + printf(" \"%s\": ", strip_name(argv[optind])); + data_to_json(res, stdout, 2); + data_node_free(res); + + return 0; +} diff --git a/metadata/parse.sh b/metadata/parse.sh new file mode 100755 index 0000000000000000000000000000000000000000..b43d024c689cf29184205dc8786b623d27081427 --- /dev/null +++ b/metadata/parse.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019 Cyril Hrubis +# Copyright (c) 2020 Petr Vorel +set -e + +top_builddir=$PWD/.. +top_srcdir="$(cd $(dirname $0)/..; pwd)" + +cd $top_srcdir + +version=$(cat $top_srcdir/VERSION) +if [ -d .git ]; then + version=$(git describe 2>/dev/null) || version=$(cat $top_srcdir/VERSION).GIT-UNKNOWN +fi + +echo '{' +echo ' "testsuite": {' +echo ' "name": "Linux Test Project",' +echo ' "short_name": "LTP",' +echo ' "url": "https://github.com/linux-test-project/ltp/",' +echo ' "scm_url_base": "https://github.com/linux-test-project/ltp/tree/master/",' +echo " \"version\": \"$version\"" +echo ' },' +echo ' "defaults": {' +echo ' "timeout": 300' +echo ' },' +echo ' "tests": {' + +first=1 + +for test in `find testcases/ -name '*.c'`; do + a=$($top_builddir/metadata/metaparse -Iinclude -Itestcases/kernel/syscalls/utils/ "$test") + if [ -n "$a" ]; then + if [ -z "$first" ]; then + echo ',' + fi + first= + cat < tmp.json + if ! diff tmp.json $i.json >/dev/null 2>&1; then + echo "***" + echo "$i output differs!" + diff -u tmp.json $i.json + echo "***" + fail=1 + fi +done + +rm -f tmp.json + +exit $fail diff --git a/pan/Makefile b/pan/Makefile old mode 100644 new mode 100755 diff --git a/pan/cgi/README b/pan/cgi/README old mode 100644 new mode 100755 diff --git a/pan/debug.c b/pan/debug.c old mode 100644 new mode 100755 diff --git a/pan/debug.h b/pan/debug.h old mode 100644 new mode 100755 diff --git a/pan/ltp-bump.c b/pan/ltp-bump.c old mode 100644 new mode 100755 diff --git a/pan/ltp-pan.c b/pan/ltp-pan.c old mode 100644 new mode 100755 index 8b9fbe5594b09c707da1518fbc39d58618ccfd7c..0bdb5147717f151c67df6ba2bd4c78b20bd79bc5 --- a/pan/ltp-pan.c +++ b/pan/ltp-pan.c @@ -263,7 +263,7 @@ int main(int argc, char **argv) ret = sscanf(optarg, "%d%c", &run_time, &modifier); if (ret == 0) { fprintf(stderr, - "Need proper time input: ####x where" + "Need proper time input: ####x where " "x is one of s,m,h,d\n"); break; } else if (ret == 1) { @@ -336,7 +336,7 @@ int main(int argc, char **argv) if (!strcmp(logfilename, "-")) { logfile = stdout; } else { - if ((logfile = fopen(logfilename, "a+")) == NULL) { + if ((logfile = fopen(logfilename, "a+e")) == NULL) { fprintf(stderr, "pan(%s): Error %s (%d) opening log file '%s'\n", panname, strerror(errno), errno, @@ -453,7 +453,7 @@ int main(int argc, char **argv) } if (failcmdfilename) { - if (!(failcmdfile = fopen(failcmdfilename, "a+"))) { + if (!(failcmdfile = fopen(failcmdfilename, "a+e"))) { fprintf(stderr, "pan(%s): Error %s (%d) opening fail cmd file '%s'\n", panname, strerror(errno), errno, @@ -463,7 +463,7 @@ int main(int argc, char **argv) } if (tconfcmdfilename) { - tconfcmdfile = fopen(tconfcmdfilename, "a+"); + tconfcmdfile = fopen(tconfcmdfilename, "a+e"); if (!tconfcmdfile) { fprintf(stderr, "pan(%s): Error %s (%d) opening " "tconf cmd file '%s'\n", panname, @@ -1389,8 +1389,8 @@ static void write_test_start(struct tag_pgrp *running, int no_kmsg) if (!strcmp(reporttype, "rts")) { printf - ("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\n%s\n", - "<<>>", running->cmd->name, running->mystime, + ("%s\ntag=%s stime=%lld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\n%s\n", + "<<>>", running->cmd->name, (long long)running->mystime, running->cmd->cmdline, "", "exit", "<<>>"); } fflush(stdout); diff --git a/pan/ltp-scanner.c b/pan/ltp-scanner.c old mode 100644 new mode 100755 diff --git a/pan/reporter.c b/pan/reporter.c old mode 100644 new mode 100755 diff --git a/pan/reporter.h b/pan/reporter.h old mode 100644 new mode 100755 diff --git a/pan/scan.h b/pan/scan.h old mode 100644 new mode 100755 diff --git a/pan/scan.l b/pan/scan.l old mode 100644 new mode 100755 diff --git a/pan/splitstr.c b/pan/splitstr.c old mode 100644 new mode 100755 diff --git a/pan/splitstr.h b/pan/splitstr.h old mode 100644 new mode 100755 diff --git a/pan/symbol.c b/pan/symbol.c old mode 100644 new mode 100755 diff --git a/pan/symbol.h b/pan/symbol.h old mode 100644 new mode 100755 diff --git a/pan/tag_report.c b/pan/tag_report.c old mode 100644 new mode 100755 diff --git a/pan/tag_report.h b/pan/tag_report.h old mode 100644 new mode 100755 diff --git a/pan/zoolib.c b/pan/zoolib.c old mode 100644 new mode 100755 diff --git a/pan/zoolib.h b/pan/zoolib.h old mode 100644 new mode 100755 diff --git a/runltp b/runltp index ec0811834862b6cd59edde9ce96bb7b078dfa398..4447da1569bd309ac4e72bda3510b961bcaa5cd4 100755 --- a/runltp +++ b/runltp @@ -122,7 +122,7 @@ usage() -T TCONFCMDFILE Command file with all test cases that are not fully tested. -d TMPDIR Directory where temporary files will be created. -D NUM_PROCS,NUM_FILES,NUM_BYTES,CLEAN_FLAG - Run LTP under additional background Load on Secondary Storage (Seperate by comma) + Run LTP under additional background Load on Secondary Storage (separated by comma) [NUM_PROCS = no. of processes creating Storage Load by spinning over write()] [NUM_FILES = Write() to these many files (Defaults to 1 when value 0 or undefined)] [NUM_BYTES = write these many bytes (defaults to 1GB, when value 0 or undefined)] @@ -138,7 +138,7 @@ usage() Log Kernel messages generated for each test cases inside this directory -l LOGFILE Log results of test in a logfile. -m NUM_PROCS,CHUNKS,BYTES,HANGUP_FLAG - Run LTP under additional background Load on Main memory (Seperate by comma) + Run LTP under additional background Load on Main memory (separated by comma) [NUM_PROCS = no. of processes creating main Memory Load by spinning over malloc()] [CHUNKS = malloc these many chunks (default is 1 when value 0 or undefined)] [BYTES = malloc CHUNKS of BYTES bytes (default is 256MB when value 0 or undefined) ] @@ -171,6 +171,7 @@ usage() -z BIG_DEVICE Some tests require a big unmounted block device to run correctly. -Z LTP_BIG_DEV_FS_TYPE The file system of the big device + -W ZOOFILE Specify the zoo file used to record current test tags (default PID of this script) @@ -219,10 +220,11 @@ main() local RANDOMRUN=0 local DEFAULT_FILE_NAME_GENERATION_TIME=`date +"%Y_%m_%d-%Hh_%Mm_%Ss"` local scenfile= + local ZOOFILE=$$ version_date=$(cat "$LTPROOT/Version") - while getopts a:b:B:c:C:T:d:D:ef:F:g:hi:I:K:l:m:M:No:pqQr:Rs:S:t:T:w:x:z:Z: arg + while getopts a:b:B:c:C:T:d:D:ef:F:g:hi:I:K:l:m:M:No:pqQr:Rs:S:t:T:w:x:z:Z:W: arg do case $arg in a) EMAIL_TO=$OPTARG ALT_EMAIL_OUT=1;; @@ -298,11 +300,11 @@ main() version_of_ltp ;; f) # Execute user defined set of testcases. - # Can be more then one file, just separate it with ',', like: + # Can be more than one file, just separate it with ',', like: # -f nfs,commands,/tmp/testfile CMDFILES=$OPTARG;; F) INJECT_KERNEL_FAULT=1 - #Seperate out the NO_OF_LOOPS & FAULT_PERCENTAGE + # Separate out the NO_OF_LOOPS & FAULT_PERCENTAGE INJECT_FAULT_LOOPS_PER_TEST=`echo $OPTARG |cut -d',' -f1 | tr -d '\n' | tr -d ' '` INJECT_KERNEL_FAULT_PERCENTAGE=`echo $OPTARG |cut -d',' -f2 | tr -d '\n' | tr -d ' '` if [ ! $INJECT_FAULT_LOOPS_PER_TEST ]; then @@ -318,9 +320,9 @@ main() /*) HTMLFILE="$OPTARG";; *) - HTMLFILE="$LTPROOT/output/$OPTARG";; + HTMLFILE="$LTPROOT/output/$OPTARG" + ALT_DIR_OUT=1;; esac - ALT_DIR_OUT=1 ALT_HTML_OUT=1;; h) usage;; @@ -446,6 +448,7 @@ main() B) LTP_DEV_FS_TYPE=$OPTARG;; z) BIG_DEVICE=$OPTARG;; Z) BIG_DEVICE_FS_TYPE=$OPTARG;; + W) ZOOFILE=$OPTARG;; \?) usage;; esac done @@ -499,10 +502,6 @@ main() OUTPUTFILE_NAME="$DEFAULT_FILE_NAME_GENERATION_TIME" OUTPUTFILE="-o $LTPROOT/output/LTP_RUN_ON-$OUTPUTFILE_NAME.output" ALT_DIR_OUT=1 - if [ ! "$HTMLFILE" ] ; then ## User has not mentioned HTML File name, We need to create one - HTMLFILE_NAME=`basename $OUTPUTFILE_NAME` - HTMLFILE="$LTPROOT/output/$HTMLFILE_NAME.html" - fi fi fi @@ -519,16 +518,17 @@ main() } } } + # If we need, create the results directory [ "$ALT_DIR_RES" -eq 1 ] && \ { - echo "INFO: creating $LTPROOT/results directory" [ ! -d $LTPROOT/results ] && \ { - mkdir -p $LTPROOT/results || \ - { - echo "ERROR: failed to create $LTPROOT/results" - exit 1 + echo "INFO: creating $LTPROOT/results directory" + mkdir -p $LTPROOT/results || \ + { + echo "ERROR: failed to create $LTPROOT/results" + exit 1 } } } @@ -552,6 +552,8 @@ main() # write to it as user nobody export TMPDIR=$TMP + trap "cleanup" 0 + chmod 777 $TMP || \ { echo "unable to chmod 777 $TMP ... aborting" @@ -706,7 +708,7 @@ EOF fi [ ! -z "$QUIET_MODE" ] && { echo "INFO: Test start time: $(date)" ; } - PAN_COMMAND="${LTPROOT}/bin/ltp-pan $QUIET_MODE $NO_KMSG -e -S $INSTANCES $DURATION -a $$ \ + PAN_COMMAND="${LTPROOT}/bin/ltp-pan $QUIET_MODE $NO_KMSG -e -S $INSTANCES $DURATION -a ${ZOOFILE} \ -n $$ $PRETTY_PRT -f ${TMP}/alltests $LOGFILE $OUTPUTFILE $FAILCMDFILE $TCONFCMDFILE" echo "COMMAND: $PAN_COMMAND" if [ ! -z "$TAG_RESTRICT_STRING" ] ; then @@ -802,7 +804,7 @@ EOF fi # Some tests need to run inside the "bin" directory. cd "${LTPROOT}/testcases/bin" - "${LTPROOT}/bin/ltp-pan" $QUIET_MODE $NO_KMSG -e -S $INSTANCES $DURATION -a $$ -n $$ $PRETTY_PRT -f ${TMP}/alltests $LOGFILE $OUTPUTFILE $FAILCMDFILE $TCONFCMDFILE + "${LTPROOT}/bin/ltp-pan" $QUIET_MODE $NO_KMSG -e -S $INSTANCES $DURATION -a ${ZOOFILE} -n $$ $PRETTY_PRT -f ${TMP}/alltests $LOGFILE $OUTPUTFILE $FAILCMDFILE $TCONFCMDFILE if [ $? -eq 0 ]; then echo "INFO: ltp-pan reported all tests PASS" @@ -835,12 +837,12 @@ EOF export LTP_VERSION=$version_date export TEST_START_TIME="$test_start_time" export TEST_END_TIME="$(date)" - OUTPUT_DIRECTORY=`echo $OUTPUTFILE | cut -c4-` + OUTPUT_FILE=`echo $OUTPUTFILE | cut -c4-` LOGS_DIRECTORY="$LTPROOT/results" export TEST_OUTPUT_DIRECTORY="$LTPROOT/output" export TEST_LOGS_DIRECTORY=$LOGS_DIRECTORY echo "Generating HTML Output.....!!" - ( perl $LTPROOT/bin/genhtml.pl $LTPROOT/bin/html_report_header.txt test_start test_end test_output execution_status $OUTPUT_DIRECTORY > $HTMLFILE; ) + ( perl $LTPROOT/bin/genhtml.pl $LTPROOT/bin/html_report_header.txt test_start test_end test_output execution_status $OUTPUT_FILE > $HTMLFILE; ) echo "Generated HTML Output.....!!" echo "Location: $HTMLFILE"; @@ -935,45 +937,9 @@ EOF exit $VALUE } -create_block() -{ - #create a block device - dd if=/dev/zero of=${TMP}/test.img bs=1024 count=262144 >/dev/null 2>&1 - if [ $? -ne 0 ]; then - echo "Failed to create loopback device image, please check disk space and re-run" - return 1 - else - ##search for an unused loop dev - LOOP_DEV=$(losetup -f) - if [ $? -ne 0 ]; then - echo "no unused loop device is found" - return 1 - else - ##attach the created file to loop dev. - losetup $LOOP_DEV ${TMP}/test.img - if [ $? -ne 0 ]; then - echo "losetup failed to create block device" - return 1 - fi - DEVICE=$LOOP_DEV - return 0 - fi - fi -} - set_block_device() { - if [ -z "$DEVICE" ]; then - create_block - if [ $? -ne 0 ]; then - echo "no block device was specified on commandline." - echo "Block device could not be created using loopback device" - echo "Tests which require block device are disabled." - echo "You can specify it with option -b" - else - export LTP_DEV=$DEVICE - fi - else + if [ -n "$DEVICE" ]; then export LTP_DEV=$DEVICE fi } @@ -988,7 +954,6 @@ cleanup() LTP_SCRIPT="$(basename $0)" if [ "$LTP_SCRIPT" = "runltp" ]; then - trap "cleanup" 0 setup main "$@" fi diff --git a/runtest/Makefile b/runtest/Makefile old mode 100644 new mode 100755 index b7caaee06d193498d0c6121ebbde161e3682c28b..6a1565b6a4f8e9fa7c31fecc7cce695830242af1 --- a/runtest/Makefile +++ b/runtest/Makefile @@ -36,7 +36,7 @@ ifneq ($(WITH_POWER_MANAGEMENT_TESTSUITE),yes) UNWANTED_FILES += power_management_tests endif -INSTALL_TARGETS := $(filter-out $(UNWANTED_FILES),$(notdir $(patsubst $(abs_srcdir)/%,%,$(wildcard $(abs_srcdir)/*)))) +INSTALL_TARGETS := $(filter-out $(UNWANTED_FILES),$(notdir $(patsubst $(abs_srcdir)/%,%,$(sort $(wildcard $(abs_srcdir)/*))))) MAKE_TARGETS := diff --git a/runtest/can b/runtest/can old mode 100644 new mode 100755 index 6aa2ae9f5a0f942821e032ee5d01493f80a84470..23cbf9acd51210403ae846d942227d7d016ff2a5 --- a/runtest/can +++ b/runtest/can @@ -1,2 +1,3 @@ -can_filter can_run_tests.sh can_filter -can_rcv_own_msgs can_run_tests.sh can_rcv_own_msgs +can_filter can_filter +can_rcv_own_msgs can_rcv_own_msgs +can_bcm01 can_bcm01 diff --git a/runtest/cap_bounds b/runtest/cap_bounds old mode 100644 new mode 100755 diff --git a/runtest/commands b/runtest/commands old mode 100644 new mode 100755 index 058266b545b21304e40aa1261c4526db5dc2c844..8cfad0449127358baaaabac1dce76ad4906d02d6 --- a/runtest/commands +++ b/runtest/commands @@ -41,3 +41,4 @@ gdb01_sh gdb01.sh unshare01_sh unshare01.sh sysctl01_sh sysctl01.sh sysctl02_sh sysctl02.sh +shell_test01 echo "SUCCESS" | shell_pipe01.sh diff --git a/runtest/connectors b/runtest/connectors old mode 100644 new mode 100755 index 6153a98e6586bb4e2d52442cab5db8dbf8940e77..2c7aed474ead29ff31e1dba091cdbd716dfa8718 --- a/runtest/connectors +++ b/runtest/connectors @@ -1,2 +1,2 @@ #DESCRIPTION:Netlink Connector tests -Connectors connector_test.sh +cn_pec_sh cn_pec.sh diff --git a/runtest/containers b/runtest/containers old mode 100644 new mode 100755 index 276096709ed86c6606147bbf74f01b7ca4cdc707..eea7bfadb7bfc926ada52cd3266f9eb48723745c --- a/runtest/containers +++ b/runtest/containers @@ -85,6 +85,7 @@ userns04 userns04 userns05 userns05 userns06 userns06 userns07 userns07 +userns08 userns08 # time namespaces sysinfo03 sysinfo03 diff --git a/runtest/controllers b/runtest/controllers old mode 100644 new mode 100755 index e3d0243f1f359da8d2a900ad2fbd0d0cbf2b4c5e..09e0107e4c78a9f1331423308c9b2ce0b8537e97 --- a/runtest/controllers +++ b/runtest/controllers @@ -16,6 +16,10 @@ memcg_usage_in_bytes memcg_usage_in_bytes_test.sh memcg_stress memcg_stress_test.sh memcg_control memcg_control_test.sh +# kselftest ports +memcontrol01 memcontrol01 +memcontrol02 memcontrol02 + cgroup_fj_function_debug cgroup_fj_function.sh debug cgroup_fj_function_cpuset cgroup_fj_function.sh cpuset cgroup_fj_function_cpu cgroup_fj_function.sh cpu diff --git a/runtest/cpuhotplug b/runtest/cpuhotplug old mode 100644 new mode 100755 diff --git a/runtest/crashme b/runtest/crashme old mode 100644 new mode 100755 index 14750749d99835cb3ac9e0cebc15c59722be6fa4..47f5f93b4336b57c89037d4873f248d83953521b --- a/runtest/crashme +++ b/runtest/crashme @@ -10,9 +10,6 @@ crash01 crash01 crash02 crash02 -v 2 # Generate random syscalls and execute them, less probability # to hose your system, but still. -mem01 mem01 -r -# Memory eater. Loves to be run in parallel with other programs. -# May panic on buggy systems if the OOM killer was not fast enough :-) fork12 fork12 # Fork as many children as possible. On systems with lots of memory # and kernels prior to 2.4.19, this can hang the system by using up all pids diff --git a/runtest/crypto b/runtest/crypto old mode 100644 new mode 100755 index be8bc81d2fe144462ee86a9cccd0305af313ed39..446559efcd7d2addbad8a88c38fac00ae5cfa92d --- a/runtest/crypto +++ b/runtest/crypto @@ -4,6 +4,7 @@ af_alg03 af_alg03 af_alg04 af_alg04 af_alg05 af_alg05 af_alg06 af_alg06 +af_alg07 af_alg07 pcrypt_aead01 pcrypt_aead01 crypto_user01 crypto_user01 crypto_user02 crypto_user02 diff --git a/runtest/cve b/runtest/cve old mode 100644 new mode 100755 index b9ab49c3b7082a63a4f94b682188396d4c2979b7..01211b5aafd8228dee76e3f70f56930b2bde7493 --- a/runtest/cve +++ b/runtest/cve @@ -12,14 +12,17 @@ cve-2016-4997 setsockopt03 cve-2016-5195 dirtyc0w cve-2016-7042 cve-2016-7042 cve-2016-7117 cve-2016-7117 +cve-2016-8655 setsockopt06 cve-2016-9604 keyctl08 cve-2016-9793 setsockopt04 cve-2016-10044 cve-2016-10044 cve-2017-2618 cve-2017-2618 +cve-2017-2636 pty05 cve-2017-2671 cve-2017-2671 cve-2017-6951 request_key05 cve-2017-7308 setsockopt02 cve-2017-7472 keyctl04 +cve-2017-7616 set_mempolicy05 cve-2017-10661 timerfd_settime02 cve-2017-12192 keyctl07 cve-2017-12193 add_key04 @@ -39,15 +42,33 @@ cve-2017-16939 cve-2017-16939 cve-2017-16995 bpf_prog03 cve-2017-17053 cve-2017-17053 cve-2017-18075 pcrypt_aead01 +cve-2017-1000111 setsockopt07 cve-2017-1000112 setsockopt05 cve-2017-1000380 snd_timer01 +cve-2017-1000405 thp04 cve-2018-5803 sctp_big_chunk cve-2018-7566 snd_seq01 cve-2018-8897 ptrace09 cve-2018-9568 connect02 +cve-2018-10124 kill13 cve-2018-1000001 realpath01 cve-2018-1000199 ptrace08 cve-2018-1000204 ioctl_sg01 +cve-2018-12896 timer_settime03 +cve-2018-13405 creat09 +cve-2018-18445 bpf_prog04 cve-2018-18559 bind06 +cve-2018-18955 userns08 cve-2018-19854 crypto_user01 +cve-2019-8912 af_alg07 cve-2020-11494 pty04 +cve-2020-14386 sendto03 +cve-2020-14416 pty03 +cve-2020-25705 icmp_rate_limit01 +cve-2020-29373 io_uring02 +cve-2021-3444 bpf_prog05 +cve-2021-3609 can_bcm01 +cve-2021-22555 setsockopt08 -i 100 +cve-2021-26708 vsock01 +# Tests below may cause kernel memory leak +cve-2020-25704 perf_event_open03 diff --git a/runtest/dio b/runtest/dio old mode 100644 new mode 100755 diff --git a/runtest/dma_thread_diotest b/runtest/dma_thread_diotest old mode 100644 new mode 100755 diff --git a/runtest/fcntl-locktests b/runtest/fcntl-locktests old mode 100644 new mode 100755 diff --git a/runtest/filecaps b/runtest/filecaps old mode 100644 new mode 100755 diff --git a/runtest/fs b/runtest/fs old mode 100644 new mode 100755 index 464ba8fb9686faa90313989908bb0681db3a2200..1d753e0ddfdc0eee077a937cb6901a02a9e4aa48 --- a/runtest/fs +++ b/runtest/fs @@ -58,7 +58,7 @@ ftest06 ftest06 ftest07 ftest07 ftest08 ftest08 -lftest01 lftest 100 +lftest01 lftest writetest01 writetest #Also run the fs_di (Data Integrity tests) @@ -69,9 +69,9 @@ fs_di fs_di -d $TMPDIR # Was not sure why it should reside in runtest/crashme and won't get tested ever proc01 proc01 -m 128 -read_all_dev read_all -d /dev -p -q -r 10 -read_all_proc read_all -d /proc -q -r 10 -read_all_sys read_all -d /sys -q -r 10 +read_all_dev read_all -d /dev -p -q -r 3 +read_all_proc read_all -d /proc -q -r 3 +read_all_sys read_all -d /sys -q -r 3 #Run the File System Race Condition Check tests as well fs_racer fs_racer.sh -t 5 @@ -85,3 +85,5 @@ fs_fill fs_fill binfmt_misc01 binfmt_misc01.sh binfmt_misc02 binfmt_misc02.sh + +squashfs01 squashfs01 diff --git a/runtest/fs_bind b/runtest/fs_bind old mode 100644 new mode 100755 index 549d700dec8701a093f371f9f981d283accde7cd..61b3e76283f32f615404b4c9708e2eae05f5b135 --- a/runtest/fs_bind +++ b/runtest/fs_bind @@ -1,2 +1,105 @@ #DESCRIPTION:Bind mounts and shared subtrees -BindMounts $LTPROOT/testscripts/test_fs_bind.sh + +fs_bind01_sh fs_bind01.sh +fs_bind02_sh fs_bind02.sh +fs_bind03_sh fs_bind03.sh +fs_bind04_sh fs_bind04.sh +fs_bind05_sh fs_bind05.sh +fs_bind06_sh fs_bind06.sh +fs_bind07_sh fs_bind07.sh +fs_bind07-2_sh fs_bind07-2.sh +fs_bind08_sh fs_bind08.sh +fs_bind09_sh fs_bind09.sh +fs_bind10_sh fs_bind10.sh +fs_bind11_sh fs_bind11.sh +fs_bind12_sh fs_bind12.sh +fs_bind13_sh fs_bind13.sh +fs_bind14_sh fs_bind14.sh +fs_bind15_sh fs_bind15.sh +fs_bind16_sh fs_bind16.sh +fs_bind17_sh fs_bind17.sh +fs_bind18_sh fs_bind18.sh +fs_bind19_sh fs_bind19.sh +fs_bind20_sh fs_bind20.sh +fs_bind21_sh fs_bind21.sh +fs_bind22_sh fs_bind22.sh +fs_bind23_sh fs_bind23.sh +fs_bind24_sh fs_bind24.sh + + +fs_bind_move01_sh fs_bind_move01.sh +fs_bind_move02_sh fs_bind_move02.sh +fs_bind_move03_sh fs_bind_move03.sh +fs_bind_move04_sh fs_bind_move04.sh +fs_bind_move05_sh fs_bind_move05.sh +fs_bind_move06_sh fs_bind_move06.sh +fs_bind_move07_sh fs_bind_move07.sh +fs_bind_move08_sh fs_bind_move08.sh +fs_bind_move09_sh fs_bind_move09.sh +fs_bind_move10_sh fs_bind_move10.sh +fs_bind_move11_sh fs_bind_move11.sh +fs_bind_move12_sh fs_bind_move12.sh +fs_bind_move13_sh fs_bind_move13.sh +fs_bind_move14_sh fs_bind_move14.sh +fs_bind_move15_sh fs_bind_move15.sh +fs_bind_move16_sh fs_bind_move16.sh +fs_bind_move17_sh fs_bind_move17.sh +fs_bind_move18_sh fs_bind_move18.sh +fs_bind_move19_sh fs_bind_move19.sh +fs_bind_move20_sh fs_bind_move20.sh +fs_bind_move21_sh fs_bind_move21.sh +fs_bind_move22_sh fs_bind_move22.sh + + +fs_bind_rbind01_sh fs_bind_rbind01.sh +fs_bind_rbind02_sh fs_bind_rbind02.sh +fs_bind_rbind03_sh fs_bind_rbind03.sh +fs_bind_rbind04_sh fs_bind_rbind04.sh +fs_bind_rbind05_sh fs_bind_rbind05.sh +fs_bind_rbind06_sh fs_bind_rbind06.sh +fs_bind_rbind07-2_sh fs_bind_rbind07-2.sh +fs_bind_rbind07_sh fs_bind_rbind07.sh +fs_bind_rbind08_sh fs_bind_rbind08.sh +fs_bind_rbind09_sh fs_bind_rbind09.sh +fs_bind_rbind10_sh fs_bind_rbind10.sh +fs_bind_rbind11_sh fs_bind_rbind11.sh +fs_bind_rbind12_sh fs_bind_rbind12.sh +fs_bind_rbind13_sh fs_bind_rbind13.sh +fs_bind_rbind14_sh fs_bind_rbind14.sh +fs_bind_rbind15_sh fs_bind_rbind15.sh +fs_bind_rbind16_sh fs_bind_rbind16.sh +fs_bind_rbind17_sh fs_bind_rbind17.sh +fs_bind_rbind18_sh fs_bind_rbind18.sh +fs_bind_rbind19_sh fs_bind_rbind19.sh +fs_bind_rbind20_sh fs_bind_rbind20.sh +fs_bind_rbind21_sh fs_bind_rbind21.sh +fs_bind_rbind22_sh fs_bind_rbind22.sh +fs_bind_rbind23_sh fs_bind_rbind23.sh +fs_bind_rbind24_sh fs_bind_rbind24.sh +fs_bind_rbind25_sh fs_bind_rbind25.sh +fs_bind_rbind26_sh fs_bind_rbind26.sh +fs_bind_rbind27_sh fs_bind_rbind27.sh +fs_bind_rbind28_sh fs_bind_rbind28.sh +fs_bind_rbind29_sh fs_bind_rbind29.sh +fs_bind_rbind30_sh fs_bind_rbind30.sh +fs_bind_rbind31_sh fs_bind_rbind31.sh +fs_bind_rbind32_sh fs_bind_rbind32.sh +fs_bind_rbind33_sh fs_bind_rbind33.sh +fs_bind_rbind34_sh fs_bind_rbind34.sh +fs_bind_rbind35_sh fs_bind_rbind35.sh +fs_bind_rbind36_sh fs_bind_rbind36.sh +fs_bind_rbind37_sh fs_bind_rbind37.sh +fs_bind_rbind38_sh fs_bind_rbind38.sh +fs_bind_rbind39_sh fs_bind_rbind39.sh + + +fs_bind_regression_sh fs_bind_regression.sh + + +fs_bind_cloneNS01_sh fs_bind_cloneNS01.sh +fs_bind_cloneNS02_sh fs_bind_cloneNS02.sh +fs_bind_cloneNS03_sh fs_bind_cloneNS03.sh +fs_bind_cloneNS04_sh fs_bind_cloneNS04.sh +fs_bind_cloneNS05_sh fs_bind_cloneNS05.sh +fs_bind_cloneNS06_sh fs_bind_cloneNS06.sh +fs_bind_cloneNS07_sh fs_bind_cloneNS07.sh diff --git a/runtest/fs_perms_simple b/runtest/fs_perms_simple old mode 100644 new mode 100755 diff --git a/runtest/fs_readonly b/runtest/fs_readonly old mode 100644 new mode 100755 index 0e1be5f6d462a77c96c5c2c3aaa8889925d7a544..dc70d28d8ad3b99d18dac022650b4e455fe0b954 --- a/runtest/fs_readonly +++ b/runtest/fs_readonly @@ -51,5 +51,5 @@ test_robind50 test_robind.sh -c "ftest05" test_robind51 test_robind.sh -c "ftest06" test_robind52 test_robind.sh -c "ftest07" test_robind53 test_robind.sh -c "ftest08" -test_robind54 test_robind.sh -c "lftest 80" +test_robind54 test_robind.sh -c "-- lftest -n 80" test_robind55 test_robind.sh -c "writetest" diff --git a/runtest/fsx b/runtest/fsx old mode 100644 new mode 100755 diff --git a/runtest/hugetlb b/runtest/hugetlb old mode 100644 new mode 100755 diff --git a/runtest/hyperthreading b/runtest/hyperthreading old mode 100644 new mode 100755 diff --git a/runtest/ima b/runtest/ima old mode 100644 new mode 100755 index f3ea88cf0f5e697a980e716adb2dd4cffee7ce76..01942eefa36399cc29663e500593197ead224aeb --- a/runtest/ima +++ b/runtest/ima @@ -3,4 +3,8 @@ ima_measurements ima_measurements.sh ima_policy ima_policy.sh ima_tpm ima_tpm.sh ima_violations ima_violations.sh +ima_keys ima_keys.sh +ima_kexec ima_kexec.sh +ima_selinux ima_selinux.sh +ima_conditionals ima_conditionals.sh evm_overlay evm_overlay.sh diff --git a/runtest/input b/runtest/input old mode 100644 new mode 100755 diff --git a/runtest/io b/runtest/io old mode 100644 new mode 100755 diff --git a/runtest/io_cd b/runtest/io_cd deleted file mode 100644 index f4ca5604c23ed57e5828886a3f5cac10b2d17be6..0000000000000000000000000000000000000000 --- a/runtest/io_cd +++ /dev/null @@ -1 +0,0 @@ -stress_cd stress_cd diff --git a/runtest/io_floppy b/runtest/io_floppy deleted file mode 100644 index c861d9f3ea783a4b7f7a6e5c877b9bfcd7079f40..0000000000000000000000000000000000000000 --- a/runtest/io_floppy +++ /dev/null @@ -1 +0,0 @@ -stress_floppy stress_floppy diff --git a/runtest/ipc b/runtest/ipc old mode 100644 new mode 100755 diff --git a/runtest/irq b/runtest/irq new file mode 100755 index 0000000000000000000000000000000000000000..56d0d23c87b156acab19b901400a8bfb0f469bf3 --- /dev/null +++ b/runtest/irq @@ -0,0 +1 @@ +irqbalance01 irqbalance01 diff --git a/runtest/kernel_misc b/runtest/kernel_misc old mode 100644 new mode 100755 index 7937c7bbff7f793e3b9e2b8a0bf66389548cb814..abb75ebaf068f0010e6e8627a1f739d836089291 --- a/runtest/kernel_misc +++ b/runtest/kernel_misc @@ -1,6 +1,7 @@ kmsg01 kmsg01 fw_load fw_load rtc01 rtc01 +rtc02 rtc02 block_dev block_dev tpci tpci tbio tbio diff --git a/runtest/ltp-aio-stress.part1 b/runtest/ltp-aio-stress.part1 old mode 100644 new mode 100755 diff --git a/runtest/ltp-aio-stress.part2 b/runtest/ltp-aio-stress.part2 old mode 100644 new mode 100755 diff --git a/runtest/ltp-aiodio.part1 b/runtest/ltp-aiodio.part1 old mode 100644 new mode 100755 diff --git a/runtest/ltp-aiodio.part2 b/runtest/ltp-aiodio.part2 old mode 100644 new mode 100755 index 00b9abf2e2f286f8e49f7eb658c350911266eb03..bed5841bcef247b38fbbe62f10e4ce39cd774172 --- a/runtest/ltp-aiodio.part2 +++ b/runtest/ltp-aiodio.part2 @@ -40,49 +40,45 @@ ADSP038 aiodio_sparse -i 4 -a 8k -w 18192k -n 512 ADSP039 aiodio_sparse -i 4 -a 8k -w 18192k -n 1000 ADSP040 dio_sparse ADSP041 dio_sparse -s 180k -ADSP042 dio_sparse -dd -s 1751k -w 11k -ADSP043 dio_sparse -d -s 180k -w 18k -ADSP044 dio_sparse -a 2k -w 2k -s 2k -n 2 -ADSP045 dio_sparse -a 4k -w 4k -s 2k -n 2 -ADSP046 dio_sparse -a 4k -w 4k -s 4k -n 2 -ADSP047 dio_sparse -a 8k -w 16k -s 16k -n 2 -ADSP048 dio_sparse -a 8k -w 32k -s 32k -n 2 -ADSP049 dio_sparse -a 8k -w 64k -s 64k -n 2 -ADSP050 dio_sparse -a 8k -w 128k -s 128k -n 2 -ADSP051 dio_sparse -a 8k -w 256k -s 256k -n 2 -ADSP052 dio_sparse -a 8k -w 512k -s 512k -n 2 -ADSP053 dio_sparse -a 8k -w 1024k -s 1024k -n 2 -ADSP054 dio_sparse -a 8k -w 2048k -s 2048k -n 2 -ADSP055 dio_sparse -a 8k -w 4096k -s 4096k -n 2 -ADSP056 dio_sparse -a 8k -w 8192k -s 8192k -n 2 -ADSP057 dio_sparse -a 8k -w 18192k -s 18192k -n 2 -ADSP058 dio_sparse -a 8k -w 518192k -s 518192k -n 2 -ADSP059 dio_sparse -a 8k -w 58192k -s 58192k -n 4 -ADSP060 dio_sparse -a 8k -w 58192k -s 58192k -n 6 -ADSP061 dio_sparse -a 8k -w 256k -s 256k -n 6 -ADSP062 dio_sparse -a 8k -w 512k -s 512k -n 6 -ADSP063 dio_sparse -a 8k -w 1024k -s 1024k -n 6 -ADSP064 dio_sparse -a 8k -w 2048k -s 2048k -n 6 -ADSP065 dio_sparse -a 8k -w 2048k -s 4096k -n 6 -ADSP066 dio_sparse -a 8k -w 8192k -s 8192k -n 6 -ADSP067 dio_sparse -a 8k -w 18192k -s 18192k -n 6 -ADSP068 dio_sparse -a 8k -w 58192k -s 518192k -n 6 -ADSP069 dio_sparse -a 8k -w 58192k -s 58192k -n 6 -ADSP070 dio_sparse -a 8k -w 518192k -s 518192k -n 6 -ADSP071 dio_sparse -a 8k -w 256k -s 256k -n 6 -ADSP072 dio_sparse -a 8k -w 512k -s 512k -n 6 -ADSP073 dio_sparse -a 8k -w 1024k -s 1024k -n 6 -ADSP074 dio_sparse -a 8k -w 1024k -s 2048k -n 6 -ADSP075 dio_sparse -a 8k -w 4096k -s 4096k -n 32 -ADSP076 dio_sparse -a 8k -w 8192k -s 8192k -n 64 -ADSP077 dio_sparse -a 8k -w 518192k -s 18192k -n 128 -ADSP078 dio_sparse -a 8k -w 518192k -s 518192k -n 512 -ADSP079 dio_sparse -a 8k -w 518192k -s 518192k -n 1000 -ADSP080 dio_sparse -a 4k -w 4k -s 2k -o 2k -n 2 -ADSP081 dio_sparse -a 2k -w 2k -s 1k -o 1k -n 2 -ADSP082 dio_sparse -a 1k -w 1k -s 512 -o 512 -n 2 -ADSP083 dio_sparse -a 4k -w 4k -s 2k -o 3k -n 2 -ADSP084 dio_sparse -a 4k -w 4k -s 4k -o 4k -n 2 -ADSP085 dio_sparse -a 4k -w 4k -s 4k -o 6k -n 2 -ADSP086 dio_sparse -a 4k -w 4k -s 4k -o 8k -n 2 -ADSP087 dio_sparse -a 4k -w 16k -s 8k -o 8k -n 2 +ADSP042 dio_sparse -s 1751k -w 11k +ADSP043 dio_sparse -s 180k -w 18k +ADSP044 dio_sparse -w 2k -s 2k -n 2 +ADSP045 dio_sparse -w 4k -s 2k -n 2 +ADSP046 dio_sparse -w 4k -s 4k -n 2 +ADSP047 dio_sparse -w 16k -s 16k -n 2 +ADSP048 dio_sparse -w 32k -s 32k -n 2 +ADSP049 dio_sparse -w 64k -s 64k -n 2 +ADSP050 dio_sparse -w 128k -s 128k -n 2 +ADSP051 dio_sparse -w 256k -s 256k -n 2 +ADSP052 dio_sparse -w 512k -s 512k -n 2 +ADSP053 dio_sparse -w 1024k -s 1024k -n 2 +ADSP054 dio_sparse -w 2048k -s 2048k -n 2 +ADSP055 dio_sparse -w 4096k -s 4096k -n 2 +ADSP056 dio_sparse -w 8192k -s 8192k -n 2 +ADSP057 dio_sparse -w 18192k -s 18192k -n 2 +ADSP058 dio_sparse -w 518192k -s 518192k -n 2 +ADSP059 dio_sparse -w 58192k -s 58192k -n 4 +ADSP060 dio_sparse -w 58192k -s 58192k -n 6 +ADSP061 dio_sparse -w 256k -s 256k -n 6 +ADSP062 dio_sparse -w 512k -s 512k -n 6 +ADSP063 dio_sparse -w 1024k -s 1024k -n 6 +ADSP064 dio_sparse -w 2048k -s 2048k -n 6 +ADSP065 dio_sparse -w 2048k -s 4096k -n 6 +ADSP066 dio_sparse -w 8192k -s 8192k -n 6 +ADSP067 dio_sparse -w 18192k -s 18192k -n 6 +ADSP068 dio_sparse -w 58192k -s 518192k -n 6 +ADSP069 dio_sparse -w 518192k -s 518192k -n 6 +ADSP070 dio_sparse -w 1024k -s 2048k -n 6 +ADSP071 dio_sparse -w 4096k -s 4096k -n 32 +ADSP072 dio_sparse -w 8192k -s 8192k -n 64 +ADSP073 dio_sparse -w 518192k -s 18192k -n 128 +ADSP074 dio_sparse -w 518192k -s 518192k -n 512 +ADSP075 dio_sparse -w 518192k -s 518192k -n 1000 +ADSP076 dio_sparse -w 4k -s 2k -o 2k -n 2 +ADSP077 dio_sparse -w 2k -s 1k -o 1k -n 2 +ADSP078 dio_sparse -w 1k -s 512 -o 512 -n 2 +ADSP079 dio_sparse -w 4k -s 2k -o 3k -n 2 +ADSP080 dio_sparse -w 4k -s 4k -o 4k -n 2 +ADSP081 dio_sparse -w 4k -s 4k -o 6k -n 2 +ADSP082 dio_sparse -w 4k -s 4k -o 8k -n 2 +ADSP083 dio_sparse -w 16k -s 8k -o 8k -n 2 diff --git a/runtest/ltp-aiodio.part3 b/runtest/ltp-aiodio.part3 old mode 100644 new mode 100755 diff --git a/runtest/ltp-aiodio.part4 b/runtest/ltp-aiodio.part4 old mode 100644 new mode 100755 index bb8abfdf10ec3de4fc5ca49a5c5b0e65a100e343..54019d47beb21c2f482c985e69fc3febf8fca8c4 --- a/runtest/ltp-aiodio.part4 +++ b/runtest/ltp-aiodio.part4 @@ -34,16 +34,16 @@ DIO07 dio_sparse DIO08 dio_sparse DIO09 dio_sparse #Running aiodio_append -AD000 aiodio_append $TMPDIR/aiodio.$$/file2 -AD001 aiodio_append $TMPDIR/aiodio.$$/file2 -AD002 aiodio_append $TMPDIR/aiodio.$$/file2 -AD003 aiodio_append $TMPDIR/aiodio.$$/file2 -AD004 aiodio_append $TMPDIR/aiodio.$$/file2 -AD005 aiodio_append $TMPDIR/aiodio.$$/file2 -AD006 aiodio_append $TMPDIR/aiodio.$$/file2 -AD007 aiodio_append $TMPDIR/aiodio.$$/file2 -AD008 aiodio_append $TMPDIR/aiodio.$$/file2 -AD009 aiodio_append $TMPDIR/aiodio.$$/file2 +AD000 aiodio_append +AD001 aiodio_append +AD002 aiodio_append +AD003 aiodio_append +AD004 aiodio_append +AD005 aiodio_append +AD006 aiodio_append +AD007 aiodio_append +AD008 aiodio_append +AD009 aiodio_append #Running dio_append ADI000 dio_append ADI001 dio_append @@ -61,8 +61,8 @@ DIT001 dio_truncate DIT002 dio_truncate #Running read_checkzero #gread_checkzero -#Running ltp-diorh -DOR000 ltp-diorh $TMPDIR/aiodio.$$/file2 -DOR001 ltp-diorh $TMPDIR/aiodio.$$/file3 -DOR002 ltp-diorh $TMPDIR/aiodio.$$/file4 -DOR003 ltp-diorh $TMPDIR/aiodio.$$/file5 +#Running dio_read +DOR000 dio_read -n 1 -i 100 -r 512k -w 512k -s 32M +DOR001 dio_read -n 10 -i 30 -r 512k -w 512k -s 32M +DOR002 dio_read -n 20 -i 15 -r 512k -w 512k -s 32M +DOR003 dio_read -n 100 -i 4 -r 512k -w 512k -s 32M diff --git a/runtest/lvm.part1 b/runtest/lvm.part1 deleted file mode 100644 index b2e9c0551bca66b47b9cec94dbcba3d363d1c102..0000000000000000000000000000000000000000 --- a/runtest/lvm.part1 +++ /dev/null @@ -1,217 +0,0 @@ -#DESCRIPTION:lvm filesystem tests -# Check the MSDOS filesystem -gf102 growfiles -W gf102 -d /test/growfiles/msdos -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -gf103 growfiles -W gf103 -d /test/growfiles/msdos -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -gf104 growfiles -W gf104 -d /test/growfiles/msdos -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -gf105 growfiles -W gf105 -d /test/growfiles/msdos -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -gf116 growfiles -W gf116 -d /test/growfiles/msdos -b -e 1 -i 0 -L 120 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -gf117 growfiles -W gf117 -d /test/growfiles/msdos -b -e 1 -i 0 -L 120 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -gf118 growfiles -W gf118 -d /test/growfiles/msdos -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -T 10 -l -S 2 -f Lgf04_ -gf119 growfiles -W gf119 -d /test/growfiles/msdos -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -gf112 mkfifo /test/growfiles/msdos/gffifo17; growfiles -W gf112 -b -e 1 -u -i 0 -L 30 /test/growfiles/msdos/gffifo17 -gf113 mkfifo /test/growfiles/msdos/gffifo18; growfiles -W gf113 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 /test/growfiles/msdos/gffifo18 -gf101 growfiles -W gf101 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 /test/growfiles/msdos/glseek20 /test/growfiles/msdos/glseek20.2 -gf106 growfiles -W gf106 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 /test/growfiles/msdos/g_rand10 /test/growfiles/msdos/g_rand10.2 -gf107 growfiles -W gf107 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p /test/growfiles/msdos/g_rand13 /test/growfiles/msdos/g_rand13.2 -gf108 growfiles -W gf108 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 /test/growfiles/msdos/g_rand11 /test/growfiles/msdos/g_rand11.2 -gf109 growfiles -W gf109 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p /test/growfiles/msdos/g_rand12 /test/growfiles/msdos/g_rand12.2 -gf110 growfiles -W gf110 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l /test/growfiles/msdos/g_lio14 /test/growfiles/msdos/g_lio14.2 -gf111 growfiles -W gf111 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L /test/growfiles/msdos/g_lio15 /test/growfiles/msdos/g_lio15.2 -gf114 growfiles -W gf114 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 /test/growfiles/msdos/glseek19 /test/growfiles/msdos/glseek19.2 -gf115 growfiles -W gf115 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 /test/growfiles/msdos/Lgfile1 -gf120 growfiles -W gf120 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 /test/growfiles/msdos/gfbigio-$$ -gf121 growfiles -W gf121 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/msdos/gf-bld-$$ -gf122 growfiles -W gf122 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/msdos/gf-bldf-$$ -gf123 growfiles -W gf123 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 /test/growfiles/msdos/gf-inf-$$ -gf124 growfiles -W gf124 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 /test/growfiles/msdos/gf-jbld-$$ -gf125 growfiles -W gf125 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 /test/growfiles/msdos/gf-large-gs-$$ -gf126 growfiles -W gf126 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 /test/growfiles/msdos/gfsmallio-$$ -gf127 growfiles -W gf127 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u /test/growfiles/msdos/gfsparse-1-$$ -gf128 growfiles -W gf128 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u /test/growfiles/msdos/gfsparse-2-$$ -gf129 growfiles -W gf129 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u /test/growfiles/msdos/gfsparse-3-$$ -gf130 growfiles -W gf130 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -o O_RDWR,O_CREAT,O_SYNC -g 20480 -T 10 -t 20480 /test/growfiles/msdos/gf-sync-$$ -rwtest01 export LTPROOT; rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:rw-sync-$$ 500b:/test/growfiles/msdos/rwtest01%f -rwtest02 export LTPROOT; rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$ 500b:/test/growfiles/msdos/rwtest02%f -rwtest03 export LTPROOT; rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$ 500b:/test/growfiles/msdos/rwtest03%f -rwtest04 export LTPROOT; rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$ 500b:/test/growfiles/msdos/rwtest04%f -rwtest05 export LTPROOT; rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:/test/growfiles/msdos/rwtest05%f -# Check the Reiserfs filesystem -gf202 growfiles -W gf202 -d /test/growfiles/reiser -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -gf203 growfiles -W gf203 -d /test/growfiles/reiser -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -gf204 growfiles -W gf204 -d /test/growfiles/reiser -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -gf205 growfiles -W gf205 -d /test/growfiles/reiser -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -gf216 growfiles -W gf216 -d /test/growfiles/reiser -b -e 1 -i 0 -L 120 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -gf217 growfiles -W gf217 -d /test/growfiles/reiser -b -e 1 -i 0 -L 120 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -gf218 growfiles -W gf218 -d /test/growfiles/reiser -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -T 10 -l -S 2 -f Lgf04_ -gf219 growfiles -W gf219 -d /test/growfiles/reiser -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -gf212 mkfifo /test/growfiles/reiser/gffifo17; growfiles -W gf212 -b -e 1 -u -i 0 -L 30 /test/growfiles/reiser/gffifo17 -gf213 mkfifo /test/growfiles/reiser/gffifo18; growfiles -W gf213 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 /test/growfiles/reiser/gffifo18 -gf201 growfiles -W gf201 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 /test/growfiles/reiser/glseek20 /test/growfiles/reiser/glseek20.2 -gf206 growfiles -W gf206 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 /test/growfiles/reiser/g_rand10 /test/growfiles/reiser/g_rand10.2 -gf207 growfiles -W gf207 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p /test/growfiles/reiser/g_rand13 /test/growfiles/reiser/g_rand13.2 -gf208 growfiles -W gf208 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 /test/growfiles/reiser/g_rand11 /test/growfiles/reiser/g_rand11.2 -gf209 growfiles -W gf209 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p /test/growfiles/reiser/g_rand12 /test/growfiles/reiser/g_rand12.2 -gf210 growfiles -W gf210 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l /test/growfiles/reiser/g_lio14 /test/growfiles/reiser/g_lio14.2 -gf211 growfiles -W gf211 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L /test/growfiles/reiser/g_lio15 /test/growfiles/reiser/g_lio15.2 -gf214 growfiles -W gf214 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 /test/growfiles/reiser/glseek19 /test/growfiles/reiser/glseek19.2 -gf215 growfiles -W gf215 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 /test/growfiles/reiser/Lgfile1 -gf220 growfiles -W gf220 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 /test/growfiles/reiser/gfbigio-$$ -gf221 growfiles -W gf221 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/reiser/gf-bld-$$ -gf222 growfiles -W gf222 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/reiser/gf-bldf-$$ -gf223 growfiles -W gf223 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 /test/growfiles/reiser/gf-inf-$$ -gf224 growfiles -W gf224 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 /test/growfiles/reiser/gf-jbld-$$ -gf225 growfiles -W gf225 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 /test/growfiles/reiser/gf-large-gs-$$ -gf226 growfiles -W gf226 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 /test/growfiles/reiser/gfsmallio-$$ -gf227 growfiles -W gf227 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u /test/growfiles/reiser/gfsparse-1-$$ -gf228 growfiles -W gf228 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u /test/growfiles/reiser/gfsparse-2-$$ -gf229 growfiles -W gf229 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u /test/growfiles/reiser/gfsparse-3-$$ -gf230 growfiles -W gf230 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -o O_RDWR,O_CREAT,O_SYNC -g 20480 -T 10 -t 20480 /test/growfiles/reiser/gf-sync-$$ -rwtest01 export LTPROOT; rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:rw-sync-$$ 500b:/test/growfiles/reiser/rwtest06%f -rwtest02 export LTPROOT; rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$ 500b:/test/growfiles/reiser/rwtest07%f -rwtest03 export LTPROOT; rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$ 500b:/test/growfiles/reiser/rwtest08%f -rwtest04 export LTPROOT; rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$ 500b:/test/growfiles/reiser/rwtest09%f -rwtest05 export LTPROOT; rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:/test/growfiles/reiser/rwtest10%f -# Check the EXT2 filesystem -gf302 growfiles -W gf302 -d /test/growfiles/ext2 -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -gf303 growfiles -W gf303 -d /test/growfiles/ext2 -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -gf304 growfiles -W gf304 -d /test/growfiles/ext2 -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -gf305 growfiles -W gf305 -d /test/growfiles/ext2 -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -gf316 growfiles -W gf316 -d /test/growfiles/ext2 -b -e 1 -i 0 -L 120 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -gf317 growfiles -W gf317 -d /test/growfiles/ext2 -b -e 1 -i 0 -L 120 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -gf318 growfiles -W gf318 -d /test/growfiles/ext2 -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -T 10 -l -S 2 -f Lgf04_ -gf319 growfiles -W gf319 -d /test/growfiles/ext2 -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -gf312 mkfifo /test/growfiles/ext2/gffifo17; growfiles -W gf312 -d /test/growfiles/ext2 -b -e 1 -u -i 0 -L 30 /test/growfiles/ext2/gffifo17 -gf313 mkfifo /test/growfiles/ext2/gffifo18; growfiles -W gf313 -d /test/growfiles/ext2 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 /test/growfiles/ext2/gffifo18 -gf301 growfiles -W gf301 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 /test/growfiles/ext2/glseek20 /test/growfiles/ext2/glseek20.2 -gf306 growfiles -W gf306 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 /test/growfiles/ext2/g_rand10 /test/growfiles/ext2/g_rand10.2 -gf307 growfiles -W gf307 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p /test/growfiles/ext2/g_rand13 /test/growfiles/ext2/g_rand13.2 -gf308 growfiles -W gf308 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 /test/growfiles/ext2/g_rand11 /test/growfiles/ext2/g_rand11.2 -gf309 growfiles -W gf309 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p /test/growfiles/ext2/g_rand12 /test/growfiles/ext2/g_rand12.2 -gf310 growfiles -W gf310 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l /test/growfiles/ext2/g_lio14 /test/growfiles/ext2/g_lio14.2 -gf311 growfiles -W gf311 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L /test/growfiles/ext2/g_lio15 /test/growfiles/ext2/g_lio15.2 -gf314 growfiles -W gf314 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 /test/growfiles/ext2/glseek19 /test/growfiles/ext2/glseek19.2 -gf315 growfiles -W gf315 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 /test/growfiles/ext2/Lgfile1 -gf320 growfiles -W gf320 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 /test/growfiles/ext2/gfbigio-$$ -gf321 growfiles -W gf321 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/ext2/gf-bld-$$ -gf322 growfiles -W gf322 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/ext2/gf-bldf-$$ -gf323 growfiles -W gf323 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 /test/growfiles/ext2/gf-inf-$$ -gf324 growfiles -W gf324 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 /test/growfiles/ext2/gf-jbld-$$ -gf325 growfiles -W gf325 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 /test/growfiles/ext2/gf-large-gs-$$ -gf326 growfiles -W gf326 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 /test/growfiles/ext2/gfsmallio-$$ -gf327 growfiles -W gf327 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u /test/growfiles/ext2/gfsparse-1-$$ -gf328 growfiles -W gf328 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u /test/growfiles/ext2/gfsparse-2-$$ -gf329 growfiles -W gf329 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u /test/growfiles/ext2/gfsparse-3-$$ -gf330 growfiles -W gf330 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -o O_RDWR,O_CREAT,O_SYNC -g 20480 -T 10 -t 20480 /test/growfiles/ext2/gf-sync-$$ -rwtest01 export LTPROOT; rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:rw-sync-$$ 500b:/test/growfiles/ext2/rwtest11%f -rwtest02 export LTPROOT; rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$ 500b:/test/growfiles/ext2/rwtest12%f -rwtest03 export LTPROOT; rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$ 500b:/test/growfiles/ext2/rwtest13%f -rwtest04 export LTPROOT; rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$ 500b:/test/growfiles/ext2/rwtest14%f -rwtest05 export LTPROOT; rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:/test/growfiles/ext2/rwtest15%f -# Check an NFS filesystem -gf402 growfiles -W gf402 -d /test/growfiles/nfs -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -gf403 growfiles -W gf403 -d /test/growfiles/nfs -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -gf404 growfiles -W gf404 -d /test/growfiles/nfs -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -gf405 growfiles -W gf405 -d /test/growfiles/nfs -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -gf416 growfiles -W gf416 -d /test/growfiles/nfs -b -e 1 -i 0 -L 120 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -gf417 growfiles -W gf417 -d /test/growfiles/nfs -b -e 1 -i 0 -L 120 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -gf418 growfiles -W gf418 -d /test/growfiles/nfs -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -T 10 -l -S 2 -f Lgf04_ -gf419 growfiles -W gf419 -d /test/growfiles/nfs -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -gf412 mkfifo /test/growfiles/nfs/gffifo17; growfiles -W gf412 -b -e 1 -u -i 0 -L 30 /test/growfiles/nfs/gffifo17 -gf413 mkfifo /test/growfiles/nfs/gffifo18; growfiles -W gf413 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 /test/growfiles/nfs/gffifo18 -gf401 growfiles -W gf401 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 /test/growfiles/nfs/glseek20 /test/growfiles/nfs/glseek20.2 -gf406 growfiles -W gf406 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 /test/growfiles/nfs/g_rand10 /test/growfiles/nfs/g_rand10.2 -gf407 growfiles -W gf407 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p /test/growfiles/nfs/g_rand13 /test/growfiles/nfs/g_rand13.2 -gf408 growfiles -W gf408 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 /test/growfiles/nfs/g_rand11 /test/growfiles/nfs/g_rand11.2 -gf409 growfiles -W gf409 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p /test/growfiles/nfs/g_rand12 /test/growfiles/nfs/g_rand12.2 -gf410 growfiles -W gf410 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l /test/growfiles/nfs/g_lio14 /test/growfiles/nfs/g_lio14.2 -gf411 growfiles -W gf411 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L /test/growfiles/nfs/g_lio15 /test/growfiles/nfs/g_lio15.2 -gf414 growfiles -W gf414 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 /test/growfiles/nfs/glseek19 /test/growfiles/nfs/glseek19.2 -gf415 growfiles -W gf415 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 /test/growfiles/nfs/Lgfile1 -gf420 growfiles -W gf420 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 /test/growfiles/nfs/gfbigio-$$ -gf421 growfiles -W gf421 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/nfs/gf-bld-$$ -gf422 growfiles -W gf422 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/nfs/gf-bldf-$$ -gf423 growfiles -W gf423 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 /test/growfiles/nfs/gf-inf-$$ -gf424 growfiles -W gf424 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 /test/growfiles/nfs/gf-jbld-$$ -gf425 growfiles -W gf425 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 /test/growfiles/nfs/gf-large-gs-$$ -gf426 growfiles -W gf426 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 /test/growfiles/nfs/gfsmallio-$$ -gf427 growfiles -W gf427 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u /test/growfiles/nfs/gfsparse-1-$$ -gf428 growfiles -W gf428 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u /test/growfiles/nfs/gfsparse-2-$$ -gf429 growfiles -W gf429 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u /test/growfiles/nfs/gfsparse-3-$$ -gf430 growfiles -W gf430 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -o O_RDWR,O_CREAT,O_SYNC -g 20480 -T 10 -t 20480 /test/growfiles/nfs/gf-sync-$$ -rwtest01 export LTPROOT; rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:rw-sync-$$ 500b:/test/growfiles/nfs/rwtest16%f -rwtest02 export LTPROOT; rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$ 500b:/test/growfiles/nfs/rwtest17%f -rwtest03 export LTPROOT; rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$ 500b:/test/growfiles/nfs/rwtest18%f -rwtest04 export LTPROOT; rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$ 500b:/test/growfiles/nfs/rwtest19%f -rwtest05 export LTPROOT; rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:/test/growfiles/nfs/rwtest20%f -# Check a Ram Disk filesystem -gf502 growfiles -W gf502 -d /test/growfiles/ramdisk -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -gf503 growfiles -W gf503 -d /test/growfiles/ramdisk -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -gf504 growfiles -W gf504 -d /test/growfiles/ramdisk -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -gf505 growfiles -W gf505 -d /test/growfiles/ramdisk -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -gf516 growfiles -W gf516 -d /test/growfiles/ramdisk -b -e 1 -i 0 -L 120 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -gf517 growfiles -W gf517 -d /test/growfiles/ramdisk -b -e 1 -i 0 -L 120 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -gf518 growfiles -W gf518 -d /test/growfiles/ramdisk -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -T 10 -l -S 2 -f Lgf04_ -gf519 growfiles -W gf519 -d /test/growfiles/ramdisk -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -gf512 mkfifo /test/growfiles/ramdisk/gffifo17; growfiles -W gf512 -b -e 1 -u -i 0 -L 30 /test/growfiles/ramdisk/gffifo17 -gf513 mkfifo /test/growfiles/ramdisk/gffifo18; growfiles -W gf513 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 /test/growfiles/ramdisk/gffifo18 -gf501 growfiles -W gf501 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 /test/growfiles/ramdisk/glseek20 /test/growfiles/ramdisk/glseek20.2 -gf506 growfiles -W gf506 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 /test/growfiles/ramdisk/g_rand10 /test/growfiles/ramdisk/g_rand10.2 -gf507 growfiles -W gf507 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p /test/growfiles/ramdisk/g_rand13 /test/growfiles/ramdisk/g_rand13.2 -gf508 growfiles -W gf508 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 /test/growfiles/ramdisk/g_rand11 /test/growfiles/ramdisk/g_rand11.2 -gf509 growfiles -W gf509 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p /test/growfiles/ramdisk/g_rand12 /test/growfiles/ramdisk/g_rand12.2 -gf510 growfiles -W gf510 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l /test/growfiles/ramdisk/g_lio14 /test/growfiles/ramdisk/g_lio14.2 -gf511 growfiles -W gf511 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L /test/growfiles/ramdisk/g_lio15 /test/growfiles/ramdisk/g_lio15.2 -gf514 growfiles -W gf514 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 /test/growfiles/ramdisk/glseek19 /test/growfiles/ramdisk/glseek19.2 -gf515 growfiles -W gf515 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 /test/growfiles/ramdisk/Lgfile1 -gf520 growfiles -W gf520 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 /test/growfiles/ramdisk/gfbigio-$$ -gf521 growfiles -W gf521 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/ramdisk/gf-bld-$$ -gf522 growfiles -W gf522 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/ramdisk/gf-bldf-$$ -gf523 growfiles -W gf523 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 /test/growfiles/ramdisk/gf-inf-$$ -gf524 growfiles -W gf524 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 /test/growfiles/ramdisk/gf-jbld-$$ -gf525 growfiles -W gf525 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 /test/growfiles/ramdisk/gf-large-gs-$$ -gf526 growfiles -W gf526 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 /test/growfiles/ramdisk/gfsmallio-$$ -gf527 growfiles -W gf527 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u /test/growfiles/ramdisk/gfsparse-1-$$ -gf528 growfiles -W gf528 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u /test/growfiles/ramdisk/gfsparse-2-$$ -gf529 growfiles -W gf529 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u /test/growfiles/ramdisk/gfsparse-3-$$ -gf530 growfiles -W gf530 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -o O_RDWR,O_CREAT,O_SYNC -g 20480 -T 10 -t 20480 /test/growfiles/ramdisk/gf-sync-$$ -rwtest01 export LTPROOT; rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:rw-sync-$$ 500b:/test/growfiles/ramdisk/rwtest21%f -rwtest02 export LTPROOT; rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$ 500b:/test/growfiles/ramdisk/rwtest22%f -rwtest03 export LTPROOT; rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$ 500b:/test/growfiles/ramdisk/rwtest23%f -rwtest04 export LTPROOT; rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$ 500b:/test/growfiles/ramdisk/rwtest24%f -rwtest05 export LTPROOT; rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:/test/growfiles/ramdisk/rwtest25%f -# Check the MINIX filesystem -gf602 growfiles -W gf602 -d /test/growfiles/minix -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -gf603 growfiles -W gf603 -d /test/growfiles/minix -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -gf604 growfiles -W gf604 -d /test/growfiles/minix -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -gf605 growfiles -W gf605 -d /test/growfiles/minix -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -gf616 growfiles -W gf616 -d /test/growfiles/minix -b -e 1 -i 0 -L 120 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -gf617 growfiles -W gf617 -d /test/growfiles/minix -b -e 1 -i 0 -L 120 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -gf618 growfiles -W gf618 -d /test/growfiles/minix -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -T 10 -l -S 2 -f Lgf04_ -gf619 growfiles -W gf619 -d /test/growfiles/minix -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -gf612 mkfifo /test/growfiles/minix/gffifo17; growfiles -W gf612 -b -e 1 -u -i 0 -L 30 /test/growfiles/minix/gffifo17 -gf613 mkfifo /test/growfiles/minix/gffifo18; growfiles -W gf613 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 /test/growfiles/minix/gffifo18 -gf601 growfiles -W gf601 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 /test/growfiles/minix/glseek20 /test/growfiles/minix/glseek20.2 -gf606 growfiles -W gf606 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 /test/growfiles/minix/g_rand10 /test/growfiles/minix/g_rand10.2 -gf607 growfiles -W gf607 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p /test/growfiles/minix/g_rand13 /test/growfiles/minix/g_rand13.2 -gf608 growfiles -W gf608 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 /test/growfiles/minix/g_rand11 /test/growfiles/minix/g_rand11.2 -gf609 growfiles -W gf609 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p /test/growfiles/minix/g_rand12 /test/growfiles/minix/g_rand12.2 -gf610 growfiles -W gf610 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l /test/growfiles/minix/g_lio14 /test/growfiles/minix/g_lio14.2 -gf611 growfiles -W gf611 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L /test/growfiles/minix/g_lio15 /test/growfiles/minix/g_lio15.2 -gf614 growfiles -W gf614 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 /test/growfiles/minix/glseek19 /test/growfiles/minix/glseek19.2 -gf615 growfiles -W gf615 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 /test/growfiles/minix/Lgfile1 -gf620 growfiles -W gf620 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 /test/growfiles/minix/gfbigio-$$ -gf621 growfiles -W gf621 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/minix/gf-bld-$$ -gf622 growfiles -W gf622 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/minix/gf-bldf-$$ -gf623 growfiles -W gf623 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 /test/growfiles/minix/gf-inf-$$ -gf624 growfiles -W gf624 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 /test/growfiles/minix/gf-jbld-$$ -gf625 growfiles -W gf625 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 /test/growfiles/minix/gf-large-gs-$$ -gf626 growfiles -W gf626 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 /test/growfiles/minix/gfsmallio-$$ -gf627 growfiles -W gf627 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u /test/growfiles/minix/gfsparse-1-$$ -gf628 growfiles -W gf628 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u /test/growfiles/minix/gfsparse-2-$$ -gf629 growfiles -W gf629 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u /test/growfiles/minix/gfsparse-3-$$ -gf630 growfiles -W gf630 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -o O_RDWR,O_CREAT,O_SYNC -g 20480 -T 10 -t 20480 /test/growfiles/minix/gf-sync-$$ -rwtest01 export LTPROOT; rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:rw-sync-$$ 500b:/test/growfiles/minix/rwtest26%f -rwtest02 export LTPROOT; rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$ 500b:/test/growfiles/minix/rwtest27%f -rwtest03 export LTPROOT; rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$ 500b:/test/growfiles/minix/rwtest28%f -rwtest04 export LTPROOT; rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$ 500b:/test/growfiles/minix/rwtest29%f -rwtest05 export LTPROOT; rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:/test/growfiles/minix/rwtest30%f diff --git a/runtest/lvm.part2 b/runtest/lvm.part2 deleted file mode 100644 index f0dbf32770dc6a61a19b9670dcc26a090ea16229..0000000000000000000000000000000000000000 --- a/runtest/lvm.part2 +++ /dev/null @@ -1,72 +0,0 @@ -# Check the EXT3 filesystem -gf702 growfiles -W gf702 -d /test/growfiles/ext3 -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -gf703 growfiles -W gf703 -d /test/growfiles/ext3 -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -gf704 growfiles -W gf704 -d /test/growfiles/ext3 -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -gf705 growfiles -W gf705 -d /test/growfiles/ext3 -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -gf716 growfiles -W gf716 -d /test/growfiles/ext3 -b -e 1 -i 0 -L 120 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -gf717 growfiles -W gf717 -d /test/growfiles/ext3 -b -e 1 -i 0 -L 120 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -gf718 growfiles -W gf718 -d /test/growfiles/ext3 -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -T 10 -l -S 2 -f Lgf04_ -gf719 growfiles -W gf719 -d /test/growfiles/ext3 -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -gf712 mkfifo gffifo17; growfiles -W gf712 -d /test/growfiles/ext3 -b -e 1 -u -i 0 -L 30 gffifo17 -gf713 mkfifo gffifo18; growfiles -W gf713 -d /test/growfiles/ext3 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 gffifo18 -gf701 growfiles -W gf701 -d /test/growfiles/ext3 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 glseek20 glseek20.2 -gf706 growfiles -W gf706 -d /test/growfiles/ext3 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand10 g_rand10.2 -gf707 growfiles -W gf707 -d /test/growfiles/ext3 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p g_rand13 g_rand13.2 -gf708 growfiles -W gf708 -d /test/growfiles/ext3 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 g_rand11 g_rand11.2 -gf709 growfiles -W gf709 -d /test/growfiles/ext3 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p g_rand12 g_rand12.2 -gf710 growfiles -W gf710 -d /test/growfiles/ext3 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l g_lio14 g_lio14.2 -gf711 growfiles -W gf711 -d /test/growfiles/ext3 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L g_lio15 g_lio15.2 -gf714 growfiles -W gf714 -d /test/growfiles/ext3 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 glseek19 glseek19.2 -gf715 growfiles -W gf715 -d /test/growfiles/ext3 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 Lgfile1 -gf720 growfiles -W gf720 -d /test/growfiles/ext3 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 gfbigio-$$ -gf721 growfiles -W gf721 -d /test/growfiles/ext3 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bld-$$ -gf722 growfiles -W gf722 -d /test/growfiles/ext3 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bldf-$$ -gf723 growfiles -W gf723 -d /test/growfiles/ext3 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 gf-inf-$$ -gf724 growfiles -W gf724 -d /test/growfiles/ext3 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 gf-jbld-$$ -gf725 growfiles -W gf725 -d /test/growfiles/ext3 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 gf-large-gs-$$ -gf726 growfiles -W gf726 -d /test/growfiles/ext3 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 gfsmallio-$$ -gf727 growfiles -W gf727 -d /test/growfiles/ext3 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u gfsparse-1-$$ -gf728 growfiles -W gf728 -d /test/growfiles/ext3 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u gfsparse-2-$$ -gf729 growfiles -W gf729 -d /test/growfiles/ext3 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u gfsparse-3-$$ -gf730 growfiles -W gf730 -d /test/growfiles/ext3 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -o O_RDWR,O_CREAT,O_SYNC -g 20480 -T 10 -t 20480 gf-sync-$$ -rwtest01 export LTPROOT; rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:rw-sync-$$ 500b:/test/growfiles/ext3/rwtest11%f -rwtest02 export LTPROOT; rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$ 500b:/test/growfiles/ext3/rwtest12%f -rwtest03 export LTPROOT; rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$ 500b:/test/growfiles/ext3/rwtest13%f -rwtest04 export LTPROOT; rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$ 500b:/test/growfiles/ext3/rwtest14%f -rwtest05 export LTPROOT; rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:/test/growfiles/ext3/rwtest15%f -# Check the JFS filesystem -gf802 growfiles -W gf802 -d /test/growfiles/jfs -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -gf803 growfiles -W gf803 -d /test/growfiles/jfs -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -gf804 growfiles -W gf804 -d /test/growfiles/jfs -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -gf805 growfiles -W gf805 -d /test/growfiles/jfs -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -gf816 growfiles -W gf816 -d /test/growfiles/jfs -b -e 1 -i 0 -L 120 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -gf817 growfiles -W gf817 -d /test/growfiles/jfs -b -e 1 -i 0 -L 120 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -gf818 growfiles -W gf818 -d /test/growfiles/jfs -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -T 10 -l -S 2 -f Lgf04_ -gf819 growfiles -W gf819 -d /test/growfiles/jfs -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -gf812 mkfifo /test/growfiles/jfs/gffifo17; growfiles -W gf812 -b -e 1 -u -i 0 -L 30 /test/growfiles/jfs/gffifo17 -gf813 mkfifo /test/growfiles/jfs/gffifo18; growfiles -W gf813 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 /test/growfiles/jfs/gffifo18 -gf801 growfiles -W gf801 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 /test/growfiles/jfs/glseek20 /test/growfiles/jfs/glseek20.2 -gf806 growfiles -W gf806 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 /test/growfiles/jfs/g_rand10 /test/growfiles/jfs/g_rand10.2 -gf807 growfiles -W gf807 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p /test/growfiles/jfs/g_rand13 /test/growfiles/jfs/g_rand13.2 -gf808 growfiles -W gf808 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 /test/growfiles/jfs/g_rand11 /test/growfiles/jfs/g_rand11.2 -gf809 growfiles -W gf809 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p /test/growfiles/jfs/g_rand12 /test/growfiles/jfs/g_rand12.2 -gf810 growfiles -W gf810 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l /test/growfiles/jfs/g_lio14 /test/growfiles/jfs/g_lio14.2 -gf811 growfiles -W gf811 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L /test/growfiles/jfs/g_lio15 /test/growfiles/jfs/g_lio15.2 -gf814 growfiles -W gf814 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 /test/growfiles/jfs/glseek19 /test/growfiles/jfs/glseek19.2 -gf815 growfiles -W gf815 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 /test/growfiles/jfs/Lgfile1 -gf820 growfiles -W gf820 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 /test/growfiles/jfs/gfbigio-$$ -gf821 growfiles -W gf821 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/jfs/gf-bld-$$ -gf822 growfiles -W gf822 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 /test/growfiles/jfs/gf-bldf-$$ -gf823 growfiles -W gf823 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 /test/growfiles/jfs/gf-inf-$$ -gf824 growfiles -W gf824 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 /test/growfiles/jfs/gf-jbld-$$ -gf825 growfiles -W gf825 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 /test/growfiles/jfs/gf-large-gs-$$ -gf826 growfiles -W gf826 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 /test/growfiles/jfs/gfsmallio-$$ -gf827 growfiles -W gf827 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u /test/growfiles/jfs/gfsparse-1-$$ -gf828 growfiles -W gf828 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u /test/growfiles/jfs/gfsparse-2-$$ -gf829 growfiles -W gf829 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u /test/growfiles/jfs/gfsparse-3-$$ -gf830 growfiles -W gf830 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -o O_RDWR,O_CREAT,O_SYNC -g 20480 -T 10 -t 20480 /test/growfiles/jfs/gf-sync-$$ -rwtest11 export LTPROOT; rwtest -N rwtest11 -c -q -i 60s -f sync 10%25000:rw-sync-$$ 500b:/test/growfiles/jfs/rwtest11%f -rwtest12 export LTPROOT; rwtest -N rwtest12 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$ 500b:/test/growfiles/jfs/rwtest12%f -rwtest13 export LTPROOT; rwtest -N rwtest13 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$ 500b:/test/growfiles/jfs/rwtest13%f -rwtest14 export LTPROOT; rwtest -N rwtest14 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$ 500b:/test/growfiles/jfs/rwtest14%f -rwtest15 export LTPROOT; rwtest -N rwtest15 -c -q -i 50 -T 64b 500b:/test/growfiles/jfs/rwtest15%f diff --git a/runtest/math b/runtest/math old mode 100644 new mode 100755 diff --git a/runtest/mm b/runtest/mm old mode 100644 new mode 100755 index a09f39c1e02ce6b553a19df1028889fca08c32c9..6537666a99484d385054a041858e799ee8b98bbb --- a/runtest/mm +++ b/runtest/mm @@ -20,9 +20,7 @@ mtest06_3 mmap3 -x 0.002 -p # Remains diabled till the infinite loop problem is solved #mtest-6_4 shmat1 -x 0.00005 -mem01 mem01 mem02 mem02 -mem03 mem03 page01 page01 page02 page02 @@ -71,7 +69,9 @@ ksm04_1 ksm04 -u 128 ksm05 ksm05 -I 10 ksm06 ksm06 ksm06_1 ksm06 -n 10 -ksm06_2 ksm06 -n 10000 +ksm06_2 ksm06 -n 8000 + +cpuset01 cpuset01 oom01 oom01 oom02 oom02 @@ -84,6 +84,7 @@ swapping01 swapping01 -i 5 thp01 thp01 -I 120 thp02 thp02 thp03 thp03 +thp04 thp04 vma01 vma01 vma02 vma02 diff --git a/runtest/net.features b/runtest/net.features old mode 100644 new mode 100755 index 44a9745638ccfca054a9e9517f69a71cecd3f36d..37c380aaa26fb95b0fead2b9b78f62aff0f82cf0 --- a/runtest/net.features +++ b/runtest/net.features @@ -60,6 +60,12 @@ gre_ipv6_01 gre01.sh -6 gre_ipv4_02 gre02.sh gre_ipv6_02 gre02.sh -6 +gue01 fou01.sh -t gue +gue01_ipv6 fou01.sh -t gue -6 + +fou01 fou01.sh +fou01_ipv6 fou01.sh -6 + dctcp_ipv4_01 dctcp01.sh dctcp_ipv6_01 dctcp01.sh -6 @@ -78,3 +84,8 @@ mpls03_ipv6 mpls03.sh -6 mpls04 mpls04.sh fanout01 fanout01 + +wireguard01 wireguard01.sh +wireguard01_ipv6 wireguard01.sh -6 +wireguard02 wireguard02.sh +wireguard02_ipv6 wireguard02.sh -6 diff --git a/runtest/net.ipv6 b/runtest/net.ipv6 old mode 100644 new mode 100755 diff --git a/runtest/net.ipv6_lib b/runtest/net.ipv6_lib old mode 100644 new mode 100755 diff --git a/runtest/net.multicast b/runtest/net.multicast old mode 100644 new mode 100755 diff --git a/runtest/net.nfs b/runtest/net.nfs old mode 100644 new mode 100755 index 3df35809a52657974363687b8a4869612a25806d..7ec20ff24980aa682255770c76a61f9093143cc3 --- a/runtest/net.nfs +++ b/runtest/net.nfs @@ -2,64 +2,75 @@ # # PLEASE READ THE README FILE network/README.md BEFORE RUNNING THESE. # -nfs3_01 nfs01 -v 3 -t udp -nfs3t_01 nfs01 -v 3 -t tcp -nfs4_01 nfs01 -v 4 -t tcp -nfs41_01 nfs01 -v 4.1 -t tcp -nfs42_01 nfs01 -v 4.2 -t tcp -nfs3_ipv6_01 nfs01 -6 -v 3 -t udp -nfs3t_ipv6_01 nfs01 -6 -v 3 -t tcp -nfs4_ipv6_01 nfs01 -6 -v 4 -t tcp -nfs41_ipv6_01 nfs01 -6 -v 4.1 -t tcp -nfs42_ipv6_01 nfs01 -6 -v 4.2 -t tcp +nfs3_01 nfs01.sh -v 3 -t udp +nfs3t_01 nfs01.sh -v 3 -t tcp +nfs4_01 nfs01.sh -v 4 -t tcp +nfs41_01 nfs01.sh -v 4.1 -t tcp +nfs42_01 nfs01.sh -v 4.2 -t tcp +nfs3_ipv6_01 nfs01.sh -6 -v 3 -t udp +nfs3t_ipv6_01 nfs01.sh -6 -v 3 -t tcp +nfs4_ipv6_01 nfs01.sh -6 -v 4 -t tcp +nfs41_ipv6_01 nfs01.sh -6 -v 4.1 -t tcp +nfs42_ipv6_01 nfs01.sh -6 -v 4.2 -t tcp -nfs3_02 nfs02 -v 3 -t udp -nfs3t_02 nfs02 -v 3 -t tcp -nfs4_02 nfs02 -v 4 -t tcp -nfs41_02 nfs02 -v 4.1 -t tcp -nfs42_02 nfs02 -v 4.2 -t tcp -nfs3_ipv6_02 nfs02 -6 -v 3 -t udp -nfs3t_ipv6_02 nfs02 -6 -v 3 -t tcp -nfs4_ipv6_02 nfs02 -6 -v 4 -t tcp -nfs41_ipv6_02 nfs02 -6 -v 4.1 -t tcp -nfs42_ipv6_02 nfs02 -6 -v 4.2 -t tcp +nfs3_02 nfs02.sh -v 3 -t udp +nfs3t_02 nfs02.sh -v 3 -t tcp +nfs4_02 nfs02.sh -v 4 -t tcp +nfs41_02 nfs02.sh -v 4.1 -t tcp +nfs42_02 nfs02.sh -v 4.2 -t tcp +nfs3_ipv6_02 nfs02.sh -6 -v 3 -t udp +nfs3t_ipv6_02 nfs02.sh -6 -v 3 -t tcp +nfs4_ipv6_02 nfs02.sh -6 -v 4 -t tcp +nfs41_ipv6_02 nfs02.sh -6 -v 4.1 -t tcp +nfs42_ipv6_02 nfs02.sh -6 -v 4.2 -t tcp -nfs3_03 nfs03 -v 3 -t udp -nfs3t_03 nfs03 -v 3 -t tcp -nfs4_03 nfs03 -v 4 -t tcp -nfs41_03 nfs03 -v 4.1 -t tcp -nfs42_03 nfs03 -v 4.2 -t tcp -nfs3_ipv6_03 nfs03 -6 -v 3 -t udp -nfs3t_ipv6_03 nfs03 -6 -v 3 -t tcp -nfs4_ipv6_03 nfs03 -6 -v 4 -t tcp -nfs41_ipv6_03 nfs03 -6 -v 4.1 -t tcp -nfs42_ipv6_03 nfs03 -6 -v 4.2 -t tcp +nfs3_03 nfs03.sh -v 3 -t udp +nfs3t_03 nfs03.sh -v 3 -t tcp +nfs4_03 nfs03.sh -v 4 -t tcp +nfs41_03 nfs03.sh -v 4.1 -t tcp +nfs42_03 nfs03.sh -v 4.2 -t tcp +nfs3_ipv6_03 nfs03.sh -6 -v 3 -t udp +nfs3t_ipv6_03 nfs03.sh -6 -v 3 -t tcp +nfs4_ipv6_03 nfs03.sh -6 -v 4 -t tcp +nfs41_ipv6_03 nfs03.sh -6 -v 4.1 -t tcp +nfs42_ipv6_03 nfs03.sh -6 -v 4.2 -t tcp -nfs3_04 nfs04 -v 3 -t udp -nfs3t_04 nfs04 -v 3 -t tcp -nfs4_04 nfs04 -v 4 -t tcp -nfs41_04 nfs04 -v 4.1 -t tcp -nfs42_04 nfs04 -v 4.2 -t tcp -nfs3_ipv6_04 nfs04 -6 -v 3 -t udp -nfs3t_ipv6_04 nfs04 -6 -v 3 -t tcp -nfs4_ipv6_04 nfs04 -6 -v 4 -t tcp -nfs41_ipv6_04 nfs04 -6 -v 4.1 -t tcp -nfs42_ipv6_04 nfs04 -6 -v 4.2 -t tcp +nfs3_04 nfs04.sh -v 3 -t udp +nfs3t_04 nfs04.sh -v 3 -t tcp +nfs4_04 nfs04.sh -v 4 -t tcp +nfs41_04 nfs04.sh -v 4.1 -t tcp +nfs42_04 nfs04.sh -v 4.2 -t tcp +nfs3_ipv6_04 nfs04.sh -6 -v 3 -t udp +nfs3t_ipv6_04 nfs04.sh -6 -v 3 -t tcp +nfs4_ipv6_04 nfs04.sh -6 -v 4 -t tcp +nfs41_ipv6_04 nfs04.sh -6 -v 4.1 -t tcp +nfs42_ipv6_04 nfs04.sh -6 -v 4.2 -t tcp -nfs3_05 nfs05 -v 3 -t udp -nfs3t_05 nfs05 -v 3 -t tcp -nfs4_05 nfs05 -v 4 -t tcp -nfs41_05 nfs05 -v 4.1 -t tcp -nfs42_05 nfs05 -v 4.2 -t tcp -nfs3_ipv6_05 nfs05 -6 -v 3 -t udp -nfs3t_ipv6_05 nfs05 -6 -v 3 -t tcp -nfs4_ipv6_05 nfs05 -6 -v 4 -t tcp -nfs41_ipv6_05 nfs05 -6 -v 4.1 -t tcp -nfs42_ipv6_05 nfs05 -6 -v 4.2 -t tcp +nfs3_05 nfs05.sh -v 3 -t udp +nfs3t_05 nfs05.sh -v 3 -t tcp +nfs4_05 nfs05.sh -v 4 -t tcp +nfs41_05 nfs05.sh -v 4.1 -t tcp +nfs42_05 nfs05.sh -v 4.2 -t tcp +nfs3_ipv6_05 nfs05.sh -6 -v 3 -t udp +nfs3t_ipv6_05 nfs05.sh -6 -v 3 -t tcp +nfs4_ipv6_05 nfs05.sh -6 -v 4 -t tcp +nfs41_ipv6_05 nfs05.sh -6 -v 4.1 -t tcp +nfs42_ipv6_05 nfs05.sh -6 -v 4.2 -t tcp -nfs01_06 nfs06 -v "3,3,3,4,4,4" -t "udp,udp,tcp,tcp,tcp,tcp" -nfs02_06 nfs06 -v "3,4,4.1,4.2,4.2,4.2" -t "udp,tcp,tcp,tcp,tcp,tcp" -nfs03_ipv6_06 nfs06 -6 -v "4,4.1,4.1,4.2,4.2,4.2" -t "tcp,tcp,tcp,tcp,tcp,tcp" +nfs01_06 nfs06.sh -v "3,3,3,4,4,4" -t "udp,udp,tcp,tcp,tcp,tcp" +nfs02_06 nfs06.sh -v "3,4,4.1,4.2,4.2,4.2" -t "udp,tcp,tcp,tcp,tcp,tcp" +nfs03_ipv6_06 nfs06.sh -6 -v "4,4.1,4.1,4.2,4.2,4.2" -t "tcp,tcp,tcp,tcp,tcp,tcp" + +nfs3_07 nfs07.sh -v 3 -t udp +nfs3t_07 nfs07.sh -v 3 -t tcp +nfs4_07 nfs07.sh -v 4 -t tcp +nfs41_07 nfs07.sh -v 4.1 -t tcp +nfs42_07 nfs07.sh -v 4.2 -t tcp +nfs3_ipv6_07 nfs07.sh -6 -v 3 -t udp +nfs3t_ipv6_07 nfs07.sh -6 -v 3 -t tcp +nfs4_ipv6_07 nfs07.sh -6 -v 4 -t tcp +nfs41_ipv6_07 nfs07.sh -6 -v 4.1 -t tcp +nfs42_ipv6_07 nfs07.sh -6 -v 4.2 -t tcp nfslock3_01 nfslock01 -v 3 -t udp nfslock3t_01 nfslock01 -v 3 -t tcp diff --git a/runtest/net.rpc b/runtest/net.rpc old mode 100644 new mode 100755 diff --git a/runtest/net.rpc_tests b/runtest/net.rpc_tests old mode 100644 new mode 100755 diff --git a/runtest/net.sctp b/runtest/net.sctp old mode 100644 new mode 100755 diff --git a/runtest/net.tcp_cmds b/runtest/net.tcp_cmds old mode 100644 new mode 100755 index afe6d7c71a69ffa8647266a70e1c098d1baadf46..7e142de11dd81025bfadfe183bd99d1b6defc7a4 --- a/runtest/net.tcp_cmds +++ b/runtest/net.tcp_cmds @@ -11,10 +11,8 @@ host host01.sh netstat netstat01.sh ping01 ping01.sh ping02 ping02.sh -rcp rcp01.sh -rlogin rlogin01.sh -rsh rsh01.sh sendfile sendfile01.sh +tc01 tc01.sh tcpdump tcpdump01.sh telnet telnet01.sh iptables iptables01.sh diff --git a/runtest/net.tirpc_tests b/runtest/net.tirpc_tests old mode 100644 new mode 100755 index 48e9ba3f5fd46c4e586c6df9c6c89d9a3bcbd9c4..8aa69ef4d8ac9200af54063c86b52494c7dc1481 --- a/runtest/net.tirpc_tests +++ b/runtest/net.tirpc_tests @@ -38,7 +38,7 @@ tirpc_clnt_control rpc_test.sh -s tirpc_svc_3 -c tirpc_clnt_control tirpc_rpc_reg rpc_test.sh -c tirpc_rpc_reg tirpc_rpc_call rpc_test.sh -s tirpc_svc_1 -c tirpc_rpc_call tirpc_rpc_broadcast rpc_test.sh -s tirpc_svc_1 -c tirpc_rpc_broadcast -tirpc_rpc_broadcast_exp rpc_test.sh -s tirpc_svc_1 -c tirpc_rpc_broadcast_exp -e "1 2" +tirpc_rpc_broadcast_exp rpc_test.sh -s tirpc_svc_1 -c tirpc_rpc_broadcast_exp -e "1,2" tirpc_clnt_create rpc_test.sh -s tirpc_svc_2 -c tirpc_clnt_create tirpc_clnt_create_timed rpc_test.sh -s tirpc_svc_2 -c tirpc_clnt_create_timed diff --git a/runtest/net_stress.appl b/runtest/net_stress.appl old mode 100644 new mode 100755 diff --git a/runtest/net_stress.broken_ip b/runtest/net_stress.broken_ip old mode 100644 new mode 100755 index ca71c3e7b69ffd8a9a20119107d4fcb4651c8e18..a5536c0c28f773734a01a7a6eedc9109e0cbb5c0 --- a/runtest/net_stress.broken_ip +++ b/runtest/net_stress.broken_ip @@ -3,15 +3,15 @@ # # Broken IP packet -broken_ip4-version broken_ip-version -broken_ip4-ihl broken_ip-ihl -broken_ip4-totlen broken_ip-totlen -broken_ip4-fragment broken_ip-fragment -broken_ip4-protcol broken_ip-protcol -broken_ip4-checksum broken_ip-checksum -broken_ip4-dstaddr broken_ip-dstaddr +broken_ip4-version broken_ip-version.sh +broken_ip4-ihl broken_ip-ihl.sh +broken_ip4-fragment broken_ip-fragment.sh +broken_ip4-plen broken_ip-plen.sh +broken_ip4-protcol broken_ip-protcol.sh +broken_ip4-checksum broken_ip-checksum.sh +broken_ip4-dstaddr broken_ip-dstaddr.sh -broken_ip6-dstaddr broken_ip-dstaddr -6 -broken_ip6-nexthdr broken_ip-nexthdr -6 -broken_ip6-plen broken_ip-plen -6 -broken_ip6-version broken_ip-version -6 +broken_ip6-dstaddr broken_ip-dstaddr.sh -6 +broken_ip6-nexthdr broken_ip-nexthdr.sh -6 +broken_ip6-plen broken_ip-plen.sh -6 +broken_ip6-version broken_ip-version.sh -6 diff --git a/runtest/net_stress.interface b/runtest/net_stress.interface old mode 100644 new mode 100755 diff --git a/runtest/net_stress.ipsec_dccp b/runtest/net_stress.ipsec_dccp old mode 100644 new mode 100755 diff --git a/runtest/net_stress.ipsec_icmp b/runtest/net_stress.ipsec_icmp old mode 100644 new mode 100755 diff --git a/runtest/net_stress.ipsec_sctp b/runtest/net_stress.ipsec_sctp old mode 100644 new mode 100755 diff --git a/runtest/net_stress.ipsec_tcp b/runtest/net_stress.ipsec_tcp old mode 100644 new mode 100755 diff --git a/runtest/net_stress.ipsec_udp b/runtest/net_stress.ipsec_udp old mode 100644 new mode 100755 diff --git a/runtest/net_stress.multicast b/runtest/net_stress.multicast old mode 100644 new mode 100755 index d2288df62f32e82e5505a9e2975beed07606739e..08b1770fb174d3db006464251426e58751b088cb --- a/runtest/net_stress.multicast +++ b/runtest/net_stress.multicast @@ -2,28 +2,28 @@ # Stress test for TCP/IP protocol stack (Multicast) # -mcast4-group-single-socket mcast-group-single-socket -mcast4-group-multiple-socket mcast-group-multiple-socket -mcast4-group-same-group mcast-group-same-group -mcast4-group-source-filter mcast-group-source-filter -mcast4-pktfld01 mcast4-pktfld01 -mcast4-pktfld02 mcast4-pktfld02 -mcast4-queryfld01 mcast4-queryfld01 -mcast4-queryfld02 mcast4-queryfld02 -mcast4-queryfld03 mcast4-queryfld03 -mcast4-queryfld04 mcast4-queryfld04 -mcast4-queryfld05 mcast4-queryfld05 -mcast4-queryfld06 mcast4-queryfld06 +mcast4-group-single-socket mcast-group-single-socket.sh +mcast4-group-multiple-socket mcast-group-multiple-socket.sh +mcast4-group-same-group mcast-group-same-group.sh +mcast4-group-source-filter mcast-group-source-filter.sh +mcast4-pktfld01 mcast-pktfld01.sh +mcast4-pktfld02 mcast-pktfld02.sh +mcast4-queryfld01 mcast-queryfld01.sh +mcast4-queryfld02 mcast-queryfld02.sh +mcast4-queryfld03 mcast-queryfld03.sh +mcast4-queryfld04 mcast-queryfld04.sh +mcast4-queryfld05 mcast-queryfld05.sh +mcast4-queryfld06 mcast-queryfld06.sh -mcast6-group-single-socket mcast-group-single-socket -6 -mcast6-group-multiple-socket mcast-group-multiple-socket -6 -mcast6-group-same-group mcast-group-same-group -6 -mcast6-group-source-filter mcast-group-source-filter -6 -mcast6-pktfld01 mcast6-pktfld01 -mcast6-pktfld02 mcast6-pktfld02 -mcast6-queryfld01 mcast6-queryfld01 -mcast6-queryfld02 mcast6-queryfld02 -mcast6-queryfld03 mcast6-queryfld03 -mcast6-queryfld04 mcast6-queryfld04 -mcast6-queryfld05 mcast6-queryfld05 -mcast6-queryfld06 mcast6-queryfld06 +mcast6-group-single-socket mcast-group-single-socket.sh -6 +mcast6-group-multiple-socket mcast-group-multiple-socket.sh -6 +mcast6-group-same-group mcast-group-same-group.sh -6 +mcast6-group-source-filter mcast-group-source-filter.sh -6 +mcast6-pktfld01 mcast-pktfld01.sh -6 +mcast6-pktfld02 mcast-pktfld02.sh -6 +mcast6-queryfld01 mcast-queryfld01.sh -6 +mcast6-queryfld02 mcast-queryfld02.sh -6 +mcast6-queryfld03 mcast-queryfld03.sh -6 +mcast6-queryfld04 mcast-queryfld04.sh -6 +mcast6-queryfld05 mcast-queryfld05.sh -6 +mcast6-queryfld06 mcast-queryfld06.sh -6 diff --git a/runtest/net_stress.route b/runtest/net_stress.route old mode 100644 new mode 100755 index 8755ef0beace36f163fe4b4048b4ffb3231cb6b2..5590ef0231d6f24fd324012e821d78bde2583901 --- a/runtest/net_stress.route +++ b/runtest/net_stress.route @@ -5,8 +5,7 @@ route4-change-if route-change-if.sh route4-change-netlink-dst route-change-netlink-dst.sh route4-change-netlink-gw route-change-netlink-gw.sh route4-change-netlink-if route-change-netlink-if.sh -route4-redirect route4-redirect -route4-rmmod route4-rmmod +route4-redirect route-redirect.sh route6-change-dst route-change-dst.sh -6 route6-change-gw route-change-gw.sh -6 @@ -14,5 +13,4 @@ route6-change-if route-change-if.sh -6 route6-change-netlink-dst route-change-netlink-dst.sh -6 route6-change-netlink-gw route-change-netlink-gw.sh -6 route6-change-netlink-if route-change-netlink-if.sh -6 -route6-redirect route6-redirect -route6-rmmod route6-rmmod +route6-redirect route-redirect.sh -6 diff --git a/runtest/nptl b/runtest/nptl old mode 100644 new mode 100755 diff --git a/runtest/numa b/runtest/numa old mode 100644 new mode 100755 index 7b9c2ae9da597e6006dc6288c3a5d55c8e828e19..3b9a9a7c5bb6c38962dbfd3b4ff70c6f0fc03307 --- a/runtest/numa +++ b/runtest/numa @@ -20,3 +20,4 @@ set_mempolicy01 set_mempolicy01 set_mempolicy02 set_mempolicy02 set_mempolicy03 set_mempolicy03 set_mempolicy04 set_mempolicy04 +set_mempolicy05 set_mempolicy05 diff --git a/runtest/power_management_tests b/runtest/power_management_tests old mode 100644 new mode 100755 diff --git a/runtest/power_management_tests_exclusive b/runtest/power_management_tests_exclusive old mode 100644 new mode 100755 diff --git a/runtest/pty b/runtest/pty old mode 100644 new mode 100755 index 5587312d3da7dfc9955cac1ba677ba544d051747..a43b18f2dfcf119d9d0f90b7589382b4ef030df1 --- a/runtest/pty +++ b/runtest/pty @@ -3,6 +3,7 @@ pty01 pty01 pty02 pty02 pty03 pty03 pty04 pty04 +pty05 pty05 ptem01 ptem01 hangup01 hangup01 diff --git a/runtest/quickhit b/runtest/quickhit deleted file mode 100644 index e01b838fb73d432b2c57d1d2fae36cb8439b2a86..0000000000000000000000000000000000000000 --- a/runtest/quickhit +++ /dev/null @@ -1,316 +0,0 @@ -#DESCRIPTION:A small subset of the syscalls -access01 access01 -# Basic test for access(2) using F_OK, R_OK, W_OK and X_OK arguments. -access03 access03 -# EFAULT error testing for access(2) -alarm02 alarm02 -# Boundary Value Test for alarm(2) -# TEST CASES -# Test Case One - A call to alarm() shall not return an error if -# seconds is a -1. -# Test FAILS if a non-zero value is returned. -# Test Case Two - A call to alarm() shall not return an error if -# seconds is the maximum unsigned integer (2**63). -# Test FAILS if a non-zero value is returned. -# Test Case Three - A call to alarm() shall not return an error if -# seconds is the maximum unsigned integer plus 1 ((2**63)+1). -# Test FAILS if a non-zero value is returned. -alarm03 alarm03 -# alarm(2) cleared by a fork -# TEST CASES -# 1.) alarm(100), fork, child's alarm(0) shall return 0; -# 2.) alarm(100), fork, parent's alarm(0) shall return non-zero. -brk01 brk01 -# Basic test for brk() -# TEST CASES -# 1.) brk(2) returns... -chdir02 chdir02 -# Basic test for chdir(2) -# TEST CASES -# 1.) chdir(2) returns... -chmod02 chmod02 -# Basic test for chmod(2) -# TEST CASES -# 1.) chmod(2) returns... -chown01 chown01 -# Basic test for chown(2) -# TEST CASES -# 1.) chown(2) returns... -close08 close08 -# Basic test for close(2) -# TEST CASES -# 1.) close(2) returns... -dup01 dup01 -# Basic test for dup(2) -# TEST CASES -# 1.) dup(2) returns...(See Description) -dup02 dup02 -# Negative test for dup(2) with bad fd -# TEST CASES -# 1-?.) dup(2) returns -1 with errno set to EBADF...(See Description) -dup03 dup03 -# Negative test for dup(2) (too many fds) -dup04 dup04 -# Basic test for dup(2) of a system pipe descriptor -dup05 dup05 -# Basic test for dup(2) of a named pipe descriptor -execl01 execl01 -# Basic test for execl(2) -execle01 execle01 -# Basic test for execle(2) -execlp01 execlp01 -# Basic test for execlp(2 -execv01 execv01 -# Basic test for execv(2) -execve01 execve01 -# Basic test for execve(2) -execvp01 execvp01 -# Basic test for execvp(2) -f00f f00f -# This is a simple test for handling of the pentium f00f bug. -# It is an example of a catistrophic test case. If the system -# doesn't correctly handle this test, it will likely lockup. -fchmod01 fchmod01 -# Basic test for fchmod(2) using 0700 argument. -fchown01 fchown01 -# Basic test for fchown(2) -fcntl02 fcntl02 -# Basic test for fcntl(2) using F_DUPFD argument -fcntl03 fcntl03 -# Basic test for fcntl(2) using F_GETFD argument -fcntl04 fcntl04 -# Basic test for fcntl(2) using F_GETFL argument -fcntl05 fcntl05 -# Basic test for fcntl(2) using F_GETLK argument -fcntl07 fcntl07 -# Close-On-Exec of named pipe functional test -fcntl08 fcntl08 -# Basic test for fcntl(2) using F_SETFL argument -fcntl09 fcntl09 -# Basic test for fcntl(2) using F_SETLK argument -fcntl10 fcntl10 -# Basic test for fcntl(2) using F_SETLKW argument -fork01 fork01 -# Basic test for fork(2) -# TEST CASES -# 1.) fork returns without error -# 2.) fork returns the pid of the child -fork04 fork04 -# Child inheritance of Environment Variables after fork() -# TEST CASES -# Test these environment variables correctly inherited by child: -# 1. TERM -# 2. NoTSetzWq -# 3. TESTPROG -fork05 fork05 -# This is a test sent in my Ulrich Drepper to test for a bug in fork() where -# %gs is not handled correctly. See fork05.c for a copy of Ulrich's email -fpathconf01 fpathconf01 -# Basic test for fpathconf(2) -fstatfs01 fstatfs01 -# Basic test for fstatfs(2) -fsync01 fsync01 -# Basic test for fsync(2) -getegid01 getegid01 -# Basic test for getegid(2) -geteuid01 geteuid01 -# Basic test for geteuid(2) -getgid01 getgid01 -# Basic test for getgid(2) -getgroups01 getgroups01 -# Getgroups system call critical test -# TEST CASES -# 1. Check to see if getgroups(-1, gidset) fails and sets errno to EINVAL -# 2. Check to see if getgroups(0, gidset) does not return -1 and gidset is -# not modified. -# 3. Check to see if getgroups(x, gigset) fails and sets errno to EINVAL, -# where x is one less then what is returned by getgroups(0, gidset). -# 4. Check to see if getgroups() succeeds and gidset contains -# group id returned from getgid(). -gethostid01 gethostid01 -# Basic test for gethostid(2) -gethostname01 gethostname01 -# Basic test for gethostname(2) -getpgrp01 getpgrp01 -# Basic test for getpgrp(2) -getpid01 getpid01 -# Basic test for getpid(2) -getppid01 getppid01 -# Basic test for getppid(2) -getuid01 getuid01 -# Basic test for getuid(2) -kill02 kill02 -# Sending a signal to processes with the same process group ID. -kill09 kill09 -# Basic test for kill(2) -link02 link02 -# Basic test for link(2) -link03 link03 -# multi links tests -link04 link04 -# Negative test cases for link(2) -link05 link05 -# multi links (EMLINK) negative test -lseek01 lseek01 -lseek02 lseek02 -lseek07 lseek07 -lseek11 lseek11 -# Negative test for lseek(2) of a pipe -lstat02 lstat02 -# Basic test for lstat(2) -qmm01 mmap001 -m 1 -# Basic mmap() test. -open03 open03 -# Basic test for open(2) -pathconf01 pathconf01 -# Basic test for pathconf(2) -pause01 pause01 -# Basic test for pause(2) -read01 read01 -# Basic test for read(2) -readdir01 readdir01 -# write multiple files and try to find them with readdir -# TEST CASES -# 1.) Create n files and check that readdir() finds n files -readlink01 readlink01 -# Basic test for readlink(2) -rename02 rename02 -# Basic test for rename(2) -sbrk01 sbrk01 -# Basic test for sbrk(2) -select01 select01 -# select to a file -# TEST CASES -# 1.) select(2) to a fd of regular file with no I/O and small timeout -select02 select02 -# select of system pipe fds -select03 select03 -select04 select04 -# select of fd of a named-pipe (FIFO) -setgid01 setgid01 -# Basic test for setgid(2) -setpgid01 setpgid01 -# Basic test for setpgid(2) -setpgrp01 setpgrp01 -# Basic test for setpgrp(2) -setregid01 setregid01 -# Basic test for setregid(2) -setreuid01 setreuid01 -# Basic test for setreuid(2) -setuid01 setuid01 -# Basic test for setuid(2) -sighold02 sighold02 -# Holding all signals -signal03 signal03 -# Boundary value and other invalid value checking of signal setup -# and signal sending. -sigrelse01 sigrelse01 -# Releasing held signals -statfs01 statfs01 -# Basic test for statfs(2) mounted filesys -statvfs01 statvfs01 -# Basic test for statvfs(2) mounted filesys -sync01 sync01 -# Basic test for sync(2) -time01 time01 -# Basic test for time(2) -times01 times01 -# Basic test for times(2) -ulimit01 ulimit01 -# Basic test for ulimit(2) -umask01 umask01 -# Basic test for umask(2) -uname01 uname01 -# Basic test for uname(2) -unlink05 unlink05 -# Basic test for unlink(2) -unlink07 unlink07 -# unlink(2) negative testcases -unlink08 unlink08 -# unlink(2) negative testcases -wait02 wait02 -# Basic test for wait(2) -write01 write01 -# Basic test for write(2) -symlink01 symlink01 -# Make a Symbolic Link to a File -# TEST CASES -# 1. Create symbolic link with abnormal object name path -# 2. Create symbolic link with normal object name path -# 3. Create symbolic link with path to an existing object file -# 4. Receive EEXIST error when creating an already existing symbolic link file. -# 5. Receive ENAMETOOLONG error when creating symbolic link which exceeds PATH_MAX in length -symlink02 symlink02 -# Basic test for symlink(2) -readlink01A symlink01 -T readlink01 -# Reads Value of a Symbolic Link -# TEST CASES -# 1. Read a symbolic link file which points at no object file -# 2. Read a symbolic link file which points at an object file -# 3. Receive ENAMETOOLONG error when reading symbolic link which exceeds PATH_MAX in length -# 4. Receive an EINVAL error when reading a file which is not a symbolic -# link file. -stat04 symlink01 -T stat04 -# Gets File Status Indirectly From a Symbolic Link File -# TEST CASES -# 1. Get object file status through symbolic link file -# 2. Receive ENOENT error when accessing non-existent object file through symbolic link file -# 3. Receive ELOOP error when nesting of symbolic links exceed maximum -lstat01A symlink01 -T lstat01 -# Get file Status About a Symbolic Link File -# TEST CASES -# 1. Get symbolic link file status when pointing at no object file -# 2. Get symbolic link file status when pointing at an object file -# 3. Get object file status when argument is not a symbolic link -# file. -mkdir05A symlink01 -T mkdir05 -# Fail When Making a Directory File Indirectly From a Symbolic Link File -# TEST CASES -# 1. Receive EEXIST error when creating a directory through a symbolic link file -rmdir03A symlink01 -T rmdir03 -# Fail When Removing a Directory File Indirectly From a Symbolic Link File -# TEST CASES -# 1. Receive ENOTDIR error when removing an existing directory through a symbolic link file -chdir01A symlink01 -T chdir01 -# Changes Current Working DIrectory Location Indirectly From a Symbolic Link File -# TEST CASES -# 1. Change current working directory through a symbolic link file -# 2. Receive ENOENT error when accessing non-existent directory through symbolic link file -# 3. Receive ELOOP error when nesting of symbolic links exceed maximum -link01 symlink01 -T link01 -# Creates a Link To a File Indirectly From a Symbolic Link File -# TEST CASES -# 1. Link an object file to a new file through symbolic link file -# 2. Receive ENOENT error when accessing non-existent object file through symbolic link file -# 3. Receive ELOOP error when nesting of symbolic links exceed maximum -unlink01 symlink01 -T unlink01 -# Removes a Link To a File And Not Any Object File Which Maybe Pointed At -# TEST CASES -# 1. Delete a symbolic link file and not the object file which it points at -chmod01A symlink01 -T chmod01 -# Change Object File Permissions Indirectly From a Symbolic Link File -# TEST CASES -# 1. Change file permissions of object file through a symbolic link file -# 2. Receive ENOENT error when accessing non-existent directory through symbolic link file -# 3. Receive ELOOP error when nesting of symbolic links exceed maximum -utime01A symlink01 -T utime01 -# Set File Access And Modify Object File Times Indirectly From a Symbolic Link File -# TEST CASES -# 1. Change inode times of object file through a symbolic link file -# 2. Receive ENOENT error when accessing non-existent directory through symbolic link file -# 3. Receive ELOOP error when nesting of symbolic links exceed maximum -rename01A symlink01 -T rename01 -# Rename a Symbolic Link File And Not Any Object File -# TEST CASES -# 1. Rename a symbolic link file which points at no object file -# 2. Rename a symbolic link file which points at an object file without any object file alterations. -# 3. Receive EXDEV when trying to rename a symbolic link file to an address outside of current file system -open01A symlink01 -T open01 -# Create/Open a File For Reading Or Writing Indirectly From a Symbolic Link File -# TEST CASES -# 1. Create an object file through a symbolic link file -# 2. Open an object file through a symbolic link file -# 3. Receive EEXIST error when exclusively creating an object file through a symbolic link file -# 4. Receive ENOENT error when accessing non-existent object file through symbolic link file -# 5. Receive ELOOP error when nesting of symbolic links exceed maximum - diff --git a/runtest/s390x_tests b/runtest/s390x_tests old mode 100644 new mode 100755 diff --git a/runtest/sched b/runtest/sched old mode 100644 new mode 100755 index bfc4f2711a16a35201d81b261a5cff16f1c0165a..59289872379e2c89462c24575362d00543c871bc --- a/runtest/sched +++ b/runtest/sched @@ -6,6 +6,7 @@ pth_str03 pth_str03 time-schedule01 time-schedule trace_sched01 trace_sched -c 1 +cfs_bandwidth01 cfs_bandwidth01 -i 5 hackbench01 hackbench 50 process 1000 hackbench02 hackbench 20 thread 1000 diff --git a/runtest/scsi_debug.part1 b/runtest/scsi_debug.part1 old mode 100644 new mode 100755 diff --git a/runtest/securebits b/runtest/securebits old mode 100644 new mode 100755 diff --git a/runtest/smack b/runtest/smack old mode 100644 new mode 100755 diff --git a/runtest/smoketest b/runtest/smoketest new file mode 100755 index 0000000000000000000000000000000000000000..7bebe4a42eea86c9a5dc706f2ce5ccccbd97f512 --- /dev/null +++ b/runtest/smoketest @@ -0,0 +1,17 @@ +# The purpose of this file is to have a quick integration test for various +# test frameworks that integrate LTP testsuite. + +access01 access01 +chdir01 chdir01 +fork01 fork01 +time01 time01 +wait02 wait02 +write01 write01 +symlink01 symlink01 +stat04 symlink01 -T stat04 +utime01A symlink01 -T utime01 +rename01A symlink01 -T rename01 +splice02 splice02 -s 20 +shell_test01 echo "SUCCESS" | shell_pipe01.sh +ping01 ping01.sh +ping602 ping02.sh -6 diff --git a/runtest/syscalls b/runtest/syscalls old mode 100644 new mode 100755 index edd3e8de786113ac157d99b1703c8f472d2797b5..3b2deb64e0803001b2820c26e21dbe96920afa30 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -22,6 +22,7 @@ add_key05 add_key05 adjtimex01 adjtimex01 adjtimex02 adjtimex02 +adjtimex03 adjtimex03 alarm02 alarm02 alarm03 alarm03 @@ -40,8 +41,11 @@ bpf_map01 bpf_map01 bpf_prog01 bpf_prog01 bpf_prog02 bpf_prog02 bpf_prog03 bpf_prog03 +bpf_prog04 bpf_prog04 +bpf_prog05 bpf_prog05 brk01 brk01 +brk02 brk02 capget01 capget01 capget02 capget02 @@ -55,15 +59,11 @@ cacheflush01 cacheflush01 chdir01 chdir01 chdir01A symlink01 -T chdir01 -chdir02 chdir02 -chdir03 chdir03 chdir04 chdir04 chmod01 chmod01 chmod01A symlink01 -T chmod01 -chmod02 chmod02 chmod03 chmod03 -chmod04 chmod04 chmod05 chmod05 chmod06 chmod06 chmod07 chmod07 @@ -96,10 +96,12 @@ clock_nanosleep04 clock_nanosleep04 clock_gettime01 clock_gettime01 clock_gettime02 clock_gettime02 clock_gettime03 clock_gettime03 +clock_gettime04 clock_gettime04 leapsec01 leapsec01 clock_settime01 clock_settime01 clock_settime02 clock_settime02 +clock_settime03 clock_settime03 clone01 clone01 clone02 clone02 @@ -116,7 +118,9 @@ clone302 clone302 close01 close01 close02 close02 -close08 close08 + +close_range01 close_range01 +close_range02 close_range02 confstr01 confstr01 @@ -130,6 +134,7 @@ creat05 creat05 creat06 creat06 creat07 creat07 creat08 creat08 +creat09 creat09 delete_module01 delete_module01 delete_module02 delete_module02 @@ -148,18 +153,31 @@ dup202 dup202 dup203 dup203 dup204 dup204 dup205 dup205 +dup206 dup206 +dup207 dup207 dup3_01 dup3_01 dup3_02 dup3_02 +epoll_create01 epoll_create01 +epoll_create02 epoll_create02 epoll_create1_01 epoll_create1_01 +epoll_create1_02 epoll_create1_02 epoll01 epoll-ltp epoll_ctl01 epoll_ctl01 epoll_ctl02 epoll_ctl02 +epoll_ctl03 epoll_ctl03 +epoll_ctl04 epoll_ctl04 +epoll_ctl05 epoll_ctl05 epoll_wait01 epoll_wait01 epoll_wait02 epoll_wait02 epoll_wait03 epoll_wait03 +epoll_wait04 epoll_wait04 epoll_pwait01 epoll_pwait01 +epoll_pwait02 epoll_pwait02 +epoll_pwait03 epoll_pwait03 +epoll_pwait04 epoll_pwait04 +epoll_pwait05 epoll_pwait05 eventfd01 eventfd01 @@ -314,6 +332,8 @@ fcntl36 fcntl36 fcntl36_64 fcntl36_64 fcntl37 fcntl37 fcntl37_64 fcntl37_64 +fcntl38 fcntl38 +fcntl38_64 fcntl38_64 fdatasync01 fdatasync01 fdatasync02 fdatasync02 @@ -323,6 +343,9 @@ fgetxattr01 fgetxattr01 fgetxattr02 fgetxattr02 fgetxattr03 fgetxattr03 +finit_module01 finit_module01 +finit_module02 finit_module02 + flistxattr01 flistxattr01 flistxattr02 flistxattr02 flistxattr03 flistxattr03 @@ -406,9 +429,6 @@ getcwd04 getcwd04 getdents01 getdents01 getdents02 getdents02 -getdents01_64 getdents01 -l -getdents02_64 getdents02 -l - getdomainname01 getdomainname01 getdtablesize01 getdtablesize01 @@ -485,6 +505,7 @@ getrlimit02 getrlimit02 getrlimit03 getrlimit03 get_mempolicy01 get_mempolicy01 +get_mempolicy02 get_mempolicy02 get_robust_list01 get_robust_list01 getrusage01 getrusage01 @@ -516,6 +537,9 @@ getxattr03 getxattr03 getxattr04 getxattr04 getxattr05 getxattr05 +init_module01 init_module01 +init_module02 init_module02 + #Needs tty device. #ioctl01 ioctl01 -D /dev/tty0 #ioctl02 ioctl02 -D /dev/tty0 @@ -528,6 +552,7 @@ ioctl05 ioctl05 ioctl06 ioctl06 ioctl07 ioctl07 ioctl08 ioctl08 +ioctl09 ioctl09 ioctl_loop01 ioctl_loop01 ioctl_loop02 ioctl_loop02 @@ -559,6 +584,7 @@ inotify06 inotify06 inotify07 inotify07 inotify08 inotify08 inotify09 inotify09 +inotify10 inotify10 fanotify01 fanotify01 fanotify02 fanotify02 @@ -576,6 +602,12 @@ fanotify13 fanotify13 fanotify14 fanotify14 fanotify15 fanotify15 fanotify16 fanotify16 +fanotify17 fanotify17 +fanotify18 fanotify18 +fanotify19 fanotify19 +fanotify20 fanotify20 +fanotify21 fanotify21 +fanotify22 fanotify22 ioperm01 ioperm01 ioperm02 ioperm02 @@ -589,14 +621,20 @@ ioprio_set02 ioprio_set02 ioprio_set03 ioprio_set03 io_cancel01 io_cancel01 +io_cancel02 io_cancel02 io_destroy01 io_destroy01 +io_destroy02 io_destroy02 io_getevents01 io_getevents01 +io_getevents02 io_getevents02 io_pgetevents01 io_pgetevents01 io_pgetevents02 io_pgetevents02 io_setup01 io_setup01 +io_setup02 io_setup02 io_submit01 io_submit01 +io_submit02 io_submit02 +io_submit03 io_submit03 keyctl01 keyctl01 keyctl02 keyctl02 @@ -611,10 +649,8 @@ kcmp01 kcmp01 kcmp02 kcmp02 kcmp03 kcmp03 -kill01 kill01 kill02 kill02 kill03 kill03 -kill04 kill04 kill05 kill05 kill06 kill06 kill07 kill07 @@ -623,6 +659,7 @@ kill09 kill09 kill10 kill10 kill11 kill11 kill12 kill12 +kill13 kill13 lchown01 lchown01 lchown01_16 lchown01_16 @@ -639,8 +676,6 @@ link02 link02 link03 link03 link04 link04 link05 link05 -link06 link06 -link07 link07 link08 link08 #linkat test cases @@ -675,6 +710,10 @@ lstat01_64 lstat01_64 lstat02 lstat02 lstat02_64 lstat02_64 +mallinfo02 mallinfo02 + +mallinfo2_01 mallinfo2_01 + mallopt01 mallopt01 mbind01 mbind01 @@ -745,6 +784,9 @@ mmap14 mmap14 #mmap11 mmap11 -i 30000 mmap15 mmap15 mmap16 mmap16 +mmap17 mmap17 +mmap18 mmap18 +mmap19 mmap19 modify_ldt01 modify_ldt01 modify_ldt02 modify_ldt02 @@ -796,6 +838,8 @@ msgctl01 msgctl01 msgctl02 msgctl02 msgctl03 msgctl03 msgctl04 msgctl04 +msgctl05 msgctl05 +msgctl06 msgctl06 msgstress01 msgstress01 msgstress02 msgstress02 msgstress03 msgstress03 @@ -805,11 +849,12 @@ msgctl12 msgctl12 msgget01 msgget01 msgget02 msgget02 msgget03 msgget03 +msgget04 msgget04 +msgget05 msgget05 msgrcv01 msgrcv01 msgrcv02 msgrcv02 msgrcv03 msgrcv03 -msgrcv04 msgrcv04 msgrcv05 msgrcv05 msgrcv06 msgrcv06 msgrcv07 msgrcv07 @@ -838,6 +883,9 @@ nanosleep01 nanosleep01 nanosleep02 nanosleep02 nanosleep04 nanosleep04 +name_to_handle_at01 name_to_handle_at01 +name_to_handle_at02 name_to_handle_at02 + nftw01 nftw01 nftw6401 nftw6401 @@ -871,11 +919,16 @@ openat201 openat201 openat202 openat202 openat203 openat203 +open_by_handle_at01 open_by_handle_at01 +open_by_handle_at02 open_by_handle_at02 + open_tree01 open_tree01 open_tree02 open_tree02 mincore01 mincore01 mincore02 mincore02 +mincore03 mincore03 +mincore04 mincore04 madvise01 madvise01 madvise02 madvise02 @@ -944,8 +997,6 @@ pread01 pread01 pread01_64 pread01_64 pread02 pread02 pread02_64 pread02_64 -pread03 pread03 -pread03_64 pread03_64 preadv01 preadv01 preadv01_64 preadv01_64 @@ -980,6 +1031,7 @@ pselect03 pselect03 pselect03_64 pselect03_64 ptrace01 ptrace01 +ptrace02 ptrace02 ptrace03 ptrace03 ptrace04 ptrace04 ptrace05 ptrace05 @@ -988,6 +1040,8 @@ ptrace05 ptrace05 ptrace07 ptrace07 ptrace08 ptrace08 ptrace09 ptrace09 +ptrace10 ptrace10 +ptrace11 ptrace11 pwrite01 pwrite01 pwrite02 pwrite02 @@ -1018,6 +1072,8 @@ quotactl04 quotactl04 quotactl05 quotactl05 quotactl06 quotactl06 quotactl07 quotactl07 +quotactl08 quotactl08 +quotactl09 quotactl09 read01 read01 read02 read02 @@ -1040,7 +1096,6 @@ readlinkat02 readlinkat02 readv01 readv01 readv02 readv02 -readv03 readv03 realpath01 realpath01 @@ -1055,6 +1110,8 @@ recvmsg01 recvmsg01 recvmsg02 recvmsg02 recvmsg03 recvmsg03 +recvmmsg01 recvmmsg01 + remap_file_pages01 remap_file_pages01 remap_file_pages02 remap_file_pages02 @@ -1115,7 +1172,6 @@ sched_get_priority_min01 sched_get_priority_min01 sched_get_priority_min02 sched_get_priority_min02 sched_getparam01 sched_getparam01 -sched_getparam02 sched_getparam02 sched_getparam03 sched_getparam03 sched_rr_get_interval01 sched_rr_get_interval01 @@ -1156,6 +1212,8 @@ semctl04 semctl04 semctl05 semctl05 semctl06 semctl06 semctl07 semctl07 +semctl08 semctl08 +semctl09 semctl09 semget01 semget01 semget02 semget02 @@ -1166,10 +1224,9 @@ semget06 semget06 semop01 semop01 semop02 semop02 semop03 semop03 -semop04 semop04 -semop05 semop05 send01 send01 +send02 send02 sendfile02 sendfile02 sendfile02_64 sendfile02_64 @@ -1194,9 +1251,11 @@ sendmsg02 sendmsg02 sendmsg03 sendmsg03 sendmmsg01 sendmmsg01 +sendmmsg02 sendmmsg02 sendto01 sendto01 sendto02 sendto02 +sendto03 sendto03 set_mempolicy01 set_mempolicy01 set_mempolicy02 set_mempolicy02 @@ -1327,6 +1386,9 @@ setsockopt02 setsockopt02 setsockopt03 setsockopt03 setsockopt04 setsockopt04 setsockopt05 setsockopt05 +setsockopt06 setsockopt06 +setsockopt07 setsockopt07 +setsockopt08 setsockopt08 settimeofday01 settimeofday01 settimeofday02 settimeofday02 @@ -1351,15 +1413,18 @@ shmctl02 shmctl02 shmctl03 shmctl03 shmctl04 shmctl04 shmctl05 shmctl05 +shmctl06 shmctl06 +shmctl07 shmctl07 +shmctl08 shmctl08 shmdt01 shmdt01 shmdt02 shmdt02 -shmget01 shmget01 shmget02 shmget02 shmget03 shmget03 shmget04 shmget04 shmget05 shmget05 +shmget06 shmget06 sigaction01 sigaction01 sigaction02 sigaction02 @@ -1408,7 +1473,7 @@ socketpair02 socketpair02 sockioctl01 sockioctl01 splice01 splice01 -splice02 seq 1 20000 | splice02 +splice02 splice02 splice03 splice03 splice04 splice04 splice05 splice05 @@ -1462,8 +1527,6 @@ symlink05 symlink05 symlinkat01 symlinkat01 sync01 sync01 -sync02 sync02 -sync03 sync03 syncfs01 syncfs01 @@ -1484,7 +1547,6 @@ sysfs02 sysfs02 sysfs03 sysfs03 sysfs04 sysfs04 sysfs05 sysfs05 -sysfs06 sysfs06 sysinfo01 sysinfo01 sysinfo02 sysinfo02 @@ -1508,7 +1570,6 @@ tgkill02 tgkill02 tgkill03 tgkill03 time01 time01 -time02 time02 times01 times01 times03 times03 @@ -1536,12 +1597,11 @@ timer_gettime01 timer_gettime01 timer_settime01 timer_settime01 timer_settime02 timer_settime02 +timer_settime03 timer_settime03 tkill01 tkill01 tkill02 tkill02 -truncate01 truncate01 -truncate01_64 truncate01_64 truncate02 truncate02 truncate02_64 truncate02_64 truncate03 truncate03 @@ -1557,7 +1617,6 @@ umask01 umask01 uname01 uname01 uname02 uname02 -uname03 uname03 uname04 uname04 unlink01 symlink01 -T unlink01 @@ -1600,7 +1659,7 @@ utime06 utime06 utimes01 utimes01 # Introduced from Kernel 2.6.22 onwards -utimensat01 utimensat_tests.sh +utimensat01 utimensat01 vfork01 vfork01 vfork02 vfork02 @@ -1619,6 +1678,7 @@ wait02 wait02 wait401 wait401 wait402 wait402 +wait403 wait403 waitpid01 waitpid01 waitpid02 waitpid02 @@ -1642,9 +1702,11 @@ write02 write02 write03 write03 write04 write04 write05 write05 +write06 write06 writev01 writev01 writev02 writev02 +writev03 writev03 writev05 writev05 writev06 writev06 writev07 writev07 @@ -1664,7 +1726,6 @@ futex_wake02 futex_wake02 futex_wake03 futex_wake03 futex_wake04 futex_wake04 futex_wait_bitset01 futex_wait_bitset01 -futex_wait_bitset02 futex_wait_bitset02 memfd_create01 memfd_create01 memfd_create02 memfd_create02 @@ -1682,5 +1743,12 @@ statx04 statx04 statx05 statx05 statx06 statx06 statx07 statx07 +statx08 statx08 membarrier01 membarrier01 + +io_uring01 io_uring01 +io_uring02 io_uring02 + +# Tests below may cause kernel memory leak +perf_event_open03 perf_event_open03 diff --git a/runtest/syscalls-ipc b/runtest/syscalls-ipc old mode 100644 new mode 100755 index 54d8622d4223e191e56555b544acdf5e7fbb3c21..b758158c3a7bed2d2b8e6561010ef4ee16f2b98c --- a/runtest/syscalls-ipc +++ b/runtest/syscalls-ipc @@ -2,6 +2,8 @@ msgctl01 msgctl01 msgctl02 msgctl02 msgctl03 msgctl03 msgctl04 msgctl04 +msgctl05 msgctl05 +msgctl06 msgctl06 msgstress01 msgstress01 msgstress02 msgstress02 msgstress03 msgstress03 @@ -11,11 +13,12 @@ msgctl12 msgctl12 msgget01 msgget01 msgget02 msgget02 msgget03 msgget03 +msgget04 msgget04 +msgget05 msgget05 msgrcv01 msgrcv01 msgrcv02 msgrcv02 msgrcv03 msgrcv03 -msgrcv04 msgrcv04 msgrcv05 msgrcv05 msgrcv06 msgrcv06 msgrcv07 msgrcv07 @@ -33,6 +36,8 @@ semctl04 semctl04 semctl05 semctl05 semctl06 semctl06 semctl07 semctl07 +semctl08 semctl08 +semctl09 semctl09 semget01 semget01 semget02 semget02 @@ -43,8 +48,6 @@ semget06 semget06 semop01 semop01 semop02 semop02 semop03 semop03 -semop04 semop04 -semop05 semop05 shmat01 shmat01 shmat02 shmat02 @@ -54,12 +57,15 @@ shmctl02 shmctl02 shmctl03 shmctl03 shmctl04 shmctl04 shmctl05 shmctl05 +shmctl06 shmctl06 +shmctl07 shmctl07 +shmctl08 shmctl08 shmdt01 shmdt01 shmdt02 shmdt02 -shmget01 shmget01 shmget02 shmget02 shmget03 shmget03 shmget04 shmget04 shmget05 shmget05 +shmget06 shmget06 diff --git a/runtest/tpm_tools b/runtest/tpm_tools old mode 100644 new mode 100755 diff --git a/runtest/tracing b/runtest/tracing old mode 100644 new mode 100755 diff --git a/runtest/uevent b/runtest/uevent old mode 100644 new mode 100755 diff --git a/scenario_groups/Makefile b/scenario_groups/Makefile old mode 100644 new mode 100755 index 2978675d90fec94b4b1da954298354012cede2a0..fcbc9270829e2e496ef8bcc0fb69e558a0bb81ed --- a/scenario_groups/Makefile +++ b/scenario_groups/Makefile @@ -31,7 +31,7 @@ UNWANTED_FILES := Makefile INSTALL_MODE := 00644 -INSTALL_TARGETS := $(filter-out $(UNWANTED_FILES),$(notdir $(patsubst $(abs_srcdir)/%,%,$(wildcard $(abs_srcdir)/*)))) +INSTALL_TARGETS := $(filter-out $(UNWANTED_FILES),$(notdir $(patsubst $(abs_srcdir)/%,%,$(sort $(wildcard $(abs_srcdir)/*))))) MAKE_TARGETS := diff --git a/scenario_groups/default b/scenario_groups/default old mode 100644 new mode 100755 index 439783dac09add5d90c38fe28ff8566325fe503e..1dc2987d58bbbe926cd1fa6b72407ebf8a1457bf --- a/scenario_groups/default +++ b/scenario_groups/default @@ -6,6 +6,7 @@ dio io mm ipc +irq sched math nptl diff --git a/scenario_groups/network b/scenario_groups/network old mode 100644 new mode 100755 diff --git a/scripts/abspath.sh b/scripts/abspath.sh deleted file mode 100755 index f0862480a776a07db1aeb1e46aeb8167f171f84f..0000000000000000000000000000000000000000 --- a/scripts/abspath.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -# -# make 3.81 $(abspath .. ) emulation layer -# -# Copyright (C) 2010, Cisco Systems Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Ngie Cooper, January 2010 -# - -. "${0%/*}/lib/file_functions.sh" - -while [ $# -gt 0 ] ; do - echo -n $(_abspath "$1") - [ $# -gt 1 ] && echo -n " " - shift -done diff --git a/scripts/checkbashisms.pl b/scripts/checkbashisms.pl new file mode 100755 index 0000000000000000000000000000000000000000..ba417c9934737d4d36986f9a0ebf4dcfa32b53f7 --- /dev/null +++ b/scripts/checkbashisms.pl @@ -0,0 +1,816 @@ +#!/usr/bin/perl + +# This script is essentially copied from /usr/share/lintian/checks/scripts, +# which is: +# Copyright (C) 1998 Richard Braakman +# Copyright (C) 2002 Josip Rodin +# This version is +# Copyright (C) 2003 Julian Gilbey +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; +use warnings; +use Getopt::Long qw(:config bundling permute no_getopt_compat); +use File::Temp qw/tempfile/; + +sub init_hashes; + +(my $progname = $0) =~ s|.*/||; + +my $usage = <<"EOF"; +Usage: $progname [-n] [-f] [-x] [-e] script ... + or: $progname --help + or: $progname --version +This script performs basic checks for the presence of bashisms +in /bin/sh scripts and the lack of bashisms in /bin/bash ones. +EOF + +my $version = <<"EOF"; +This is $progname, from the Debian devscripts package, version 2.20.5 +This code is copyright 2003 by Julian Gilbey , +based on original code which is copyright 1998 by Richard Braakman +and copyright 2002 by Josip Rodin. +This program comes with ABSOLUTELY NO WARRANTY. +You are free to redistribute this code under the terms of the +GNU General Public License, version 2, or (at your option) any later version. +EOF + +my ($opt_echo, $opt_force, $opt_extra, $opt_posix, $opt_early_fail); +my ($opt_help, $opt_version); +my @filenames; + +# Detect if STDIN is a pipe +if (scalar(@ARGV) == 0 && (-p STDIN or -f STDIN)) { + push(@ARGV, '-'); +} + +## +## handle command-line options +## +$opt_help = 1 if int(@ARGV) == 0; + +GetOptions( + "help|h" => \$opt_help, + "version|v" => \$opt_version, + "newline|n" => \$opt_echo, + "force|f" => \$opt_force, + "extra|x" => \$opt_extra, + "posix|p" => \$opt_posix, + "early-fail|e" => \$opt_early_fail, + ) + or die +"Usage: $progname [options] filelist\nRun $progname --help for more details\n"; + +if ($opt_help) { print $usage; exit 0; } +if ($opt_version) { print $version; exit 0; } + +$opt_echo = 1 if $opt_posix; + +my $mode = 0; +my $issues = 0; +my $status = 0; +my $makefile = 0; +my (%bashisms, %string_bashisms, %singlequote_bashisms); + +my $LEADIN + = qr'(?:(?:^|[`&;(|{])\s*|(?:(?:if|elif|while)(?:\s+!)?|then|do|shell)\s+)'; +init_hashes; + +my @bashisms_keys = sort keys %bashisms; +my @string_bashisms_keys = sort keys %string_bashisms; +my @singlequote_bashisms_keys = sort keys %singlequote_bashisms; + +foreach my $filename (@ARGV) { + my $check_lines_count = -1; + + my $display_filename = $filename; + + if ($filename eq '-') { + my $tmp_fh; + ($tmp_fh, $filename) + = tempfile("chkbashisms_tmp.XXXX", TMPDIR => 1, UNLINK => 1); + while (my $line = ) { + print $tmp_fh $line; + } + close($tmp_fh); + $display_filename = "(stdin)"; + } + + if (!$opt_force) { + $check_lines_count = script_is_evil_and_wrong($filename); + } + + if ($check_lines_count == 0 or $check_lines_count == 1) { + warn +"script $display_filename does not appear to be a /bin/sh script; skipping\n"; + next; + } + + if ($check_lines_count != -1) { + warn +"script $display_filename appears to be a shell wrapper; only checking the first " + . "$check_lines_count lines\n"; + } + + unless (open C, '<', $filename) { + warn "cannot open script $display_filename for reading: $!\n"; + $status |= 2; + next; + } + + $issues = 0; + $mode = 0; + my $cat_string = ""; + my $cat_indented = 0; + my $quote_string = ""; + my $last_continued = 0; + my $continued = 0; + my $found_rules = 0; + my $buffered_orig_line = ""; + my $buffered_line = ""; + my %start_lines; + + while () { + next unless ($check_lines_count == -1 or $. <= $check_lines_count); + + if ($. == 1) { # This should be an interpreter line + if (m,^\#!\s*(?:\S+/env\s+)?(\S+),) { + my $interpreter = $1; + + if ($interpreter =~ m,(?:^|/)make$,) { + init_hashes if !$makefile++; + $makefile = 1; + } else { + init_hashes if $makefile--; + $makefile = 0; + } + next if $opt_force; + + if ($interpreter =~ m,(?:^|/)bash$,) { + $mode = 1; + } elsif ($interpreter !~ m,(?:^|/)(sh|dash|posh)$,) { +### ksh/zsh? + warn +"script $display_filename does not appear to be a /bin/sh script; skipping\n"; + $status |= 2; + last; + } + } else { + warn +"script $display_filename does not appear to have a \#! interpreter line;\nyou may get strange results\n"; + } + } + + chomp; + my $orig_line = $_; + + # We want to remove end-of-line comments, so need to skip + # comments that appear inside balanced pairs + # of single or double quotes + + # Remove comments in the "quoted" part of a line that starts + # in a quoted block? The problem is that we have no idea + # whether the program interpreting the block treats the + # quote character as part of the comment or as a quote + # terminator. We err on the side of caution and assume it + # will be treated as part of the comment. + # s/^(?:.*?[^\\])?$quote_string(.*)$/$1/ if $quote_string ne ""; + + # skip comment lines + if ( m,^\s*\#, + && $quote_string eq '' + && $buffered_line eq '' + && $cat_string eq '') { + next; + } + + # Remove quoted strings so we can more easily ignore comments + # inside them + s/(^|[^\\](?:\\\\)*)\'(?:\\.|[^\\\'])+\'/$1''/g; + s/(^|[^\\](?:\\\\)*)\"(?:\\.|[^\\\"])+\"/$1""/g; + + # If inside a quoted string, remove everything before the quote + s/^.+?\'// + if ($quote_string eq "'"); + s/^.+?[^\\]\"// + if ($quote_string eq '"'); + + # If the remaining string contains what looks like a comment, + # eat it. In either case, swap the unmodified script line + # back in for processing. + if (m/(?:^|[^[\\])[\s\&;\(\)](\#.*$)/) { + $_ = $orig_line; + s/\Q$1\E//; # eat comments + } else { + $_ = $orig_line; + } + + # Handle line continuation + if (!$makefile && $cat_string eq '' && m/\\$/) { + chop; + $buffered_line .= $_; + $buffered_orig_line .= $orig_line . "\n"; + next; + } + + if ($buffered_line ne '') { + $_ = $buffered_line . $_; + $orig_line = $buffered_orig_line . $orig_line; + $buffered_line = ''; + $buffered_orig_line = ''; + } + + if ($makefile) { + $last_continued = $continued; + if (/[^\\]\\$/) { + $continued = 1; + } else { + $continued = 0; + } + + # Don't match lines that look like a rule if we're in a + # continuation line before the start of the rules + if (/^[\w%-]+:+\s.*?;?(.*)$/ + and !($last_continued and !$found_rules)) { + $found_rules = 1; + $_ = $1 if $1; + } + + last + if m%^\s*(override\s|export\s)?\s*SHELL\s*:?=\s*(/bin/)?bash\s*%; + + # Remove "simple" target names + s/^[\w%.-]+(?:\s+[\w%.-]+)*::?//; + s/^\t//; + s/(?|<|;|\Z)/o + and m/$LEADIN(\.\s+[^\s;\`:]+\s+([^\s;]+))/o) { + if ($2 =~ /^(\&|\||\d?>|<)/) { + # everything is ok + ; + } else { + $found = 1; + $match = $1; + $explanation = "sourced script with arguments"; + output_explanation($display_filename, $orig_line, + $explanation); + } + } + + # Remove "quoted quotes". They're likely to be inside + # another pair of quotes; we're not interested in + # them for their own sake and removing them makes finding + # the limits of the outer pair far easier. + $line =~ s/(^|[^\\\'\"])\"\'\"/$1/g; + $line =~ s/(^|[^\\\'\"])\'\"\'/$1/g; + + foreach my $re (@singlequote_bashisms_keys) { + my $expl = $singlequote_bashisms{$re}; + if ($line =~ m/($re)/) { + $found = 1; + $match = $1; + $explanation = $expl; + output_explanation($display_filename, $orig_line, + $explanation); + } + } + + my $re = '(?); + } + } + + # $cat_line contains the version of the line we'll check + # for heredoc delimiters later. Initially, remove any + # spaces between << and the delimiter to make the following + # updates to $cat_line easier. However, don't remove the + # spaces if the delimiter starts with a -, as that changes + # how the delimiter is searched. + my $cat_line = $line; + $cat_line =~ s/(<\<-?)\s+(?!-)/$1/g; + + # Ignore anything inside single quotes; it could be an + # argument to grep or the like. + $line =~ s/(^|[^\\\"](?:\\\\)*)\'(?:\\.|[^\\\'])+\'/$1''/g; + + # As above, with the exception that we don't remove the string + # if the quote is immediately preceded by a < or a -, so we + # can match "foo <<-?'xyz'" as a heredoc later + # The check is a little more greedy than we'd like, but the + # heredoc test itself will weed out any false positives + $cat_line =~ s/(^|[^<\\\"-](?:\\\\)*)\'(?:\\.|[^\\\'])+\'/$1''/g; + + $re = '(?); + } + } + + foreach my $re (@string_bashisms_keys) { + my $expl = $string_bashisms{$re}; + if ($line =~ m/($re)/) { + $found = 1; + $match = $1; + $explanation = $expl; + output_explanation($display_filename, $orig_line, + $explanation); + } + } + + # We've checked for all the things we still want to notice in + # double-quoted strings, so now remove those strings as well. + $line =~ s/(^|[^\\\'](?:\\\\)*)\"(?:\\.|[^\\\"])+\"/$1""/g; + $cat_line =~ s/(^|[^<\\\'-](?:\\\\)*)\"(?:\\.|[^\\\"])+\"/$1""/g; + foreach my $re (@bashisms_keys) { + my $expl = $bashisms{$re}; + if ($line =~ m/($re)/) { + $found = 1; + $match = $1; + $explanation = $expl; + output_explanation($display_filename, $orig_line, + $explanation); + } + } + # This check requires the value to be compared, which could + # be done in the regex itself but requires "use re 'eval'". + # So it's better done in its own + if ($line =~ m/$LEADIN((?:exit|return)\s+(\d{3,}))/o && $2 > 255) { + $explanation = 'exit|return status code greater than 255'; + output_explanation($display_filename, $orig_line, + $explanation); + } + + # Only look for the beginning of a heredoc here, after we've + # stripped out quoted material, to avoid false positives. + if ($cat_line + =~ m/(?:^|[^<])\<\<(\-?)\s*(?:(?!<|'|")((?:[^\s;>|]+(?:(?<=\\)[\s;>|])?)+)|[\'\"](.*?)[\'\"])/ + ) { + $cat_indented = ($1 && $1 eq '-') ? 1 : 0; + my $quoted = defined($3); + $cat_string = $quoted ? $3 : $2; + unless ($quoted) { + # Now strip backslashes. Keep the position of the + # last match in a variable, as s/// resets it back + # to undef, but we don't want that. + my $pos = 0; + pos($cat_string) = $pos; + while ($cat_string =~ s/\G(.*?)\\/$1/) { + # position += length of match + the character + # that followed the backslash: + $pos += length($1) + 1; + pos($cat_string) = $pos; + } + } + $start_lines{'cat_string'} = $.; + } + } + } + + warn +"error: $display_filename: Unterminated heredoc found, EOF reached. Wanted: <$cat_string>, opened in line $start_lines{'cat_string'}\n" + if ($cat_string ne ''); + warn +"error: $display_filename: Unterminated quoted string found, EOF reached. Wanted: <$quote_string>, opened in line $start_lines{'quote_string'}\n" + if ($quote_string ne ''); + warn "error: $display_filename: EOF reached while on line continuation.\n" + if ($buffered_line ne ''); + + close C; + + if ($mode && !$issues) { + warn "could not find any possible bashisms in bash script $filename\n"; + $status |= 4; + } +} + +exit $status; + +sub output_explanation { + my ($filename, $line, $explanation) = @_; + + if ($mode) { + # When examining a bash script, just flag that there are indeed + # bashisms present + $issues = 1; + } else { + warn "possible bashism in $filename line $. ($explanation):\n$line\n"; + if ($opt_early_fail) { + exit 1; + } + $status |= 1; + } +} + +# Returns non-zero if the given file is not actually a shell script, +# just looks like one. +sub script_is_evil_and_wrong { + my ($filename) = @_; + my $ret = -1; + # lintian's version of this function aborts if the file + # can't be opened, but we simply return as the next + # test in the calling code handles reporting the error + # itself + open(IN, '<', $filename) or return $ret; + my $i = 0; + my $var = "0"; + my $backgrounded = 0; + local $_; + while () { + chomp; + next if /^#/o; + next if /^$/o; + last if (++$i > 55); + if ( + m~ + # the exec should either be "eval"ed or a new statement + (^\s*|\beval\s*[\'\"]|(;|&&|\b(then|else))\s*) + + # eat anything between the exec and $0 + exec\s*.+\s* + + # optionally quoted executable name (via $0) + .?\$$var.?\s* + + # optional "end of options" indicator + (--\s*)? + + # Match expressions of the form '${1+$@}', '${1:+"$@"', + # '"${1+$@', "$@", etc where the quotes (before the dollar + # sign(s)) are optional and the second (or only if the $1 + # clause is omitted) parameter may be $@ or $*. + # + # Finally the whole subexpression may be omitted for scripts + # which do not pass on their parameters (i.e. after re-execing + # they take their parameters (and potentially data) from stdin + .?(\$\{1:?\+.?)?(\$(\@|\*))?~x + ) { + $ret = $. - 1; + last; + } elsif (/^\s*(\w+)=\$0;/) { + $var = $1; + } elsif ( + m~ + # Match scripts which use "foo $0 $@ &\nexec true\n" + # Program name + \S+\s+ + + # As above + .?\$$var.?\s* + (--\s*)? + .?(\$\{1:?\+.?)?(\$(\@|\*))?.?\s*\&~x + ) { + + $backgrounded = 1; + } elsif ( + $backgrounded + and m~ + # the exec should either be "eval"ed or a new statement + (^\s*|\beval\s*[\'\"]|(;|&&|\b(then|else))\s*) + exec\s+true(\s|\Z)~x + ) { + + $ret = $. - 1; + last; + } elsif (m~\@DPATCH\@~) { + $ret = $. - 1; + last; + } + + } + close IN; + return $ret; +} + +sub init_hashes { + + %bashisms = ( + qr'(?:^|\s+)function [^<>\(\)\[\]\{\};|\s]+(\s|\(|\Z)' => + q<'function' is useless>, + $LEADIN . qr'select\s+\w+' => q<'select' is not POSIX>, + qr'(test|-o|-a)\s*[^\s]+\s+==\s' => q, + qr'\[\s+[^\]]+\s+==\s' => q, + qr'\s\|\&' => q, + qr'[^\\\$]\{([^\s\\\}]*?,)+[^\\\}\s]*\}' => q, + qr'\{\d+\.\.\d+(?:\.\.\d+)?\}' => + q, + qr'(?i)\{[a-z]\.\.[a-z](?:\.\.\d+)?\}' => q, + qr'(?:^|\s+)\w+\[\d+\]=' => q, + $LEADIN + . qr'read\s+(?:-[a-qs-zA-Z\d-]+)' => + q, + $LEADIN + . qr'read\s*(?:-\w+\s*)*(?:\".*?\"|[\'].*?[\'])?\s*(?:;|$)' => + q, + $LEADIN . qr'echo\s+(-n\s+)?-n?en?\s' => q, + $LEADIN . qr'exec\s+-[acl]' => q, + $LEADIN . qr'let\s' => q, + qr'(? q<'((' should be '$(('>, + qr'(?:^|\s+)(\[|test)\s+-a' => q, + qr'\&>' => qword 2\>&1>, + qr'(<\&|>\&)\s*((-|\d+)[^\s;|)}`&\\\\]|[^-\d\s]+(? + qword 2\>&1>, + qr'\[\[(?!:)' => + q, + qr'/dev/(tcp|udp)' => q, + $LEADIN . qr'builtin\s' => q, + $LEADIN . qr'caller\s' => q, + $LEADIN . qr'compgen\s' => q, + $LEADIN . qr'complete\s' => q, + $LEADIN . qr'declare\s' => q, + $LEADIN . qr'dirs(\s|\Z)' => q, + $LEADIN . qr'disown\s' => q, + $LEADIN . qr'enable\s' => q, + $LEADIN . qr'mapfile\s' => q, + $LEADIN . qr'readarray\s' => q, + $LEADIN . qr'shopt(\s|\Z)' => q, + $LEADIN . qr'suspend\s' => q, + $LEADIN . qr'time\s' => q