diff --git a/.gitignore b/.gitignore index 5d947ca8879f8a9072fe485c566204e3c2929e80..58e4787beb020edc957dcb993daa628a2d6dad1e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ bin-release/ # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` # should NOT be excluded as they contain compiler settings and other important # information for Eclipse / Flash Builder. +*.install/ \ No newline at end of file diff --git a/README.md b/README.md index 471340633e9c7c2cb27c5eee738a662c4f82414b..14183a9c0718ee8501150c97171ae6c037823da8 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,11 @@ tst-open-ltp/ -- 项目顶层目录,tst-open-为固定项目名 更新上游项目步骤: 1. 保存对上游项目代码的修改 + - 第一次提交源码时commit的格式为: "上传原始仓库`原始仓库url`的`此次提交的代码在原始仓库中对应的commit-hash`",同时需要删除原始仓库除`.gitignore`以外的git配置文件 + - 本仓库的`.gitignore`中需要加上:`*.install`,忽略编译后的文件 2. 在目录下更新到上游项目最新代码 3. 将第一步保存的更改合入到最新代码中,如果有冲突则需要挨个处理 + + 如果需要保存当前项目的版本,则将目录重命名为带版本,然后添加上游项目代码并适配 diff --git a/ltp/.b4-config b/ltp/.b4-config new file mode 100644 index 0000000000000000000000000000000000000000..36aa15c38f1fce4bdef65d42943b625ae30554bd --- /dev/null +++ b/ltp/.b4-config @@ -0,0 +1,9 @@ +# Configuration for the `b4` tool +# See https://b4.docs.kernel.org/en/latest/config.html +[b4] + send-series-to = Linux Test Project + pw-url = https://patchwork.ozlabs.org/ + pw-project = ltp + prep-perpatch-check-cmd = ./scripts/checkpatch.pl -q --terse --no-summary --mailback --showfile --no-tree --ignore CONST_STRUCT,VOLATILE,SPLIT_STRING,FILE_PATH_CHANGES + am-perpatch-check-cmd = ./scripts/checkpatch.pl -q --terse --no-summary --mailback --no-tree --ignore CONST_STRUCT,VOLATILE,SPLIT_STRING,FILE_PATH_CHANGES + diff --git a/ltp/.dockerignore b/ltp/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..bbcd7072f06d35bf44b3e450bd2b136835ac67dd --- /dev/null +++ b/ltp/.dockerignore @@ -0,0 +1 @@ +Containerfile diff --git a/ltp/.gitignore b/ltp/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..24f4a4ea834e0b919e640e879fe5e5b5d7aec466 --- /dev/null +++ b/ltp/.gitignore @@ -0,0 +1,62 @@ +CVS +.*.swp +*~ +*.o +*.o.d +*.obj +*.gdb +core +.gdb_history +.gdbinit +lib*.a +.cache.mk +*.dwo +*.mod +built-in.a + +/aclocal.m4 +autom4te.cache +/compile +/configure +/config.cache +/config.guess +/config.log +/config.mk +/config.status +/config.sub +/conf*/ +/install-sh +/missing +/include/config.h +/include/config.h.in +/include/stamp-h1 +/m4/Makefile +/m4/Makefile.in + +/tags +/Version +/include/mk/config.mk +/include/mk/config-openposix.mk +/include/mk/features.mk +/m4/ltp-version.m4 +/pan/ltp-bump +/pan/ltp-pan + +cscope.* +ncscope.* + +.dep_modules +.gitattributes +.pc/ +patches/ +*.diff +*.patch +*.rej +*.orig +*.eml + +*.run-test +*.test +logfile.* + +/utils/benchmark/ebizzy-0.3/ebizzy diff --git a/ltp/.mailmap b/ltp/.mailmap new file mode 100644 index 0000000000000000000000000000000000000000..221e2295699dc88357f9648cd799dd2d9d9296d9 --- /dev/null +++ b/ltp/.mailmap @@ -0,0 +1,3 @@ +Petr Vorel +Petr Vorel +Xinjian Ma (Fujitsu) diff --git a/ltp/.readthedocs.yml b/ltp/.readthedocs.yml new file mode 100644 index 0000000000000000000000000000000000000000..51825da77f968588c2b12c9546fa95a00640674b --- /dev/null +++ b/ltp/.readthedocs.yml @@ -0,0 +1,26 @@ +version: 2 + +build: + os: "ubuntu-24.04" + tools: + python: "3.12" + apt_packages: + - autoconf + - enchant-2 + - hunspell-en-us + - make + jobs: + # Doc requires to have ltp.json + pre_build: + - make autotools + - ./configure + - make -C metadata/ + +# Build from the doc/ directory with Sphinx +sphinx: + configuration: doc/conf.py + +# Explicitly set the version of Python and its requirements +python: + install: + - requirements: doc/requirements.txt diff --git a/ltp/COPYING b/ltp/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1 --- /dev/null +++ b/ltp/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/ltp/Containerfile b/ltp/Containerfile new file mode 100644 index 0000000000000000000000000000000000000000..227c7d39da6a70b29a7d90135617268353281b15 --- /dev/null +++ b/ltp/Containerfile @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 SUSE LLC + +ARG PREFIX=docker.io/ +ARG DISTRO_NAME=alpine +ARG DISTRO_RELEASE=3.18 + +FROM $PREFIX$DISTRO_NAME:$DISTRO_RELEASE AS build +ARG LTPROOT=/opt/ltp +ARG DISTRO_NAME=alpine +ARG DISTRO_RELEASE=3.18 + +RUN mkdir /build +WORKDIR /build +COPY . /build +RUN ./ci/${DISTRO_NAME}.sh +RUN git clean -fdX +RUN ./build.sh -p $LTPROOT -i + +FROM $PREFIX$DISTRO_NAME:$DISTRO_RELEASE +ARG LTPROOT=/opt/ltp +ARG KIRKROOT=/opt/kirk +ARG DISTRO_NAME=alpine + +COPY --from=build /build/ci/${DISTRO_NAME}-runtime.sh $LTPROOT/runtime-deps.sh +RUN $LTPROOT/runtime-deps.sh + +COPY --from=build $LTPROOT $LTPROOT +ENV LTPROOT=$LTPROOT +ENV PATH=$LTPROOT/testcases/bin:$LTPROOT/bin:$PATH + +RUN mkdir -p $KIRKROOT +COPY --from=build /build/tools/kirk $KIRKROOT + +USER ltp diff --git a/ltp/IDcheck.sh b/ltp/IDcheck.sh new file mode 100755 index 0000000000000000000000000000000000000000..c6c41b965386561e4e698a1db2705ab8c9cb6ce9 --- /dev/null +++ b/ltp/IDcheck.sh @@ -0,0 +1,196 @@ +#!/bin/sh +# +# Copyright (c) International Business Machines Corp., 2001 +# +# 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 +# +# FILE : IDcheck.sh +# DESCRIPTION : checks for req'd users/groups and will create them if requested. +# HISTORY : see the cvs log +# + +# Prompt user if ids/groups should be created +echo "Checking for required user/group ids" +echo "" + +# Check ids and create if needed. +NO_ROOT_ID=1 +NO_NOBODY_ID=1 +NO_BIN_ID=1 +NO_DAEMON_ID=1 +NO_ROOT_GRP=1 +NO_NOBODY_GRP=1 +NO_BIN_GRP=1 +NO_DAEMON_GRP=1 +NO_USERS_GRP=1 +NO_SYS_GRP=1 + +group="$DESTDIR/etc/group" +passwd="$DESTDIR/etc/passwd" + +# find entry. +fe() { + ID=$1 + FILE=$2 + [ -e "$FILE" ] || return $? + grep -q "^$ID:" "$FILE" +} + +prompt_for_create() { + if [ -z "$CREATE_ENTRIES" ] ; then + + if [ $NO_ROOT_ID -ne 0 -o $NO_NOBODY_ID -ne 0 -o $NO_BIN_ID -ne 0 -o $NO_DAEMON_ID -ne 0 -o $NO_ROOT_GRP -ne 0 -o $NO_NOBODY_GRP -ne 0 -o $NO_BIN_GRP -ne 0 -o $NO_DAEMON_GRP -ne 0 -o $NO_USERS_GRP -ne 0 -o $NO_SYS_GRP -ne 0 ] ; then + echo -n "If any required user ids and/or groups are missing, would you like these created? [y/N]" + read ans + case "$ans" in + [Yy]*) CREATE_ENTRIES=1 ;; + *) CREATE_ENTRIES=0 ;; + esac + else + CREATE_ENTRIES=0 + fi + + fi +} + +if [ -z ${EUID} ] ; then + EUID=$(id -u) +fi + +for i in "$passwd" "$group"; do + if [ -e "$i" -a ! -r "$i" ] ; then + echo "$i not readable by uid $EUID" + exit 1 + fi +done + +fe root "$passwd"; NO_ROOT_ID=$? +fe bin "$passwd"; NO_BIN_ID=$? +fe daemon "$passwd"; NO_DAEMON_ID=$? +fe nobody "$passwd"; NO_NOBODY_ID=$? + +fe root "$group"; NO_ROOT_GRP=$? +fe bin "$group"; NO_BIN_GRP=$? +fe daemon "$group"; NO_DAEMON_GRP=$? +fe nobody "$group" || fe nogroup "$group"; NO_NOBODY_GRP=$? +fe sys "$group"; NO_SYS_GRP=$? +fe users "$group"; NO_USERS_GRP=$? + +prompt_for_create + +debug_vals() { + +echo "Missing the following group / user entries:" +echo "Group file: $group" +echo "Password file: $passwd" +echo "root $NO_ROOT_ID" +echo "nobody: $NO_NOBODY_ID" +echo "bin: $NO_BIN_ID" +echo "daemon: $NO_DAEMON_ID" +echo "root grp: $NO_ROOT_GRP" +echo "nobody[/nogroup] grp: $NO_NOBODY_GRP" +echo "bin grp: $NO_BIN_GRP" +echo "daemon grp: $NO_DAEMON_GRP" +echo "sys grp: $NO_SYS_GRP" +echo "users grp: $NO_USERS_GRP" +echo "" + +} + +#debug_vals + +if [ $CREATE_ENTRIES -ne 0 ] ; then + if ! touch "$group" "$passwd" 2>/dev/null; then + echo "Failed to touch $group or $passwd" + exit 1 + fi +fi + +make_user_group() { + local name=$1 id=$2 no_id=$3 no_grp=$4 + + if [ $no_id -eq 0 -a $no_grp -eq 0 ] ; then + echo "'$name' user id and group found." + elif [ $CREATE_ENTRIES -ne 0 ] ; then + echo "Creating entries for $name" + + # Avoid chicken and egg issue with id(1) call + # made above and below. + if ! fe "$name" "$passwd" && [ $no_id -ne 0 ] ; then + echo "${name}:x:${id}:${id}:${name}::" >> "$passwd" + fi + if [ $no_grp -ne 0 ] ; then + echo "${name}:x:$(id -u ${name}):" >> "$group" + fi + fi +} +make_user_group root 0 $NO_ROOT_ID $NO_ROOT_GRP +make_user_group nobody 65534 $NO_NOBODY_ID $NO_NOBODY_GRP +make_user_group bin 1 $NO_BIN_ID $NO_BIN_GRP +make_user_group daemon 2 $NO_DAEMON_ID $NO_DAEMON_GRP + +if [ $NO_USERS_GRP -eq 0 ] ; then + echo "Users group found." +elif [ $CREATE_ENTRIES -ne 0 ] ; then + echo 'users:x:100:' >> "$group" +fi + +if [ $NO_SYS_GRP -eq 0 ] ; then + echo "Sys group found." +elif [ $CREATE_ENTRIES -ne 0 ] ; then + echo 'sys:x:3:' >> "$group" +fi + +MISSING_ENTRY=0 + +# For entries that exist in both $group and $passwd. +for i in root bin daemon; do + for file in "$group" "$passwd"; do + if ! fe "$i" "$file"; then + MISSING_ENTRY=1 + break + fi + done + if [ $MISSING_ENTRY -ne 0 ]; then + break + fi +done + +# nobody is a standard group on all distros, apart from debian based ones; +# let's account for the fact that they use the nogroup group instead. +if ! fe "nobody" "$passwd" || ! (fe "nogroup" "$group" || fe "nobody" "$group") +then + MISSING_ENTRY=1 +fi + +# For entries that only exist in $group. +for i in users sys; do + if ! fe "$i" "$group" ; then + MISSING_ENTRY=1 + fi +done + +if [ $MISSING_ENTRY -eq 0 ] ; then + echo "Required users/groups exist." + exit 0 +fi + +echo "" +echo "*****************************************" +echo "* Required users/groups do NOT exist!!! *" +echo "* *" +echo "* Some kernel/syscall tests will FAIL! *" +echo "*****************************************" +exit 1 diff --git a/ltp/INSTALL b/ltp/INSTALL new file mode 100644 index 0000000000000000000000000000000000000000..81b1f74faf460110f981c3edb8a6517cfe5f5cae --- /dev/null +++ b/ltp/INSTALL @@ -0,0 +1,199 @@ +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 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 + +These are minimal build requirements for git compilation. Some tests require +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 +on older distros) are required only for compilation from git (used for creating +configure file). + +pkgconf is recommended also for compilation from tarball as it +does automatic detection of some library support. + +Configuration +------------- + +Configuration requires autoconf: + + $ cd $TOP_SRCDIR + $ make autotools + $ mkdir -p $TOP_BUILDDIR + $ 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. + +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. + + $ make all + $ make \ + "DESTDIR=$SYSROOT" \ + install + +- Specifying DESTDIR is optional, but required when installing to a non-host + sysroot, as opposed to the host system's sysroot. + +If you get a build error, please report it to ltp@lists.linux.it with +following information, + + 1. The error output before the failure. + 2. If you used configure: + i. include/config.h + ii. include/mk/config.mk + 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. + +NOTE: This is by and large correctly implemented, but there are several corner +cases, where this isn't implemented properly. Please see TODO for a list of +items which need fixing in the LTP tree. + + $ mkdir "$OUT_OF_BUILD_TREE_DIR" + $ make \ + -C "$OUT_OF_BUILD_TREE_DIR" \ + -f "$TOP_SRCDIR/Makefile" \ + "top_srcdir=$TOP_SRCDIR" \ + "top_builddir=$OUT_OF_BUILD_TREE_DIR" + $ make \ + -C "$OUT_OF_BUILD_TREE_DIR" \ + -f "$TOP_SRCDIR/Makefile" \ + "top_srcdir=$TOP_SRCDIR" \ + "top_builddir=$OUT_OF_BUILD_TREE_DIR" \ + "DESTDIR=$SYSROOT" \ + install + +- Specifying DESTDIR is optional, but required when installing to a non-host + sysroot, as opposed to the host system's sysroot. + +Quick Start +----------- + + $ 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 +groups. If these IDs do not exist, certain tests will fail. The respective +user and group IDs should be the same, i.e. if `nobody's' user ID is 99, then +its group ID should also be 99. The names of the groups are irrelevant. +- The installation directory is /opt/ltp by default. Please see +"Using autoconf" above and specify the appropriate path via --prefix. +DESTDIR= is also honored for install and will install into $DESTDIR/$prefix, +if you want to install into a chroot or a rootfs for instance. + +Detailed Installation +--------------------- + +Beyond the "Quick Start" instructions, there are only a few other things +that should be done. The Linux Test Project build process uses a +minimalist approach. There is a lot of room for improvement and +contributions are welcome. + +1. Log in as root. + +2. Untar the ltp tarball into a spare directory. There is not a + standard location for it yet. We put it in our home directory + while we're working on it. + Note that the full path to this location must be accessible for + unprivileged users, as some tests are run as a different user than root. + Hence /root is not a good choice on several distributions. + +3. Build and install everything, as described above. Note the minimum software + requirements above before doing so. + +4. The disk I/O tests can be run by executing the diskio.sh script. In order + for these tests to successfully operate a writable high-density 3.5" floppy + must be in the disk drive and a CD-ROM with more than 100Mb of data must be + in the CD-ROM drive. The corresponding tests will fail if either disk is + missing. + +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 +PKG_CONFIG_SYSROOT_DIR=$SYSROOT + +After configure has run, it will generate include/mk/config.mk. You can tweak +settings in there if need be, but you should not specificy settings on the +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.) +PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig CFLAGS=-m32 LDFLAGS=-m32 ./configure + +* Debian / Ubuntu and derivates +PKG_CONFIG_LIBDIR=/usr/lib/i386-linux-gnu/pkgconfig CFLAGS=-m32 LDFLAGS=-m32 ./configure + +* Arch Linux +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: + +CFLAGS - used when compiling/linking C code, e.g. -D_GNU_SOURCE (no CPPFLAGS!) + +CPPFLAGS - used when preprocessor is run (so C/C++ compiling with $(CPP) + functions, e.g. -I$SYSROOT/usr/include -I$SYSROOT/include -I$SYSROOT + +LDFLAGS - linker flags, e.g. "-L$SYSROOT/usr/lib" "-L$SYSROOT/lib". DO NOT + PUT LIBRARIES IN THIS LIST (see LDLIBS for that). + +LDLIBS - libraries listed after objects during link, e.g. -lc, -lpthread, + -lltp. + +For other variables and more info about the build systems see +doc/developers/build_system.rst. diff --git a/ltp/Makefile b/ltp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eab40da8a6b979540c5fe8dd24d17e23fbcb0142 --- /dev/null +++ b/ltp/Makefile @@ -0,0 +1,219 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2009-2024 +# Copyright (c) Cisco Systems Inc., 2009-2010 +# Ngie Cooper, July 2009 + +# Avoid funny character set dependencies +unexport LC_ALL +LC_COLLATE=C +LC_NUMERIC=C +export LC_COLLATE LC_NUMERIC + +top_srcdir ?= $(CURDIR) + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/automake.mk + +.SUFFIXES: +.SUFFIXES: .am .default .h .in .m4 .mk + +vpath %.am $(top_srcdir)/m4 +vpath %.default $(top_srcdir)/include +vpath %.h $(top_srcdir)/include:$(top_builddir)/include +vpath %.in $(top_srcdir)/include +vpath %.m4 $(top_srcdir)/m4 +vpath %.mk $(top_srcdir)/mk:$(top_srcdir)/mk/include + +# CLEAN_TARGETS: Targets which exist solely in clean. +# COMMON_TARGETS: Targets which exist in all, clean, and install. +# INSTALL_TARGETS: Targets which exist in clean and install (contains +# COMMON_TARGETS). +# BOOTSTRAP_TARGETS: Directories required to bootstrap out-of-build-tree +# support. + +COMMON_TARGETS := pan utils + +define target_to_dir_dep_mapping +ifeq ($$(filter %-clean,$(1)),) # not *-clean +$(1): | $$(abs_top_builddir)/$$(basename $$(subst -,.,$(1))) +else # clean +$(1):: | $$(abs_top_builddir)/$$(basename $$(subst -,.,$(1))) +endif +endef + +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 +CLEAN_TARGETS += include runtest scenario_groups testscripts +endif +INSTALL_TARGETS += $(COMMON_TARGETS) +CLEAN_TARGETS += $(COMMON_TARGETS) lib libs +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 +# overtaxed one, or one where -j => 1 was specified. +all: $(addsuffix -all,$(COMMON_TARGETS)) Version + +$(MAKE_TARGETS): lib-all libs-all + +.PHONY: include-all include-install +include-install: $(top_builddir)/include/config.h include/mk/config.mk include-all + +INSTALL_DIR := $(DESTDIR)/$(prefix) + +# DO NOT REMOVE THIS CALL (see clean_install_dir call below...)!!!! +INSTALL_DIR := $(abspath $(INSTALL_DIR)) + +# build tree bootstrap targets and $(INSTALL_DIR) target. +$(sort $(addprefix $(abs_top_builddir)/,$(BOOTSTRAP_TARGETS)) $(INSTALL_DIR) $(DESTDIR)/$(bindir)): + mkdir -m 00755 -p "$@" + +## Pattern based subtarget rules. +lib-install: lib-all + +libs-all: $(abs_top_builddir)/libs + +$(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,,$@)" \ + -f "$(abs_top_srcdir)/$(subst -clean,,$@)/Makefile" clean + +# Just like everything depends on include-all / -install, we need to get rid +# of include last to ensure that things won't be monkey screwed up. Only do +# this if we're invoking clean, distclean or a subclean directly though. +ifneq ($(filter clean distclean,$(MAKECMDGOALS)),) +INCLUDE_CLEAN_RDEP_SUBJECT := $(CLEAN_TARGETS) +else +ifneq ($(filter %clean,$(MAKECMDGOALS)),) +INCLUDE_CLEAN_RDEP_SUBJECT := $(MAKECMDGOALS) +endif +endif + +# Remove potential for circular dependencies. +INCLUDE_CLEAN_RDEPS := $(filter-out include-clean,$(INCLUDE_CLEAN_RDEP_SUBJECT)) + +include-clean:: $(INCLUDE_CLEAN_RDEPS) | $(abs_top_builddir)/include + -$(MAKE) -C include -f "$(abs_top_srcdir)/include/Makefile" clean + +# include-install is separate to avoid creating a circular dependency below in +# the install target. +$(INSTALL_TARGETS) include-install lib-install: + $(MAKE) -C "$(subst -install,,$@)" \ + -f "$(abs_top_srcdir)/$(subst -install,,$@)/Makefile" install + +# Just in case configure hasn't been run yet, let's not overambitiously remove +# the $(INSTALL_DIR). +.PHONY: clean_install_dir +clean_install_dir:: + $(RM) -Rf "$(INSTALL_DIR)" + +# Clean the directory if the build-tree is properly configured and not set to +# the srcdir. +ifeq ($(filter $(BUILD_TREE_STATE),$(BUILD_TREE_SRCDIR_INSTALL) $(BUILD_TREE_UNCONFIGURED)),) +# Make sure that we don't whack `/'!!!!! +ifneq ($(INSTALL_DIR),/) +CLEAN_TARGETS += clean_install_dir +endif +endif + +clean:: $(CLEAN_TARGETS) + $(RM) -f Version + +$(foreach tgt,$(MAKE_TARGETS) include-all lib-all $(filter-out clean_install_dir,$(CLEAN_TARGETS)) $(INSTALL_TARGETS) include-install lib-install,$(eval $(call target_to_dir_dep_mapping,$(tgt)))) + +SRCDIR_INSTALL_SCRIPTS := IDcheck.sh runltp ver_linux +SRCDIR_INSTALL_READONLY := Version +SRCDIR_INSTALL_TARGETS := $(SRCDIR_INSTALL_SCRIPTS) $(SRCDIR_INSTALL_READONLY) + +# +# If we are in git repository, use git describe to indentify current version, +# otherwise if downloaded as tarball use VERSION file. +# +.PHONY: Version +Version: + if git describe >/dev/null 2>&1; then \ + git describe > "$@"; \ + else \ + cp $(top_srcdir)/VERSION "$@"; \ + fi + +$(INSTALL_DIR)/Version: Version + install -m 00644 "$(top_builddir)/$(@F)" "$@" + +$(addprefix $(DESTDIR)/$(bindir)/,$(BINDIR_INSTALL_SCRIPTS)): %: + install -m 00755 "$(top_builddir)/$(@F)" "$@" + +$(addprefix $(INSTALL_DIR)/,$(SRCDIR_INSTALL_SCRIPTS)): %: + install -m 00755 "$(top_srcdir)/$(@F)" "$@" + +ifneq ($(BUILD_TREE_STATE),$(BUILD_TREE_SRCDIR_INSTALL)) +INSTALL_TARGETS += $(addprefix $(INSTALL_DIR)/,$(SRCDIR_INSTALL_TARGETS)) +endif +INSTALL_TARGETS += $(addprefix $(DESTDIR)/$(bindir)/,$(BINDIR_INSTALL_SCRIPTS)) + +$(INSTALL_TARGETS): $(INSTALL_DIR) $(DESTDIR)/$(bindir) + +.PHONY: doc +doc: metadata-all + +.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-shell-loader + $(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-shell-loader: lib-all +ifneq ($(build),$(host)) + $(error running tests on cross-compile build not supported) +endif + $(top_srcdir)/testcases/lib/run_tests.sh -b $(abs_builddir) + +test-metadata: metadata-all + $(MAKE) -C $(abs_srcdir)/metadata test + +## Help +.PHONY: help +help: + @echo "Please read the Configuration section in $(top_srcdir)/INSTALL" + @exit 1 diff --git a/ltp/README.rst b/ltp/README.rst new file mode 100644 index 0000000000000000000000000000000000000000..3e176bd0b6e83e7128b66e7dbfcee7e7db3df25e --- /dev/null +++ b/ltp/README.rst @@ -0,0 +1,29 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Linux Test Project +================== + +Linux Test Project is a joint project started by SGI, OSDL and Bull developed +and maintained by SUSE, Red Hat, Fujitsu, IBM, Cisco, Oracle and others. The +project goal is to deliver tests to the open source community that validate +reliability, robustness, and stability of the Linux Kernel. + +The testing suites contain a collection of tools for testing the Linux kernel +and related features. Our goal is to improve the Linux kernel and system +libraries by bringing test automation. + +.. warning:: + + LTP tests shouldn't run in production systems. In particular, + growfiles, doio, and iogen, stress the I/O capabilities of the systems and + they are intended to find (or cause) problems. + +Some references: + +* `Documentation `_ +* `Source code `_ +* `Releases `_ +* `Mailing List `_ +* `Working patches (patchwork) `_ +* `Working patches (lore.kernel.org) `_ +* `#ltp @ libera chat `_ diff --git a/ltp/TODO b/ltp/TODO new file mode 100644 index 0000000000000000000000000000000000000000..fe0a3ab9b28c9fb8b4e8bdc530c25f6f59dad34f --- /dev/null +++ b/ltp/TODO @@ -0,0 +1,39 @@ +LTP TODO +-------- + + +Write more syscall tests +~~~~~~~~~~~~~~~~~~~~~~~~ + +Syscalls and new syscall flags are added to Linux kernel each development cycle +and LTP still falls behind. Unfortunately there is no single place that would +store comprehensive list of syscalls, but there are a few places to look at: + +One of the options would be looking at changes in man-pages git[1] in man2/ +directory to find out newly documented functionality. + +Another good source of information are kernel pages in LWN[2] weekly +editions. + +Then there is linux-api mailing list[3] where changes in kernel userspace API +should be discussed. + +[1] http://git.kernel.org/cgit/docs/man-pages/man-pages.git +[2] http://lwn.net +[3] http://dir.gmane.org/gmane.linux.kernel.api + + +Rewrite old and add new controller testcases +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We already started working on this with rewriting cgroup_fj testcases and +newly added pids testcases. Have a look at testcases/kernel/controllers/. + + +Shell tests cleanups +~~~~~~~~~~~~~~~~~~~~ + +There are numerous testcases written in shell that does not follow single style +and use the broken-by-design binaries from tools/apicmds. These should be +cleaned up and fixed to use the test.sh test library. These include most of +tests in testcases/commands/ for example. diff --git a/ltp/VERSION b/ltp/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..ac27433357659113e3cab8793c0ca577082d1447 --- /dev/null +++ b/ltp/VERSION @@ -0,0 +1 @@ +20250530 diff --git a/ltp/build.sh b/ltp/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..47a5a7b0507b9122b8abab5a37771054c448a850 --- /dev/null +++ b/ltp/build.sh @@ -0,0 +1,252 @@ +#!/bin/sh +# Copyright (c) 2017-2021 Petr Vorel +# Script for CI builds. + +set -e + +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_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_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" + +run_configure() +{ + 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 +} + +configure_in_tree() +{ + run_configure ./configure $CONFIGURE_OPTS_IN_TREE --prefix=$prefix $@ +} + +configure_out_tree() +{ + mkdir -p $BUILD_DIR + cd $BUILD_DIR + run_configure $SRC_DIR/configure $CONFIGURE_OPTS_OUT_TREE $@ +} + +configure_32() +{ + local tree="$1" + 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 + + CFLAGS="-m32 $CFLAGS" LDFLAGS="-m32 $LDFLAGS" + + eval configure_${tree}_tree +} + +configure_native() +{ + local tree="$1" + local prefix="$2" + + echo "===== native ${tree}-tree build into $prefix =====" + eval configure_${tree}_tree +} + +configure_cross() +{ + local tree="$1" + local prefix="$2" + local host=$(basename "${CC%-gcc}") + + 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() +{ + make $MAKE_OPTS +} + +build_out_tree() +{ + cd $BUILD_DIR + make $MAKE_OPTS_OUT_TREE +} + +test_in_tree() +{ + make $1 +} + +test_out_tree() +{ + cd $BUILD_DIR + make $MAKE_OPTS_OUT_TREE $1 +} + +install_in_tree() +{ + make $MAKE_OPTS install +} + +install_out_tree() +{ + cd $BUILD_DIR + make $MAKE_OPTS_OUT_TREE DESTDIR="$prefix" install +} + +usage() +{ + cat << EOF +Usage: +$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), 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 + value passed to DESTDIR variable (i.e. sysroot) of make install + target, which means that LTP will be actually installed into + DIR/PREFIX (i.e. DIR/opt/ltp). + Default for in-tree build: '$DEFAULT_PREFIX' + Default for out-of-tree build: '$DEFAULT_PREFIX/opt/ltp' +-r RUN Run only certain step (usable for CI), default: all +-t TYPE Specify build type, default: $DEFAULT_BUILD, only for configure step + +TREE: +in in-tree build +out out-of-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) +test-shell-loader run only 'make test-shell-loader' (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" +build="$DEFAULT_BUILD" +tree="$DEFAULT_TREE" +install= +run= + +while getopts "c:hio:p:r:t:" opt; do + case "$opt" in + c) CC="$OPTARG";; + h) usage; exit 0;; + i) install=1;; + o) case "$OPTARG" in + in|out) tree="$OPTARG";; + *) echo "Wrong build tree '$OPTARG'" >&2; usage; exit 1;; + esac;; + p) prefix="$OPTARG";; + r) case "$OPTARG" in + autotools|configure|build|test|test-c|test-shell|test-shell-loader|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;; + esac;; + ?) usage; exit 1;; + esac +done + +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 + +if [ -z "$run" -o "$run" = "test" -o "$run" = "test-c" -o "$run" = "test-shell" -o "$run" = "test-shell-loader" ]; then + if [ "$build" = "cross" ]; then + echo "cross-compile build, skipping running tests" >&2 + else + eval test_${tree}_tree $run + fi +fi + +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 + +exit $? diff --git a/ltp/ci/alpine-runtime.sh b/ltp/ci/alpine-runtime.sh new file mode 100755 index 0000000000000000000000000000000000000000..d0e1990d2c25c9f300dd47fb979af4d38e3ad3f9 --- /dev/null +++ b/ltp/ci/alpine-runtime.sh @@ -0,0 +1,20 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 SUSE LLC + +apk add \ + acl \ + curl \ + jq \ + keyutils \ + libaio \ + libacl \ + libcap \ + libselinux \ + libsepol \ + libtirpc \ + numactl \ + openssl \ + py3-msgpack + +adduser -D -g "Unprivileged LTP user" ltp diff --git a/ltp/ci/alpine.sh b/ltp/ci/alpine.sh new file mode 100755 index 0000000000000000000000000000000000000000..254f4aaece66ef177bc5b4a92cf5160443552378 --- /dev/null +++ b/ltp/ci/alpine.sh @@ -0,0 +1,39 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019-2024 Petr Vorel + +apk update + +apk add \ + acl-dev \ + autoconf \ + automake \ + clang \ + curl \ + jq \ + gcc \ + git \ + acl-dev \ + keyutils-dev \ + libaio-dev \ + libcap-dev \ + libselinux-dev \ + libsepol-dev \ + libtirpc-dev \ + linux-headers \ + make \ + musl-dev \ + numactl-dev \ + openssl-dev \ + pkgconfig + +cat /etc/os-release + +echo "WARNING: remove unsupported tests (until they're fixed)" +cd $(dirname $0)/.. +rm -rfv \ + testcases/kernel/syscalls/fmtmsg/fmtmsg01.c \ + testcases/kernel/syscalls/timer_create/timer_create01.c \ + testcases/kernel/syscalls/timer_create/timer_create03.c + +cd - diff --git a/ltp/ci/debian.cross-compile.sh b/ltp/ci/debian.cross-compile.sh new file mode 100755 index 0000000000000000000000000000000000000000..95cf11da221b6203876007e40b4377c48c7da708 --- /dev/null +++ b/ltp/ci/debian.cross-compile.sh @@ -0,0 +1,24 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2018-2020 Petr Vorel + +if [ -z "$ARCH" ]; then + echo "missing \$ARCH!" >&2 + exit 1 +fi + +case "$ARCH" in +arm64) gcc_arch="aarch64";; +ppc64el) gcc_arch="powerpc64le";; +s390x) gcc_arch="$ARCH";; +*) echo "unsupported arch: '$ARCH'!" >&2; exit 1;; +esac + +dpkg --add-architecture $ARCH +apt update + +apt install -y --no-install-recommends \ + gcc-${gcc_arch}-linux-gnu \ + libc6-dev-${ARCH}-cross \ + libmnl-dev:$ARCH \ + libtirpc-dev:$ARCH diff --git a/ltp/ci/debian.i386.sh b/ltp/ci/debian.i386.sh new file mode 100755 index 0000000000000000000000000000000000000000..44c7ddf2ff6f049ab847b374213c6aee74fbc130 --- /dev/null +++ b/ltp/ci/debian.i386.sh @@ -0,0 +1,22 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2018-2024 Petr Vorel + +dpkg --add-architecture i386 +apt update + +apt install -y --no-install-recommends \ + curl \ + jq \ + linux-libc-dev:i386 \ + gcc-multilib \ + libacl1-dev:i386 \ + libaio-dev:i386 \ + libcap-dev:i386 \ + libc6-dev-i386 \ + libc6:i386 \ + libkeyutils-dev:i386 \ + libnuma-dev:i386 \ + libssl-dev:i386 \ + libtirpc-dev:i386 \ + pkg-config:i386 diff --git a/ltp/ci/debian.minimal.sh b/ltp/ci/debian.minimal.sh new file mode 100755 index 0000000000000000000000000000000000000000..1e8dd19af24bbc9affd4e1318825dfd4774615dc --- /dev/null +++ b/ltp/ci/debian.minimal.sh @@ -0,0 +1,5 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2018-2024 Petr Vorel + +ACTION="remove-nonessential" $(dirname $0)/debian.sh diff --git a/ltp/ci/debian.sh b/ltp/ci/debian.sh new file mode 100755 index 0000000000000000000000000000000000000000..0445c92ec40819e49c0435b1881cf6b202d14087 --- /dev/null +++ b/ltp/ci/debian.sh @@ -0,0 +1,66 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2018-2024 Petr Vorel + +# workaround for missing oldstable-updates repository +# W: Failed to fetch http://deb.debian.org/debian/dists/oldstable-updates/main/binary-amd64/Packages +grep -v oldstable-updates /etc/apt/sources.list > /tmp/sources.list && mv /tmp/sources.list /etc/apt/sources.list + +apt update + +# workaround for Ubuntu impish asking to interactively configure tzdata +export DEBIAN_FRONTEND="noninteractive" + +install="apt install -y --no-install-recommends" +remove="apt remove -y" + +# libc6-dev and libtirpc-dev are hard dependencies for gcc toolchain +# LTP should be compilable without linux-libc-dev, but we expect kernel headers. +pkg_minimal=" + autoconf + automake + build-essential + debhelper + devscripts + clang + curl + jq + gcc + git + iproute2 + libc6-dev + libtirpc-dev + linux-libc-dev + lsb-release + pkg-config +" + +pkg_nonessential=" + acl-dev + libacl1-dev + libaio-dev + libcap-dev + libkeyutils-dev + libnuma-dev + libmnl-dev + libselinux1-dev + libsepol-dev + libssl-dev +" + +case "$ACTION" in + minimal) + echo "=== Installing only minimal dependencies ===" + $install $pkg_minimal + ;; + remove-nonessential) + echo "=== Make sure devel libraries are removed ===" + $remove $pkg_nonessential + ;; + *) + echo "=== Installing dependencies ===" + $install $pkg_minimal $pkg_nonessential + ;; +esac + +df -hT diff --git a/ltp/ci/fedora.sh b/ltp/ci/fedora.sh new file mode 100755 index 0000000000000000000000000000000000000000..f57806ebf7e153d5f774620985920841f970d510 --- /dev/null +++ b/ltp/ci/fedora.sh @@ -0,0 +1,32 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2018-2021 Petr Vorel + +if command -v dnf5 >/dev/null 2>&1; then + yum="dnf5 -y install --skip-broken --skip-unavailable" +elif command -v dnf >/dev/null 2>&1; then + yum="dnf -y install --skip-broken" +else + yum="yum -y install --skip-broken" +fi + +$yum \ + autoconf \ + automake \ + make \ + clang \ + gawk \ + curl \ + jq \ + gcc \ + git \ + findutils \ + iproute \ + numactl-devel \ + libtirpc \ + libtirpc-devel \ + pkg-config \ + redhat-lsb-core + +# CentOS 8 fixes +$yum libmnl-devel || $yum libmnl diff --git a/ltp/ci/opensuse.sh b/ltp/ci/opensuse.sh new file mode 120000 index 0000000000000000000000000000000000000000..11c5f4b632c61eaf870f293d6b7d088870eb543b --- /dev/null +++ b/ltp/ci/opensuse.sh @@ -0,0 +1 @@ +tumbleweed.sh \ No newline at end of file diff --git a/ltp/ci/quay.io.sh b/ltp/ci/quay.io.sh new file mode 120000 index 0000000000000000000000000000000000000000..1479a43e04edfb75be5f5dc450eb59807efcfaa2 --- /dev/null +++ b/ltp/ci/quay.io.sh @@ -0,0 +1 @@ +fedora.sh \ No newline at end of file diff --git a/ltp/ci/tools/patchwork.sh b/ltp/ci/tools/patchwork.sh new file mode 100755 index 0000000000000000000000000000000000000000..3e18ee9480c443837bc4269a408fc3151d76b165 --- /dev/null +++ b/ltp/ci/tools/patchwork.sh @@ -0,0 +1,197 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Shell script to communicate with Patchwork via REST API. +# It has been mainly created for CI purposes, but it can be used in the shell +# by satisfying minimum requirements. +# +# Copyright (c) 2025 Andrea Cervesato + +PATCHWORK_URL="${PATCHWORK_URL:-https://patchwork.ozlabs.org}" +PATCHWORK_SINCE="${PATCHWORK_SINCE:-3600}" + +command_exists() { + local cmd + + for cmd in "$@"; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "'$1' must be present in the system" >&2 + exit 1 + fi + done +} + +command_exists "curl" "jq" + +fetch_series() { + local current_time=$(date +%s) + local since_time=$(expr $current_time - $PATCHWORK_SINCE) + local date=$(date -u -d @$since_time +"%Y-%m-%dT%H:%M:%SZ") + local stdout + + stdout=$(curl -k -G "$PATCHWORK_URL/api/events/" \ + --data "category=series-completed" \ + --data "project=ltp" \ + --data "state=new" \ + --data "since=$date" \ + --data "archive=no") + + [ $? -eq 0 ] || exit 1 + + echo "$stdout" | jq -r '.[] | "\(.payload.series.id) \(.payload.series.mbox)"' +} + +get_patches() { + local series_id="$1" + local stdout + + stdout="$(curl -k -G $PATCHWORK_URL/api/patches/ \ + --data project=ltp \ + --data series=$series_id)" + + [ $? -eq 0 ] || exit 1 + + echo "$stdout" | jq -r '.[] | "\(.id)"' +} + +verify_token_exists() { + if [ -z "$PATCHWORK_TOKEN" ]; then + echo "For this feature you need \$PATCHWORK_TOKEN" + exit 1 + fi +} + +set_patch_state() { + local patch_id="$1" + local state="$2" + + verify_token_exists + + curl -k -X PATCH \ + -H "Authorization: Token $PATCHWORK_TOKEN" \ + -F "state=$state" \ + "$PATCHWORK_URL/api/patches/$patch_id/" + + [ $? -eq 0 ] || exit 1 +} + +set_series_state() { + if [ $# -ne 2 ]; then + echo "'state' command expects 2 parameters ($#)" + exit 1 + fi + + local series_id="$1" + local state="$2" + + get_patches "$series_id" | while read -r patch_id; do + if [ "$patch_id" ]; then + set_patch_state "$patch_id" "$state" + fi + done +} + +get_checks() { + local patch_id="$1" + local stdout + + stdout="$(curl -k -G $PATCHWORK_URL/api/patches/$patch_id/checks/)" + + [ $? -eq 0 ] || exit 1 + + echo "$stdout" | jq -r '.[] | "\(.id)"' +} + +already_tested() { + local series_id="$1" + + get_patches "$series_id" | while read -r patch_id; do + [ "$patch_id" ] || continue + + get_checks "$patch_id" | while read -r check_id; do + if [ -n "$check_id" ]; then + echo "$check_id" + return + fi + done + done +} + +verify_new_patches() { + local tmp=$(mktemp -d) + local output="$tmp/series_ids.txt" + + touch "$output" + + fetch_series | while read -r series_id series_mbox; do + [ "$series_id" ] || continue + + tested=$(already_tested "$series_id") + [ "$tested" ] && continue + + echo "$series_id|$series_mbox" >>"$output" + done + + cat "$output" +} + +send_results() { + if [ $# -ne 4 -a $# -ne 5 ]; then + echo "'check' command expects 4 or 5 parameters ($#)" + exit 1 + fi + + local series_id="$1" + local target_url="$2" + + verify_token_exists + + local context=$(echo "$3" | sed 's/:/_/g; s/\//-/g; s/\./-/g') + + [ "$CC" ] && context="${context}_${CC}" + [ "$ARCH" ] && context="${context}_${ARCH}" + + local result="$4" + [ "$result" = "cancelled" ] && return + + local description="${5:-$result}" + + local state="fail" + + # patchwork REST API allowed states: pending, success, warning, fail. + # https://github.com/getpatchwork/patchwork/blob/main/docs/api/schemas/v1.2/patchwork.yaml#L708 + # https://patchwork.readthedocs.io/en/latest/api/rest/schemas/v1.2/#get--api-1.2-patches-patch_id-checks + case "$result" in + success|pending) state=$result;; + esac + + get_patches "$series_id" | while read -r patch_id; do + [ "$patch_id" ] || continue + + curl -k -X POST \ + -H "Authorization: Token $PATCHWORK_TOKEN" \ + -F "state=$state" \ + -F "context=$context" \ + -F "target_url=$target_url" \ + -F "description=$description" \ + "$PATCHWORK_URL/api/patches/$patch_id/checks/" + + [ $? -eq 0 ] || exit 1 + done +} + +case "$1" in +state) + set_series_state "$2" "$3" + ;; +check) + send_results "$2" "$3" "$4" "$5" "$6" + ;; +verify) + verify_new_patches + ;; +*) + echo "Available commands: state, check, verify" >&2 + exit 1 + ;; +esac diff --git a/ltp/ci/tumbleweed-runtime.sh b/ltp/ci/tumbleweed-runtime.sh new file mode 100755 index 0000000000000000000000000000000000000000..3eea991aa48abccaa4a5cd12a28f87b685747867 --- /dev/null +++ b/ltp/ci/tumbleweed-runtime.sh @@ -0,0 +1,15 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 SUSE LLC + +zyp="zypper --non-interactive install --force-resolution --no-recommends" + +$zyp \ + iproute2 \ + keyutils \ + libaio1 \ + libmnl0 \ + libnuma1 \ + libtirpc3 + +useradd ltp diff --git a/ltp/ci/tumbleweed.sh b/ltp/ci/tumbleweed.sh new file mode 100755 index 0000000000000000000000000000000000000000..8a30b02c2dd403ef23b9d85b87166ede42d73ad4 --- /dev/null +++ b/ltp/ci/tumbleweed.sh @@ -0,0 +1,46 @@ +#!/bin/sh -eux +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2018-2025 Petr Vorel + +zyp="zypper --non-interactive install --force-resolution --no-recommends" + +i=10 +while [ $i != 0 ]; do + $zyp \ + autoconf \ + automake \ + clang \ + curl \ + jq \ + findutils \ + gcc \ + git \ + gzip \ + iproute2 \ + make \ + kernel-default-devel \ + keyutils-devel \ + libacl-devel \ + libaio-devel \ + libcap-devel \ + libmnl-devel \ + libnuma-devel \ + libopenssl-devel \ + libselinux-devel \ + libtirpc-devel \ + linux-glibc-devel \ + lsb-release \ + pkg-config + + ret=$? + + if [ $ret -eq 106 ]; then + echo "Broken repositories, try $i..." + sleep 5 + i=$((i-1)) + continue + fi + break +done + +exit $ret diff --git a/ltp/ci/ubuntu.sh b/ltp/ci/ubuntu.sh new file mode 120000 index 0000000000000000000000000000000000000000..0edcb8b838caefc65740edf02e1004815468036d --- /dev/null +++ b/ltp/ci/ubuntu.sh @@ -0,0 +1 @@ +debian.sh \ No newline at end of file diff --git a/ltp/configure.ac b/ltp/configure.ac new file mode 100644 index 0000000000000000000000000000000000000000..11e599a814b0ad2fbae0119597e420d3e1c47565 --- /dev/null +++ b/ltp/configure.ac @@ -0,0 +1,456 @@ +# Copyright (c) Linux Test Project, 2008-2025 +# SPDX-License-Identifier: GPL-2.0-or-later + +AC_PREREQ(2.64) +AC_INIT([ltp], [LTP_VERSION], [ltp@lists.linux.it]) +AC_CONFIG_AUX_DIR([.]) +AM_INIT_AUTOMAKE +AC_CONFIG_HEADERS([include/config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +# Adding files here? Please update include/mk/automake.mk +AC_CONFIG_FILES([ \ + include/mk/config.mk \ + include/mk/config-openposix.mk \ + include/mk/features.mk \ + lib/ltp.pc \ + m4/Makefile \ +]) + +AC_ARG_VAR(HOSTCC, [The C compiler on the host]) + +AM_MAINTAINER_MODE([enable]) + +AC_CANONICAL_HOST + +AC_PROG_CC +# <= autoconf 2.61 doesn't have AC_PROG_AR, but 2.63 has it. Not sure about +# 2.62. +AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) +AC_PROG_AR +AC_PROG_RANLIB +AC_DEFUN([AC_PROG_STRIP], [AC_CHECK_TOOL(STRIP, strip, :)]) +AC_PROG_STRIP +AC_PROG_YACC +AC_CHECK_TOOL([OBJCOPY], [objcopy], [:]) + +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([LANDLOCK_RULE_PATH_BENEATH],,,[#include ]) +AC_CHECK_DECLS([LANDLOCK_RULE_NET_PORT],,,[#include ]) +AC_CHECK_DECLS([MADV_MERGEABLE],,,[#include ]) +AC_CHECK_DECLS([NFTA_CHAIN_ID, NFTA_VERDICT_CHAIN_ID],,,[#include ]) +AC_CHECK_DECLS([PR_CAPBSET_DROP, PR_CAPBSET_READ],,,[#include ]) +AC_CHECK_DECLS([SEM_STAT_ANY],,,[#include ]) + +AC_CHECK_HEADERS_ONCE([ \ + asm/ldt.h \ + asm/prctl.h \ + cpuid.h \ + emmintrin.h \ + ifaddrs.h \ + keyutils.h \ + linux/blkdev.h \ + linux/can.h \ + linux/cgroupstats.h \ + linux/cryptouser.h \ + linux/close_range.h \ + linux/dccp.h \ + linux/futex.h \ + linux/genetlink.h \ + linux/if_alg.h \ + linux/if_ether.h \ + linux/if_packet.h \ + linux/io_uring.h \ + linux/ioprio.h \ + linux/keyctl.h \ + linux/landlock.h \ + linux/lsm.h \ + linux/mempolicy.h \ + linux/module.h \ + linux/mount.h \ + linux/netlink.h \ + linux/seccomp.h \ + linux/securebits.h \ + linux/tls.h \ + linux/tty.h \ + linux/types.h \ + linux/userfaultfd.h \ + netinet/sctp.h \ + pthread.h \ + sys/epoll.h \ + sys/fanotify.h \ + sys/inotify.h \ + sys/pidfd.h + sys/prctl.h \ + sys/random.h \ + sys/shm.h \ + sys/timerfd.h \ + sys/ustat.h \ + sys/utsname.h \ + sys/xattr.h \ + xfs/xqm.h \ +]) +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_ONCE([ \ + cachestat \ + clone3 \ + close_range \ + copy_file_range \ + epoll_pwait \ + epoll_pwait2 \ + execveat \ + faccessat2 \ + fallocate \ + fsconfig \ + fsmount \ + fsopen \ + fspick \ + fstatat \ + getauxval \ + getcontext \ + getcpu \ + getdents \ + getdents64 \ + io_pgetevents \ + io_uring_setup \ + io_uring_register \ + io_uring_enter \ + kcmp \ + mallinfo \ + mallinfo2 \ + mallopt \ + modify_ldt \ + mount_setattr \ + move_mount \ + name_to_handle_at \ + open_tree \ + openat \ + openat2 \ + pidfd_getfd \ + pidfd_open \ + pidfd_send_signal \ + pkey_mprotect \ + preadv \ + preadv2 \ + profil \ + pwritev \ + pwritev2 \ + quotactl_fd \ + rand_r \ + recvmmsg \ + renameat2 \ + sched_getcpu \ + sendmmsg \ + sethostid \ + setns \ + sigpending \ + splice \ + statx \ + stime \ + sync_file_range \ + syncfs \ + tee \ + timerfd_create \ + timerfd_gettime \ + timerfd_settime \ + unshare \ + ustat \ + vmsplice \ +]) +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, struct statx.stx_dio_mem_align],,,[ +#define _GNU_SOURCE +#include +]) + +AC_CHECK_MEMBERS([struct utsname.domainname],,,[ +#define _GNU_SOURCE +#include +]) + +AC_CHECK_TYPES([enum kcmp_type],,,[#include ]) +AC_CHECK_TYPES([struct acct_v3],,,[#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, + struct fanotify_event_info_range],,,[#include ]) +AC_CHECK_TYPES([struct file_clone_range],,,[#include ]) +AC_CHECK_TYPES([struct file_dedupe_range],,,[#include ]) +AC_CHECK_TYPES([struct procmap_query],,,[#include ]) + +AC_CHECK_TYPES([struct file_handle],,,[ +#define _GNU_SOURCE +#include +]) + +AC_CHECK_TYPES([struct fs_quota_statv],,,[ +#define _GNU_SOURCE +#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 landlock_path_beneath_attr],,,[#include ]) +AC_CHECK_TYPES([struct landlock_net_port_attr],,,[#include ]) +AC_CHECK_TYPES([struct lsm_ctx],,,[#include ]) +AC_CHECK_TYPES([struct mmsghdr],,,[ +#define _GNU_SOURCE +#include +#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],,,[# 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 +#include +#include +#include +#include +]) + +AC_CHECK_TYPES([struct __kernel_old_timeval, struct __kernel_old_timespec, struct __kernel_timespec, + struct __kernel_old_itimerspec, struct __kernel_itimerspec, + struct __kernel_old_itimerval],,,[#include ]) + +AC_CHECK_TYPES([struct futex_waitv],,,[#include ]) +AC_CHECK_TYPES([struct mount_attr],,,[ +#ifdef HAVE_MOUNT_SETATTR +# include +#elif HAVE_LINUX_MOUNT_H +# include +#endif +]) + +AC_CHECK_TYPES([struct cachestat_range],,,[#include ]) +AC_CHECK_TYPES([struct cachestat],,,[#include ]) + +# Defined in , but include/lapi/mount.h includes */ +AC_CHECK_TYPES([struct mnt_id_req],,,[#include ]) +AC_CHECK_TYPES([struct statmount],,,[#include ]) + +# Tools knobs + +# Bash +AC_ARG_WITH([bash], + [AS_HELP_STRING([--with-bash], + [have the Bourne Again Shell interpreter])], + [with_bash=$withval], + [with_bash=no] +) +if test "x$with_bash" = xyes; then + AC_SUBST([WITH_BASH],["yes"]) +else + AC_SUBST([WITH_BASH],["no"]) +fi + +# Expect +AC_ARG_WITH([expect], + [AS_HELP_STRING([--with-expect], + [have the Tcl/expect library])], + [with_expect=$withval], + [with_expect=no] +) +if test "x$with_expect" = xyes; then + AC_SUBST([WITH_EXPECT],["yes"]) +else + AC_SUBST([WITH_EXPECT],["no"]) +fi + +# Numa +AC_ARG_WITH([numa], + AS_HELP_STRING([--without-numa], + [without numa support]), + [with_numa=$withval], + [with_numa=yes] +) + +# Perl +AC_ARG_WITH([perl], + [AS_HELP_STRING([--with-perl], + [have a perl interpreter])], + [with_perl=$withval], + [with_perl=no] +) +if test "x$with_perl" = xyes; then + AC_SUBST([WITH_PERL],["yes"]) +else + AC_SUBST([WITH_PERL],["no"]) +fi + +# Python +AC_ARG_WITH([python], + [AS_HELP_STRING([--with-python], + [have a python interpreter])], + [with_python=$withval], + [with_python=no] +) +if test "x$with_python" = xyes; then + AC_SUBST([WITH_PYTHON],["yes"]) +else + AC_SUBST([WITH_PYTHON],["no"]) +fi + +# TI RPC +AC_ARG_WITH([tirpc], + AS_HELP_STRING([--without-tirpc], + [without libtirpc support]), + [with_tirpc=$withval], + [with_tirpc=yes] +) +# END tools knobs + +# Testsuites knobs + +AC_ARG_WITH([open-posix-testsuite], + [AS_HELP_STRING([--with-open-posix-testsuite], + [compile and install the open posix testsuite])], + [with_open_posix_testsuite=$withval], + [with_open_posix_testsuite=no] +) + +# Allow setting the directoy, where the open posix testsuite is installed to. +# If nothing is defined, we have to pass our default value to submake +AC_ARG_WITH([open-posix-testdir], + [AS_HELP_STRING([--with-open-posix-testdir=], + [set the directory, where the open posix testsuite will be installed under prefix])], + [], + [ac_configure_args="$ac_configure_args --with-open-posix-testdir=testcases/open_posix_testsuite"] +) + +if test "x$with_open_posix_testsuite" = xyes; then + AC_SUBST([WITH_OPEN_POSIX_TESTSUITE],["yes"]) + AC_CONFIG_SUBDIRS([testcases/open_posix_testsuite]) +else + AC_SUBST([WITH_OPEN_POSIX_TESTSUITE],["no"]) +fi + +# TODO: testcases/realtime requires bash and python. +AC_ARG_WITH([realtime-testsuite], + [AS_HELP_STRING([--with-realtime-testsuite], + [unused, kept for compatibility reason])], + [with_realtime_testsuite=$withval], + [with_realtime_testsuite=no] +) + +if test "x$with_realtime_testsuite" = xyes; then + AC_SUBST([WITH_REALTIME_TESTSUITE],["yes"]) +else + AC_SUBST([WITH_REALTIME_TESTSUITE],["no"]) +fi + +AC_CONFIG_COMMANDS([syscalls.h], [cd ${ac_top_srcdir}/include/lapi/syscalls; ./generate_syscalls.sh ../syscalls.h; cd - >/dev/null]) + +# custom functions +# NOTE: don't create custom functions for simple checks, put them into this file +LTP_CHECK_ACL_SUPPORT +LTP_CHECK_ATOMIC_MEMORY_MODEL +LTP_CHECK_BUILTIN_CLEAR_CACHE +LTP_CHECK_CAPABILITY_SUPPORT +LTP_CHECK_CC_WARN_OLDSTYLE +LTP_CHECK_CRYPTO +LTP_CHECK_FORTIFY_SOURCE +LTP_CHECK_KERNEL_DEVEL +LTP_CHECK_KEYUTILS_SUPPORT +LTP_CHECK_LIBMNL +LTP_CHECK_SELINUX +LTP_CHECK_SYNC_ADD_AND_FETCH +LTP_CHECK_SYSCALL_EVENTFD +LTP_CHECK_SYSCALL_FCNTL +LTP_CHECK_FSVERITY + +AX_CHECK_COMPILE_FLAG([-no-pie], [LTP_CFLAGS_NOPIE=1]) +AX_CHECK_COMPILE_FLAG([-ffixed-ebp], [LTP_CFLAGS_FFIXED_EBP=1]) +AC_SUBST([LTP_CFLAGS_NOPIE]) +AC_SUBST([LTP_CFLAGS_FFIXED_EBP]) + +if test "x$with_numa" = xyes; then + LTP_CHECK_SYSCALL_NUMA + numa_error_msg="test requires libnuma development packages with LIBNUMA_API_VERSION >= 2" +else + numa_error_msg="NUMA support was disabled during build" +fi +AC_DEFINE_UNQUOTED(NUMA_ERROR_MSG, ["$numa_error_msg"], [Error message when no NUMA support]) + + +LTP_CHECK_SYSCALL_SIGNALFD +LTP_CHECK_SYSCALL_UTIMENSAT +LTP_CHECK_TASKSTATS +test "x$with_tirpc" = xyes && LTP_CHECK_TIRPC +LTP_DETECT_HOST_CPU + +AC_MSG_CHECKING([whether linker can handle KVM payloads]) +ltp_backup_ldflags="$LDFLAGS" +ltp_backup_flags="$[]_AC_LANG_PREFIX[]FLAGS" +LDFLAGS="-T ${srcdir}/testcases/kernel/kvm/linker/${HOST_CPU}.lds" +_AC_LANG_PREFIX[]FLAGS= +AC_LINK_IFELSE([AC_LANG_PROGRAM()], + [ + AC_MSG_RESULT([yes]) + AC_SUBST([WITH_KVM_TESTSUITE],["yes"]) + have_kvm=yes + ], + [ + AC_MSG_RESULT([no]) + AC_SUBST([WITH_KVM_TESTSUITE],["no"]) + have_kvm=no + ]) +_AC_LANG_PREFIX[]FLAGS="$ltp_backup_flags" +LDFLAGS="$ltp_backup_ldflags" + +AC_OUTPUT + +cat << EOF + +TESTSUITES +kernel modules: $WITH_MODULES (kernel: $LINUX_VERSION) +KVM testsuite: $have_kvm +open posix testsuite: ${with_open_posix_testsuite:-no} +TI-RPC testsuite: ${with_tirpc:-yes} + +LIBRARIES +keyutils: ${have_keyutils:-yes} +libacl: ${have_libacl:-no} +libaio: ${have_libaio:-no} (aio: ${have_aio:-no}) +libcap: $cap_libs (newer: ${has_newer_libcap:-no}) +libcrypto: ${have_libcrypto:-no} (sha: ${have_sha:-no}) +libmnl: ${have_libmnl:-yes} +libnuma: ${have_libnuma:-no} (headers: ${have_numa_headers:-yes}, v2 headers: ${have_numa_headers_v2:-no}) +libtirpc: ${have_libtirpc:-no} +glibc SUN-RPC: ${have_rpc_glibc:-no} +EOF + +if test "x$with_realtime_testsuite" = xyes; then + AC_MSG_WARN([--with-realtime-testsuite has no effect and is kept for compatibilty reason. It will be removed in the future.]) +fi diff --git a/ltp/doc/.gitignore b/ltp/doc/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2b05a1ec368573778cfe7ee6a1cb5d6c5ecb0b5a --- /dev/null +++ b/ltp/doc/.gitignore @@ -0,0 +1,5 @@ +html/ +build/ +_static/syscalls.rst +_static/tests.rst +syscalls.tbl diff --git a/ltp/doc/Makefile b/ltp/doc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3123b1cd7a1568d2c7783c28a3d42cb313253e3c --- /dev/null +++ b/ltp/doc/Makefile @@ -0,0 +1,37 @@ +# Copyright (c) Linux Test Project, 2024-2025 +# SPDX-License-Identifier: GPL-2.0-or-later + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk + +PYTHON := python3 +VENV_DIR := .venv + +# only fish and bash/zsh supported +VENV_CMD := if [ "x${FISH_VERSION}" != "x" ]; then . $(VENV_DIR)/bin/activate.fish; else . $(VENV_DIR)/bin/activate; fi + +RUN_VENV := if [ -d $(VENV_DIR) ]; then $(VENV_CMD); fi + +$(VENV_DIR): + $(PYTHON) -m virtualenv $(VENV_DIR) + $(VENV_CMD) && pip install -r requirements.txt + +.PHONY: setup +setup: $(VENV_DIR) + +${abs_top_builddir}/metadata/ltp.json: + $(MAKE) -C ${abs_top_builddir}/metadata + +all: ${abs_top_builddir}/metadata/ltp.json + $(RUN_VENV); sphinx-build -v -b html . html + +spelling: + $(RUN_VENV); sphinx-build -b spelling -d build/doctree . build/spelling + +clean: + rm -rf html/ build/ _static/syscalls.rst _static/tests.rst syscalls.tbl \ + ${abs_top_builddir}/metadata/ltp.json + +distclean: clean + rm -rf $(VENV_DIR) diff --git a/ltp/doc/_static/custom.css b/ltp/doc/_static/custom.css new file mode 100644 index 0000000000000000000000000000000000000000..c5816a55346fa28416377375bc91966780075dc3 --- /dev/null +++ b/ltp/doc/_static/custom.css @@ -0,0 +1,9 @@ +/* set multiline tables cells */ +.wy-table-responsive table td { + white-space: normal; +} + +/* remove margin for multiline cells */ +.rst-content table td div.line-block { + margin-bottom: 0; +} diff --git a/ltp/doc/conf.py b/ltp/doc/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..cadfeb2b3d74c63741a28a3df5f8e1fd8a8d5582 --- /dev/null +++ b/ltp/doc/conf.py @@ -0,0 +1,539 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +import os +import re +import json +import socket +import urllib.request +import sphinx + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'Linux Test Project' +copyright = '2024, Linux Test Project' +author = 'Linux Test Project' +release = '1.0' +ltp_repo = 'https://github.com/linux-test-project/ltp' +ltp_repo_base_url = f"{ltp_repo}/tree/master" + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'linuxdoc.rstKernelDoc', + 'sphinxcontrib.spelling', + 'sphinx.ext.autosectionlabel', + 'sphinx.ext.extlinks', +] + +exclude_patterns = ["html*", '_static*'] +extlinks = { + 'repo': (f'{ltp_repo}/%s', '%s'), + 'master': (f'{ltp_repo}/blob/master/%s', '%s'), + 'git_man': ('https://git-scm.com/docs/git-%s', 'git %s'), + # TODO: allow 2nd parameter to show page description instead of plain URL + 'kernel_doc': ('https://docs.kernel.org/%s.html', 'https://docs.kernel.org/%s.html'), + 'kernel_tree': ('https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/%s', '%s'), +} + +spelling_lang = "en_US" +spelling_warning = True +spelling_exclude_patterns = ['users/stats.rst'] +spelling_word_list_filename = "spelling_wordlist" + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'sphinx_rtd_theme' +html_static_path = ['_static'] + + +def generate_syscalls_stats(_): + """ + Generate statistics for syscalls. We fetch the syscalls list from the kernel + sources, then we compare it with testcases/kernel/syscalls folder and + generate a file that is included in the statistics documentation section. + """ + output = '_static/syscalls.rst' + + # sometimes checking testcases/kernel/syscalls file names are not enough, + # because in some cases (i.e. io_ring) syscalls are tested, but they are + # part of a more complex scenario. In the following list, we define syscalls + # which we know they are 100% tested already. + ltp_syscalls_path = "testcases/kernel/syscalls" + white_list = { + 'bpf': f'{ltp_syscalls_path}/bpf', + 'epoll_pwait2': f'{ltp_syscalls_path}/epoll_pwait', + 'fadvise64': f'{ltp_syscalls_path}/fadvise', + 'fanotify_init': f'{ltp_syscalls_path}/fanotify', + 'fanotify_mark': f'{ltp_syscalls_path}/fanotify', + 'futex': f'{ltp_syscalls_path}/futex', + 'getdents64': f'{ltp_syscalls_path}/gettdents', + 'inotify_add_watch': f'{ltp_syscalls_path}/inotify', + 'inotify_init': f'{ltp_syscalls_path}/inotify', + 'inotify_rm_watch': f'{ltp_syscalls_path}/inotify', + 'io_uring_enter': f'{ltp_syscalls_path}/io_uring', + 'io_uring_register': f'{ltp_syscalls_path}/io_uring', + 'io_uring_setup': f'{ltp_syscalls_path}/io_uring', + 'landlock_add_rule': f'{ltp_syscalls_path}/landlock', + 'landlock_create_ruleset': f'{ltp_syscalls_path}/landlock', + 'landlock_restrict_self': f'{ltp_syscalls_path}/landlock', + 'lsetxattr': f'{ltp_syscalls_path}/lgetxattr', + 'newfstatat': f'{ltp_syscalls_path}/fstatat', + 'pkey_alloc': f'{ltp_syscalls_path}/pkeys', + 'pkey_free': f'{ltp_syscalls_path}/pkeys', + 'pkey_mprotect': f'{ltp_syscalls_path}/pkeys', + 'prlimit64': f'{ltp_syscalls_path}/getrlimit', + 'pread64': f'{ltp_syscalls_path}/pread', + 'pselect6': f'{ltp_syscalls_path}/pselect', + 'pwrite64': f'{ltp_syscalls_path}/pwrite', + 'quotactl_fd': f'{ltp_syscalls_path}/quotactl', + 'rt_sigpending': f'{ltp_syscalls_path}/sigpending', + 'semtimedop': f'{ltp_syscalls_path}/ipc/semop', + 'sethostname': f'{ltp_syscalls_path}/sethostname' + } + + # populate with not implemented, reserved, unmaintained syscalls defined + # inside the syscalls file + black_list = [ + '_newselect', + '_sysctl', + 'afs_syscall', + 'cachectl', + 'create_module', + 'get_kernel_syms', + 'getmsg', + 'getpmsg', + 'mq_getsetattr', + 'nfsservctl', + 'putmsg', + 'putpmsg', + 'query_module', + 'reserved177', + 'reserved193', + 'restart_syscall', + 'rseq', + 'sysmips', + 'vserver', + ] + + # fetch syscalls file + syscalls_url = "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/arch/mips/kernel/syscalls" + error = False + try: + socket.setdefaulttimeout(3) + + # kernel.org doesn't always allow to download syscalls file, so we need + # to emulate a different client in order to download it. Browser + # emulation might fail due to captcha request and for this reason we + # use the 'curl' command instead + req = urllib.request.Request( + f"{syscalls_url}/syscall_n64.tbl", + headers={'User-Agent': 'curl/8.6.0'}) + + with urllib.request.urlopen(req) as response: + with open("syscalls.tbl", 'wb') as out_file: + out_file.write(response.read()) + except urllib.error.URLError as err: + error = True + logger = sphinx.util.logging.getLogger(__name__) + msg = f"Can't download syscall_n64.tbl from kernel sources ({err})" + logger.warning(msg) + + with open(output, 'w+', encoding='utf-8') as stats: + stats.write(f".. warning::\n\n {msg}") + + if error: + return + + text = [ + 'Syscalls\n', + '--------\n\n', + ] + + # collect all available kernel syscalls + regexp = re.compile(r'\d+\s+n64\s+(?P\w+)\s+\w+') + ker_syscalls = [] + with open("syscalls.tbl", 'r', encoding='utf-8') as data: + for line in data: + match = regexp.search(line) + if not match: + continue + + ker_syscalls.append(match.group('syscall')) + + # collect all LTP tested syscalls + name_patterns = [ + re.compile(r'(?P[a-zA-Z_]+[^_])\d{2}\.c'), + re.compile(r'(?P[a-zA-Z_]+[1-9])_\d{2}\.c'), + ] + ltp_syscalls = {} + for dirpath, _, files in os.walk(f'../{ltp_syscalls_path}'): + for myfile in files: + match = None + for pattern in name_patterns: + match = pattern.search(myfile) + if match: + break + + if not match: + continue + + # we need to use relative path from the project root + path = dirpath.replace('../', '') + name = match.group('name') + + ltp_syscalls[name] = f'{ltp_repo_base_url}/{path}' + + # compare kernel syscalls with LTP tested syscalls + syscalls = {} + for kersc in ker_syscalls: + if kersc in black_list: + continue + + if kersc not in syscalls: + if kersc in white_list: + syscalls[kersc] = f'{ltp_repo_base_url}/{white_list[kersc]}' + continue + + syscalls[kersc] = None + + for ltpsc, ltpsp in ltp_syscalls.items(): + if ltpsc == kersc: + syscalls[kersc] = ltpsp + + # generate the statistics file + tested_syscalls = [key for key, val in syscalls.items() if val is not None] + text.append('syscalls which are tested under ' + ':master:`testcases/kernel/syscalls`:\n\n') + text.append(f'* kernel syscalls: {len(ker_syscalls)}\n') + text.append(f'* tested syscalls: {len(tested_syscalls)}\n\n') + + # create tested/untested syscalls table + index_tested = 0 + table_tested = [ + 'Tested syscalls\n', + '~~~~~~~~~~~~~~~\n\n', + '.. list-table::\n', + ' :header-rows: 0\n\n', + ] + + index_untest = 0 + table_untest = [ + 'Untested syscalls\n', + '~~~~~~~~~~~~~~~~~\n\n', + '.. list-table::\n', + ' :header-rows: 0\n\n', + ] + + max_columns = 3 + + for sysname, path in syscalls.items(): + if path is not None: + if (index_tested % max_columns) == 0: + table_tested.append(f' * - `{sysname} <{path}>`_\n') + else: + table_tested.append(f' - `{sysname} <{path}>`_\n') + + index_tested += 1 + else: + if (index_untest % max_columns) == 0: + table_untest.append(f' * - {sysname}\n') + else: + table_untest.append(f' - {sysname}\n') + + index_untest += 1 + + left = index_tested % max_columns + if left > 0: + for _ in range(0, max_columns - left): + table_tested.append(' -\n') + + left = index_untest % max_columns + if left > 0: + for _ in range(0, max_columns - left): + table_untest.append(' -\n') + + text.extend(table_tested) + text.append('\n') + text.extend(table_untest) + + # write the file + with open(output, 'w+', encoding='utf-8') as stats: + stats.writelines(text) + + +def _generate_tags_table(tags): + """ + Generate the tags table from tags hash. + """ + supported_url_ref = { + "linux-git": "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=", + "linux-stable-git": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=", + "glibc-git": "https://sourceware.org/git/?p=glibc.git;a=commit;h=", + "musl-git": "https://git.musl-libc.org/cgit/musl/commit/src/linux/clone.c?id=", + "CVE": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-", + } + + table = [ + '.. list-table::', + ' :header-rows: 1', + '', + ' * - Tag', + ' - Info', + ] + + for tag in tags: + tag_key = tag[0] + tag_val = tag[1] + + tag_url = supported_url_ref.get(tag_key, None) + if tag_url: + tag_val = f'`{tag_val} <{tag_url}{tag_val}>`_' + + table.extend([ + f' * - :c:struct:`{tag_key} `', + f' - {tag_val}', + ]) + + return table + + +def _generate_options_table(options): + """ + Generate the options table from the options hash. + """ + table = [ + '.. list-table::', + ' :header-rows: 1', + '', + ' * - Option', + ' - Description', + ] + + for opt in options: + if not isinstance(opt, list): + table.clear() + break + + key = opt[0] + val = opt[2] + + if key.endswith(':'): + key = key[:-1] if key.endswith(':') else key + + key = f'-{key}' + + table.extend([ + f' * - {key}', + f' - {val}', + ]) + + return table + + +def _generate_table_cell(key, values): + """ + Generate a cell which can be multiline if value is a list. + """ + cell = [] + key = f' :c:struct:`{key} `' + + if len(values) > 1: + cell.extend([ + f' * - {key}', + f' - | {values[0]}', + ]) + + for item in values[1:]: + cell.append(f' | {item}') + else: + cell.extend([ + f' * - {key}', + f' - {values[0]}', + ]) + + return cell + + +def _generate_setup_table(keys): + """ + Generate the table with test setup configuration. + """ + exclude = [ + # following keys are already handled + 'options', + 'runtime', + 'timeout', + 'fname', + 'doc', + # following keys don't need to be shown + 'child_needs_reinit', + 'needs_checkpoints', + 'forks_child', + 'tags', + ] + my_keys = {k: v for k, v in keys.items() if k not in exclude} + if len(my_keys) == 0: + return [] + + table = [ + '.. list-table::', + ' :header-rows: 1', + '', + ' * - Key', + ' - Value', + ] + + values = [] + + for key, value in my_keys.items(): + if key in exclude: + continue + + values.clear() + + if key == 'ulimit': + for item in value: + values.append(f'{item[0]} : {item[1]}') + elif key == 'hugepages': + if len(value) == 1: + values.append(f'{value[0]}') + else: + values.append(f'{value[0]}, {value[1]}') + elif key == 'filesystems': + for params in value: + for pkey, pval in params.items(): + if pkey == "type": + values.append(f"- {pval}") + else: + values.append(f" {pkey}: {pval}") + elif key == "save_restore": + for item in value: + values.append(item[0]) + else: + if isinstance(value, list): + values.extend(value) + else: + values.append(value) + + if values: + table.extend(_generate_table_cell(key, values)) + + return table + + +def generate_test_catalog(_): + """ + Generate the test catalog from ltp.json metadata file. + """ + output = '_static/tests.rst' + metadata_file = '../metadata/ltp.json' + text = [ + '.. warning::', + ' The following catalog has been generated using LTP metadata', + ' which is including only tests using the new :ref:`LTP C API`.', + '' + ] + + metadata = None + with open(metadata_file, 'r', encoding='utf-8') as data: + metadata = json.load(data) + + timeout_def = metadata['defaults']['timeout'] + regexp = re.compile(r'^\[([A-Za-z][\w\W]+)\]') + + for test_name, conf in sorted(metadata['tests'].items()): + text.extend([ + f'{test_name}', + len(test_name) * '-' + ]) + + # source url location + test_fname = conf.get('fname', None) + if test_fname: + text.extend([ + '', + f"`source <{ltp_repo_base_url}/{test_fname}>`__", + '' + ]) + + # test description + desc = conf.get('doc', None) + if desc: + desc_text = [] + for line in desc: + line = regexp.sub(r'**\1**', line) + desc_text.append(line) + + text.extend([ + '\n'.join(desc_text), + ]) + + # timeout information + timeout = conf.get('timeout', None) + if timeout: + text.extend([ + '', + f'Test timeout is {timeout} seconds.', + ]) + else: + text.extend([ + '', + f'Test timeout defaults is {timeout_def} seconds.', + ]) + + # runtime information + runtime = conf.get('runtime', None) + if runtime: + text.extend([ + f'Maximum runtime is {runtime} seconds.', + '' + ]) + else: + text.append('') + + # options information + opts = conf.get('options', None) + if opts: + text.append('') + text.extend(_generate_options_table(opts)) + text.append('') + + # tags information + tags = conf.get('tags', None) + if tags: + text.append('') + text.extend(_generate_tags_table(tags)) + text.append('') + + # parse struct tst_test content + text.append('') + text.extend(_generate_setup_table(conf)) + text.append('') + + # small separator between tests + text.extend([ + '', + '.. raw:: html', + '', + '
', + '', + ]) + + with open(output, 'w+', encoding='utf-8') as new_tests: + new_tests.write('\n'.join(text)) + + +def setup(app): + """ + Setup the current documentation, using self generated data and graphics + customizations. + """ + app.add_css_file('custom.css') + app.connect('builder-inited', generate_syscalls_stats) + app.connect('builder-inited', generate_test_catalog) diff --git a/ltp/doc/developers/api_c_tests.rst b/ltp/doc/developers/api_c_tests.rst new file mode 100644 index 0000000000000000000000000000000000000000..d146459818904b6be95f813c1a8be9f7a18d092b --- /dev/null +++ b/ltp/doc/developers/api_c_tests.rst @@ -0,0 +1,56 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later +.. Copyright (c) Linux Test Project, 2024 + +.. Include headers in this file with: +.. .. kernel-doc:: ../../include/tst_test.h + +LTP C API +========= + +Core LTP API +------------ +.. kernel-doc:: ../../include/tst_res_flags.h +.. kernel-doc:: ../../include/tst_test.h + +Test macros +----------- +.. kernel-doc:: ../../include/tst_test_macros.h + +Capabilities +------------ +.. kernel-doc:: ../../include/tst_capability.h + +Checkpoints +----------- + +.. kernel-doc:: ../../include/tst_checkpoint.h + +Crypto +------ +.. kernel-doc:: ../../include/tst_crypto.h +.. kernel-doc:: ../../include/tst_af_alg.h + +Guarded buffers +--------------- +.. kernel-doc:: ../../include/tst_buffers.h + +Kernel +------ +.. kernel-doc:: ../../include/tst_kernel.h + +NUMA +---- +.. kernel-doc:: ../../include/tst_numa.h + +Option parsing +-------------- + +.. kernel-doc:: ../../include/tst_parse.h + +Temporary directory +------------------- +.. kernel-doc:: ../../include/tst_tmpdir.h + +LTP libraries +------------- +.. kernel-doc:: ../../include/libswap.h diff --git a/ltp/doc/developers/api_kvm_tests.rst b/ltp/doc/developers/api_kvm_tests.rst new file mode 100644 index 0000000000000000000000000000000000000000..5ec3fc3a4db82000d55203fac7945508e482a108 --- /dev/null +++ b/ltp/doc/developers/api_kvm_tests.rst @@ -0,0 +1,7 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +.. Include headers in this file with: +.. .. kernel-doc:: ../../include/tst_test.h + +Developing using KVM API +======================== diff --git a/ltp/doc/developers/api_network_tests.rst b/ltp/doc/developers/api_network_tests.rst new file mode 100644 index 0000000000000000000000000000000000000000..3e487d7f2e9d2f9f5d49a51287de32980ea9cfd7 --- /dev/null +++ b/ltp/doc/developers/api_network_tests.rst @@ -0,0 +1,7 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +.. Include headers in this file with: +.. .. kernel-doc:: ../../include/tst_test.h + +Developing using network API +============================ diff --git a/ltp/doc/developers/api_shell_tests.rst b/ltp/doc/developers/api_shell_tests.rst new file mode 100644 index 0000000000000000000000000000000000000000..b6e8560d9d13b0cfdb3f0a7f1974c8c494111f1f --- /dev/null +++ b/ltp/doc/developers/api_shell_tests.rst @@ -0,0 +1,4 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +LTP shell API +============= diff --git a/ltp/doc/developers/build_system.rst b/ltp/doc/developers/build_system.rst new file mode 100644 index 0000000000000000000000000000000000000000..8dca5720795f3b7a2b9c9f1650852f4049cf1cab --- /dev/null +++ b/ltp/doc/developers/build_system.rst @@ -0,0 +1,209 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Build system +============ + +The following document briefly describes the steps and methodologies used for +the new and improved Makefile system. + +The Problem +----------- + +The problem with the old Makefile system is that it was very difficult to +maintain and it lacked any sense of formal structure, thus developing for LTP +and including new targets was more difficult than it should have been +(maintenance). Furthermore, proper option-based cross-compilation was +impossible due to the fact that the Makefiles didn't support a prefixing +system, and the appropriate implicit / static rules hadn't been configured to +compile into multiple object directories for out-of-tree build support (ease of +use / functionality). Finally, there wasn't a means to setup dependencies +between components, such that if a component required ``libltp.a`` in order to +compile, it would go off and compile ``libltp.a`` first (ease of use). + +These items needed to be fixed to reduce maintenance nightmares for the +development community contributing to LTP, and the project maintainers. + +Design +------ + +The system was designed such that including a single GNU Makefile compatible +set in each new directory component is all that's essentially required to +build the system. + +Say you had a directory like the following (with ``.c`` files in them which +directly tie into applications, e.g. baz.c -> baz): + +.. code-block:: + + .../foo/ + |--> Makefile + | + --> bar/ + | + --> Makefile + | + --> baz.c + +.. code-block:: make + :caption: .../foo/Makefile + + # SPDX-License-Identifier: GPL-2.0-or-later + + top_srcdir ?= .. + + include $(top_srcdir)/include/mk/env_pre.mk + include $(top_srcdir)/include/mk/generic_trunk_target.mk + +.. code-block:: make + :caption: .../foo/bar/Makefile + + # SPDX-License-Identifier: GPL-2.0-or-later + + top_srcdir ?= ../.. + + include $(top_srcdir)/include/mk/env_pre.mk + include $(top_srcdir)/include/mk/generic_leaf_target.mk + +Kernel Modules +-------------- + +Some of the tests need to build kernel modules, happily LTP has +infrastructure for this. + +.. code-block:: make + + ifneq ($(KERNELRELEASE),) + + obj-m := module01.o + + else + + top_srcdir ?= ../../../.. + include $(top_srcdir)/include/mk/testcases.mk + + REQ_VERSION_MAJOR := 2 + REQ_VERSION_PATCH := 6 + MAKE_TARGETS := test01 test02 module01.ko + + include $(top_srcdir)/include/mk/module.mk + include $(top_srcdir)/include/mk/generic_leaf_target.mk + + endif + +This is a Makefile example that allows you to build kernel modules inside LTP. +The prerequisites for the build are detected by the ``configure`` script. + +The ``REQ_VERSION_MAJOR`` and ``REQ_VERSION_PATCH`` describe minimal kernel +version for which the build system tries to build the module. + +The build system is also forward compatible with changes in Linux kernel +internal API so that, if module fails to build, the failure is ignored both on +build and installation. If the userspace counterpart of the test fails to load +the module because the file does not exists, the test is skipped. + +Note the ``ifneq($(KERNELRELEASE),)``. The reason it exists, it is that the +Makefile is executed twice: once by LTP build system and once by kernel kbuild, +see :kernel_doc:`kbuild/modules` in the Linux kernel documentation for details +on external module build. + +Make Rules and Make Variables +----------------------------- + +When using make rules, avoid writing ad hoc rules like: + +.. code-block:: make + + [prog]: [dependencies] + cc -I../../include $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LDLIBS) \ + -o [prog] [dependencies] + +This makes cross-compilation and determinism difficult, if not impossible. +Besides, implicit rules are your friends and as long as you use ``MAKEOPTS=;`` +in the top-level caller (or do ``$(subst r,$(MAKEOPTS)``) to remove ``-r``), +the compile will complete successfully, assuming all other prerequisites have +been fulfilled (libraries, headers, etc). + +.. list-table:: + :header-rows: 1 + + * - Variable + - Explanation + + * - $(AR) + - The library archiver + + * - $(CC) + - The system C compiler + + * - $(CCP) + - The system C preprocessor + + * - $(CFLAGS) + - C compiler flags + + * - $(CPPFLAGS) + - Preprocessor flags, e.g. ``-I`` arguments + + * - $(DEBUG_CFLAGS) + - Debug flags to pass to ``$(CC)``, ``-g``, etc + + * - $(KVM_LD) + - Special linker for wrapping KVM payload binaries into linkable object + files. Defaults to ``$(LD)``. Change this variable if the KVM Makefile + fails to build files named ``*-payload.o`` + + * - $(LD) + - The system linker (typically ``$(CC)``, but not necessarily) + + * - $(LDFLAGS) + - What to pass in to the linker, including ``-L`` arguments and other ld + arguments, apart from ``-l`` library includes (see ``$(LDLIBS)``). + This should be done in the ``$(CC)`` args passing style when + ``LD := $(CC)``, e.g. ``-Wl,-foo``, as opposed to ``-foo`` + + * - $(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 fstrict-aliasing optimization + bugs in the tree optimizer. Search for **fstrict-aliasing optimization + bug** with your favorite search engine. + + Examples of more recent bugs: tree-optimization/17510 + and tree-optimization/39100. + + Various bugs have occurred in the past due to buggy logic in the + tree-optimization portion of the gcc compiler, from 3.3.x to 4.4. + + * - $(RANLIB) + - What to run after archiving a library + + * - $(WCFLAGS) + - Warning flags to pass to ``$(CC)``, e.g. ``-Werror``, ``-Wall``, etc. + +Make System Variables +--------------------- + +A series of variables are used within the make system that direct what actions +need to be taken. Rather than listing the variables here, please refer to the +comments contained in :master:`include/mk/env_pre.mk`. + +Guidelines and Recommendations +------------------------------ + +Of course, GNU Make manual is the key to understand the Make system, but +following manuals are probably the most important: + +* `Implicit Rules `_ +* `Variables and Expansion `_ +* `Origin Use `_ +* `VPath Use `_ + +.. warning:: + + Rebuild from scratch before committing anything in the build system. diff --git a/ltp/doc/developers/debugging.rst b/ltp/doc/developers/debugging.rst new file mode 100644 index 0000000000000000000000000000000000000000..181e5b09638fe3e206d7f5a9547959cbc03071a7 --- /dev/null +++ b/ltp/doc/developers/debugging.rst @@ -0,0 +1,23 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Debugging +========= + +This section explains some tricks which can be used to debug test binaries. + +Debug messages +-------------- + +The LTP framework supports ``TDEBUG`` flag test debug messages. These +messages can be enabled using the ``-D`` parameter or setting ``LTP_ENABLE_DEBUG=1`` +environment variable (see :doc:`../users/setup_tests`). + +Tracing and debugging syscalls +------------------------------ + +The new test library runs the actual test (i.e. the ``test()`` function) in a +forked process. To get stack trace of a crashing test in ``gdb`` it's needed to +`set follow-fork-mode child `_. + +To trace the test, please use ``strace -f`` to enable tracing also for the +forked processes. diff --git a/ltp/doc/developers/documentation.rst b/ltp/doc/developers/documentation.rst new file mode 100644 index 0000000000000000000000000000000000000000..abb8ac8ee25f1a46cf5c68a1c3b2186d47411a8e --- /dev/null +++ b/ltp/doc/developers/documentation.rst @@ -0,0 +1,55 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Documentation +============= + +This section explains how to use and develop the LTP documentation. The current +documentation format is written using +`reStructedText `_ +and it's built on top of `Sphinx `_. + +Building documentation +~~~~~~~~~~~~~~~~~~~~~~ + +Before building, make sure you have python3 ``virtualenv`` module installed. + +.. code-block:: bash + + # run configure to be able to compile doc dependencies in metadata/ + make autotools + ./configure + cd doc + + # prepare virtual environment + python3 -m virtualenv .venv + . .venv/bin/activate + pip install -r requirements.txt + + # build documentation + make + +Once the procedure has been completed, documentation will be visible at +``doc/html/index.html``. + +.. warning:: + + Documentation requires ``Python >= 3.6``. + The current :master:`.readthedocs.yml` workflow is using ``Python 3.12``, + it is tested in GitHub Actions :master:`.github/workflows/ci-sphinx-doc.yml`. + +Validating spelling +~~~~~~~~~~~~~~~~~~~ + +To check documentation words spelling, we provide support for +`aspell `_, so make sure that it's installed. The +documentation can be tested via ``make spelling`` command. Output will be +visible in the ``doc/build`` folder and, if any error will be found, a warning +message will be shown. + +C API documentation +~~~~~~~~~~~~~~~~~~~ + +The C API documentation is generated from headers using +`kernel-doc `_ +syntax which is supported by Sphinx via +`linuxdoc `_ extension. diff --git a/ltp/doc/developers/ltp_library.rst b/ltp/doc/developers/ltp_library.rst new file mode 100644 index 0000000000000000000000000000000000000000..f76cbb75e69aa2b6e8c8cf4666df9cfbd6644d74 --- /dev/null +++ b/ltp/doc/developers/ltp_library.rst @@ -0,0 +1,45 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +LTP Library guidelines +====================== + +General Rules +------------- + +For extending the LTP library API it applies the same general rules as +for :doc:`writing tests <../developers/writing_tests>` +(with strong focus on readability and simplicity), plus: + +#. LTP library tests must go inside :master:`lib/newlib_tests` directory +#. LTP documentation has to be updated according to API changes +#. Do not add new API functions to the old API. Add new functions to + ``tst_.[ch]`` files. + +Shell API +--------- + +API source code is in :master:`testcases/lib/tst_test.sh`, +:master:`testcases/lib/tst_security.sh` and :master:`testcases/lib/tst_net.sh`. + +Changes in the shell API should not introduce uncommon dependencies +(use basic commands installed everywhere by default). + +Shell libraries +~~~~~~~~~~~~~~~ + +Aside from shell API libraries in :master:`testcases/lib` directory, it's +worth putting common code for a group of tests into a shell library. +The filename should end with ``_lib.sh`` and the library should load +``tst_test.sh`` or ``tst_net.sh``. + +Shell libraries should have conditional expansion for ``TST_SETUP`` or +``TST_CLEANUP``, to avoid surprises when test specific setup/cleanup function is +redefined by shell library. + +.. code-block:: bash + + # ipsec_lib.sh + # SPDX-License-Identifier: GPL-2.0-or-later + TST_SETUP="${TST_SETUP:-ipsec_lib_setup}" + ... + . tst_test.sh diff --git a/ltp/doc/developers/setup_mailinglist.rst b/ltp/doc/developers/setup_mailinglist.rst new file mode 100644 index 0000000000000000000000000000000000000000..1eee0ae9f9f9dfbf058cdd12392f456446cb831a --- /dev/null +++ b/ltp/doc/developers/setup_mailinglist.rst @@ -0,0 +1,50 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Setting up the Mailing list +=========================== + +Before using ``git send-email``, you need to set up your email client to send +emails from the command line. This typically involves configuring an SMTP server +and authentication details. + +Open a terminal and configure Git with your email settings using the following +commands: + +.. code-block:: bash + + git config --global sendemail.from "Your Name " + git config --global sendemail.smtpserver "smtp.example.com" + git config --global sendemail.smtpuser "your_email@example.com" + git config --global sendemail.smtpserverport 587 + git config --global sendemail.smtpencryption tls + +Replace ``smtp.example.com`` with the SMTP server address provided by your email +provider. Replace ``your_email@example.com`` with your email address. Adjust the +SMTP port and encryption settings according to your email provider's +requirements. + +To test the configuration you can use ``--dry-run`` parameter. + +.. code-block:: bash + + git send-email --dry-run --to "ltp@lists.linux.it" --subject "Test Email" --body "This is a test email." HEAD^ + +Depending on your SMTP server's configuration, you may need to authenticate +before sending emails. If required, configure authentication settings using: + +.. code-block:: bash + + git config --global sendemail.smtpuser "your_email@example.com" + git config --global sendemail.smtppass "your_password" + +Replace ``your_email@example.com`` with your email address and ``your_password`` +with your email account password. + +For any corner case, please take a look at the +`email + git `_ documentation. + +.. note:: + + This method still works in most of the cases, but nowadays we often + require to setup a two factor authentication. If this is the case, please + consider setting up Git accordingly. diff --git a/ltp/doc/developers/test_case_tutorial.rst b/ltp/doc/developers/test_case_tutorial.rst new file mode 100644 index 0000000000000000000000000000000000000000..bc67d15c0a35b2e56e955575b89b164de29932f5 --- /dev/null +++ b/ltp/doc/developers/test_case_tutorial.rst @@ -0,0 +1,1034 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Test case tutorial +================== + +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 +others not so much. If you find an exercise is leading you off at too much of +a tangent, just leave it for later and move on. + +LTP tests can be written in C or Shell script. This tutorial is **only for tests +written in C** using the new LTP test API. Note that while we go into some +detail on using Git, this is not intended as a canonical or complete guide +for Git. + +Assumptions & Feedback +---------------------- + +We assume the reader is familiar with C, Git and common Unix/Linux/GNU tools +and has some general knowledge of Operating Systems. Experienced Linux +developers may find it too verbose while people new to system level Linux +development may find it overwhelming. + +Comments and feedback are welcome, please direct them to the Mailing list. + +Getting Started +--------------- + +First of all, make sure you have a copy of LTP in the current folder +and we recommended cloning the Linux kernel repository for reference, this +guide will refer to files and directories. + +.. code-block:: bash + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + +There are a number of other repositories which are useful for reference as +well, including the GNU C library ``glibc`` and the alternative C library +``musl``. Some system calls are partially or even entirely implemented in user +land as part of the standard C library. So in these cases, the C library is an +important reference. ``glibc`` is the most common C library for Linux, however +``musl`` is generally easier to understand. + +How system calls are implemented varies from one architecture to another and +across kernel and C library versions. To find out whether a system call is +actually accessing the kernel (whether it is actually a system call) on any +given machine you can use the ``strace`` utility. This intercepts system calls +made by an executable and prints them. We will use this later in the tutorial. + +Choose a System Call to test +---------------------------- + +We will use the ``statx()`` system call, to provide a concrete example of a +test. At the time of writing there is no test for this call which was +introduced in Linux kernel version 4.11. + +Linux system call specific tests are primarily contained in +:master:`testcases/kernel/syscalls`, but you should also :git_man:`grep` the +entire LTP repository to check for any existing usages of a system call. + +One way to find a system call which is not currently tested by the LTP is to +look at :kernel_tree:`include/linux/syscalls.h` in the Linux kernel tree. + +Something the LTP excels to ensure bug-fixes are back ported to +maintenance releases, so targeting a specific regression is another +option. + +Find an untested System call +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Try to find an untested system call which has a manual page (i.e. ``man +syscall`` produces a result). It is a good idea to Git-clone the latest kernel +man-pages repository. + +.. code-block:: bash + + git clone git://git.kernel.org/pub/scm/docs/man-pages/man-pages.git + +At the time of writing, the difference between the latest man-pages release and +the ``HEAD`` of the repository (usually the latest commit) is well over 100 +commits. This represents about 9 weeks of changes. If you are using a stable +Linux distribution, your man-pages package may well be years old. So as with +the kernel, it is best to have the Git repository as a reference. + +You could also find a system call with untested parameters or use whatever it +is you are planning to use the LTP for. + +Create the test skeleton +------------------------ + +I shall call my test ``statx01.c``, by the time you read this that file name +will probably be taken, so increment the number in the file name as +appropriate or replace ``statx`` with the system call in the chosen exercise. + +.. code-block:: bash + + mkdir testcases/kernel/syscalls/statx + cd testcases/kernel/syscalls/statx + echo statx >> .gitignore + +Next open ``statx01.c`` and add the following boilerplate. Make sure to change +the copyright notice to your name/company, correct the test name and minimum +kernel version if necessary. I will explain what the code does below. + +.. code-block:: c + + // SPDX-License-Identifier: GPL-2.0-or-later + /* + * Copyright (c) 2017 Instruction Ignorer <"can't"@be.bothered.com> + */ + + /*\ + * All tests should start with a description of _what_ we are testing. + * Non-trivial explanations of _how_ the code works should also go here. + * Include relevant links, Git commit hashes and CVE numbers. + * Inline comments should be avoided. + */ + + #include "tst_test.h" + + static void run(void) + { + tst_res(TPASS, "Doing hardly anything is easy"); + } + + static struct tst_test test = { + .test_all = run, + .min_kver = "4.11", + }; + +Starting with the ``#include`` statement we copy in the main LTP test library +headers. This includes the most common test API functions and the test harness +initialization code. It is important to note that this is a completely +ordinary, independent C program, however ``main()`` is missing because it is +implemented in ``tst_test.h``. + +We specify what code we want to run as part of the test using the ``tst_test +test`` structure. Various callbacks can be set by the test writer, including +``test.test_all``, which we have set to ``run()``. The test harness will execute +this callback in a separate process (using ``fork()``), forcibly terminating it +if it does not return after ``test.timeout`` seconds. + +We have also set ``test.min_kver`` to the kernel version where ``statx`` was +introduced. The test library will determine the kernel version at runtime. If +the version is less than 4.11 then the test harness will return ``TCONF``, +indicating that this test is not suitable for the current system +configuration. + +Occasionally features are back ported to older kernel versions, so ``statx`` may +exist on kernels with a lower version. However we don't need to worry about +that unless there is evidence of it happening. + +As mentioned in the code itself, you should specify what you are testing and +the expected outcome, even if it is relatively simple. If your program flow is +necessarily complex and difficult to understand (which is often the case when +trying to manipulate the kernel into doing something bad), then a detailed +explanation of how the code works is welcome. + +What you should not do, is use inline comments or include the same level of +explanation which is written here. As a general rule, if something is easy to +document, then the code should also be easy to read. So don't document the easy +stuff (except for the basic test specification). + +Before continuing we should compile this and check that the basics work. In +order to compile the test we need a ``Makefile`` in the same subdirectory. If +one already exists, then nothing needs to be done, otherwise add one with the +following contents. + +.. code-block:: make + + # SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (c) 2019 Linux Test Project + + top_srcdir ?= ../../../.. + + include $(top_srcdir)/include/mk/testcases.mk + + include $(top_srcdir)/include/mk/generic_leaf_target.mk + +This will automatically add ``statx01.c`` as a build target producing a +``statx01`` executable. Unless you have heavily deviated from the tutorial, and +probably need to change ``top_srcdir``, nothing else needs to be done. + +Normally, if you were starting a Makefile from scratch, then you would need to +add ``statx01`` as a build target. Specifying that you would like to run some +program (e.g. ``gcc`` or ``clang``) to transform ``statx01.c`` into ``statx01``. +Here we don't need to do that, but sometimes it is still necessary. For example, +if we needed to link to the POSIX threading library, then we could add the +following line after ``testcases.mk``. + +.. code-block:: make + + statx01: CFLAGS += -pthread + +Assuming you are in the test's subdirectory :master:`testcases/kernel/syscalls/statx`, +please do: + +.. code-block:: bash + + make + ./statx01 + +This should build the test and then run it. However, even though the test is +in :master:`testcases/kernel/syscalls` directory it won't be automatically ran +as part of the syscalls test group (e.g. not run via ``kirk -r math`` or +``./runltp -f syscalls``). For this we need to add it to the runtest file. So +open :master:`runtest/syscalls` and add the lines starting with a ``+``. + +.. code-block:: + + statvfs01 statvfs01 + statvfs02 statvfs02 + + +statx01 statx01 + + + stime01 stime01 + stime02 stime02 + +The :master:`runtest` files are in a two column format. The first column is the +test name, which is mainly used by test runners for reporting and filtering. It +is just a single string of text with no spaces. The second column, which can +contain spaces, is passed to the shell in order to execute the test. Often it +is just the executable name, but some tests also take arguments (the LTP has a +library for argument parsing, by the way). + +If you haven't done so already, we should add all these new files to Git. It +is vitally important that you do not make changes to the master branch. If you +do then pulling changes from upstream becomes a major issue. So first of all +create a new branch. + +.. code-block:: bash + + git checkout -b statx01 master + +Now we want to add the files we have created or modified, but before doing a +commit make sure you have configured Git correctly. You need to at least set +your Name and e-mail address in ``~/.gitconfig``, but there are some other +settings which come in handy too. My relatively simple configuration is similar +to the below: + +.. code-block:: ini + + [user] + name = Sarah Jane + email = sjane@e-mail.address + [core] + editor = emacs + [sendemail] + smtpServer = smtp.server.address + +Obviously you need to at least change your name and e-mail. The SMTP server is +useful for :git_man:`send-email`, which we will discuss later. The editor value is +used for things like writing commits (without the ``-m`` option). + +.. code-block:: bash + + git add -v :/testcases/kernel/syscalls/statx :/runtest/syscalls + git commit -m "statx01: Add new test for statx syscall" + +This should add all the new files in the ``statx`` directory and the ``runtest`` +file. It is good practice to commit early and often. Later on we will do a +Git-rebase, which allows us to clean up the commit history. So don't worry +about how presentable your commit log is for now. Also don't hesitate to +create a new branch when doing the exercises or experimenting. This will allow +you to diverge from the tutorial and then easily come back again. + +I can't emphasize enough that Git makes things easy through branching and that +things quickly get complicated if you don't do it. However if you do get into +a mess, Git-reflog and Git-reset, will usually get you out of it. If you also +mess that up then it may be possible to cherry pick 'dangling' commits out of +the database into a branch. + +Report TCONF instead of TPASS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Maybe the test should report ``TCONF: Not implemented`` instead or perhaps +``TBROK``. Try changing it do so. + +Check Git ignores the executable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Is your ``.gitignore`` correct? + +Run make check +~~~~~~~~~~~~~~~~~~ + +Check coding style with ``make check``. + +Install the LTP and run the test with runtest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Run ``statx01`` on its own, also using ``-I0`` amd ``-I10``. + +Call the system call +-------------------- + +At the time of writing ``statx`` has no ``glibc`` wrapper. It is also fairly common +for a distribution's C library version to be older than its kernel or it may use a +cut down C library in comparison to the GNU one. So we must call ``statx()`` +using the general ``syscall()`` interface. + +LTP contains a library for dealing with the ``syscall`` interface, which is +located in :master:`include/lapi`. System call numbers are listed against the relevant +call in the ``*.in`` files (e.g. ``x86_64.in``) which are used to generate +``syscalls.h``, the header you should include. +System call numbers vary between architectures, hence there are multiple +``*.in`` files for each architecture. + +On rare occasions, you may find that system call number is missing from ``*.in`` +files. In these cases, they will need to be updated using +:master:`include/lapi/syscalls/generate_arch.sh` script as following: + +.. code-block:: bash + + $ include/lapi/syscalls/generate_arch.sh /path/to/Linux/sources + +The script will generate all the needed ``*.in`` files accordingly to the Linux +source code which has been used. Make sure that your Linux source code has +been updated to the latest version. + +Once the new syscalls files have been updated, to rebuild our ``syscalls.h`` +file, please re-run ``./configure`` script. + +.. code-block:: c + + /* + * Test statx + * + * Check if statx exists and what error code it returns when we give it dodgy + * data. + */ + + #include + #include "tst_test.h" + #include "lapi/syscalls.h" + + struct statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t __reserved; + }; + + struct statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t __spare0[1]; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct statx_timestamp stx_atime; + struct statx_timestamp stx_btime; + struct statx_timestamp stx_ctime; + struct statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t __spare2[14]; + }; + + static int sys_statx(int dirfd, const char *pathname, int flags, + unsigned int mask, struct statx *statxbuf) + { + return tst_syscall(__NR_statx, dirfd, pathname, flags, mask, statxbuf); + } + + ... + +So the top part of the code is now boiler plate for calling ``statx``. It is +common for the kernel to be newer than the user land libraries and headers. So +for new system calls like ``statx``, we copy, with a few modifications, the +relevant definitions into the LTP. This is somewhat like 'vendoring', although +we are usually just copying headers required for interacting with the Kernel's +ABI (Application Binary Interface), rather than integrating actual +functionality. + +So from the top we include the ``stdint.h`` library which gives us the standard +``(u)int*_t`` type definitions. We use these in place of the Kernel type +definitions such as ``__u64`` in ``linux/types.h``. We then have a couple of +structure definitions which form part of the ``statx`` API. These were copied +from :kernel_tree:`include/uapi/linux/stat.h` in the Linux kernel tree. + +After that, there is a wrapper function, which saves us from writing +``tst_syscall(__NR_statx, ...``, every time we want to make a call to +``statx``. This also provides a stub for when ``statx`` is eventually integrated +into the LTP library and also implemented by the C library. At that point we +can switch to using the C library implementation if available or fallback to +our own. + +The advantage of using the C library implementation is that it will often be +better supported across multiple architectures. It will also mean we are using +the system call in the same way most real programs would. Sometimes there are +advantages to bypassing the C library, but in general it should not be our +first choice. + +The final test should do a check during configuration (i.e. when we run +``./configure`` before building) which checks if the ``statx`` system call and +associated structures exists. This requires writing an ``m4`` file for use with +:master:`configure.ac` which is processed during ``make autotools`` and produces the +configure script. + +For the time being though we shall just ignore this. All you need to know for +now is that this is a problem which eventually needs to be dealt with and that +there is a system in place to handle it. + +.. code-block:: c + + ... + + static void run(void) + { + struct statx statxbuf = { 0 }; + + TEST(sys_statx(0, NULL, 0, 0, &statxbuf)); + + if (TST_RET == 0) + tst_res(TFAIL, "statx thinks it can stat NULL"); + else if (TST_ERR == EFAULT) + tst_res(TPASS, "statx set errno to EFAULT as expected"); + else + tst_res(TFAIL | TERRNO, "statx set errno to some unexpected value"); + } + + static struct tst_test test = { + .test_all = run, + .min_kver = "4.11", + }; + +The ``TEST`` macro sets ``TST_RET`` to the return value of ``tst_statx()`` and +``TST_ERR`` to the value of ``errno`` immediately after the functions +return. This is mainly just for convenience, although it potentially could +have other uses. + +We check whether the return value indicates success and if it doesn't also +check the value of ``errno``. The last call to ``tst_res`` includes ``TERRNO``, +which will print the current error number and associated description in +addition to the message we have provided. Note that it uses the current value +of ``errno`` not ``TST_ERR``. + +What we should have done in the example above is use ``TTERRNO`` which takes the +value of ``TST_ERR``. + +If we try to run the test on a kernel where ``statx`` does not exist, then +``tst_syscall`` will cause it to fail gracefully with ``TCONF``. Where ``TCONF`` +indicates the test is not applicable to our configuration. + +The function ``tst_syscall`` calls ``tst_brk(TCONF,...)`` on failure. ``tst_brk`` +causes the test to exit immediately, which prevents any further test code from +being run. + +What are the differences between ``tst_brk`` and ``tst_res``? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See :master:`include/tst_test.h`. Also what do they have in common? + +What happens if you call ``tst_res(TINFO, ...)`` after ``sys_statx``? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Does the test still function correctly? + +Extend the test to handle other basic error conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For example, see if you can trigger ``ENOENT`` instead. You shouldn't +have to create any files, which is discussed in the next section. + +Setup, Cleanup and files +------------------------ + +Some tests require resources to be allocated, or system settings to be +changed, before the test begins. This ``setup`` only has to be done once at the +beginning and at the end of the test needs to be removed or reverted. The +``cleanup`` also has to be done regardless of whether the test breaks. + +Fortunately, like most test libraries, we have setup and cleanup (teardown) +callbacks. ``setup`` is called once before ``run`` and ``cleanup`` is called once +afterwards. Note that ``run`` itself can be called multiple times by the test +harness, but that ``setup`` and ``cleanup`` are only called once. + +If either your code, a ``SAFE_*`` macro or a library function such as +``tst_syscall`` call ``tst_brk``, then ``run`` will exit immediately and the +``cleanup`` function is then called. Once ``cleanup`` is completed, the test +executable will then exit altogether abandoning any remaining iterations of +``run``. + +For ``statx`` we would like to create some files or file like objects which we +have control over. Deciding where to create the files is easy, we just create +it in the current working directory and let the LTP test harness handle where +that should be by setting ``.needs_tmpdir = 1``. + +.. code-block:: c + + /* + * Test statx + * + * Check if statx exists and what error code it returns when we give it dodgy + * data. Then stat a file and check it returns success. + */ + + #include + #include "tst_test.h" + #include "lapi/syscalls.h" + #include "lapi/fcntl.h" + + #define FNAME "file_to_stat" + #define STATX_BASIC_STATS 0x000007ffU + + /*************** statx structure and wrapper goes here ! ***************/ + ... + +We have added an extra include :master:`lapi/fcntl.h` which wraps the system header by +the same name (``#include ``). This header ensures we have definitions +for recently added macros such as ``AT_FDCWD`` by providing fall backs if the +system header does not have them. The :master:`lapi/` directory contains a number of +headers like this. + +At some point we may wish to add :master:`lapi/stat.h` to provide a fall back for +macros such as ``STATX_BASIC_STATS``. However for the time being we have just +defined it in the test. + + +.. code-block:: c + + ... + + static void setup(void) + { + SAFE_TOUCH(FNAME, 0777, NULL); + } + + static void run(void) + { + struct statx statxbuf = { 0 }; + + TEST(sys_statx(0, NULL, 0, 0, &statxbuf)); + if (TST_RET == 0) + tst_res(TFAIL, "statx thinks it can stat NULL"); + else if (TST_ERR == EFAULT) + tst_res(TPASS, "statx set errno to EFAULT as expected"); + else + tst_res(TFAIL | TERRNO, "statx set errno to some unexpected value"); + + TEST(sys_statx(AT_FDCWD, FNAME, 0, STATX_BASIC_STATS, &statxbuf)); + if (TST_RET == 0) + tst_res(TPASS, "It returned zero so it must have worked!"); + else + tst_res(TFAIL | TERRNO, "statx can not stat a basic file"); + } + + static struct tst_test test = { + .setup = setup, + .test_all = run, + .min_kver = "4.11", + .needs_tmpdir = 1 + }; + +The ``setup`` callback uses one of the LTP's ``SAFE`` functions to create an empty +file ``file_to_stat``. Because we have set ``.needs_tmpdir``, we can just create +this file in the present working directory. We don't need to create a +``cleanup`` callback yet because the LTP test harness will recursively delete +the temporary directory and its contents. + +The ``run`` function can be called multiple times by the test harness, however +``setup`` and ``cleanup`` callbacks will only be ran once. + +.. warning:: + + By this point you may have begun to explore the LTP library headers or older + tests. In which case you will have come across functions from the old API such + as ``tst_brkm``. The old API is being phased out, so you should not use these + functions. + +So far we haven't had to do any clean up. So our example doesn't answer the +question "what happens if part of the clean up fails?". To answer this we are +going to modify the test to ask the (highly contrived) question "What happens +if I create and open a file, then create a hard-link to it, then call open +again on the hard-link, then ``stat`` the file". + + +.. code-block:: c + + #define LNAME "file_to_stat_link" + + ... + + static void setup(void) + { + fd = SAFE_OPEN(FNAME, O_CREAT, 0777); + SAFE_LINK(FNAME, LNAME); + lfd = SAFE_OPEN(LNAME, 0); + } + + static void cleanup(void) + { + if (lfd != 0) + SAFE_CLOSE(lfd); + + if (fd != 0) + SAFE_CLOSE(fd); + } + + static void run(void) + { + ... + + TEST(sys_statx(AT_FDCWD, LNAME, 0, STATX_BASIC_STATS, &statxbuf)); + if (TST_RET == 0) + tst_res(TPASS, "It returned zero so it must have worked!"); + else + tst_res(TFAIL | TERRNO, "statx can not stat a basic file"); + } + + static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .tcnt = 2, + .min_kver = "4.11", + .needs_tmpdir = 1 + }; + +Because we are now opening a file, we need a ``cleanup`` function to close the +file descriptors. We have to manually close the files to ensure the temporary +directory is deleted by the test harness (see :doc:`writing_tests` for details). + +As a matter of good practice, the file descriptors are closed in reverse +order. In some circumstances the order which ``cleanup`` is performed is +significant. In those cases, resources created towards the end of ``setup`` are +dependent to ones near the beginning. During ``cleanup`` we remove the +dependants before their dependencies. + +If, for some reason, the file descriptor ``lfd`` became invalid during the test, +but ``fd`` was still open, we do not want ``SAFE_CLOSE(lfd)`` to cause the +``cleanup`` function to exit prematurely. If it did, then ``fd`` would remain +open which would cause problems on some file systems. + +Nor do we want to call ``cleanup`` recursively. So during ``cleanup`` +``tst_brk``, and consequently the ``SAFE`` functions, do not cause the test to +exit with ``TBROK``. Instead they just print an error message with ``TWARN``. + +It is not entirely necessary to check if the file descriptors have a none zero +value before attempting to close them. However it avoids a bunch of spurious +warning messages if we fail to open ``file_to_stat``. Test case failures can be +difficult to interpret at the best of times, so avoid filling the log with +noise. + +Check ``statx`` returns the correct number of hard links +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The field ``statx.stx_nlink`` should be equal to 2, right? + +Git-branch +~~~~~~~~~~ + +We are about to make some organizational changes to the test, so now would be +a good time to branch. Then we can switch between the old and new versions, to +check the behavior has not been changed by accident. + +Split the test +-------------- + +In our current test, we have essentially rolled two different test cases into +one. Firstly we check if an error is returned when bad arguments are provided +and secondly we check what happens when we stat an actual file. Quite often it +makes sense to call ``tst_res`` multiple times in a single test case because we +are checking different properties of the same result, but here we are clearly +testing two different scenarios. + +So we should split the test in two. One obvious way to do this is to create +``statx02.c``, but that seems like overkill in order to separate two simple test +cases. So, for now at least, we are going to do it a different way. + +.. code-block:: c + + ... + + static void run_stat_null(void) + { + struct statx statxbuf = { 0 }; + + TEST(sys_statx(0, NULL, 0, 0, &statxbuf)); + if (TST_RET == 0) + tst_res(TFAIL, "statx thinks it can stat NULL"); + else if (TST_ERR == EFAULT) + tst_res(TPASS, "statx set errno to EFAULT as expected"); + else + tst_res(TFAIL | TERRNO, "statx set errno to some unexpected value"); + } + + static void run_stat_symlink(void) + { + struct statx statxbuf = { 0 }; + + TEST(sys_statx(AT_FDCWD, LNAME, 0, STATX_BASIC_STATS, &statxbuf)); + if (TST_RET == 0) + tst_res(TPASS, "It returned zero so it must have worked!"); + else + tst_res(TFAIL | TERRNO, "statx can not stat a basic file"); + } + + static void run(unsigned int i) + { + switch(i) { + case 0: run_stat_null(); + case 1: run_stat_symlink(); + } + } + + static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = run, + .tcnt = 2, + .min_kver = "4.11", + .needs_tmpdir = 1 + }; + +So we have used an alternative form of the ``test`` or ``run`` callback which +accepts an index. Some tests use this index with an array of parameters and +expected return values. Others do something similar to the above. The index +can be used how you want so long as each iteration calls ``tst_res`` in a +meaningful way. + +If an iteration fails to return a result (i.e. call ``tst_res`` with a value +other than ``TINFO``) then the test harness will report ``TBROK`` and print the +iteration which failed. This prevents a scenario in your test from silently +failing due to some faulty logic. + +What is wrong with the switch statement? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Were you paying attention? Also see the output of ``make check``. + +Test a feature unique to statx +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +So far we have not tested anything which is unique to ``statx``. So, for +example, you could check stx_btime is correct (possibly only to within a +margin of error) and that it differs from ``stx_mtime`` after writing to the +file. + +Alternatively you could check that ``stx_dev_major`` and ``stx_dev_minor`` are set +correctly. Note that the LTP has helper functions for creating devices and +file systems. + +This could be quite a challenging exercise. You may wish to tackle an +altogether different test scenario instead. If you get stuck just move onto +the next section and come back later. + +Submitting the test for review +------------------------------ + +Ignoring the fact we should probably create :master:`lapi/stat.h` along with a bunch +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 +``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 +commit, but if you have been using Git correctly then you should have +many. The main reason we want to compress it to a single commit, is to make +the LTP's Git-log readable. It also allows us to write a coherent description +of the work as a whole in retrospective. Although, when adding a new test, the +test description in the code will probably make the commit message redundant. + +Anyway, as an example, we shall look at my personal commit history from this +tutorial and ``rebase`` it. You should try following along with your own +repository. First lets look at the commit history since we branched from +master. + +.. code-block:: bash + + git log --oneline master..HEAD + 152d39fe7 (HEAD -> tutorial-rebase2, tutorial-rebase) tutorial: Start Submitting patch section + 70f7ce7ce statx01: Stop checkpatch from complaining + bb0332bd7 tutorial: Fix review problems + 6a87a084a statx01: Fix review problems + d784b1e85 test-writing-guidelines: Remove old API argument + c26e1be7a fixup! tutorial + 1e24a5fb5 (me/tutorial-rebase) fixup! tutorial + 568a3f7be fixup! tutorial + 09dd2c829 statx: stage 6 + bfeef7902 statx: stage 5b + 76e03d714 statx: stage 5a + 98f5bc7ac statx: stage 4 + 6f8c16438 statx: stage 3 (Add statx01) + 5d93b84d8 Add statx and other syscall numbers + 5ca627b78 tutorial: Add a step-by-step C test tutorial + +So we have told git to show all the commits which don't exist in ``master``, but +are in ``HEAD``, where ``HEAD`` is the top of the current branch. The current +branch is ``tutorial-rebase2`` which I just created. I have already done one +``rebase`` and submitted a patch for review, so my original branch was just called +``tutorial``. + +As usual my commit history is starting to look like a bit of mess! There is +even a commit in there which should not be in the this branch (Remove old API +argument), however it can be ignored for now and 'cherry picked' into a new branch +later. + +For my patch I actually need at least two commits, one which contains the +tutorial text and one which contains the test and associated files. So first +of all I want to 'squash' (amalgamate) all the commits appended with +``tutorial:`` into the bottom commit. + +.. code-block:: bash + + $ git rebase -i 5ca627b78\^ + ... + +This begins an interactive ``rebase`` where commit ``5ca6427b78`` is the earliest +commit we want to edit. The ``^`` symbol after the commit hash, specifies the +commit before this one. The interactive ``rebase`` command takes the last commit +we want to keep unaltered as it's argument (in other words it takes a +non-inclusive range). + +Upon entering a similar command you will be presented with a text file +similar to the following. The file should be displayed in your text editor of +choice, if it doesn't, then you may change the editor variable in +``.gitconfig``. + +.. code-block:: bash + + pick 5ca627b78 tutorial: Add a step-by-step C test tutorial + pick 5d93b84d8 Add statx and other syscall numbers + pick 6f8c16438 statx: stage 3 (Add statx01) + pick 98f5bc7ac statx: stage 4 + pick 76e03d714 statx: stage 5a + pick bfeef7902 statx: stage 5b + pick 09dd2c829 statx: stage 6 + pick 568a3f7be fixup! tutorial + pick 1e24a5fb5 fixup! tutorial + pick c26e1be7a fixup! tutorial + pick d784b1e85 test-writing-guidelines: Remove old API argument + pick 6a87a084a statx01: Fix review problems + pick bb0332bd7 tutorial: Fix review problems + pick 70f7ce7ce statx01: Stop checkpatch from complaining + pick 152d39fe7 tutorial: Start Submitting patch section + +The last commit from Git-log is shown at the top. The left hand column +contains the commands we want to run on each commit. ``pick`` just means we +re-apply the commit as-is. We can reorder the lines to apply the commits in a +different order, but we need to be careful when reordering commits to the same +file. If your ``rebase`` results in a merge conflict, then you have probably +reordered some commits which contained changes to the same piece of code. + +Perhaps a better name for the interactive ``rebase`` command would be 'replay'. As +we pick a point in the commit history, undo all those commits before that +point, then reapply them one at a time. During the replay we can reorder the +commits, drop, merge, split and edit them, creating a new history. + +The commands I am going to use are ``reword`` and ``fixup``. The ``reword`` command +allows you to edit a single commit's message. The 'fixup' command 'squashes' a +commit into the commit above/preceding it, merging the two commits into +one. The commit which has ``fixup`` applied has its commit message deleted. If +you think a commit might have something useful in its message then you can use +``squash`` instead. + +.. code-block:: bash + + reword 5ca627b78 tutorial: Add a step-by-step C test tutorial + fixup 568a3f7be fixup! tutorial + fixup 1e24a5fb5 fixup! tutorial + fixup c26e1be7a fixup! tutorial + fixup bb0332bd7 tutorial: Fix review problems + fixup 152d39fe7 tutorial: Start Submitting patch section + fixup 276edecab tutorial: Save changes before rebase + pick 5d93b84d8 Add statx and other syscall numbers + pick 6f8c16438 statx: stage 3 (Add statx01) + pick 98f5bc7ac statx: stage 4 + pick 76e03d714 statx: stage 5a + pick bfeef7902 statx: stage 5b + pick 09dd2c829 statx: stage 6 + pick d784b1e85 test-writing-guidelines: Remove old API argument + pick 6a87a084a statx01: Fix review problems + +So all the commits marked with ``fixup`` will be re-played by Git immediately +after 5ca62 at the top. A new commit will then be created with the amalgamated +changes of all the commits and 5ca62's log message. It turns out that I didn't +need to reword anything, but there is no harm in checking. It is easy to +forget the ``Signed-off-by:`` line. + +I could now do the same for the commits to the ``statx`` test, making the commit +message prefixes consistent. However I am not actually going to submit the +test (yet). + +I won't attempt to show you this, but if you need to do the opposite and split +apart a commit. It is also possible using Git-rebase by marking a line with +``edit``. This will pause Git just after replaying the marked commit. You can +then use a 'soft' Git-reset to bring the selected commit's changes back into +the 'index' where you are then able to un-stage some parts before +re-committing. + +You can also use ``edit`` and ``git commit --amend`` together to change a commit +deep in your history, but without resetting the 'index'. The 'index' contains +changes which you have staged with :git_man:`add`, but not yet committed. + +So now that the commit history has been cleaned up, we need to submit a patch +to the mailing list or make a pull request on GitHub. The mailing list is the +preferred place to make submissions and is more difficult for most people, so +I will only cover that method. + +Just before we create the patch, we need to check that our changes will still +apply to the master branch without problems. To do this we can use another +type of ``rebase`` and then try rebuilding and running the test. + +.. code-block:: bash + + git checkout master + git pull origin + git checkout tutorial-rebase2 + git rebase master + +Above, I update the master branch and then replay our changes onto it using +``git rebase master``. You may find that after the rebase there is a merge +conflict. This will result in something which looks like the following (taken +from a Makefile conflict which was caused by reordering commits in a ``rebase``). + +.. code-block:: diff + + <<<<<<< HEAD + cve-2016-7117: LDFLAGS += -lpthread + ======= + cve-2014-0196: LDFLAGS += -lpthread -lutil -lrt + cve-2016-7117: LDFLAGS += -lpthread -lrt + >>>>>>> 4dbfb8e79... Add -lrt + +The first line tells us this is the beginning of a conflict. The third line +separates the two conflicting pieces of content and the last line is the end +of the conflict. Usually, all you need to do is remove the lines you don't +want, stage the changes and continue the ``rebase`` with ``git rebase +--continue``. + +In order to create a patch e-mail we use :git_man:`format-patch`, +we can then send that e-mail using :git_man:`send-email`. +It is also possible to import the patch (``mbox``) file into a number of e-mail +programs. + +.. code-block:: bash + + $ git format-patch -1 -v 2 -o output --to ltp@lists.linux.it fd3cc8596 + output/v2-0001-tutorial-Add-a-step-by-step-C-test-tutorial.patch + +The first argument ``-1`` specifies we want one commit from fd3cc8596 +onwards. If we wanted this commit and the one after it we could specify ``-2`` +instead. + +This is my second patch submission so I have used ``-v 2``, which indicates this +is the second version of a patch set. The ``-o`` option specifies the output +directory (literally called ``output``). The ``--to`` option adds the ``To:`` e-mail +header, which I have set to the LTP mailing list. + +We can then send this patch with the following command sans ``--dry-run``. + +.. code-block:: bash + + git send-email --dry-run output/v2-0001-tutorial-Add-a-step-by-step-C-test-tutorial.patch + +Git will ask some questions (which you can ignore) and then tell you what it +would do if this weren't a dry-run. In order for this to work you have to have +a valid SMTP server set in ``.gitconfig`` and also be signed up to the LTP +mailing list under the same e-mail address you have configured in Git. You can +sign up at https://lists.linux.it/listinfo/ltp. + +Doing code review +----------------- + +While waiting for your test to be reviewed, you are invited and encouraged to +review other contributors' code. This may seem bizarre when you are completely +new to the project, but there are two important ways in which you can +contribute here: + +A. Point out logical errors in the code. +B. Improve your own understanding + +It doesn't matter whether you know the canonical way of writing an LTP test in +C. An error of logic, when properly explained, is usually indisputable. These +are the most important errors to find as they always result in false test +results. Once someone points out such an error it is usually obvious to +everyone that it is a bug and needs to be fixed. + +Obviously testing the patch is one way of finding errors. You can apply patches +using :git_man:`am`. Then it is just a case of compiling and running the tests. + +Finally, reading and attempting to comment on other peoples patches, gives +you a better understanding of the reviewers perspective. This is better for +the project and for you. + +Style and organizational issues are best left to after you have found logical +errors. + +Final notes +----------- + +Hopefully you can now grasp the structure of an LTP test and have some idea of +what is available in the LTP test library. There are a vast number of library +functions available (mainly located in include and lib), some of which are +documented in the test writing guidelines and many of which are not. + +We have only scratched the surface of the immense technical complexity of +systems programming across multiple Kernel and C lib versions as well as +different hardware architectures. The important thing to take away from this +is that you have to be conscientious of what will happen on systems different +from yours. The LTP has a huge and varied user base, so situations you may +think are unlikely can and do happen to somebody. + +Of course you don't want to spend time allowing for situations which may never +arise either, so you have to do your research and think about each situation +critically. The more systems you can test on before submitting your changes, +the better, although we understand not everyone has access to a lab. + +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 synchronizing and forking processes. + +.. note:: + + 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 + to the kernel for formatting and submitting patches. Generally speaking the + review cycle is easier for small patches, so try to make small changes or + additions where possible. diff --git a/ltp/doc/developers/writing_tests.rst b/ltp/doc/developers/writing_tests.rst new file mode 100644 index 0000000000000000000000000000000000000000..9b18ec059c3a94a014c68955d4f7b36dc156f2e6 --- /dev/null +++ b/ltp/doc/developers/writing_tests.rst @@ -0,0 +1,537 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Writing tests +============= + +This document describes LTP guidelines and it's intended for anybody who wants +to write or to modify a LTP testcase. It's not a definitive guide and it's not, +by any means, a substitute for common sense. + +Guide to clean and understandable code +-------------------------------------- + +Testcases require that the source code is easy to follow. When a test starts to +fail, the failure has to be analyzed and clean test codebase makes this task +much easier and quicker. + +Keep things simple +~~~~~~~~~~~~~~~~~~ + +It's worth to keep 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, 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. + +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. + +Do not over-comment +~~~~~~~~~~~~~~~~~~~ + +Comments can sometimes save your 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 `RST +`_ +formatted comment paragraph with high-level 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. + +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 +you find bug in the code that has been copied all around the tree. What about +moving it to a library instead? + +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. + +C coding style +-------------- + +LTP adopted `Linux kernel coding style `_. +Run ``make check`` in the test's directory and/or use ``make check-$TCID``, it +uses (among other checks) our vendoring version of +`checkpatch.pl `_ +script from kernel git tree. + +.. 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. + +The following linting code can be found when we run ``make check``: + +.. list-table:: + :header-rows: 1 + + * - Linting code + - Message + - Explanation + + * - LTP-001 + - Library source files have ``tst_`` prefix + - API source code is inside headers in ``include/{empty}*.h``, + ``include/lapi/{empty}*.h`` (backward compatibility for old kernel and + libc) and C sources in ``lib/{empty}*.c``. Files must have ``tst_`` + prefix. + + * - LTP-002 + - ``TST_RET`` and ``TST_ERR`` are never modified by test library functions + - 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. + + * - 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. + + * - 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. + + * - LTP-005 + - Array must terminate with a sentinel value (i.e. ``NULL`` or ``{}``) + - When defining arrays in the ``struct tst_test`` structure, we need to + end the array items with a sentinel ``NULL`` value. + +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 +example dash) too. + +*Portable shell* means Shell Command Language as defined by POSIX with an +exception of few widely used extensions, namely **local** keyword used inside of +functions and ``-o`` and ``-a`` test parameters (that are marked as obsolete in +POSIX). + +You can either try to run the testcases in Debian which has ``/bin/sh`` pointing +to ``dash`` by default, or to install ``dash`` on your favorite distribution, +then use it to run tests. If your distribution lacks ``dash`` package, you can +always compile it from `sources `_. + +Run ``make check`` in the test's directory and/or use ``make check-$TCID.sh``. +It uses (among other checks) our vendoring version of +`checkbashism.pl `_ +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`` is used for checking only common mistakes. + +Here there are some common sense style rules for shell + +* Keep lines under 80 chars +* Use tabs for indentation +* Keep things simple, avoid unnecessary subshells +* Don't do confusing things (i.e. don't name your functions like common shell + commands, etc.) +* Quote variables +* Be consistent + +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 +release) or of an embedded platform that needs to use several years old +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``. + +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 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, the 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 a kernel ``.config`` parser. A test can define a boolean + expression of kernel config variables that has to be satisfied in order to run + a test. At the moment, this is mostly used for kernel namespaces. + +* Sometimes it makes sense to define a few macros instead of creating a + configure test. One example is Linux specific POSIX clock ids in + :master:`include/lapi/posix_clocks.h`. + +Dealing with messed up legacy code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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 of it. +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. + +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 to rename or to move +files, do it in a separate patch. + +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`` + +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 +and/or command line parameters, it prints additional information into the +stdout and reports overall success/failure via the exit value. + +Tests are generally placed under the :master:`testcases` directory. Everything that +is a syscall or (slightly confusingly) libc syscall wrapper, goes under +:master:`testcases/kernel/syscalls/`. + +There is also :master:`testcases/open_posix_testsuite/` which is a well maintained +fork of the Open POSIX testsuite project, that has been dead since 2005. + +We also have a number of directories with tests for more specific features, such +as containers, etc. + +Runtest Files +~~~~~~~~~~~~~ + +The list of tests to be executed is stored in runtest files under the +:master:`runtest` directory. The default set of runtest files to be executed is +stored in :master:`scenario_groups/default`. When you add a test, you should add +corresponding entries into some runtest file(s) as well. + +Each line of runtest file contains one test. The first item is the test name. +All other items, separated by space will be executed as a command. + +.. code-block:: bash + + shell_test01 echo "SUCCESS" | shell_pipe01.sh + splice02 splice02 -s 20 + +Blank lines and lines starting with a ``#`` (comments) are ignored. + +Syscalls tests, placed under :master:`testcases/kernel/syscalls/`, use +:master:`runtest/syscalls` file. For kernel related tests for memory management we +have :master:`runtest/mm`, etc. + +.. note:: + + 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. + +Datafiles +--------- + +If your test needs data files, these should be put into a subdirectory +named ``datafiles`` and installed into the ``testcases/data/$TCID`` directory. +This will require to add ``INSTALL_DIR := testcases/data/TCID`` into +correspondent ``datafiles/Makefile``. + +You can obtain path to datafiles via ``$TST_DATAROOT`` provided by ``test.sh`` +or via C function ``tst_dataroot()`` provided by libltp: + +.. code-block:: c + + const char *dataroot = tst_dataroot(); + +Datafiles can also be accessed as ``$LTPROOT/testcases/data/$TCID/...``, +but ``$TST_DATAROOT`` and ``tst_dataroot()`` are preferred, as these can be used +when running testcases directly in git tree as well as from install location. + +Sub-executables +~~~~~~~~~~~~~~~ + +If your test needs to execute a binary, place it in the same directory of the +testcase and name the binary with ``$TESTNAME_`` prefix, where ``$TESTNAME`` is +the name of the test binary. Once the test is executed by the framework, the +path to the directory with all LTP binaries is added to the ``$PATH`` and you +can execute it via its name. + +.. note:: + + If you need to execute a test from the LTP tree, you can add ``PATH`` to + the current directory with ``PATH="$PATH:$PWD" ./foo01``. + +Test Contribution Checklist +--------------------------- + +#. Test compiles and it runs fine (check with ``-i 10`` and ``-i 0`` too) +#. ``make check`` should 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``) +#. The runtest entries are in place +#. New test binaries are added into the corresponding ``.gitignore`` files +#. Patches apply over the latest git + +About .gitignore files +~~~~~~~~~~~~~~~~~~~~~~ + +There are numerous ``.gitignore`` files in the LTP tree. Usually, there is a +``.gitignore`` file for a group of tests. The reason of this setup is simple: +it's easier to maintain a ``.gitignore`` file per tests' directory, rather +than having a single file in the project root directory. In this way, we don't +have to update all the gitignore files when moving directories, and they get +deleted automatically when a directory with tests is removed. + +Testing pre-release kernel features +----------------------------------- + +Tests for features not yet in the mainline kernel release are accepted. However, +they must be added only to :master:`runtest/staging`. Once a feature is part +of the stable kernel ABI, the associated test must be moved out of staging. + +Testing builds with GitHub Actions +---------------------------------- + +Master branch is tested in GitHub :repo:`actions` +to ensure LTP builds in various distributions, including old, current and +bleeding edge. ``gcc`` and ``clang`` toolchains are also tested for various +architectures using cross-compilation. For a full list of tested distros, please +check :master:`.github/workflows/ci-docker-build.yml`. + +.. note:: + + Passing the GitHub Actions CI means that LTP compiles in a variety of + different distributions on their **newest releases**. + The CI also checks for code linting, running ``make check`` in the whole + LTP project. + +LTP C And Shell Test API Comparison +----------------------------------- + +.. list-table:: + :header-rows: 1 + + * - C API ``struct tst_test`` members + - Shell API ``$TST_*`` variables + + * - .all_filesystems + - TST_ALL_FILESYSTEMS + + * - .bufs + - \- + + * - .caps + - \- + + * - .child_needs_reinit + - not applicable + + * - .cleanup + - TST_CLEANUP + + * - .dev_extra_opts + - TST_DEV_EXTRA_OPTS + + * - .dev_fs_opts + - TST_DEV_FS_OPTS + + * - .dev_fs_type + - TST_FS_TYPE + + * - .dev_min_size + - TST_DEVICE_SIZE + + * - .format_device + - TST_FORMAT_DEVICE + + * - .max_runtime + - TST_TIMEOUT (not exactly the same, a real timeout based on old .timeout + concept. .max_runtime has also an extra 30 sec safety margin for + teardown of the test.) + + * - .min_cpus + - not applicable + + * - .min_kver + - TST_MIN_KVER + + * - .min_mem_avail + - not applicable + + * - .mnt_flags + - TST_MNT_PARAMS + + * - .min_swap_avail + - not applicable + + * - .mntpoint | .mnt_data + - TST_MNTPOINT + + * - .mount_device + - TST_MOUNT_DEVICE + + * - .needs_cgroup_ctrls + - \- + + * - .needs_checkpoints + - TST_NEEDS_CHECKPOINTS + + * - .needs_cmds + - TST_NEEDS_CMDS + + * - .needs_devfs + - \- + + * - .needs_device + - TST_NEEDS_DEVICE + + * - .needs_drivers + - TST_NEEDS_DRIVERS + + * - .needs_kconfigs + - TST_NEEDS_KCONFIGS + + * - .needs_overlay + - \- + + * - .needs_rofs + - \- + + * - .needs_root + - TST_NEEDS_ROOT + + * - .needs_tmpdir + - TST_NEEDS_TMPDIR + + * - .options + - TST_PARSE_ARGS | TST_OPTS + + * - .resource_files + - \- + + * - .restore_wallclock + - not applicable + + * - .sample + - \- + + * - .save_restore + - \- + + * - .scall + - not applicable + + * - .setup + - TST_SETUP + + * - .skip_filesystems + - TST_SKIP_FILESYSTEMS + + * - .skip_in_compat + - \- + + * - .skip_in_lockdown + - TST_SKIP_IN_LOCKDOWN + + * - .skip_in_secureboot + - TST_SKIP_IN_SECUREBOOT + + * - .supported_archs + - not applicable + + * - .tags + - \- + + * - .taint_check + - \- + + * - .tcnt + - TST_CNT + + * - .tconf_msg + - not applicable + + * - .test | .test_all + - TST_TESTFUNC + + * - .test_variants + - \- + + * - .tst_hugepage + - not applicable + + * - .ulimit + - not applicable + + * - not applicable + - TST_NEEDS_KCONFIGS_IFS + + * - not applicable + - TST_NEEDS_MODULE + + * - not applicable + - TST_POS_ARGS + + * - not applicable + - TST_USAGE + +.. list-table:: + :header-rows: 1 + + * - C API other structs + - Shell API ``$TST_*`` variables + + * - struct tst_device + - TST_DEVICE diff --git a/ltp/doc/index.rst b/ltp/doc/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..acd16cdbf6464ea40eff470548818112a8e002c4 --- /dev/null +++ b/ltp/doc/index.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +.. include:: ../README.rst + +.. toctree:: + :maxdepth: 3 + :hidden: + :caption: For users + + users/quick_start + users/setup_tests + users/testers_guide + users/supported_systems + users/stats + users/test_catalog + +.. toctree:: + :maxdepth: 3 + :hidden: + :caption: For developers + + developers/setup_mailinglist + developers/writing_tests + developers/test_case_tutorial + developers/api_c_tests + developers/api_shell_tests + developers/api_network_tests + developers/api_kvm_tests + developers/ltp_library + developers/build_system + developers/debugging + developers/documentation + +.. toctree:: + :maxdepth: 3 + :hidden: + :caption: For maintainers + + maintainers/patch_review + maintainers/ltp_release_procedure + +For users +--------- + +.. descriptions here are active + +:doc:`users/quick_start` + How to build and use LTP framework in few steps + +:doc:`users/setup_tests` + How to setup tests execution + +:doc:`users/supported_systems` + A list of supported technologies by the LTP framework + +:doc:`users/stats` + Some LTP statistics + +:doc:`users/test_catalog` + The LTP test catalog + +For developers +-------------- + +.. descriptions here are active + +:doc:`developers/setup_mailinglist` + How to configure git and to start sending patches via :git_man:`send-email`. + +:doc:`developers/writing_tests` + Starting guide on writing tests + +:doc:`developers/test_case_tutorial` + A tutorial showing how to write a test from scratch using C API + +:doc:`developers/api_c_tests` + Walk through the C API features + +:doc:`developers/api_shell_tests` + Walk through the Shell API features + +:doc:`developers/api_network_tests` + Walk through the network API features + +:doc:`developers/api_kvm_tests` + Walk through the KVM API features + +:doc:`developers/ltp_library` + Developing new features in the LTP library + +:doc:`developers/build_system` + Short introduction to the LTP build system + +:doc:`developers/debugging` + How to debug LTP tests + +:doc:`developers/documentation` + How to use and develop LTP documentation + +For maintainers +--------------- + +:doc:`maintainers/patch_review` + Steps to follow when reviewing patches + +:doc:`maintainers/ltp_release_procedure` + Steps to follow for a new LTP release + + +Getting help +------------ +To report a problem or suggest any feature, please write at ltp@lists.linux.it diff --git a/ltp/doc/maintainers/ltp_release_procedure.rst b/ltp/doc/maintainers/ltp_release_procedure.rst new file mode 100644 index 0000000000000000000000000000000000000000..6dbafa4f81ebd3c843ef66547340012c59521fb8 --- /dev/null +++ b/ltp/doc/maintainers/ltp_release_procedure.rst @@ -0,0 +1,166 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Release process +=============== + +Preparations +------------ + +The release procedure generally takes a few weeks. In the first week or two, +patches that should go into the release are reviewed and possibly merged. These +patches are either fixes or patches pointed out by the community. + +Patch review, when finished, is followed by a git freeze, which is a period +where only fixes are pushed to the git. During that period community is +expected to run a LTP pre-release tests, reports problems, and/or send fixes to +the mailing list. In this period we are especially making sure that there are +no regressions in the test results on a wide range of distributions and +architectures. + +Once the stabilization period has ended the time has finally come to proceed +with the release. + +Prepare the release notes +------------------------- + +Part of the preparation is also to write the release notes, which are then +added to the GitHub release and also sent as announcement to various mailing +lists (see below). + +Have a look at `this release letter `_ +to get the idea how it should look. + +Tag the git and push changes to github +-------------------------------------- + +.. code-block:: bash + + cd ltp + echo YYYYMMDD > VERSION + git commit -S -s -m 'LTP YYYYMMDD' VERSION + git tag -s -a YYYYMMDD -m 'LTP YYYYMMDD' + git push origin master:master + git push origin YYYYMMDD + +The string ``YYYYMMDD`` should be substituted to the current date. + +You can use :master:`tools/tag-release.sh` script to have the above automated +process. It allows you to verify the tag before pushing it and does other +checks. + +.. code-block:: bash + + $ ./tools/tag-release.sh + ===== git push ===== + new tag: 'YYYYMMDD', previous tag: '20230127' + tag YYYYMMDD + Tagger: Person-who-released LTP + Date: ... + + LTP YYYYMMDD + -----BEGIN PGP SIGNATURE----- + ... + -----END PGP SIGNATURE----- + + commit 3ebc2dfa85c2445bb68d8c0d66e33c4da1e1b3a7 + gpg: using RSA key ... + ... + Primary key fingerprint: ... + Author: Person-who-released LTP + Date: ... + + LTP YYYYMMDD + + Signed-off-by: Person-who-released LTP + + diff --git a/VERSION b/VERSION + index af4c41fec..ae488c0e7 100644 + --- a/VERSION + +++ b/VERSION + @@ -1 +1 @@ + -20230127 + +YYYYMMDD + + Please check tag and signature. Proceed? [N/y]: y + Pushing changes to upstream git. Proceed? [N/y]: y + ... + To github.com:linux-test-project/ltp.git + * [new tag] YYYYMMDD -> YYYYMMDD + +Prepare tarballs and metadata documentation +------------------------------------------- + +The following procedure will show how to create the release archives and the +metadata documentation: + +.. code-block:: bash + + # clone already clonned git repository to new folder + cd .. + git clone ltp ltp-full-YYYYMMDD + cd ltp-full-YYYYMMDD + + # update all submodules + git submodule update --init + + # Generate configure script + make autotools + + # Generate tarballs + cd .. + tar -cjf ltp-full-YYYYMMDD.tar.bz2 ltp-full-YYYYMMDD --exclude .git + tar -cJf ltp-full-YYYYMMDD.tar.xz ltp-full-YYYYMMDD --exclude .git + + # Generate checksums + md5 ltp-full-YYYYMMDD.tar.xz > ltp-full-YYYYMMDD.tar.xz.md5 + sha1 ltp-full-YYYYMMDD.tar.xz > ltp-full-YYYYMMDD.tar.xz.sha1 + sha256sum ltp-full-YYYYMMDD.tar.xz > ltp-full-YYYYMMDD.tar.xz.sha256 + +You can use :master:`tools/create-tarballs-metadata.sh` script to have the above +procedure automated. All generated files are placed in the +``ltp-release-YYYYMMDD`` directory. + +.. code-block:: bash + + $ ./tools/create-tarballs-metadata.sh + ===== git clone ===== + Cloning into 'ltp-full-YYYYMMDD'... + done. + ===== Update submodules ===== + Submodule 'tools/kirk' (https://github.com/linux-test-project/kirk.git) registered for path 'tools/kirk' + ... + ===== Generate configure script ===== + sed -n '1{s:LTP-:m4_define([LTP_VERSION],[:;s:$:]):;p;q}' VERSION > m4/ltp-version.m4 + aclocal -I m4 + ... + ===== Generate tarballs ===== + ===== Generate checksums ===== + ===== Generate metadata documentation ===== + checking for a BSD-compatible install... /usr/bin/install -c + ... + Generated files are in '/home/foo/ltp-release-YYYYMMDD', upload them to github + +Upload the generated files to GitHub +------------------------------------ + +Go to :repo:`tags`. Click on ``Add release notes``. +There should be ``Attach binaries ...`` link at the bottom of the page. + +Don't forget to upload checksums for the tarballs and metadata documentation +as well. + +Send release announcement +------------------------- + +The announcement is sent to: + +* ltp at lists.linux.it (requires a subscription) +* linux-kernel at vger.kernel.org +* libc-alpha at sourceware.org (requires a subscription) +* valgrind-developers at lists.sourceforge.net (requires a subscription) + +CCed to: + +* lwn at lwn.net +* akpm at linux-foundation.org +* torvalds at linux-foundation.org diff --git a/ltp/doc/maintainers/patch_review.rst b/ltp/doc/maintainers/patch_review.rst new file mode 100644 index 0000000000000000000000000000000000000000..28bc4faf343047edfcf647b38f053f923b7de5c7 --- /dev/null +++ b/ltp/doc/maintainers/patch_review.rst @@ -0,0 +1,167 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Patch review +============ + +Anyone can and should review patches. It's the only way to get good at patch +review and for the project to scale. For this reason, we have a short guide on +what to do during the review process. + +Goals of patch review +--------------------- + +#. Prevent false positive test results +#. Prevent false negative test results +#. Keep the code as simple as possible, but no simpler + +How to find clear errors +------------------------ + +A clear error is one where there is unlikely to be any argument if you +provide evidence of it. Evidence being an error trace or logical proof +that an error will occur in a common situation. + +The following are examples and may not be appropriate for all tests. + +* Merge the patch locally. It should apply cleanly to master. +* Compile the patch with default and non-default configurations. + + * Use sanitizers e.g. undefined behavior, address. + * Compile on non-x86 + * Compile on x86 with ``-m32`` + * Compile testing patches with GitHub Actions in LTP repo fork can cover + various distros/architectures + +* Use ``make check`` +* Run effected tests in a VM + + * Use single vCPU + * Use many vCPUs and enable NUMA + * Restrict RAM to < 1GB. + +* Run effected tests on an embedded device +* Run effected tests on non-x86 machine in general +* Run reproducers on a kernel where the bug is present +* Run tests with ``-i0`` and ``-i2`` +* Compare usage of system calls with man page descriptions +* Compare usage of system calls with kernel code +* Double check commit message +* Search the LTP library for existing helper functions +* Check doc formatting, see :doc:`../developers/documentation`. + +How to find subtle errors +------------------------- + +A subtle error is one where you can expect some argument because you +do not have clear evidence of an error. It is best to state these as +questions and not make assertions if possible. + +Although if it is a matter of style or "taste" then senior maintainers +can assert what is correct to avoid bike shedding. + +* Ask what happens if there is an error, could it be debugged just + with the test output? +* Are we testing undefined behavior? + + * Could future kernel behavior change without "breaking userland"? + * Does the kernel behave differently depending on hardware? + * Does it behave differently depending on kernel configuration? + * Does it behave differently depending on the compiler? + * Would it behave differently if the order of checks on syscall parameters + changed in the kernel? + +* Will it scale to tiny and huge systems? + + * What happens if there are 100+ CPUs? + * What happens if each CPU core is very slow? + * What happens if there are 2TB of RAM? + +* Are we repeating a pattern that can be turned into a library function? +* Is a single test trying to do too much? +* Could multiple similar tests be merged? +* Race conditions + + * What happens if a process gets preempted? + * Could checkpoints or fuzzsync by used instead? + * Note, usually you can insert a sleep to prove a race condition + exists however finding them is hard + +* Is there a simpler way to achieve the same kernel coverage? + +How to get patches merged +------------------------- + +Once you think a patch is good enough you should add your ``Reviewed-by`` +and/or ``Tested-by`` tags. This means you will get some credit for getting +the patch merged. Also some blame if there are problems. + +If you ran the test you can add the ``Tested-by`` tag. If you read the +code or used static analysis tools on it, you can add the Reviewed-by +tag. + +In addition you can expect others to review your patches and add their +tags. This will speed up the process of getting your patches merged. + +Maintainers Checklist +--------------------- + +Patchset should be tested locally and ideally also in maintainer's fork in +GitHub Actions on GitHub. + +.. note:: + + GitHub Actions do 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 +* LTP documentation should be kept up to date. + +After patch is accepted or rejected, set correct state and archive in the +`LTP patchwork instance `_. + +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``) +* Run with ``-i 0`` to check that setup and cleanup are coded properly + (no test is being run) +* Have a brief description +* License: the default license for new tests is GPL v2 or later, use + ``GPL-2.0-or-later``; the license 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 :doc:`../developers/api_c_tests`, implementing :ref:`struct tst_test` +* Test binaries are added into corresponding ``.gitignore`` files +* Check coding style with ``make check`` +* Metadata documentation +* If a test is a regression test it should include :ref:`.tags` in the + :ref:`struct tst_test` definition + +Shell tests +~~~~~~~~~~~ + +* Use :doc:`../developers/api_shell_tests` +* Check coding style with ``make check`` +* If a test is a regression test it should include related kernel or glibc + commits as a comment + +LTP library +~~~~~~~~~~~ + +For patchset touching the LTP library, follow :doc:`../developers/ltp_library`. diff --git a/ltp/doc/old/C-Test-API.asciidoc b/ltp/doc/old/C-Test-API.asciidoc new file mode 100644 index 0000000000000000000000000000000000000000..72fd2731d38fcd0ba3ea106353ffa40bd0a05d36 --- /dev/null +++ b/ltp/doc/old/C-Test-API.asciidoc @@ -0,0 +1,2514 @@ +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] +------------------------------------------------------------------------------- +/*\ + * Tests basic functionality of getenv(). + * + * - create an env variable and verify that getenv() can 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 run(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 = run, + .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 limit on how long it can run, composed of two parts: 'runtime' +and 'timeout'. The 'runtime' is the limit for how long the '.test_all' or a set +of '.test' main functions can execute. The 'timeout', on the other hand, applies +to the total time for setup, single test function invocation, cleanup, and some +additional safety margin. If test without an explicit 'runtime', the 'timeout' +governs the entire test duration. + +The timeout timer is also reset on each subsequent iteration with the test -i +parameter, variants or .all_filesystems. + +Any test that runs for more than a second or two has to make sure to: + +- set the runtime by setting '.runtime' in tst_test and calling 'tst_set_runtime()' + to monitor the remaining runtime and ensure the test exits when the runtime + limit is reached. + +- set the timeout by setting '.timeout' in tst_test to limit the whole test + run that does not use 'tst_remaining_runtime()'. + +Test is free to exit before runtime has been used up for example when +minimal number of iteration was finished. + +The limit is applied to a single call of the '.test_all' function that means +that for example when '.test_variants' or '.all_filesystems' is set the whole +test will be limited by 'variants * (runtime + timeout)' seconds and the +test runtime will be likely close to 'variants * runtime' seconds. + +[source,c] +------------------------------------------------------------------------------- +/* + * Returns number of seconds or zero in case that runtime has been used up. + */ + +int tst_remaining_runtime(void); +------------------------------------------------------------------------------- + +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. +| 'TDEBUG' | Debug message (new C API only, printed with '-D' or via 'LTP_ENABLE_DEBUG=1' or 'y' + environment variable), only for messages which would be too verbose for normal run. +| '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 result and exits current test. If test uses +'.all_filesystems', '.test_variants' etc. the 'tst_brk()' exits current test +iteration e.g. currently running filesystem test or a test variant unless +'ttype' is set to 'TBROK'. + +If 'ttype' is set to 'TBROK' all test processes are killed and the test exits +immediately with an error. + +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 run(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 run(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 run(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 run(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. + +'TST_EXP_FAIL_SILENT()' and 'TST_EXP_FAIL2_SILENT()' variants are less verbose +and do not print TPASS messages when SCALL fails as expected. + +[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 +TTERRNO+ 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 or zero, this macro will print a pass +result and set +TST_PASS+ appropriately. If the return value is negative, then +it will print fail. There are many similar macros to those shown here, please +see 'tst_test_macros.h'. + +[source,c] +------------------------------------------------------------------------------- +TST_EXP_EQ_LI(val1, val2); +TST_EXP_EQ_UI(val1, val2); +TST_EXP_EQ_SZ(val1, val2); +TST_EXP_EQ_SSZ(val1, val2); + +/* Use as */ +TST_EXP_EQ_LI(sig_caught, SIGCHLD); +------------------------------------------------------------------------------- + +Set of macros for different integer type comparsions. These macros print the +variable names as well as values in both pass and fail scenarios. + +[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(int timeout); +------------------------------------------------------------------------------- + +Allows for setting the entire timeout dynamically during the test setup(). The +timeout is specified in seconds and represents the total time allowed for a single +test iteration, including setup, runtime, and teardown phases. + +[source,c] +------------------------------------------------------------------------------- +void tst_set_runtime(int runtime); +------------------------------------------------------------------------------- + +Allows for setting the runtime per test iteration dynamically during the test 'setup()'. +The runtime is specified in seconds and represents the duration the test is allowed +to execute its main workload, excluding setup and teardown phases. + +This function is useful for tests where the duration of the main workload can be +controlled or needs to be adjusted dynamically. For example, tests that loop until +the runtime expires can use this function to define how long they should run. + +[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. + +[source,c] +------------------------------------------------------------------------------- +#include +#include "tst_test.h" + +static char *str_threads; +static int threads = 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 = (struct tst_option[]) { + {"t:", &str_threads, "Number of threads (default 10)"}, + {}, + ... +}; +------------------------------------------------------------------------------- + + +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 = "4.10.0"'. + +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 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. + +[source,c] +------------------------------------------------------------------------------- +if (tst_kvercmp(5, 19, 0) >= 0) + tst_res(TCONF, "Test valid only for kernel < 5.19"); + +static struct tst_kern_exv kvers[] = { + { "UBUNTU", "4.4.0-48.69" }, + { NULL, NULL}, +}; + +if (tst_kvercmp2(4, 4, 27, kvers) < 0) + /* code for kernel < v4.4.27 or ubuntu kernel < 4.4.0-48.69 */ +------------------------------------------------------------------------------- + +WARNING: The shell 'tst_kvercmp' maps the result into unsigned integer - the + process exit value. + +NOTE: See also LTP + https://github.com/linux-test-project/ltp/wiki/Supported-kernel,-libc,-toolchain-versions#13-minimal-supported-kernel-version[minimal supported kernel version]. + +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 set the test library abort flag and +exits the test immediately. 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()'. That means that all +test child processes are supposed to exit with success unless they are +explicitly waited for. + +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 first 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 +~~~~~~~~~~~~~~~~~~ + +These macros are defined in 'include/tst_common.h'. + +[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. + +[source,c] +------------------------------------------------------------------------------- +TST_TO_STR(s) /* stringification */ +TST_TO_STR_(s) /* macro expansion */ +------------------------------------------------------------------------------- + +Macros for stringification. + +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. + +NOTE: ext2, ext3 or ext4 in '.skip_filesystems' on tests which does *not* use + '.all_filesystems' needs to be defined as 'ext2/ext3/ext4'. The reason + is that it is hard to detect used filesystem due to overlapping the functionality. + OTOH tests which use '.skip_filesystems' *with* '.all_filesystems' can skip + only filesystems which are actually used in '.all_filesystems': ext2, ext3, + ext4, xfs, btrfs, vfat, exfat, ntfs, tmpfs (defined in 'fs_type_whitelist[]'). + It does not make sense to list other filesystems. + + +[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" + +void tst_find_backing_dev(const char *path, char *dev, size_t dev_size); +------------------------------------------------------------------------------- + +This function finds the block dev that this path belongs to, using uevent in sysfs. +For Btrfs it uses '/sys/fs/btrfs/UUID/devices/DEV_NAME/uevent'; for other +filesystems it uses '/sys/dev/block/MAJOR:MINOR/uevent'. + +[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. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_dev_block_size(const char *path); +------------------------------------------------------------------------------- + +This function returns the physical device block size for the specific `path`. +It finds the device where `path` is located and then uses `ioctl` (BLKSSZGET) +to get a physical device block size. + +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. + +'SAFE_CMD()' is a wrapper for 'tst_cmd()' which can be used for automatic +handling non-zero exit (exits with 'TBROK') and 'ENOENT' (the program not in +'$PATH', 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 supported 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. + +The detection is based on reading 'modules.dep' and 'modules.builtin' files +generated by kmod. The check is skipped on Android. + +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 struct +'tst_path_val' where each tst_path_val.path represents a file, whose +value is saved at the beginning and restored at the end of the test. +If non-NULL string is passed in tst_path_val.val, it is written +to the respective file at the beginning of the test. Only the first line +of a specified file is saved and restored. + +By default, the test will end with TCONF if the file is read-only or +does not exist. If the optional write of new value fails, the test will end +with 'TBROK'. This behavior can be changed using tst_path_val.flags: + +* 'TST_SR_TBROK_MISSING' – End test with 'TBROK' if the file does not exist +* 'TST_SR_TCONF_MISSING' – End test with 'TCONF' if the file does not exist +* 'TST_SR_SKIP_MISSING' – Continue without saving the file if it does not exist +* 'TST_SR_TBROK_RO' – End test with 'TBROK' if the file is read-only +* 'TST_SR_TCONF_RO' – End test with 'TCONF' if the file is read-only +* 'TST_SR_SKIP_RO' – Continue without saving the file if it is read-only +* 'TST_SR_IGNORE_ERR' – Ignore all errors during reading and writing the file + +Common flag combinations also have shortcuts: + +* 'TST_SR_TCONF' – Equivalent to 'TST_SR_TCONF_MISSING | TST_SR_TCONF_RO' +* 'TST_SR_TBROK' – Equivalent to 'TST_SR_TBROK_MISSING | TST_SR_TBROK_RO' +* 'TST_SR_SKIP' – Equivalent to 'TST_SR_SKIP_MISSING | TST_SR_SKIP_RO' + +'restore' is always strict and will TWARN if it encounters any error. + +[source,c] +------------------------------------------------------------------------------- +static struct tst_test test = { + ... + .setup = setup, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/core_pattern", NULL, TST_SR_TCONF}, + {"/proc/sys/user/max_user_namespaces", NULL, TST_SR_SKIP}, + {"/sys/kernel/mm/ksm/run", "1", TST_SR_TBROK}, + {} + }, +}; +------------------------------------------------------------------------------- + +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 this feature 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 beginning 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 between '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 via '.hugepages = {xx, TST_REQUEST}'. + +We achieved two policies for reserving hugepages: + +TST_REQUEST: + It will try the best to reserve available huge pages and return the number + of available hugepages in tst_hugepages, which may be 0 if hugepages are + not supported at all. + +TST_NEEDS: + This is an enforced requirement, LTP should strictly do hpages applying and + guarantee the 'HugePages_Free' no less than pages which makes that test can + use these specified numbers correctly. Otherwise, test exits with TCONF if + the attempt to reserve hugepages fails or reserves less than requested. + +With success test stores the reserved hugepage number in 'tst_hugepages'. For +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 '.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.hugepages.number) + TEST(do_hpage_test); + else + ... + ... +} + +struct tst_test test = { + .test_all = run, + .hugepages = {2, TST_REQUEST}, + ... +}; +------------------------------------------------------------------------------- + +or, + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void run(void) +{ + ... +} + +static void setup(void) +{ + /* TST_NEEDS achieved this automatically in the library */ + if (tst_hugepages != test.hugepages.number) + tst_brk(TCONF, "..."); +} + +struct tst_test test = { + .test_all = run, + .hugepages = {2, TST_NEEDS}, + ... +}; +------------------------------------------------------------------------------- + +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.37 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 where possible. Allowing one +to write code that works on both V1 or V2. At least some of the time anyway; +often the behavioural differences between V1 and V2 are too great. In such cases +we revert to branching on the CGroup version. + +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" + +static void run(void) +{ + ... + // do test under cgroup + ... +} + +static void setup(void) +{ + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", MEMSIZE); + if (SAFE_CG_HAS(tst_cg, "memory.swap.max")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%zu", memsw); +} + +struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup, + .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, + ... +}; +------------------------------------------------------------------------------- + +Above, we first ensure the memory controller is available on the +test's CGroup with '.needs_cgroup_ctrls'. This populates a structure, +'tst_cg', which represents the test's CGroup. + +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_CG_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 struct tst_cg_group *cg_child; + +static void run(void) +{ + char buf[BUFSIZ]; + size_t mem = 0; + + cg_child = tst_cg_group_mk(tst_cg, "child"); + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + + if (!TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+memory"); + if (!TST_CG_VER_IS_V1(tst_cg, "cpuset")) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+cpuset"); + + if (!SAFE_FORK()) { + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + + if (SAFE_CG_HAS(cg_child, "memory.swap")) { + SAFE_CG_SCANF(cg_child, + "memory.swap.current", "%zu", &mem); + } + SAFE_CG_READ(cg_child, "cpuset.mems", buf, sizeof(buf)); + + // Do something with cpuset.mems and memory.current values + ... + + exit(0); + } + + tst_reap_children(); + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cg_group_rm(cg_child); +} + +static void cleanup(void) +{ + if (cg_child) { + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cg_group_rm(cg_child); + } +} + +struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_cgroup_ctrls = (const char *const []){ + "cpuset", + "memory", + NULL + }, + ... +}; +------------------------------------------------------------------------------- + +Starting with setup; we can see here that we 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. + +Note that 'tst_cg_get_drain_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. + +In 'run', we first create a child CGroup with 'tst_cg_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 a behavioral difference between versions is shown below. + +[source,c] +------------------------------------------------------------------------------- + if (TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lu", ~0UL); + else + SAFE_CG_PRINT(tst_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. Presently the LTP library does not attempt to handle most +differences in semantics. It does the minimal amount of work to make testing on +both V1 and V2 feasible. + +1.38 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.39 Require minimum memory or swap size for a testcase +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests require at least size(MB) of free RAM or Swap. + +To make sure that test will run only on systems with more than minimal +required amount of RAM set `.min_mem_avail = N`. + +Similarly for tests that require certain amount of free Swap use +`.min_swap_avail = N`. + +1.40 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 and musl git commits in a regression test for glibc and musl bugs: +[source,c] +------------------------------------------------------------------------------- +struct tst_test test = { + ... + .tags = (const struct tst_tag[]) { + {"glibc-git", "574500a108be"}, + {"musl-git", "fa4a8abd06a4"}, + {} + } +}; +------------------------------------------------------------------------------- + +1.41 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 + }, +}; +------------------------------------------------------------------------------- + +1.42 Skipping test based on system state +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Test can be skipped on various conditions: on enabled SecureBoot +('.skip_in_secureboot = 1'), lockdown ('.skip_in_lockdown = 1') or in 32-bit +compat mode ('.skip_in_compat = 1'). + +1.43 Set resource limits +~~~~~~~~~~~~~~~~~~~~~~~~ + +'.ulimit' allows to set resource limits on particular resource. NOTE: It sets 'rlim_max' +only if it's higher than 'rlim_cur'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct tst_test test = { + ... + .ulimit = (const struct tst_ulimit_val[]) { + {RLIMIT_STACK, RLIM_INFINITY}, + {} + }, +}; +------------------------------------------------------------------------------- + +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/ltp/doc/old/C-Test-Network-API.asciidoc b/ltp/doc/old/C-Test-Network-API.asciidoc new file mode 100644 index 0000000000000000000000000000000000000000..feedd5a9587742d7398defce5c680ff6121d876f --- /dev/null +++ b/ltp/doc/old/C-Test-Network-API.asciidoc @@ -0,0 +1,506 @@ +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 netlink 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 Netlink API +------------- + ++#include "tst_netlink.h"+ + +The netlink 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_netlink_context; + +struct tst_netlink_attr_list { + unsigned short type; + const void *data; + ssize_t len; + const struct tst_netlink_attr_list *sublist; +}; + +struct tst_netlink_message { + struct nlmsghdr *header; + struct nlmsgerr *err; + void *payload; + size_t payload_size; +}; +------------------------------------------------------------------------------- + ++struct tst_netlink_context+ is an opaque netlink socket with buffer for +constructing and sending arbitrary messages using the functions described +below. Create a new context using +NETLINK_CREATE_CONTEXT()+, then free it +using +NETLINK_DESTROY_CONTEXT()+ when you're done with it. + ++struct tst_netlink_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 nlattr.nla_type+ + or +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 nlattr.nla_len+ or + +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_netlink_message+ is a structure holding partially parsed netlink +messages received from the kernel. +NETLINK_RECV()+ returns an array of these +structures with the last item having +NULL+ in the +header+ field. Call ++NETLINK_FREE_MESSAGE()+ to free a message list returned by +NETLINK_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_netlink_context *NETLINK_CREATE_CONTEXT(int protocol)+ – Creates + a new netlink communication context with given netlink protocol for use + with the functions described below. Returns +NULL+ on error. + +- +void NETLINK_FREE_MESSAGE(struct tst_netlink_message *msg)+ – Frees + an array of messages returned by +NETLINK_RECV()+. + +- +void NETLINK_DESTROY_CONTEXT(struct tst_netlink_context *ctx)+ – Closes a + communication context created by +NETLINK_CREATE_CONTEXT()+. + +- +int NETLINK_SEND(struct tst_netlink_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 NETLINK_SEND_VALIDATE(struct tst_netlink_context *ctx)+ – Sends all + messages just like +NETLINK_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 +NETLINK_CHECK_ACKS()+ below for + explanation of the return value. + +- +int NETLINK_WAIT(struct tst_netlink_context *ctx)+ – Waits until data becomes + available to read from the netlink socket (timeout: 1 second). Returns 1 + if there is data to read, 0 on timeout or -1 on error. + +- +struct tst_netlink_message *NETLINK_RECV(struct tst_netlink_context *ctx)+ – + Receives netlink messages from the kernel. The messages are received + in non-blocking mode so calling +NETLINK_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 +NETLINK_FREE_MESSAGE()+ to free + the returned data. + +- +int NETLINK_CHECK_ACKS(struct tst_netlink_context *ctx, + struct tst_netlink_message *response)+ – Validate results of requests sent + with the +NLM_F_ACK+ flag. Do not call +NETLINK_ADD_MESSAGE()+ between + +NETLINK_SEND()+ and +NETLINK_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_netlink_errno+ (sign-flipped just like regular libc +errno+). + +3.3 Creating messages +~~~~~~~~~~~~~~~~~~~~~ + +- +int NETLINK_ADD_MESSAGE(struct tst_netlink_context *ctx, const struct + nlmsghdr *header, const void *payload, size_t payload_size)+ – Adds new + netlink 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 + +NETLINK_ADD_MESSAGE()+ after +NETLINK_SEND()+ will reset the state of +ctx+ + and +NETLINK_CHECK_ACKS()+ will not work correctly until the next + +NETLINK_SEND()+. + +- +int NETLINK_ADD_ATTR(struct tst_netlink_context *ctx, unsigned short type, + const void *data, unsigned short len)+ – Adds new +struct nlattr+ attribute + to the last message in +ctx+ buffer. See +NETLINK_ADD_MESSAGE()+. You need + to provide attribute +type+ which will be stored in +struct nlattr.nla_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 NETLINK_ADD_ATTR_STRING(struct tst_netlink_context *ctx, unsigned short + type, const char *data)+ – Adds new +struct nlattr+ string attribute to the + last message in +ctx+ buffer. Parameters and return value are the same as + for +NETLINK_ADD_ATTR()+, except the payload length is calculated using + +strlen()+. + +- +int NETLINK_ADD_ATTR_LIST(struct tst_netlink_context *ctx, const struct + tst_netlink_attr_list *list)+ – Adds a list of +struct nlattr+ attributes + to the last message in +ctx+ buffer. See description of + +struct tst_netlink_attr_list+ and +NETLINK_ADD_MESSAGE()+ above. Returns + the number of added attributes on success (nested attributes are not + counted), -1 on error. + +- +int RTNL_ADD_ATTR(struct tst_netlink_context *ctx, unsigned short type, + const void *data, unsigned short len)+ – Adds new +struct rtattr+ attribute + to the last message in +ctx+ buffer. See +NETLINK_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_netlink_context *ctx, unsigned short + type, const char *data)+ – Adds new +struct rtattr+ 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_netlink_context *ctx, const struct + tst_netlink_attr_list *list)+ – Adds a list of +struct rtattr+ attributes + to the last message in +ctx+ buffer. See description of + +struct tst_netlink_attr_list+ and +NETLINK_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_netlink.h" +#include "tst_netdevice.h" + +... + +void setup(void) +{ + struct tst_netlink_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 = NETLINK_CREATE_CONTEXT(NETLINK_ROUTE); + NETLINK_ADD_MESSAGE(ctx, &header, &info, sizeof(info)); + addr = inet_addr("192.168.123.45"); + RTNL_ADD_ATTR(ctx, IFA_LOCAL, &addr, sizeof(addr)); + ret = NETLINK_SEND_VALIDATE(ctx); + NETLINK_DESTROY_CONTEXT(ctx); + + if (!ret) { + tst_brk(TBROK, "Failed to set ltp_veth1 address"); + } +} +------------------------------------------------------------------------------- diff --git a/ltp/doc/old/KVM-Test-API.asciidoc b/ltp/doc/old/KVM-Test-API.asciidoc new file mode 100644 index 0000000000000000000000000000000000000000..7e537afcb7b44e36742cf34b1a5a8df71497d378 --- /dev/null +++ b/ltp/doc/old/KVM-Test-API.asciidoc @@ -0,0 +1,487 @@ +LTP KVM Test API +================ + +Testing KVM is more complex than other Linux features. Some KVM bugs allow +userspace code running inside the virtual machine to bypass (emulated) hardware +access restrictions and elevate its privileges inside the guest operating +system. The worst types of KVM bugs may even allow the guest code to crash or +compromise the physical host. KVM tests therefore need to be split into two +components – a KVM controller program running on the physical host and a guest +payload program running inside the VM. The cooperation of these two components +allows testing even of bugs that somehow cross the virtualization boundary. + +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]. + +1. Basic KVM test structure +--------------------------- + +KVM tests are simple C source files containing both the KVM controller code +and the guest payload code separated by `#ifdef COMPILE_PAYLOAD` preprocessor +condition. The file will be compiled twice. Once to compile the payload part, +once to compile the KVM controller part and embed the payload binary inside. +The result is a single self-contained binary that'll execute the embedded +payload inside a KVM virtual machine and print results in the same format as +a normal LTP test. + +A KVM test source should start with `#include "kvm_test.h"` instead of the +usual `tst_test.h`. The `kvm_test.h` header file will include the other basic +headers appropriate for the current compilation pass. Everything else in the +source file should be enclosed in `#ifdef COMPILE_PAYLOAD ... #else ... #endif` +condition, including any other header file includes. Note that the standard +LTP headers are not available in the payload compilation pass, only the KVM +guest library headers can be included. + +.Example KVM test +[source,c] +------------------------------------------------------------------------------- +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD + +/* Guest payload code */ + +void main(void) +{ + tst_res(TPASS, "Hello, world!"); +} + +#else /* COMPILE_PAYLOAD */ + +/* KVM controller code */ + +static struct tst_test test = { + .test_all = tst_kvm_run, + .setup = tst_kvm_setup, + .cleanup = tst_kvm_cleanup, +}; + +#endif /* COMPILE_PAYLOAD */ +------------------------------------------------------------------------------- + +The KVM controller code is a normal LTP test and needs to define an instance +of `struct tst_test` with metadata and the usual setup, cleanup, and test +functions. Basic implementation of all three functions is provided by the KVM +host library. + +On the other hand, the payload is essentially a tiny kernel that'll run +on bare virtual hardware. It cannot access any files, Linux syscalls, standard +library functions, etc. except for the small subset provided by the KVM guest +library. The payload code must define a `void main(void)` function which will +be the VM entry point of the test. + +2. KVM host library +------------------- + +The KVM host library provides helper functions for creating and running +a minimal KVM virtual machine. + +2.1 Data structures +~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +struct tst_kvm_instance { + int vm_fd, vcpu_fd; + struct kvm_run *vcpu_info; + size_t vcpu_info_size; + struct kvm_userspace_memory_region ram[MAX_KVM_MEMSLOTS]; + struct tst_kvm_result *result; +}; +------------------------------------------------------------------------------- + +`struct tst_kvm_instance` holds the file descriptors and memory buffers +of a single KVM virtual machine: + +- `int vm_fd` is the main VM file descriptor created by `ioctl(KVM_CREATE_VM)` +- `int vcpu_fd` is the virtual CPU filedescriptor created by + `ioctl(KVM_CREATE_VCPU)` +- `struct kvm_run *vcpu_info` is the VCPU state structure created by + `mmap(vcpu_fd)` +- `size_t vcpu_info_size` is the size of `vcpu_info` buffer +- `struct kvm_userspace_memory_region ram[MAX_KVM_MEMSLOTS]` is the list + of memory slots defined in this VM. Unused memory slots have zero + in the `userspace_addr` field. +- `struct tst_kvm_result *result` is a buffer for passing test result data + from the VM to the controller program, mainly `tst_res()`/`tst_brk()` flags + and messages. + +[source,c] +------------------------------------------------------------------------------- +struct tst_kvm_result { + int32_t result; + int32_t lineno; + uint64_t file_addr; + char message[0]; +}; +------------------------------------------------------------------------------- + +`struct tst_kvm_result` is used to pass test results and synchronization data +between the KVM guest and the controller program. Most often, it is used +to pass `tst_res()` and `tst_brk()` messages from the VM, but special values +can also be used to send control flow requests both ways. + +- `int32_t result` is the message type, either one of the `TPASS`, `TFAIL`, + `TWARN`, `TBROK`, `TINFO` flags or a special control flow value. Errno flags + are not supported. +- `int32_t lineno` is the line number for `tst_res()`/`tst_brk()` messages. +- `uint64_t file_addr` is the VM address of the filename string for + `tst_res()`/`tst_brk()` messages. +- `char message[0]` is the buffer for arbitrary message data, most often used + to pass `tst_res()`/`tst_brk()` message strings. + +2.2 Working with virtual machines +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The KVM host library provides default implementation of the setup, cleanup +and test functions for `struct tst_test` in cases where you do not need +to customize the VM configuration. You can either assign these functions +to the `struct tst_test` instance directly or call them from your own function +that does some additional steps. All three function must be used together. + +- `void tst_kvm_setup(void)` +- `void tst_kvm_run(void)` +- `void tst_kvm_cleanup(void)` + +Note: `tst_kvm_run()` calls `tst_free_all()`. Calling it will free all +previously allocated guarded buffers. + +- `void tst_kvm_validate_result(int value)` – Validate whether the value + returned in `struct tst_kvm_result.result` can be safely passed + to `tst_res()` or `tst_brk()`. If the value is not valid, the controller + program will be terminated with error. + +- `uint64_t tst_kvm_get_phys_address(const struct tst_kvm_instance *inst, + uint64_t addr)` – Converts pointer value (virtual address) from KVM virtual + machine `inst` to the corresponding physical address. Returns 0 if + the virtual address is not mapped to any physical address. If virtual memory + mapping is not enabled in the VM or not available on the arch at all, this + function simply returns `addr` as is. + +- `int tst_kvm_find_phys_memslot(const struct tst_kvm_instance *inst, + uint64_t paddr)` – Returns index of the memory slot in KVM virtual machine + `inst` which contains the physical address `paddr`. If the address is not + backed by a memory buffer, returns -1. + +- `int tst_kvm_find_memslot(const struct tst_kvm_instance *inst, + uint64_t addr)` – Returns index of the memory slot in KVM virtual machine + `inst` which contains the virtual address `addr`. If the virtual address + is not mapped to a valid physical address backed by a memory buffer, + returns -1. + +- `void *tst_kvm_get_memptr(const struct tst_kvm_instance *inst, + uint64_t addr)` – Converts pointer value (virtual address) from KVM virtual + machine `inst` to host-side pointer. + +- `void *tst_kvm_alloc_memory(struct tst_kvm_instance *inst, unsigned int slot, + uint64_t baseaddr, size_t size, unsigned int flags)` – Allocates a guarded + buffer of given `size` in bytes and installs it into specified memory `slot` + of the KVM virtual machine `inst` at base address `baseaddr`. The buffer + will be automatically page aligned at both ends. See the kernel + documentation of `KVM_SET_USER_MEMORY_REGION` ioctl for list of valid + `flags`. Returns pointer to page-aligned beginning of the allocated buffer. + The actual requested `baseaddr` will be located at + `ret + baseaddr % pagesize`. + +- `struct kvm_cpuid2 *tst_kvm_get_cpuid(int sysfd)` – Get a list of supported + virtual CPU features returned by `ioctl(KVM_GET_SUPPORTED_CPUID)`. + The argument must be an open file descriptor returned by `open("/dev/kvm")`. + +- `void tst_kvm_create_instance(struct tst_kvm_instance *inst, + size_t ram_size)` – Creates and fully initializes a new KVM virtual machine + with at least `ram_size` bytes of memory. The VM instance info will be + stored in `inst`. + +- `int tst_kvm_run_instance(struct tst_kvm_instance *inst, int exp_errno)` – + Executes the program installed in KVM virtual machine `inst`. Any result + messages returned by the VM will be automatically printed to controller + program output. Returns zero. If `exp_errno` is non-zero, the VM execution + syscall is allowed to fail with the `exp_errno` error code and + `tst_kvm_run_instance()` will return -1 instead of terminating the test. + +- `void tst_kvm_destroy_instance(struct tst_kvm_instance *inst)` – Deletes + the KVM virtual machine `inst`. Note that the guarded buffers assigned + to the VM by `tst_kvm_create_instance()` or `tst_kvm_alloc_memory()` will + not be freed. + +The KVM host library does not provide any way to reset a VM instance back +to initial state. Running multiple iterations of the test requires destroying +the old VM instance and creating a new one. Otherwise the VM will exit +without reporting any results on the second iteration and the test will fail. +The `tst_kvm_run()` function handles this issue correctly. + +3. KVM guest library +-------------------- + +The KVM guest library provides a minimal implementation of both the LTP +test library and the standard C library functions. Do not try to include +the usual LTP or C headers in guest payload code, it will not work. + +3.1 Standard C functions +~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +The functions listed below are implemented according to the C standard: + +- `void *memset(void *dest, int val, size_t size)` +- `void *memzero(void *dest, size_t size)` +- `void *memcpy(void *dest, const void *src, size_t size)` +- `char *strcpy(char *dest, const char *src)` +- `char *strcat(char *dest, const char *src)` +- `size_t strlen(const char *str)` + +3.2 LTP library functions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +The KVM guest library currently provides the LTP functions for reporting test +results. All standard result flags except for `T*ERRNO` are supported +with the same rules as usual. However, the printf-like formatting is not +implemented yet. + +- `void tst_res(int result, const char *message)` +- `void tst_brk(int result, const char *message) __attribute__((noreturn))` + +A handful of useful macros is also available: + +- `TST_TEST_TCONF(message)` – Generates a test program that will simply print + a `TCONF` message and exit. This is useful when the real test cannot be + built due to missing dependencies or arch limitations. + +- `ARRAY_SIZE(arr)` – Returns the number of items in statically allocated + array `arr`. + +- `LTP_ALIGN(x, a)` – Aligns integer `x` to be a multiple of `a`, which + must be a power of 2. + +3.3 Arch independent functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +Memory management in KVM guest library currently uses only primitive linear +buffer for memory allocation. There are no checks whether the VM can allocate +more memory and the already allocated memory cannot be freed. + +- `void *tst_heap_alloc(size_t size)` – Allocates a block of memory on the heap. + +- `void *tst_heap_alloc_aligned(size_t size, size_t align)` – Allocates + a block of memory on the heap with the starting address aligned to given + value. + +3.4 x86 specific functions +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +`#include "kvm_x86.h"` + +- `struct kvm_interrupt_frame` – Opaque arch-dependent structure which holds + interrupt frame information. Use the functions below to get individual values: + +- `uintptr_t kvm_get_interrupt_ip(const struct kvm_interrupt_frame *ifrm)` – + Get instruction pointer value from interrupt frame structure. This may be + the instruction which caused an interrupt or the one immediately after, + depending on the interrupt vector semantics. + +- `int (*tst_interrupt_callback)(void *userdata, + struct kvm_interrupt_frame *ifrm, unsigned long errcode)` – Interrupt handler + callback prototype. When an interrupt occurs, the assigned callback function + will be passed the `userdata` pointer that was given + to `tst_set_interrupt_callback()`, interrupt frame `ifrm` and the error + code `errcode` defined by the interrupt vector semantics. If the interrupt + vector does not generate an error code, `errcode` will be set to zero. + The callback function must return 0 if the interrupt was successfully + handled and test execution should resume. Non-zero return value means that + the interrupt could not be handled and the test will terminate with error. + +- `void tst_set_interrupt_callback(unsigned int vector, + tst_interrupt_callback func, void *userdata)` – Register new interrupt + handler callback function `func` for interrupt `vector`. The `userdata` + argument is an arbitrary pointer that will be passed to `func()` every time + it gets called. The previous interrupt handler callback will be removed. + Setting `func` to `NULL` will remove any existing interrupt handler + from `vector` and the interrupt will become fatal error. + +[source,c] +------------------------------------------------------------------------------- +struct page_table_entry_pae { + unsigned int present: 1; + unsigned int writable: 1; + unsigned int user_access: 1; + unsigned int write_through: 1; + unsigned int disable_cache: 1; + unsigned int accessed: 1; + unsigned int dirty: 1; + unsigned int page_type: 1; + unsigned int global: 1; + unsigned int padding: 3; + uint64_t address: 40; + unsigned int padding2: 7; + unsigned int prot_key: 4; + unsigned int noexec: 1; +} __attribute__((__packed__)); + +struct kvm_cpuid { + unsigned int eax, ebx, ecx, edx; +}; + +struct kvm_cregs { + unsigned long cr0, cr2, cr3, cr4; +}; + +struct kvm_sregs { + uint16_t cs, ds, es, fs, gs, ss; +}; +------------------------------------------------------------------------------- + +`struct page_table_entry_pae` is the page table entry structure for PAE and +64bit paging modes. See Intel(R) 64 and IA-32 Architectures Software +Developer's Manual, Volume 3, Chapter 4 for explanation of the fields. + +- `uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry)` + – Returns the physical address of the memory page referenced by the given + page table `entry`. Depending on memory mapping changes done by the test, + the physical address may not be a valid pointer. The caller must determine + whether the address points to another page table entry or a data page, using + the known position in page table hierarchy and `entry->page_type`. Returns + zero if the `entry` does not reference any memory page. + +- `void kvm_set_segment_descriptor(struct segment_descriptor *dst, uint64_t baseaddr, uint32_t limit, unsigned int flags)` - + Fill the `dst` segment descriptor with given values. The maximum value + of `limit` is `0xfffff` (inclusive) regardless of `flags`. + +- `void kvm_parse_segment_descriptor(struct segment_descriptor *src, uint64_t *baseaddr, uint32_t *limit, unsigned int *flags)` - + Parse data in the `src` segment descriptor and copy them to variables + pointed to by the other arguments. Any parameter except the first one can + be `NULL`. + +- `int kvm_find_free_descriptor(const struct segment_descriptor *table, size_t size)` - + Find the first segment descriptor in `table` which does not have + the `SEGFLAG_PRESENT` bit set. The function handles double-size descriptors + correctly. Returns index of the first available descriptor or -1 if all + `size` descriptors are taken. + +- `unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table, size_t tabsize, void *stack_base)` - + Convenience function for registering a stack segment descriptor. It'll + automatically find a free slot in `table` and fill the necessary flags. + The `stack_base` pointer must point to the bottom of the stack. + +- `void kvm_get_cpuid(unsigned int eax, unsigned int ecx, + struct kvm_cpuid *buf)` – Executes the CPUID instruction with the given + `eax` and `ecx` arguments and stores the results in `buf`. + +- `void kvm_read_cregs(struct kvm_cregs *buf)` – Copies the current values + of control registers to `buf`. + +- `void kvm_read_sregs(struct kvm_sregs *buf)` - Copies the current values + of segment registers to `buf`. + +- `uint64_t kvm_rdmsr(unsigned int msr)` – Returns the current value + of model-specific register `msr`. + +- `void kvm_wrmsr(unsigned int msr, uint64_t value)` – Stores `value` + into model-specific register `msr`. + +- `void kvm_exit(void) __attribute__((noreturn))` – Terminate the test. + Similar to calling `exit(0)` in a regular LTP test, although `kvm_exit()` + will terminate only one iteration of the test, not the whole host process. + +See Intel(R) 64 and IA-32 Architectures Software Developer's Manual +for documentation of standard and model-specific x86 registers. + +3.5 AMD SVM helper functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +`#include "kvm_x86.h"` + +`#include "kvm_x86_svm.h"` + +The KVM guest library provides basic helper functions for creating and running +nested virtual machines using the AMD SVM technology. + +.Example code to execute nested VM +[source,c] +------------------------------------------------------------------------------- +int guest_main(void) +{ + ... + return 0; +} + +void main(void) +{ + struct kvm_svm_vcpu *vm; + + kvm_init_svm(); + vm = kvm_create_svm_vcpu(guest_main, 1); + kvm_svm_vmrun(vm); +} +------------------------------------------------------------------------------- + +- `int kvm_is_svm_supported(void)` - Returns non-zero value if the CPU + supports AMD SVM, otherwise returns 0. + +- `int kvm_get_svm_state(void)` - Returns non-zero value if SVM is currently + enabled, otherwise returns 0. + +- `void kvm_set_svm_state(int enabled)` - Enable or disable SVM according + to argument. If SVM is disabled by host or not supported, the test will exit + with `TCONF`. + +- `void kvm_init_svm(void)` - Enable and fully initialize SVM, including + allocating and setting up host save area VMCB. If SVM is disabled by host or + not supported, the test will exit with `TCONF`. + +- `struct kvm_vmcb *kvm_alloc_vmcb(void)` - Allocate new VMCB structure + with correct memory alignment and fill it with zeroes. + +- `void kvm_vmcb_set_intercept(struct kvm_vmcb *vmcb, unsigned int id, unsigned int state)` - + Set SVM intercept bit `id` to given `state`. + +- `void kvm_init_guest_vmcb(struct kvm_vmcb *vmcb, uint32_t asid, uint16_t ss, void *rsp, int (*guest_main)(void))` - + Initialize new SVM virtual machine. The `asid` parameter is the nested + page table ID. The `ss` and `rsp` parameters set the stack segment and stack + pointer values, respectively. The `guest_main` parameter sets the code entry + point of the virtual machine. All control registers, segment registers + (except stack segment register), GDTR and IDTR will be copied + from the current CPU state. + +- `struct kvm_svm_vcpu *kvm_create_svm_vcpu(int (*guest_main)(void), int alloc_stack)` - + Convenience function for allocating and initializing new SVM virtual CPU. + The `guest_main` parameter is passed to `kvm_init_guest_vmcb()`, + the `alloc_stack` parameter controls whether a new 8KB stack will be + allocated and registered in GDT. Interception will be enabled for `VMSAVE` + and `HLT` instructions. If you set `alloc_stack` to zero, you must configure + the stack segment register and stack pointer manually. + +- `void kvm_svm_vmrun(struct kvm_svm_vcpu *cpu)` - Start or continue execution + of a nested virtual machine. Beware that FPU state is not saved. Do not use + floating point types or values in nested guest code. Also do not use + `tst_res()` or `tst_brk()` functions in nested guest code. + +See AMD64 Architecture Programmer's Manual Volume 2 for documentation +of the Secure Virtual Machine (SVM) technology. + +4. KVM guest environment +------------------------ + +KVM guest payload execution begins with bootstrap code which will perform +the minimal guest environment setup required for running C code: + +- Activate the appropriate CPU execution mode (IA-32 protected mode + on 32-bit x86 or the 64-bit mode on x86_64). +- Create indentity mapping (virtual address = physical address) of the lower + 2GB memory region, even if parts of the region are not backed by any host + memory buffers. The memory region above 2GB threshold is left unmapped + except for one memory page reserved for the `struct tst_kvm_result` buffer. +- Initialize 8KB stack. +- Install default interrupt handlers for standard CPU exception vectors. + +When the environment setup is complete, bootstrap will call `void main(void)` +function implemented by the test program. To finish execution of guest payload, +the test can either return from the `main()` function or call `kvm_exit()` +at any point. diff --git a/ltp/doc/old/Shell-Test-API.asciidoc b/ltp/doc/old/Shell-Test-API.asciidoc new file mode 100644 index 0000000000000000000000000000000000000000..c38fb0698a4c83e8772bd756cd3474ad5a8f2d56 --- /dev/null +++ b/ltp/doc/old/Shell-Test-API.asciidoc @@ -0,0 +1,828 @@ +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 + +do_test() +{ + true + ret=$? + + if [ $ret -eq 0 ]; then + tst_res TPASS "true returned 0" + else + tst_res TFAIL "true returned $ret" + fi +} + +. tst_test.sh +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 + +test1() +{ + tst_res TPASS "Test $1 passed" +} + +test2() +{ + tst_res TPASS "Test $1 passed" +} + +. tst_test.sh +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 + +do_test() +{ + case $1 in + 1) tst_res TPASS "Test $1 passed";; + 2) tst_res TPASS "Test $1 passed";; + esac +} + +. tst_test.sh +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=":" + +do_test() +{ + tst_res TPASS "Test $1 passed with data '$2'" +} + +. tst_test.sh +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" + +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_test.sh +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 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similarly to the C library various checks and preparations can be requested +simply by setting right '$TST_FOO'. + +[options="header"] +|============================================================================= +| Variable name | Action done +| 'TST_ALL_FILESYSTEMS' | Testing on all available filesystems + ('tst_test.all_filesystems' equivalent). + When 'TST_SKIP_FILESYSTEMS' any listed filesystem is not + included in the resulting list of supported filesystems. +| 'TST_DEV_EXTRA_OPTS' | Pass extra 'mkfs' options _after_ device name, + to 'tst_mkfs', use with 'TST_FORMAT_DEVICE=1'. +| 'TST_DEV_FS_OPTS' | Pass 'mkfs' options _before_ the device name, + to 'tst_mkfs', use with 'TST_FORMAT_DEVICE=1'. +| 'TST_FORMAT_DEVICE' | Format a block device with a filesystem, see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#formatting-device-with-a-filesystem[Formatting device with a filesystem]. + See also 'TST_DEV_EXTRA_OPTS', 'TST_DEV_FS_OPTS', 'TST_FS_TYPE'. + Implies 'TST_NEEDS_DEVICE=1' (no need to set it). +| 'TST_DEVICE' | Block device name for 'tst_mount' and 'tst_mkfs', see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#formatting-device-with-a-filesystem[Formatting device with a filesystem]. +| 'TST_FS_TYPE' | Override the default filesystem to be used. Also + contains currently used filesystem during looping + filesystems in 'TST_ALL_FILESYSTEMS=1' + ('tst_device->fs_type' equivalent). +| 'TST_MNTPOINT' | Holds path to mountpoint used in 'tst_mount', see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#formatting-device-with-a-filesystem[Formatting device with a filesystem]. +| 'TST_MNT_PARAMS' | Extra mount params for 'tst_mount', see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#formatting-device-with-a-filesystem[Formatting device with a filesystem]. +| 'TST_MOUNT_DEVICE' | Mount device, see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#mounting-and-unmounting-filesystems[Mounting and unmounting filesystems]. +| '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_SKIP_FILESYSTEMS' | Comma separated list of filesystems on which test will be skipped + (tst_test.skip_filesystems equivalent). +| '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 + +do_test() +{ + tst_check_cmds cmd || return + cmd --foo + ... +} + +. tst_test.sh +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 + +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_test.sh +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 + +usage() +{ + cat << EOF +usage: $0 [min] [max] [size] + +EOF +} + +min="$1" +max="$2" +size="$3" + +do_test() +{ + ... +} + +. tst_test.sh +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 ++++++++++++++++++++++++++++++++++++ + +'TST_FORMAT_DEVICE=1' can be used to format device before running the test. +Uses '$TST_FS_TYPE' (by default ext2), '$TST_DEVICE' a block device to be +formatted, usually prepared by the library (TST_NEEDS_DEVICE=1 must be set). +'$TST_DEV_FS_OPTS' a 'mkfs' options _before_ the device path and +'$TST_DEV_EXTRA_OPTS' extra 'mkfs'' options _after_ the device path. + +[source,sh] +------------------------------------------------------------------------------- +TST_FORMAT_DEVICE=1 +TST_DEV_FS_OPTS="-b 1024 -O quota" +TST_DEV_EXTRA_OPTS="5m" +TST_TESTFUNC=test + +test() +{ + tst_res TPASS "device formatted" +} +------------------------------------------------------------------------------- + +[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 4.0.0 +if tst_kvcmp -le 4.0.0; then + tst_brk TCONF "Kernel newer than 4.0.0 is needed" +fi + +# Exit the test if kernel is newer than 3.16 and older than 4.0.1 +if tst_kvcmp -gt 3.16 -a -lt 4.0.1; then + tst_brk TCONF "Kernel must be older than 3.16 or newer than 4.0.1" +fi + +if tst_kvcmp -lt "6.1 RHEL9:5.14.0-191"; then + # code for kernel < 6.1 or RHEL9 kernel < 5.14.0-191 +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'. + +Kernel version can also be followed by a space separated list of extra versions +prefixed by distribution which when matched take precedence, e.g. '6.1 RHEL9:5.14.0-191'. + +For more info see 'tst_kvercmp()' and 'tst_kvercmp2()' in +https://github.com/linux-test-project/ltp/wiki/C-Test-API#16-runtime-kernel-version-detection[C Test API]. + +NOTE: See also LTP + https://github.com/linux-test-project/ltp/wiki/Supported-kernel,-libc,-toolchain-versions#13-minimal-supported-kernel-version[minimal supported kernel version]. + +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 +------------------------------------------------------------------------------- + +1.8 Skipping test based on system state +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Test can be skipped on various conditions: on enabled SecureBoot +('TST_SKIP_IN_SECUREBOOT=1'), lockdown ('TST_SKIP_IN_LOCKDOWN=1'). diff --git a/ltp/doc/old/namespaces-helper-tools.txt b/ltp/doc/old/namespaces-helper-tools.txt new file mode 100644 index 0000000000000000000000000000000000000000..b911dd6cc63a7b1ead3b31abe3692dab61bbc709 --- /dev/null +++ b/ltp/doc/old/namespaces-helper-tools.txt @@ -0,0 +1,58 @@ +LTP namespaces helper tools +=========================== + + +1. Introduction +--------------- + +LTP provides helper tools for creating and working with namespaces. These are +located in ltp/testcases/kernel/containers/share directory and include: + +* tst_ns_create +** creates a child process in the new specified namespace(s) +** child is then daemonized and is running in the background +** PID of the daemonized child process is printed on the stdout +** the new namespace(s) is(are) maintained by the daemonized child process +** namespace(s) can be removed by killing the daemonized process +* tst_ns_exec +** enters the namespace(s) of a process specified by a PID +** then executes the indicated program inside that namespace(s) +* tst_ns_ifmove +** moves a network interface to the namespace of a process specified by a PID + +Purpose of these helper tools is the ability to execute test cases utilizing +namespaces even on older kernels which do not provide tooling (i.e. unshare(1) +or nsenter(1) from util-linux) required for working with namespaces. The only +requirement from kernel side is the support of "setns" syscall. + +2. Example usage +---------------- + +The following code shows how test cases can use the namespaces helper tools: + +[source,sh] +------------------------------------------------------------------------------- +# Creates a new network and ipc namespace and stores the PID of the daemonized +# process inside that namespace into variable myns +myns=$(tst_ns_create net,ipc) + +ip link add veth0 type veth peer name veth1 + +# Executes command 'ip a' inside the namespace specified by PID in myns variable +tst_ns_exec $myns net,ipc ip a +1: lo: mtu 65536 qdisc noop state DOWN + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + +# Moves interface veth1 into the namespace specified by PID in myns variable +tst_ns_ifmove veth1 $myns +tst_ns_exec $myns net,ipc ip a +1: lo: mtu 65536 qdisc noop state DOWN + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 +6: veth1: mtu 1500 qdisc noop state DOWN qlen 1000 + link/ether 6a:0a:45:ed:6e:d0 brd ff:ff:ff:ff:ff:ff + +# cleanup +ip link del veth0 +# By killing the daemonized process we also delete the namespace +kill -9 $myns +------------------------------------------------------------------------------- diff --git a/ltp/doc/requirements.txt b/ltp/doc/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b9a984547dedc3ca95d76ddd8d2361279b032c9 --- /dev/null +++ b/ltp/doc/requirements.txt @@ -0,0 +1,7 @@ +# Use the same sphinx as on readthedocs.org. When updated, make sure +# sphinx-rtd-theme is compatible with sphinx. +sphinx==7.2.6 +sphinx-rtd-theme==2.0.0 + +linuxdoc==20231020 +sphinxcontrib-spelling==7.7.0 diff --git a/ltp/doc/spelling_wordlist b/ltp/doc/spelling_wordlist new file mode 100644 index 0000000000000000000000000000000000000000..506e5bdad8b1c151ec32aef31e3badbfd8773eb3 --- /dev/null +++ b/ltp/doc/spelling_wordlist @@ -0,0 +1,161 @@ +aarch +akpm +amd +archiver +archs +args +asciidoc +autoconf +automake +backport +baz +btime +bufs +CCed +cgroup +cgroups +checksum +checksums +cmds +codebase +compat +config +cpus +ctrls +datafiles +dependants +dev +devfs +dio +distro +distros +docparse +doio +executables +fd +filesystem +filesystems +fixup +fs +fstrict +fuzzsync +gcc +gdb +github +gitignore +glibc +growfiles +hugepage +iogen +kbuild +kconfigs +kver +ld +le +libc +libltp +libs +linkable +linux +lockdown +ltp +lwn +Maipo +Makefile +Makefiles +mem +mnt +mntpoint +msg +namespace +namespaces +onwards +openSUSE +patchset +pkgconf +posix +ppc +pre +pre +preprocessor +rebase +reflog +reinit +repo +rofs +runtest +scall +secureboot +sourceware +statx +stdout +structs +stx +subdirectory +subshell +subshells +syscall +syscalls +tcnt +tconf +teardown +testcase +testcases +testsuite +testsuites +tmp +tmpdir +toolchain +toolchains +torvalds +tst +uClibc +ulimit +un +userland +userspace +vCPU +vCPUs +vendoring +vger +wallclock +pid +TBROK +mkfs +hugepages +hugetlbfs +printf +scanf +argv +argc +pthread +futex +hdr +brk +iovec +iov +strdup +aprintf +alloc +hexd +tcases +strsig +strstatus +strerrno +libcap +capset +capget +musl +setrlimit +rlim +optstr +tmpfs +nodev +sys +proc +arg +ver +bitwise +dereferenced +allocator +ptr diff --git a/ltp/doc/users/quick_start.rst b/ltp/doc/users/quick_start.rst new file mode 100644 index 0000000000000000000000000000000000000000..8a25b91291a0b8b065a13bff6a068fce80792ba9 --- /dev/null +++ b/ltp/doc/users/quick_start.rst @@ -0,0 +1,127 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Installation and tests execution +================================ + +Basics requirements to build LTP are the following: + +* git +* autoconf +* automake +* make +* gcc +* m4 +* pkgconf / pkg-config +* libc headers +* linux headers + +.. code-block:: console + + $ git clone --recurse-submodules https://github.com/linux-test-project/ltp.git + $ cd ltp + $ make autotools + $ ./configure + +.. note:: + + For optional library dependencies, take a look at the scripts inside :master:`ci/` + directory. + +Running single tests +-------------------- + +LTP provides the possibility to build and run single tests: + +.. code-block:: console + + $ cd testcases/kernel/syscalls/foo + $ make + $ PATH=$PATH:$PWD ./foo01 + +Shell testcases are a bit more complicated, since they need to setup ``PATH`` +as well as to compiled binary helpers: + +.. code-block:: console + + $ cd testcases/lib + $ make + $ cd ../commands/foo + $ PATH=$PATH:$PWD:$PWD/../../lib/ ./foo01.sh + +Open Posix Testsuite has it's own build system which needs Makefiles to be +generated first: + +.. code-block:: console + + $ ./configure --with-open-posix-testsuite + $ cd testcases/open_posix_testsuite/ + $ make generate-makefiles + $ cd conformance/interfaces/foo + $ make + $ ./foo_1-1.run-test + +Compiling and installing all testcases +-------------------------------------- + +To compile all tests is really simple: + +.. code-block:: console + + $ make + + $ # install LTP inside /opt/ltp by default + $ make install + +.. note:: + + Some tests will be disabled if ``configure`` script won't find the build + dependencies. + +Running tests +------------- + +To run all the test suites + +.. code-block:: console + + $ cd /opt/ltp + + $ # run syscalls testing suite + $ ./kirk -f ltp -r syscalls + +.. note:: + + Many test cases have to be executed as root. + +Test suites (e.g. syscalls) are defined in the ``runtest`` directory. Each file +contains a list of test cases in a simple format. + +Each test case has its own executable or script that can directly executed: + +.. code-block:: console + + $ testcases/bin/abort01 + + $ # some tests have arguments + $ testcases/bin/mesgq_nstest -m none + + $ # vast majority of tests have a help + $ testcases/bin/ioctl01 -h + + $ # Many require certain environment variables to be set + $ LTPROOT=/opt/ltp PATH="$PATH:$LTPROOT/testcases/bin" testcases/bin/wc01.sh + +Most commonly, the ``PATH`` variable needs to be set and also ``LTPROOT``, but +there are a number of other variables which usually ``kirk`` sets for you. + +.. note:: + + All shell scripts need the ``PATH`` to be set. However, this is not limited + to shell scripts and some C based tests need environment variables as well. + They usually raise a configuration error when this is needed. + +Network tests +------------- + +Network tests usually require a certain setup that is described in +:master:`testcases/network/README.md`. diff --git a/ltp/doc/users/setup_tests.rst b/ltp/doc/users/setup_tests.rst new file mode 100644 index 0000000000000000000000000000000000000000..38976f3b0aa7ab0afa4a8c1be0b9733eccbf879e --- /dev/null +++ b/ltp/doc/users/setup_tests.rst @@ -0,0 +1,120 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Tests setup +=========== + +The internal LTP library provides a set of features that permits to customize +tests behavior by setting environment variables and using specific tests +arguments. + +Library environment variables +----------------------------- + +Following environment variables are expected to be set by LTP users. Therefore, +with some exceptions, they have ``LTP_`` prefix. Environment variables with +``TST_`` prefix are used inside LTP shell API and should **not** be set by +users. + +.. list-table:: + :header-rows: 1 + + * - Variable + - Note + + * - 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. **Should be always set**, since some tests + need it to use data files (``LTP_DATAROOT``). LTP is by default installed + into ``/opt/ltp`` + + * - LTP_COLORIZE_OUTPUT + - By default LTP colorizes it's output unless it's redirected to a pipe or + file. Force colorized output behavior: ``y`` or ``1``: always colorize, + ``n`` or ``0``: never colorize. + + * - LTP_DEV + - Path to the block device to be used. C Language: ``.needs_device = 1``. + Shell language: ``TST_NEEDS_DEVICE=1``. + + * - LTP_REPRODUCIBLE_OUTPUT + - When set to ``1`` or ``y`` discards the actual content of the messages + printed by the test (suitable for a reproducible output). + + * - LTP_SINGLE_FS_TYPE + - Specifies single filesystem to run the test on instead all supported + (for tests with ``.all_filesystems``). + + * - LTP_FORCE_SINGLE_FS_TYPE + - Testing only. Behaves like LTP_SINGLE_FS_TYPE but ignores test skiplists. + + * - LTP_DEV_FS_TYPE + - Filesystem used for testing (default: ``ext2``). + + * - LTP_TIMEOUT_MUL + - Multiplies timeout, must be number >= 0.1 (> 1 is useful for slow + machines to avoid unexpected timeout). It's mainly for shell API, which + does not have LTP_RUNTIME_MUL. In C API it scales the default 30 sec + safety margin, probably LTP_RUNTIME_MUL should be used instead. + + * - LTP_RUNTIME_MUL + - Multiplies maximal test iteration runtime. Tests that run for more than a + second or two are capped on runtime. You can scale the default runtime + both up and down with this multiplier. This is not yet implemented in the + shell API. + + * - LTP_IMA_LOAD_POLICY + - Load IMA example policy, see :master:`testcases/kernel/security/integrity/ima/README.md`. + + * - LTP_VIRT_OVERRIDE + - Overrides virtual machine detection in the test library. Setting it to + empty string, tells 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 adjust path: ``PATH="$PATH:$LTPROOT/testcases/bin"`` + + * - TMPDIR + - Base directory for template directory (C language: ``.needs_tmpdir = 1`` + and shell: ``TST_NEEDS_TMPDIR=1``). Must be an absolute path (default: + '/tmp'). + + * - LTP_NO_CLEANUP + - Disable running test cleanup (defined in ``TST_CLEANUP``). + Shell API only. + + * - LTP_ENABLE_DEBUG + - Enable debug info (value ``1`` or ``y``). Equivalent of ``-D`` parameter. + +Environment variables for network tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +See :master:`testcases/network/README.md`. + +Test execution time and timeout +------------------------------- + +The limit on how long a test can run does compose of two parts: ``runtime`` +and ``timeout``. The limit does apply to a single test variant. That means, for +example, that tests which run for all available filesystems will apply this +limit for a single filesystem only. + +The ``runtime`` is a cap on how long the ``run()`` function can take and for +most testcases this part is set to zero. For tests that do run for more than a +second or two the ``runtime`` has to be defined and the ``run()`` function +has to check actively how much runtime is left. + +Test runtime can be scaled up and down with ``LTP_RUNTIME_MUL`` environment +variable or set on a command-line by the ``-I`` parameter. However, +setting the runtime too low will cause long running tests to exit prematurely, +possibly before having a chance to actually test anything. + +The timeout is a limit for test setup and cleanup and it's also a safety +margin for the runtime accounting. It's currently set to 30 seconds but it may +change later. If your target machine is too slow, it can be scaled up with the +``LTP_TIMEOUT_MUL`` environment variable. diff --git a/ltp/doc/users/stats.rst b/ltp/doc/users/stats.rst new file mode 100644 index 0000000000000000000000000000000000000000..7073442aaacd6348de70b12b034180c9212a605f --- /dev/null +++ b/ltp/doc/users/stats.rst @@ -0,0 +1,9 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Statistics +========== + +In this section we collect some statistics related to the current state of +LTP tests. + +.. include:: ../_static/syscalls.rst diff --git a/ltp/doc/users/supported_systems.rst b/ltp/doc/users/supported_systems.rst new file mode 100644 index 0000000000000000000000000000000000000000..dabb5883ad634e5ed589a09e6f0d83c533aa99e8 --- /dev/null +++ b/ltp/doc/users/supported_systems.rst @@ -0,0 +1,114 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Supported systems +================= + +LTP `master `_ +branch is build tested in +`GitHub Actions `_. + +.. note:: + + There is no CI for the actual test runs. + +Kernel version +-------------- + +Minimal supported kernel version is **4.4**. + +Oldest build tested distributions +--------------------------------- + +.. list-table:: + :header-rows: 1 + + * - Distro + - Kernel + - glibc + - gcc + - clang + + * - openSUSE Leap 42.2 + - 4.4 + - 2.22 + - 4.8.5 + - \- + + * - Ubuntu 18.04 LTS bionic + - 4.15 + - 2.27 + - 7.3.0 + - \- + + * - Debian 11 (bullseye) + - 5.10 + - 2.31 + - 10.2.1 + - 11.0.1 + +For a full list of build tested distros, please check :master:`.github/workflows/ci-docker-build.yml`. + +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. + +Build tested architectures +-------------------------- + +.. list-table:: + :header-rows: 1 + + * - Architecture + - Build + + * - x86_64 + - native + + * - x86 emulation + - native + + * - aarch64 + - cross compilation + + * - ppc64le + - cross compilation + + * - s390x + - cross compilation + +Supported C libraries +--------------------- + +.. list-table:: + :header-rows: 1 + + * - C library + - Note + + * - `glibc `_ + - Targeted libc, tested both compilation and actual test results. + + * - `uClibc-ng `_ + - Although not being tested, it should work as it attempt to maintain a glibc compatible interface. + + * - `uClibc `_ + - Older uClibc might have problems. + + * - `musl `_ + - Not yet fully supported. Check :master:`ci/alpine.sh` script. + + * - Android + - Please use `AOSP fork `_. + +C version +--------- + +LTP is compiled with ``-std=gnu99``. diff --git a/ltp/doc/users/test_catalog.rst b/ltp/doc/users/test_catalog.rst new file mode 100644 index 0000000000000000000000000000000000000000..b1674f9dc614ea04a89cf084e92b72c6862a5f48 --- /dev/null +++ b/ltp/doc/users/test_catalog.rst @@ -0,0 +1,7 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Test catalog +============ + +.. include:: ../_static/tests.rst + diff --git a/ltp/doc/users/testers_guide.rst b/ltp/doc/users/testers_guide.rst new file mode 100644 index 0000000000000000000000000000000000000000..9c1ddb98827280ddc8bdcfb273943266d65ef27c --- /dev/null +++ b/ltp/doc/users/testers_guide.rst @@ -0,0 +1,155 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Testers guide to the Linux test project +======================================= + +While we try to make LTP work out of the box as much as possible there are +still many things that testers need to consider before the actual testing +starts. It's advisable to make a test plan in order to asses and formalize the +expected test coverage or even just sit down for a while and consider different +aspects of the problem at hand. + + +Is testing even required? +------------------------- + +Some may argue that testing the Linux kernel locally is unnecessary because it +is already thoroughly tested upstream and considered stable. While it's true +that upstream releases generally go through extensive validation, including +test suites like LTP, stability is only guaranteed when you use the upstream +kernel sources and configuration exactly as released. + +This assumption breaks down once you apply any changes: whether that's +modifying the source code, enabling/disabling different `.config` options, or +backporting patches. Such changes can introduce subtle bugs or unintended +behavior, even if the upstream kernel is stable. + +For example, backporting patches without their full dependency chain can lead +to unexpected regressions. Therefore, it’s crucial to test your own kernel +builds in the environment where they will actually run, using tools like LTP to +catch issues that does not exists or are not triggered in the upstream +configuration. + + +Multi dimensionality +-------------------- + +First of all kernel testing is a multi dimensional problem, just compiling and +running LTP will give you some coverage but very likely not enough. There are +several big gaps that may be easily missed. + +For example 64bit Linux kernel provides compatibility layer for 32bit +applications whose code quality is usually a bit worse than the 64bit ABI. +Hence recompiling LTP with `-m32` in compiler flags and running both 64bit and +32bit test binaries is a good start. If you try to make an argument that your +application does not need 32bit support it's better to disable the compat layer +completely since it's possible source of security bugs. + +Another dimension is the number of architectures you need to test, for a +general distribution testing you may end up with a couple of them. Different +architectures have different platform code as well as differences in memory +orderings, etc. that all means that running tests on one architecture out of +several will give you incomplete coverage. + +Since most of the POSIX API deals with files, the choice of filesystem for the +testing changes the focus and coverage too. LTP defaults to using `/tmp/` as a +temporary directory for the tests. If `/tmp/` is mounted as tmpfs subset of +tests will be skipped, if that is the case it's advisable to point environment +variable `TMPDIR` to a path with a different filesystem instead. Then there are +tests that format a device with a filesystem. LTP defaults to `ext2` and loop +devices for these testcases, that can be changed with environment variables as +well. Lastly but not least a few testcases repeat the test for all supported +filesystem, if you are interested in testing on a single filesystem only, you +can limit these tests to a single filesystem too. See the tests setup for a +comprehensive list of the `evironment variables +`_. + +Then you also have to decide if you are going to run tests in virtual machine +e.g. `qemu-kvm`, on bare metal or both. Testing in virtual machine will give you +about 90% of the coverage for bare metal and vice versa. + +There are other options worth of consideration too, Linux kernel has many +debugging options that are usually disabled on runtime since they incur +significant performance penalty. Having a few more LTP test runs with different +debug options enabled e.g. `KASAN +`_ or `KMEMLEAK +`_ may help +catch bugs before they materialize in production. + +In practice your test matrix may easily explode and you may end up with dozens +of differently configured testruns based on different considerations. The hard +task at hand is not to have too many since computing power is not an infinite +resource and does not scale that easily. If you managed to read up to this +point *"Don't Panic!"* things are almost never as bad as they may seem at first +glance. + +It's a good idea to start small with an environment that models your +production. Once that works well you can try different configurations. Select +a few interesting ones and run them for some time in order to get an idea of +their usefulness. If you are feeling adventurous you may try to measure and +compare actual test coverage with one of the tools such as `gcov +`_ and `lcov +`_. If you do so do not fall into a +trap of attempting to have 100% line coverage. Having 100% of lines executed +during the test does not mean that your test coverage is 100%. Good tests +validate much more than just how much code from the tested binary was executed. + +You may need to sacrifice some coverage in order to match the tests runtime to +the available computing power. When doing so `Pareto principle +`_ is your friend. + + +Test scope +---------- + +So far we were talking about a code coverage from a point of maximizing test +coverage while keeping our test matrix as small as possible. While that is a +noble goal it's not the universal holy grail of testing. Different use cases +have different considerations and scope. For a testing before a final release +such testing is very desirable, however for a continuous integration or smoke +testing the main requirement is that feedback loops are as short as possible. + +When a developer changes the kernel and submits the changes to be merged it's +desirable to run some tests. Again the hard question is which tests. If we run +all possible tests in all possible combinations it may take a day or two and +the developer will move to a different tasks before the tests have a chance to +finish. If you multiply that by a number of developers in the team you may end +up in a situation where a developer will retire before tests for his patch may +have had a chance to finish. + +In this case careful selection of tests is even more important. Having less is +more in this context. One of the first ideas for CI is to skip tests that run +for more than a second or so, happily this can be easily done with `kirk +`_. In the future we may want to +explore some heuristics that would map the code changes in kernel into a subset +of tests, which would allow for a very quick feedback. + + +Debugging test failures +----------------------- + +You may think that you will enjoy some rest once you have your test matrix +ready and your tests are running. Unfortunately that's where the actual work +starts. Debugging test failures is probably the hardest part of the testing +process. In some cases failures are easily reproducible and it's not that hard +to locate the bug, either in the test or in the kernel itself. There are +however, quite common, cases where the test failure reproduces only in 10% or +even 1% of the test runs. Sometimes tests are not failing in isolation, that is +because operating system has a huge internal state and a test failure manifests +only after running right sequence of tests. All of that does not mean that +there is no bug, that usually means that the bug depends on more prerequisites +that have to manifest at the right time in order to trigger the failure. Sadly +for modern systems that are asynchronous in nature such bugs are more and more +common. + +The debugging process itself is not complicated by its nature. You have to +attempt to understand the failure by checking the logs, reading and +understanding the source code, debugging with strace, gdb, etc. Then form a +hypothesis and either prove or disprove it. Rinse and repeat until you end up +with a clear description of what went wrong. Hopefully you will manage to find +the root cause, but you should not be discouraged, if you do not. Debugging +kernel bugs takes a lot of experience and skill one can say as much as is +needed to write the kernel code. + + +Happy testing! diff --git a/ltp/include/Makefile b/ltp/include/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6b31b046e452e71afb5097cc3fadf8af01282629 --- /dev/null +++ b/ltp/include/Makefile @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk + +INSTALL_DIR := $(includedir) + +INSTALL_MODE := 00644 + +INSTALL_TARGETS := *.h + +MAKE_TARGETS := + +.PHONY: ac-clean ac-distclean ac-maintainer-clean distclean maintainer-clean +distclean:: clean ac-distclean +maintainer-clean:: distclean ac-maintainer-clean +ac-clean ac-distclean:: + $(RM) -f config.h lapi/syscalls.h stamp-h1 +ac-maintainer-clean:: ac-clean + $(RM) -f config.h.in + +vpath %.h $(abs_srcdir) + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/include/ipcmsg.h b/ltp/include/ipcmsg.h new file mode 100644 index 0000000000000000000000000000000000000000..3b3fa32c0b04ae618d80427ea231b3182de77617 --- /dev/null +++ b/ltp/include/ipcmsg.h @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2001 + * + * 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 + */ + +/* + * ipcmsg.h - common definitions for the IPC message tests. + */ + +#ifndef __IPCMSG_H +#define __IPCMSG_H 1 + +#include +#include +#include +#include + +#include "test.h" + +void cleanup(void); +void setup(void); + +#define MSG_RD 0400 /* read permission for the queue */ +#define MSG_WR 0200 /* write permission for the queue */ +#define MSG_RW MSG_RD | MSG_WR + +#define MSGSIZE 1024 /* a resonable size for a message */ +#define MSGTYPE 1 /* a type ID for a message */ + +#define NR_MSGQUEUES 16 /* MSGMNI as defined in linux/msg.h */ + +typedef struct mbuf { /* a generic message structure */ + long mtype; + char mtext[MSGSIZE + 1]; /* add 1 here so the message can be 1024 */ +} MSGBUF; /* characters long with a '\0' termination */ + +#ifdef LIBIPC +key_t msgkey; /* the ftok() generated message key */ +#else +extern key_t msgkey; /* the ftok() generated message key */ +#endif + +void init_buf(MSGBUF *, int, int); +void rm_queue(int); + +key_t getipckey(); +int getuserid(char *); + +int get_max_msgqueues(void); +int get_used_msgqueues(void); + +#endif /* ipcmsg.h */ diff --git a/ltp/include/ipcsem.h b/ltp/include/ipcsem.h new file mode 100644 index 0000000000000000000000000000000000000000..09a0b3cbe70e3625c6c52b521572678d1a106b82 --- /dev/null +++ b/ltp/include/ipcsem.h @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2001 + * + * 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 + */ + +/* + * ipcsem.h - common definitions for the IPC semaphore tests + */ + +#ifndef __IPCSEM_H +#define __IPCSEM_H + +#include +#include +#include + +#include "test.h" +#include "lapi/sem.h" + +void cleanup(void); +void setup(void); + +#define SEM_RD 0400 +#define SEM_ALT 0200 +#define SEM_RA SEM_RD | SEM_ALT + +#define PSEMS 10 /* a reasonable value for the number of */ + /* "primitive semaphores" per ID */ + +#ifdef LIBIPC +key_t semkey; /* an IPC key generated by ftok() */ +#else +extern key_t semkey; /* an IPC key generated by ftok() */ +#endif + +void rm_sema(int sem_id); + +int getipckey(); +int getuserid(char *); + +#endif /* ipcsem.h */ diff --git a/ltp/include/lapi/.gitignore b/ltp/include/lapi/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9867b3f254b6a29032d8dc4c7641c41c1705c1e1 --- /dev/null +++ b/ltp/include/lapi/.gitignore @@ -0,0 +1 @@ +syscalls.h diff --git a/ltp/include/lapi/abisize.h b/ltp/include/lapi/abisize.h new file mode 100644 index 0000000000000000000000000000000000000000..d19d73f0bae7d9125679e2a68e9aadacc2ed90bf --- /dev/null +++ b/ltp/include/lapi/abisize.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014-2019 Linux Test Project + * Cyril Hrubis + * Petr Vorel + */ + +#ifndef LAPI_ABISIZE_H__ +#define LAPI_ABISIZE_H__ + +/* __WORDSIZE replacement */ +#if defined(__LP64__) || defined(_LP64) +# define TST_ABI64 +# define TST_ABI 64 +#else +# define TST_ABI32 +# define TST_ABI 32 +#endif + +/* + * Determines if we have to split up 64 bit arguments or not + * + * Deals with 32bit ABIs that have 64bit syscalls + */ +#define LTP_USE_64_ABI \ + (defined(__mips__) && _MIPS_SIM == _ABIN32) || \ + (defined(__x86_64__) && defined(__ILP32__)) || \ + (defined(__aarch64__) && defined(__ILP32__)) || \ + defined(TST_ABI64) + +#endif /* LAPI_ABISIZE_H__ */ diff --git a/ltp/include/lapi/acct.h b/ltp/include/lapi/acct.h new file mode 100644 index 0000000000000000000000000000000000000000..6c521118e27679d34d081ac2cb5166aadb9e8ec5 --- /dev/null +++ b/ltp/include/lapi/acct.h @@ -0,0 +1,74 @@ +//SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef LAPI_ACCT_H__ +#define LAPI_ACCT_H__ + +#include +#include "config.h" + +#ifdef HAVE_STRUCT_ACCT_V3 +#include +#else + +#define ACCT_COMM 16 + +typedef uint16_t comp_t; + +/* Fallback structures to parse the process accounting file */ +struct acct { + char ac_flag; + uint16_t ac_uid; + uint16_t ac_gid; + uint16_t ac_tty; + uint32_t ac_btime; + comp_t ac_utime; + comp_t ac_stime; + comp_t ac_etime; + comp_t ac_mem; + comp_t ac_io; + comp_t ac_rw; + comp_t ac_minflt; + comp_t ac_majflt; + comp_t ac_swaps; + uint32_t ac_exitcode; + char ac_comm[ACCT_COMM+1]; + char ac_pad[10]; +}; + +struct acct_v3 { + char ac_flag; + char ac_version; + uint16_t ac_tty; + uint32_t ac_exitcode; + uint32_t ac_uid; + uint32_t ac_gid; + uint32_t ac_pid; + uint32_t ac_ppid; + uint32_t ac_btime; + float ac_etime; + comp_t ac_utime; + comp_t ac_stime; + comp_t ac_mem; + comp_t ac_io; + comp_t ac_rw; + comp_t ac_minflt; + comp_t ac_majflt; + comp_t ac_swaps; + char ac_comm[ACCT_COMM]; +}; + +/* Possible values for the ac_flag member */ +enum { + AFORK = 0x01, + ASU = 0x02, + ACORE = 0x08, + AXSIG = 0x10 +}; +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define ACCT_BYTEORDER 0x80 +# elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define ACCT_BYTEORDER 0x00 +# endif +#endif /* HAVE_STRUCT_ACCT_V3 */ + +#endif /* LAPI_ACCT_H__ */ diff --git a/ltp/include/lapi/arch_prctl.h b/ltp/include/lapi/arch_prctl.h new file mode 100644 index 0000000000000000000000000000000000000000..a4e7f84585b648c9d4e9772542f832f7c597674a --- /dev/null +++ b/ltp/include/lapi/arch_prctl.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Cyril Hrubis + */ +#ifndef LAPI_ARCH_PRCTL_H__ +#define LAPI_ARCH_PRCTL_H__ + +#include "config.h" + +#ifdef HAVE_ASM_PRCTL_H +# include +#endif + +#ifndef ARCH_GET_CPUID +# define ARCH_GET_CPUID 0x1011 +#endif + +#ifndef ARCH_SET_CPUID +# define ARCH_SET_CPUID 0x1012 +#endif + +#endif /* LAPI_ARCH_PRCTL_H__ */ diff --git a/ltp/include/lapi/blkdev.h b/ltp/include/lapi/blkdev.h new file mode 100644 index 0000000000000000000000000000000000000000..3ee058ce0a6770e44143fa857f81a9e0539b490d --- /dev/null +++ b/ltp/include/lapi/blkdev.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Linux Test Project + * Li Wang + */ + +#ifndef LAPI_BLKDEV_H__ +#define LAPI_BLKDEV_H__ + +#ifdef HAVE_LINUX_BLKDEV_H +#include +#endif + +/* Define BLK_MAX_BLOCK_SIZE for older kernels */ +#ifndef BLK_MAX_BLOCK_SIZE +#define BLK_MAX_BLOCK_SIZE 0x00010000 /* 64K */ +#endif + +#endif /* LAPI_BLKDEV_H */ diff --git a/ltp/include/lapi/bpf.h b/ltp/include/lapi/bpf.h new file mode 100644 index 0000000000000000000000000000000000000000..b44ab7d6595e654ccc50b7a644168d29ec3cac9b --- /dev/null +++ b/ltp/include/lapi/bpf.h @@ -0,0 +1,627 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Richard Palethorpe + * + * Essential Extended Berkeley Packet Filter (eBPF) headers + * + * Mostly copied/adapted from linux/bpf.h and libbpf so that we can perform + * some eBPF testing without any external dependencies. + */ + +#ifndef LAPI_BPF_H__ +#define LAPI_BPF_H__ + +#include + +#include "lapi/syscalls.h" + +/* Start copy from linux/bpf_(common).h */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 + +#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) */ + +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_MEM 0x60 + +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_MOD 0x90 + +#define BPF_JEQ 0x10 + +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +#define BPF_ALU64 0x07 /* alu mode in double word width */ +#define BPF_MOV 0xb0 /* mov reg to reg */ +#define BPF_CALL 0x80 /* function call */ +#define BPF_EXIT 0x90 /* function return */ + +/* Register numbers */ +enum { + BPF_REG_0 = 0, + BPF_REG_1, + BPF_REG_2, + BPF_REG_3, + BPF_REG_4, + BPF_REG_5, + BPF_REG_6, + BPF_REG_7, + BPF_REG_8, + BPF_REG_9, + BPF_REG_10, + MAX_BPF_REG, +}; + +struct bpf_insn { + uint8_t code; /* opcode */ + uint8_t dst_reg:4; /* dest register */ + uint8_t src_reg:4; /* source register */ + int16_t off; /* signed offset */ + int32_t imm; /* signed immediate constant */ +}; + +enum bpf_cmd { + BPF_MAP_CREATE, + BPF_MAP_LOOKUP_ELEM, + BPF_MAP_UPDATE_ELEM, + BPF_MAP_DELETE_ELEM, + BPF_MAP_GET_NEXT_KEY, + BPF_PROG_LOAD, + BPF_OBJ_PIN, + BPF_OBJ_GET, + BPF_PROG_ATTACH, + BPF_PROG_DETACH, + BPF_PROG_TEST_RUN, + BPF_PROG_GET_NEXT_ID, + BPF_MAP_GET_NEXT_ID, + BPF_PROG_GET_FD_BY_ID, + BPF_MAP_GET_FD_BY_ID, + BPF_OBJ_GET_INFO_BY_FD, + BPF_PROG_QUERY, + BPF_RAW_TRACEPOINT_OPEN, + BPF_BTF_LOAD, + BPF_BTF_GET_FD_BY_ID, + BPF_TASK_FD_QUERY, + BPF_MAP_LOOKUP_AND_DELETE_ELEM, + BPF_MAP_FREEZE, +}; + +enum bpf_map_type { + BPF_MAP_TYPE_UNSPEC, + BPF_MAP_TYPE_HASH, + BPF_MAP_TYPE_ARRAY, + BPF_MAP_TYPE_PROG_ARRAY, + BPF_MAP_TYPE_PERF_EVENT_ARRAY, + BPF_MAP_TYPE_PERCPU_HASH, + BPF_MAP_TYPE_PERCPU_ARRAY, + BPF_MAP_TYPE_STACK_TRACE, + BPF_MAP_TYPE_CGROUP_ARRAY, + BPF_MAP_TYPE_LRU_HASH, + BPF_MAP_TYPE_LRU_PERCPU_HASH, + BPF_MAP_TYPE_LPM_TRIE, + BPF_MAP_TYPE_ARRAY_OF_MAPS, + BPF_MAP_TYPE_HASH_OF_MAPS, + BPF_MAP_TYPE_DEVMAP, + BPF_MAP_TYPE_SOCKMAP, + BPF_MAP_TYPE_CPUMAP, + BPF_MAP_TYPE_XSKMAP, + BPF_MAP_TYPE_SOCKHASH, + BPF_MAP_TYPE_CGROUP_STORAGE, + BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, + BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, + BPF_MAP_TYPE_QUEUE, + BPF_MAP_TYPE_STACK, + BPF_MAP_TYPE_SK_STORAGE, + BPF_MAP_TYPE_DEVMAP_HASH, + BPF_MAP_TYPE_STRUCT_OPS, + BPF_MAP_TYPE_RINGBUF, + BPF_MAP_TYPE_INODE_STORAGE, + BPF_MAP_TYPE_TASK_STORAGE, + BPF_MAP_TYPE_BLOOM_FILTER, +}; + +enum bpf_prog_type { + BPF_PROG_TYPE_UNSPEC, + BPF_PROG_TYPE_SOCKET_FILTER, + BPF_PROG_TYPE_KPROBE, + BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, + BPF_PROG_TYPE_TRACEPOINT, + BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_PERF_EVENT, + BPF_PROG_TYPE_CGROUP_SKB, + BPF_PROG_TYPE_CGROUP_SOCK, + BPF_PROG_TYPE_LWT_IN, + BPF_PROG_TYPE_LWT_OUT, + BPF_PROG_TYPE_LWT_XMIT, + BPF_PROG_TYPE_SOCK_OPS, + BPF_PROG_TYPE_SK_SKB, + BPF_PROG_TYPE_CGROUP_DEVICE, + BPF_PROG_TYPE_SK_MSG, + BPF_PROG_TYPE_RAW_TRACEPOINT, + BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_PROG_TYPE_LWT_SEG6LOCAL, + BPF_PROG_TYPE_LIRC_MODE2, + BPF_PROG_TYPE_SK_REUSEPORT, + BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_CGROUP_SYSCTL, + BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, + BPF_PROG_TYPE_CGROUP_SOCKOPT, +}; + +#define BPF_PSEUDO_MAP_FD 1 + +#define BPF_OBJ_NAME_LEN 16U + +#define BPF_ANY 0 /* create new element or update existing */ +#define BPF_NOEXIST 1 /* create new element if it didn't exist */ +#define BPF_EXIST 2 /* update existing element */ +#define BPF_F_LOCK 4 /* spin_lock-ed map_lookup/map_update */ + +#define aligned_uint64_t uint64_t __attribute__((aligned(8))) + +union bpf_attr { + struct { /* anonymous struct used by BPF_MAP_CREATE command */ + uint32_t map_type; /* one of enum bpf_map_type */ + uint32_t key_size; /* size of key in bytes */ + uint32_t value_size; /* size of value in bytes */ + uint32_t max_entries; /* max number of entries in a map */ + uint32_t map_flags; /* BPF_MAP_CREATE related + * flags defined above. + */ + uint32_t inner_map_fd; /* fd pointing to the inner map */ + uint32_t numa_node; /* numa node (effective only if + * BPF_F_NUMA_NODE is set). + */ + char map_name[BPF_OBJ_NAME_LEN]; + uint32_t map_ifindex; /* ifindex of netdev to create on */ + uint32_t btf_fd; /* fd pointing to a BTF type data */ + uint32_t btf_key_type_id; /* BTF type_id of the key */ + uint32_t btf_value_type_id; /* BTF type_id of the value */ + }; + + struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ + uint32_t map_fd; + aligned_uint64_t key; + union { + aligned_uint64_t value; + aligned_uint64_t next_key; + }; + uint64_t flags; + }; + + struct { /* anonymous struct used by BPF_PROG_LOAD command */ + uint32_t prog_type; /* one of enum bpf_prog_type */ + uint32_t insn_cnt; + aligned_uint64_t insns; + aligned_uint64_t license; + uint32_t log_level; /* verbosity level of verifier */ + uint32_t log_size; /* size of user buffer */ + aligned_uint64_t log_buf; /* user supplied buffer */ + uint32_t kern_version; /* not used */ + uint32_t prog_flags; + char prog_name[BPF_OBJ_NAME_LEN]; + uint32_t prog_ifindex; /* ifindex of netdev to prep for */ + /* For some prog types expected attach type must be known at + * load time to verify attach type specific parts of prog + * (context accesses, allowed helpers, etc). + */ + uint32_t expected_attach_type; + uint32_t prog_btf_fd; /* fd pointing to BTF type data */ + uint32_t func_info_rec_size; /* userspace bpf_func_info size */ + aligned_uint64_t func_info; /* func info */ + uint32_t func_info_cnt; /* number of bpf_func_info records */ + uint32_t line_info_rec_size; /* userspace bpf_line_info size */ + aligned_uint64_t line_info; /* line info */ + uint32_t line_info_cnt; /* number of bpf_line_info records */ + }; + + struct { /* anonymous struct used by BPF_OBJ_* commands */ + aligned_uint64_t pathname; + uint32_t bpf_fd; + uint32_t file_flags; + }; + + struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ + uint32_t target_fd; /* container object to attach to */ + uint32_t attach_bpf_fd; /* eBPF program to attach */ + uint32_t attach_type; + uint32_t attach_flags; + }; + + struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */ + uint32_t prog_fd; + uint32_t retval; + uint32_t data_size_in; /* input: len of data_in */ + uint32_t data_size_out; /* input/output: len of data_out + * returns ENOSPC if data_out + * is too small. + */ + aligned_uint64_t data_in; + aligned_uint64_t data_out; + uint32_t repeat; + uint32_t duration; + uint32_t ctx_size_in; /* input: len of ctx_in */ + uint32_t ctx_size_out; /* input/output: len of ctx_out + * returns ENOSPC if ctx_out + * is too small. + */ + aligned_uint64_t ctx_in; + aligned_uint64_t ctx_out; + } test; + + struct { /* anonymous struct used by BPF_*_GET_*_ID */ + union { + uint32_t start_id; + uint32_t prog_id; + uint32_t map_id; + uint32_t btf_id; + }; + uint32_t next_id; + uint32_t open_flags; + }; + + struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */ + uint32_t bpf_fd; + uint32_t info_len; + aligned_uint64_t info; + } info; + + struct { /* anonymous struct used by BPF_PROG_QUERY command */ + uint32_t target_fd; /* container object to query */ + uint32_t attach_type; + uint32_t query_flags; + uint32_t attach_flags; + aligned_uint64_t prog_ids; + uint32_t prog_cnt; + } query; + + struct { + uint64_t name; + uint32_t prog_fd; + } raw_tracepoint; + + struct { /* anonymous struct for BPF_BTF_LOAD */ + aligned_uint64_t btf; + aligned_uint64_t btf_log_buf; + uint32_t btf_size; + uint32_t btf_log_size; + uint32_t btf_log_level; + }; + + struct { + uint32_t pid; /* input: pid */ + uint32_t fd; /* input: fd */ + uint32_t flags; /* input: flags */ + uint32_t buf_len; /* input/output: buf len */ + aligned_uint64_t buf; /* input/output: + * tp_name for tracepoint + * symbol for kprobe + * filename for uprobe + */ + uint32_t prog_id; /* output: prod_id */ + uint32_t fd_type; /* output: BPF_FD_TYPE_* */ + uint64_t probe_offset; /* output: probe_offset */ + uint64_t probe_addr; /* output: probe_addr */ + } task_fd_query; +} __attribute__((aligned(8))); + +#define __BPF_FUNC_MAPPER(FN) \ + FN(unspec), \ + FN(map_lookup_elem), \ + FN(map_update_elem), \ + FN(map_delete_elem), \ + FN(probe_read), \ + FN(ktime_get_ns), \ + FN(trace_printk), \ + FN(get_prandom_u32), \ + FN(get_smp_processor_id), \ + FN(skb_store_bytes), \ + FN(l3_csum_replace), \ + FN(l4_csum_replace), \ + FN(tail_call), \ + FN(clone_redirect), \ + FN(get_current_pid_tgid), \ + FN(get_current_uid_gid), \ + FN(get_current_comm), \ + FN(get_cgroup_classid), \ + FN(skb_vlan_push), \ + FN(skb_vlan_pop), \ + FN(skb_get_tunnel_key), \ + FN(skb_set_tunnel_key), \ + FN(perf_event_read), \ + FN(redirect), \ + FN(get_route_realm), \ + FN(perf_event_output), \ + FN(skb_load_bytes), \ + FN(get_stackid), \ + FN(csum_diff), \ + FN(skb_get_tunnel_opt), \ + FN(skb_set_tunnel_opt), \ + FN(skb_change_proto), \ + FN(skb_change_type), \ + FN(skb_under_cgroup), \ + FN(get_hash_recalc), \ + FN(get_current_task), \ + FN(probe_write_user), \ + FN(current_task_under_cgroup), \ + FN(skb_change_tail), \ + FN(skb_pull_data), \ + FN(csum_update), \ + FN(set_hash_invalid), \ + FN(get_numa_node_id), \ + FN(skb_change_head), \ + FN(xdp_adjust_head), \ + FN(probe_read_str), \ + FN(get_socket_cookie), \ + FN(get_socket_uid), \ + FN(set_hash), \ + FN(setsockopt), \ + FN(skb_adjust_room), \ + FN(redirect_map), \ + FN(sk_redirect_map), \ + FN(sock_map_update), \ + FN(xdp_adjust_meta), \ + FN(perf_event_read_value), \ + FN(perf_prog_read_value), \ + FN(getsockopt), \ + FN(override_return), \ + FN(sock_ops_cb_flags_set), \ + FN(msg_redirect_map), \ + FN(msg_apply_bytes), \ + FN(msg_cork_bytes), \ + FN(msg_pull_data), \ + FN(bind), \ + FN(xdp_adjust_tail), \ + FN(skb_get_xfrm_state), \ + FN(get_stack), \ + FN(skb_load_bytes_relative), \ + FN(fib_lookup), \ + FN(sock_hash_update), \ + FN(msg_redirect_hash), \ + FN(sk_redirect_hash), \ + FN(lwt_push_encap), \ + FN(lwt_seg6_store_bytes), \ + FN(lwt_seg6_adjust_srh), \ + FN(lwt_seg6_action), \ + FN(rc_repeat), \ + FN(rc_keydown), \ + FN(skb_cgroup_id), \ + FN(get_current_cgroup_id), \ + FN(get_local_storage), \ + FN(sk_select_reuseport), \ + FN(skb_ancestor_cgroup_id), \ + FN(sk_lookup_tcp), \ + FN(sk_lookup_udp), \ + FN(sk_release), \ + FN(map_push_elem), \ + FN(map_pop_elem), \ + FN(map_peek_elem), \ + FN(msg_push_data), \ + FN(msg_pop_data), \ + FN(rc_pointer_rel), \ + FN(spin_lock), \ + FN(spin_unlock), \ + FN(sk_fullsock), \ + FN(tcp_sock), \ + FN(skb_ecn_set_ce), \ + FN(get_listener_sock), \ + FN(skc_lookup_tcp), \ + FN(tcp_check_syncookie), \ + FN(sysctl_get_name), \ + FN(sysctl_get_current_value), \ + FN(sysctl_get_new_value), \ + FN(sysctl_set_new_value), \ + FN(strtol), \ + FN(strtoul), \ + FN(sk_storage_get), \ + FN(sk_storage_delete), \ + FN(send_signal), \ + FN(tcp_gen_syncookie), \ + FN(skb_output), \ + FN(probe_read_user), \ + FN(probe_read_kernel), \ + FN(probe_read_user_str), \ + FN(probe_read_kernel_str), \ + FN(tcp_send_ack), \ + FN(send_signal_thread), \ + FN(jiffies64), \ + FN(read_branch_records), \ + FN(get_ns_current_pid_tgid), \ + FN(xdp_output), \ + FN(get_netns_cookie), \ + FN(get_current_ancestor_cgroup_id), \ + FN(sk_assign), \ + FN(ktime_get_boot_ns), \ + FN(seq_printf), \ + FN(seq_write), \ + FN(sk_cgroup_id), \ + FN(sk_ancestor_cgroup_id), \ + FN(ringbuf_output), \ + FN(ringbuf_reserve), \ + FN(ringbuf_submit), \ + FN(ringbuf_discard), \ + FN(ringbuf_query), \ + FN(csum_level), + +/* integer value in 'imm' field of BPF_CALL instruction selects which helper + * function eBPF program intends to call + */ +#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x +enum bpf_func_id { + __BPF_FUNC_MAPPER(__BPF_ENUM_FN) + __BPF_FUNC_MAX_ID, +}; +#undef __BPF_ENUM_FN + +/* End copy from linux/bpf.h */ + +/* Start copy from tools/include/filter.h */ + +#define BPF_ALU64_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .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, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .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, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .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) + +#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_LD | BPF_DW | BPF_IMM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = (uint32_t) (IMM) }), \ + ((struct bpf_insn) { \ + .code = 0, /* zero is reserved opcode */ \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = ((uint64_t) (IMM)) >> 32 }) + +/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */ +#define BPF_LD_MAP_FD(DST, MAP_FD) \ + BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) + +#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = OFF, \ + .imm = IMM }) + +#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) + +#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) + +#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = OFF, \ + .imm = IMM }) + +#define BPF_MOV64_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +#define BPF_MOV32_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +#define BPF_EMIT_CALL(FUNC) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_CALL, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = ((FUNC) - BPF_FUNC_unspec) }) + +#define BPF_EXIT_INSN() \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_EXIT, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = 0 }) + +/* End copy from tools/include/filter.h */ + +/* Start copy from tools/lib/bpf */ +static inline uint64_t ptr_to_u64(const void *ptr) +{ + return (uint64_t) (unsigned long) ptr; +} + +static inline int bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size) +{ + return tst_syscall(__NR_bpf, cmd, attr, size); +} +/* End copy from tools/lib/bpf */ + +#endif /* LAPI_BPF_H__ */ diff --git a/ltp/include/lapi/capability.h b/ltp/include/lapi/capability.h new file mode 100644 index 0000000000000000000000000000000000000000..14d2d3c12c051006875f1f864ec58a88a3870ec0 --- /dev/null +++ b/ltp/include/lapi/capability.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2019 Richard Palethorpe + */ + +#ifndef LAPI_CAPABILITY_H__ +#define LAPI_CAPABILITY_H__ + +#include "config.h" + +#ifdef HAVE_SYS_CAPABILITY_H +# include +/** + * Some old libcap-devel(1.96~2.16) define _LINUX_TYPES_H in + * sys/capability.h that makes ltp-lib cann't include linux/types.h + * essentially. Here undefine it if include such old header-file. + */ +# ifndef HAVE_NEWER_LIBCAP +# undef _LINUX_TYPES_H +# endif +#endif + +#ifndef CAP_NET_BIND_SERVICE +# define CAP_NET_BIND_SERVICE 10 +#endif + +#ifndef CAP_NET_RAW +# define CAP_NET_RAW 13 +#endif + +#ifndef CAP_IPC_LOCK +# define CAP_IPC_LOCK 14 +#endif + +#ifndef CAP_SYS_CHROOT +# define CAP_SYS_CHROOT 18 +#endif + +#ifndef CAP_SYS_ADMIN +# define CAP_SYS_ADMIN 21 +#endif + +#ifndef CAP_SYS_NICE +# define CAP_SYS_NICE 23 +#endif + +#ifndef CAP_SYS_TIME +# define CAP_SYS_TIME 25 +#endif + +#ifndef CAP_SYS_RESOURCE +# define CAP_SYS_RESOURCE 24 +#endif + +#ifndef CAP_MKNOD +# define CAP_MKNOD 27 +#endif + +#ifndef CAP_AUDIT_READ +# define CAP_AUDIT_READ 37 +#endif + +#ifndef CAP_BPF +# define CAP_BPF 39 +#endif + +#ifndef CAP_TO_INDEX +# define CAP_TO_INDEX(x) ((x) >> 5) +#endif + +#ifndef CAP_TO_MASK +# define CAP_TO_MASK(x) (1 << ((x) & 31)) +#endif + +#endif /* LAPI_CAPABILITY_H__ */ diff --git a/ltp/include/lapi/close_range.h b/ltp/include/lapi/close_range.h new file mode 100644 index 0000000000000000000000000000000000000000..0e464bb308129ac5f2f2182f441ba64d865688cf --- /dev/null +++ b/ltp/include/lapi/close_range.h @@ -0,0 +1,41 @@ +// 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 + +static inline void close_range_supported_by_kernel(void) +{ + long ret; + + if ((tst_kvercmp(5, 9, 0)) < 0) { + /* Check if the syscall is backported on an older kernel */ + ret = syscall(__NR_close_range, 1, 0, 0); + if (ret == -1 && errno == ENOSYS) + tst_brk(TCONF, "Test not supported on kernel version < v5.9"); + } +} + +#endif /* LAPI_CLOSE_RANGE_H__ */ diff --git a/ltp/include/lapi/common_timers.h b/ltp/include/lapi/common_timers.h new file mode 100644 index 0000000000000000000000000000000000000000..884c997a1b19f710bc3526f15e0f224fae71844b --- /dev/null +++ b/ltp/include/lapi/common_timers.h @@ -0,0 +1,76 @@ +/* + * File: common_timers.h + * + * Keep all the common defines/checks for the timer tests here + */ + +#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 (1000000000LL) +#endif + +static const clock_t clock_list[] = { + CLOCK_REALTIME, + CLOCK_MONOTONIC, + CLOCK_PROCESS_CPUTIME_ID, + CLOCK_THREAD_CPUTIME_ID, + CLOCK_BOOTTIME, + CLOCK_BOOTTIME_ALARM, + CLOCK_REALTIME_ALARM, + CLOCK_TAI, +}; +/* CLOCKS_DEFINED is the number of clock sources defined for sure */ +#define CLOCKS_DEFINED (sizeof(clock_list) / sizeof(*clock_list)) +/* MAX_CLOCKS is the maximum number of clock sources supported by kernel */ +#define MAX_CLOCKS 16 + +#define CLOCK_TO_STR(def_name) \ + case def_name: \ + return #def_name; + +static inline const char *get_clock_str(const int clock_id) +{ + switch (clock_id) { + CLOCK_TO_STR(CLOCK_REALTIME); + CLOCK_TO_STR(CLOCK_MONOTONIC); + CLOCK_TO_STR(CLOCK_PROCESS_CPUTIME_ID); + CLOCK_TO_STR(CLOCK_THREAD_CPUTIME_ID); + CLOCK_TO_STR(CLOCK_BOOTTIME); + CLOCK_TO_STR(CLOCK_BOOTTIME_ALARM); + CLOCK_TO_STR(CLOCK_REALTIME_ALARM); + CLOCK_TO_STR(CLOCK_TAI); + default: + return "CLOCK_!?!?!?"; + } +} + +static inline int possibly_unsupported(clock_t clock) +{ + switch (clock) { + case CLOCK_BOOTTIME: + case CLOCK_BOOTTIME_ALARM: + case CLOCK_REALTIME_ALARM: + case CLOCK_TAI: + return 1; + default: + return 0; + } +} + +#include "lapi/syscalls.h" + +#include +#include + +/* timer_t in kernel(int) is different from Glibc definition(void*). + * Use the kernel definition for syscall tests + */ +typedef int kernel_timer_t; + +#endif /* LAPI_COMMON_TIMERS_H__ */ diff --git a/ltp/include/lapi/cpuid.h b/ltp/include/lapi/cpuid.h new file mode 100644 index 0000000000000000000000000000000000000000..7ec785ecf17565e89bc25b3fcb761659aeeb1298 --- /dev/null +++ b/ltp/include/lapi/cpuid.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#if !(defined(__i386__) || defined(__x86_64__)) +# error "cpuid.h should only be included on x86" +#endif + +#ifdef HAVE_CPUID_H +# include +#endif + +#ifndef LAPI_CPUID_H__ +#define LAPI_CPUID_H__ + +/* + * gcc cpuid.h provides __cpuid_count() since v4.4. + * Clang/LLVM cpuid.h provides __cpuid_count() since v3.4.0. + * + * Provide local define for tests needing __cpuid_count() because + * ltp needs to work in older environments that do not yet + * have __cpuid_count(). + */ +#ifndef __cpuid_count +#define __cpuid_count(level, count, a, b, c, d) ({ \ + __asm__ __volatile__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level), "2" (count)); \ +}) +#endif + +#endif /* LAPI_CPUID_H__ */ diff --git a/ltp/include/lapi/cpuset.h b/ltp/include/lapi/cpuset.h new file mode 100644 index 0000000000000000000000000000000000000000..f4d62e3ee61d25a6ac9c11aade7dad46f28d844d --- /dev/null +++ b/ltp/include/lapi/cpuset.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved. + */ + +/* + * Some old libcs (like glibc < 2.7) do not provide interfaces for + * dynamically sized cpu sets, but provide only static cpu_set_t type + * with no more than CPU_SETSIZE cpus in it. + * + * This file is a wrapper of the dynamic interfaces using the static ones. + * + * If the number of cpus available on the system is greater than + * CPU_SETSIZE, this interface will not work. Update libc in this case :) + */ + +#define _GNU_SOURCE +#include + +#ifndef LAPI_CPUSET_H__ +#define LAPI_CPUSET_H__ + +#ifndef CPU_ALLOC +#define CPU_ALLOC(ncpus) malloc(sizeof(cpu_set_t)); \ +if (ncpus > CPU_SETSIZE) { \ + tst_brk(TCONF, \ + "Your libc does not support masks with %ld cpus", (long)ncpus); \ +} +#endif + +#ifndef CPU_FREE +#define CPU_FREE(ptr) free(ptr) +#endif + +#ifndef CPU_ALLOC_SIZE +#define CPU_ALLOC_SIZE(size) sizeof(cpu_set_t) +#endif + +#ifndef CPU_ZERO_S +#define CPU_ZERO_S(size, mask) CPU_ZERO(mask) +#endif + +#ifndef CPU_SET_S +#define CPU_SET_S(cpu, size, mask) CPU_SET(cpu, mask) +#endif + +#ifndef CPU_ISSET_S +#define CPU_ISSET_S(cpu, size, mask) CPU_ISSET(cpu, mask) +#endif + +#endif /* LAPI_CPUSET_H__ */ diff --git a/ltp/include/lapi/cryptouser.h b/ltp/include/lapi/cryptouser.h new file mode 100644 index 0000000000000000000000000000000000000000..31d1c345345ad875ee277fc4afdc3457013adb23 --- /dev/null +++ b/ltp/include/lapi/cryptouser.h @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Richard Palethorpe + */ + +#ifndef LAPI_CRYPTOUSER_H__ +#define LAPI_CRYPTOUSER_H__ + +#ifdef HAVE_LINUX_CRYPTOUSER_H +# include +#else +# include +# define CRYPTO_MAX_NAME 64 + +enum { + CRYPTO_MSG_BASE = 0x10, + CRYPTO_MSG_NEWALG = 0x10, + CRYPTO_MSG_DELALG, + CRYPTO_MSG_UPDATEALG, + CRYPTO_MSG_GETALG, + CRYPTO_MSG_DELRNG, + __CRYPTO_MSG_MAX +}; + +enum crypto_attr_type_t { + CRYPTOCFGA_UNSPEC, + CRYPTOCFGA_PRIORITY_VAL, /* uint32_t */ + CRYPTOCFGA_REPORT_LARVAL, /* struct crypto_report_larval */ + CRYPTOCFGA_REPORT_HASH, /* struct crypto_report_hash */ + CRYPTOCFGA_REPORT_BLKCIPHER, /* struct crypto_report_blkcipher */ + CRYPTOCFGA_REPORT_AEAD, /* struct crypto_report_aead */ + CRYPTOCFGA_REPORT_COMPRESS, /* struct crypto_report_comp */ + CRYPTOCFGA_REPORT_RNG, /* struct crypto_report_rng */ + CRYPTOCFGA_REPORT_CIPHER, /* struct crypto_report_cipher */ + CRYPTOCFGA_REPORT_AKCIPHER, /* struct crypto_report_akcipher */ + CRYPTOCFGA_REPORT_KPP, /* struct crypto_report_kpp */ + CRYPTOCFGA_REPORT_ACOMP, /* struct crypto_report_acomp */ + __CRYPTOCFGA_MAX + +#define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1) +}; + +struct crypto_user_alg { + char cru_name[CRYPTO_MAX_NAME]; + char cru_driver_name[CRYPTO_MAX_NAME]; + char cru_module_name[CRYPTO_MAX_NAME]; + uint32_t cru_type; + uint32_t cru_mask; + uint32_t cru_refcnt; + uint32_t cru_flags; +}; + +struct crypto_report_larval { + char type[CRYPTO_MAX_NAME]; +}; + +struct crypto_report_hash { + char type[CRYPTO_MAX_NAME]; + unsigned int blocksize; + unsigned int digestsize; +}; + +struct crypto_report_cipher { + char type[CRYPTO_MAX_NAME]; + unsigned int blocksize; + unsigned int min_keysize; + unsigned int max_keysize; +}; + +struct crypto_report_blkcipher { + char type[CRYPTO_MAX_NAME]; + char geniv[CRYPTO_MAX_NAME]; + unsigned int blocksize; + unsigned int min_keysize; + unsigned int max_keysize; + unsigned int ivsize; +}; + +struct crypto_report_aead { + char type[CRYPTO_MAX_NAME]; + char geniv[CRYPTO_MAX_NAME]; + unsigned int blocksize; + unsigned int maxauthsize; + unsigned int ivsize; +}; + +struct crypto_report_comp { + char type[CRYPTO_MAX_NAME]; +}; + +struct crypto_report_rng { + char type[CRYPTO_MAX_NAME]; + unsigned int seedsize; +}; + +struct crypto_report_akcipher { + char type[CRYPTO_MAX_NAME]; +}; + +struct crypto_report_kpp { + char type[CRYPTO_MAX_NAME]; +}; + +struct crypto_report_acomp { + char type[CRYPTO_MAX_NAME]; +}; + +#endif /* HAVE_LINUX_CRYPTOUSER_H */ + +/* These are taken from include/crypto.h in the kernel tree. They are not + * currently included in the user API. + */ +#ifndef CRYPTO_MAX_ALG_NAME +# define CRYPTO_MAX_ALG_NAME 128 +#endif + +#ifndef CRYPTO_ALG_TYPE_MASK +# define CRYPTO_ALG_TYPE_MASK 0x0000000f +#endif +#ifndef CRYPTO_ALG_TYPE_CIPHER +# define CRYPTO_ALG_TYPE_CIPHER 0x00000001 +#endif +#ifndef CRYPTO_ALG_TYPE_COMPRESS +# define CRYPTO_ALG_TYPE_COMPRESS 0x00000002 +#endif +#ifndef CRYPTO_ALG_TYPE_AEAD +# define CRYPTO_ALG_TYPE_AEAD 0x00000003 +#endif +#ifndef CRYPTO_ALG_TYPE_BLKCIPHER +# define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 +#endif +#ifndef CRYPTO_ALG_TYPE_ABLKCIPHER +# define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005 +#endif +#ifndef CRYPTO_ALG_TYPE_SKCIPHER +# define CRYPTO_ALG_TYPE_SKCIPHER 0x00000005 +#endif +#ifndef CRYPTO_ALG_TYPE_GIVCIPHER +# define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006 +#endif +#ifndef CRYPTO_ALG_TYPE_KPP +# define CRYPTO_ALG_TYPE_KPP 0x00000008 +#endif +#ifndef CRYPTO_ALG_TYPE_ACOMPRESS +# define CRYPTO_ALG_TYPE_ACOMPRESS 0x0000000a +#endif +#ifndef CRYPTO_ALG_TYPE_SCOMPRESS +# define CRYPTO_ALG_TYPE_SCOMPRESS 0x0000000b +#endif +#ifndef CRYPTO_ALG_TYPE_RNG +# define CRYPTO_ALG_TYPE_RNG 0x0000000c +#endif +#ifndef CRYPTO_ALG_TYPE_AKCIPHER +# define CRYPTO_ALG_TYPE_AKCIPHER 0x0000000d +#endif +#ifndef CRYPTO_ALG_TYPE_DIGEST +# define CRYPTO_ALG_TYPE_DIGEST 0x0000000e +#endif +#ifndef CRYPTO_ALG_TYPE_HASH +# define CRYPTO_ALG_TYPE_HASH 0x0000000e +#endif +#ifndef CRYPTO_ALG_TYPE_SHASH +# define CRYPTO_ALG_TYPE_SHASH 0x0000000e +#endif +#ifndef CRYPTO_ALG_TYPE_AHASH +# define CRYPTO_ALG_TYPE_AHASH 0x0000000f +#endif + +#ifndef CRYPTO_ALG_TYPE_HASH_MASK +# define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e +#endif +#ifndef CRYPTO_ALG_TYPE_AHASH_MASK +# define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e +#endif +#ifndef CRYPTO_ALG_TYPE_BLKCIPHER_MASK +# define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c +#endif +#ifndef CRYPTO_ALG_TYPE_ACOMPRESS_MASK +# define CRYPTO_ALG_TYPE_ACOMPRESS_MASK 0x0000000e +#endif + +#endif /* LAPI_CRYPTOUSER_H__ */ diff --git a/ltp/include/lapi/dccp.h b/ltp/include/lapi/dccp.h new file mode 100644 index 0000000000000000000000000000000000000000..a0f014850364f2b34a28024d1d4b40ac16ca3389 --- /dev/null +++ b/ltp/include/lapi/dccp.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Petr Vorel + */ + +#ifndef LAPI_DCCP_H__ +#define LAPI_DCCP_H__ + +#ifdef HAVE_LINUX_DCCP_H +# include +#endif + +#ifndef DCCP_SOCKOPT_SERVICE +# define DCCP_SOCKOPT_SERVICE 2 +#endif + +#endif /* LAPI_DCCP_H__ */ diff --git a/ltp/include/lapi/epoll.h b/ltp/include/lapi/epoll.h new file mode 100644 index 0000000000000000000000000000000000000000..fc068ae20c80c588f36f937aa7aad432dc651720 --- /dev/null +++ b/ltp/include/lapi/epoll.h @@ -0,0 +1,58 @@ +/* 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 +#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/ltp/include/lapi/execveat.h b/ltp/include/lapi/execveat.h new file mode 100644 index 0000000000000000000000000000000000000000..de4963b3f7d0b494fd0174c5ba9c77575d92074c --- /dev/null +++ b/ltp/include/lapi/execveat.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + */ + +#ifndef LAPI_EXECVEAT_H__ +#define LAPI_EXECVEAT_H__ + +#include +#include "config.h" +#include "lapi/syscalls.h" + +#if !defined(HAVE_EXECVEAT) +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 /* LAPI_EXECVEAT_H__ */ diff --git a/ltp/include/lapi/faccessat.h b/ltp/include/lapi/faccessat.h new file mode 100644 index 0000000000000000000000000000000000000000..05997d9757f652183aa8d3012f3698d4df34b73d --- /dev/null +++ b/ltp/include/lapi/faccessat.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yang Xu + */ + +#ifndef FACCESSAT2_H +#define FACCESSAT2_H + +#include "tst_test.h" +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef HAVE_FACCESSAT2 +int faccessat2(int dirfd, const char *pathname, int mode, int flags) +{ + return tst_syscall(__NR_faccessat2, dirfd, pathname, mode, flags); +} +#endif + +#endif /* FACCESSAT2_H */ diff --git a/ltp/include/lapi/fallocate.h b/ltp/include/lapi/fallocate.h new file mode 100644 index 0000000000000000000000000000000000000000..fc246bcfc1686af4036f6cd0881924dd42273e8c --- /dev/null +++ b/ltp/include/lapi/fallocate.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2007 + * Copyright (c) 2014 Fujitsu Ltd. + */ + +#ifndef LAPI_FALLOCATE_H__ +#define LAPI_FALLOCATE_H__ + +#include +#include +#include "config.h" +#include "lapi/abisize.h" +#include "lapi/seek.h" +#include "lapi/syscalls.h" + +#ifndef FALLOC_FL_KEEP_SIZE +# define FALLOC_FL_KEEP_SIZE 0x01 +#endif + +#ifndef FALLOC_FL_PUNCH_HOLE +# define FALLOC_FL_PUNCH_HOLE 0x02 +#endif + +#ifndef FALLOC_FL_COLLAPSE_RANGE +# define FALLOC_FL_COLLAPSE_RANGE 0x08 +#endif + +#ifndef FALLOC_FL_ZERO_RANGE +# define FALLOC_FL_ZERO_RANGE 0x10 +#endif + +#ifndef FALLOC_FL_INSERT_RANGE +# define FALLOC_FL_INSERT_RANGE 0x20 +#endif + +#if !defined(HAVE_FALLOCATE) + +static inline long fallocate(int fd, int mode, loff_t offset, loff_t len) +{ + /* Deal with 32bit ABIs that have 64bit syscalls. */ +# if LTP_USE_64_ABI + return tst_syscall(__NR_fallocate, fd, mode, offset, len); +# else + return (long)tst_syscall(__NR_fallocate, fd, mode, + __LONG_LONG_PAIR((off_t) (offset >> 32), + (off_t) offset), + __LONG_LONG_PAIR((off_t) (len >> 32), + (off_t) len)); +# endif +} +#endif + +#endif /* LAPI_FALLOCATE_H__ */ diff --git a/ltp/include/lapi/fanotify.h b/ltp/include/lapi/fanotify.h new file mode 100644 index 0000000000000000000000000000000000000000..8d04c8f28969d0b3d5fec71824d569b01c9ec054 --- /dev/null +++ b/ltp/include/lapi/fanotify.h @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2012-2022 Linux Test Project. All Rights Reserved. + * Author: Jan Kara, November 2013 + */ + +#ifndef LAPI_FANOTIFY_H__ +#define LAPI_FANOTIFY_H__ + +#include "config.h" +#include +#include + +#ifndef FAN_REPORT_TID +#define FAN_REPORT_TID 0x00000100 +#endif +#ifndef FAN_REPORT_FID +#define FAN_REPORT_FID 0x00000200 +#endif +#ifndef FAN_REPORT_DIR_FID +#define FAN_REPORT_DIR_FID 0x00000400 +#endif +#ifndef FAN_REPORT_NAME +#define FAN_REPORT_NAME 0x00000800 +#define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) +#endif +#ifndef FAN_REPORT_PIDFD +#define FAN_REPORT_PIDFD 0x00000080 +#endif +#ifndef FAN_REPORT_TARGET_FID +#define FAN_REPORT_TARGET_FID 0x00001000 +#define FAN_REPORT_DFID_NAME_TARGET (FAN_REPORT_DFID_NAME | \ + FAN_REPORT_FID | FAN_REPORT_TARGET_FID) +#endif +#ifndef FAN_REPORT_FD_ERROR +#define FAN_REPORT_FD_ERROR 0x00002000 +#endif + + +/* Non-uapi convenience macros */ +#ifndef FAN_REPORT_DFID_NAME_FID +#define FAN_REPORT_DFID_NAME_FID (FAN_REPORT_DFID_NAME | FAN_REPORT_FID) +#endif +#ifndef FAN_REPORT_DFID_FID +#define FAN_REPORT_DFID_FID (FAN_REPORT_DIR_FID | FAN_REPORT_FID) +#endif + +#ifndef FAN_MARK_INODE +#define FAN_MARK_INODE 0 +#endif +#ifndef FAN_MARK_FILESYSTEM +#define FAN_MARK_FILESYSTEM 0x00000100 +#endif +#ifndef FAN_MARK_EVICTABLE +#define FAN_MARK_EVICTABLE 0x00000200 +#endif +#ifndef FAN_MARK_IGNORE +#define FAN_MARK_IGNORE 0x00000400 +#endif +#ifndef FAN_MARK_IGNORE_SURV +#define FAN_MARK_IGNORE_SURV (FAN_MARK_IGNORE | FAN_MARK_IGNORED_SURV_MODIFY) +#endif +/* Non-uapi convenience macros */ +#ifndef FAN_MARK_IGNORED_SURV +#define FAN_MARK_IGNORED_SURV (FAN_MARK_IGNORED_MASK | \ + FAN_MARK_IGNORED_SURV_MODIFY) +#endif +#ifndef FAN_MARK_PARENT +#define FAN_MARK_PARENT FAN_MARK_ONLYDIR +#endif +#ifndef FAN_MARK_SUBDIR +#define FAN_MARK_SUBDIR FAN_MARK_ONLYDIR +#endif +#ifndef FAN_MARK_TYPES +#define FAN_MARK_TYPES (FAN_MARK_INODE | FAN_MARK_MOUNT | FAN_MARK_FILESYSTEM) +#endif + +/* New dirent event masks */ +#ifndef FAN_ATTRIB +#define FAN_ATTRIB 0x00000004 +#endif +#ifndef FAN_MOVED_FROM +#define FAN_MOVED_FROM 0x00000040 +#endif +#ifndef FAN_MOVED_TO +#define FAN_MOVED_TO 0x00000080 +#endif +#ifndef FAN_CREATE +#define FAN_CREATE 0x00000100 +#endif +#ifndef FAN_DELETE +#define FAN_DELETE 0x00000200 +#endif +#ifndef FAN_DELETE_SELF +#define FAN_DELETE_SELF 0x00000400 +#endif +#ifndef FAN_MOVE_SELF +#define FAN_MOVE_SELF 0x00000800 +#endif +#ifndef FAN_MOVE +#define FAN_MOVE (FAN_MOVED_FROM | FAN_MOVED_TO) +#endif +#ifndef FAN_OPEN_EXEC +#define FAN_OPEN_EXEC 0x00001000 +#endif +#ifndef FAN_OPEN_EXEC_PERM +#define FAN_OPEN_EXEC_PERM 0x00040000 +#endif +#ifndef FAN_FS_ERROR +#define FAN_FS_ERROR 0x00008000 +#endif +#ifndef FAN_PRE_ACCESS +#define FAN_PRE_ACCESS 0x00100000 +#endif +#ifndef FAN_RENAME +#define FAN_RENAME 0x10000000 +#endif + +/* Additional error status codes that can be returned to userspace */ +#ifndef FAN_NOPIDFD +#define FAN_NOPIDFD -1 +#endif +#ifndef FAN_EPIDFD +#define FAN_EPIDFD -2 +#endif + +/* errno other than EPERM can specified in upper byte of deny response */ +#ifndef FAN_DENY_ERRNO +#define FAN_ERRNO(err) (((((__u32)(err)) & 0xff) << 24)) +#define FAN_DENY_ERRNO(err) (FAN_DENY | FAN_ERRNO(err)) +#endif + +#ifndef FAN_RESPONSE_ERRNO +#define FAN_RESPONSE_ERRNO(res) ((int)((res) >> 24)) +#endif + +/* Flags required for unprivileged user group */ +#define FANOTIFY_REQUIRED_USER_INIT_FLAGS (FAN_REPORT_FID) + +/* + * FAN_ALL_PERM_EVENTS has been deprecated, so any new permission events + * are not to be added to it. To cover the instance where a new permission + * event is defined, we create a new macro that is to include all + * permission events. Any new permission events should be added to this + * macro. + */ +#define LTP_ALL_PERM_EVENTS (FAN_OPEN_PERM | FAN_OPEN_EXEC_PERM | \ + FAN_ACCESS_PERM) + +#define LTP_PRE_CONTENT_EVENTS (FAN_PRE_ACCESS) + +struct fanotify_group_type { + unsigned int flag; + const char *name; +}; + +struct fanotify_mark_type { + unsigned int flag; + const char *name; +}; + +#ifndef __kernel_fsid_t +typedef struct { + int val[2]; +} lapi_fsid_t; +#define __kernel_fsid_t lapi_fsid_t +#endif /* __kernel_fsid_t */ + +#ifndef FAN_EVENT_INFO_TYPE_FID +#define FAN_EVENT_INFO_TYPE_FID 1 +#endif +#ifndef FAN_EVENT_INFO_TYPE_DFID_NAME +#define FAN_EVENT_INFO_TYPE_DFID_NAME 2 +#endif +#ifndef FAN_EVENT_INFO_TYPE_DFID +#define FAN_EVENT_INFO_TYPE_DFID 3 +#endif +#ifndef FAN_EVENT_INFO_TYPE_PIDFD +#define FAN_EVENT_INFO_TYPE_PIDFD 4 +#endif +#ifndef FAN_EVENT_INFO_TYPE_ERROR +#define FAN_EVENT_INFO_TYPE_ERROR 5 +#endif +#ifndef FAN_EVENT_INFO_TYPE_RANGE +#define FAN_EVENT_INFO_TYPE_RANGE 6 +#endif + +#ifndef FAN_EVENT_INFO_TYPE_OLD_DFID_NAME +#define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10 +#endif +#ifndef FAN_EVENT_INFO_TYPE_NEW_DFID_NAME +#define FAN_EVENT_INFO_TYPE_NEW_DFID_NAME 12 +#endif + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER +struct fanotify_event_info_header { + uint8_t info_type; + uint8_t pad; + uint16_t len; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER */ + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID +struct fanotify_event_info_fid { + struct fanotify_event_info_header hdr; + __kernel_fsid_t fsid; + unsigned char handle[0]; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID */ + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_PIDFD +struct fanotify_event_info_pidfd { + struct fanotify_event_info_header hdr; + int32_t pidfd; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_PIDFD */ + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_ERROR +struct fanotify_event_info_error { + struct fanotify_event_info_header hdr; + __s32 error; + __u32 error_count; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_ERROR */ + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_RANGE +struct fanotify_event_info_range { + struct fanotify_event_info_header hdr; + __u32 pad; + __u64 offset; + __u64 count; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_RANGE */ + +/* NOTE: only for struct fanotify_event_info_fid */ +#ifdef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL +# define FSID_VAL_MEMBER(fsid, i) (fsid.__val[i]) +#else +# define FSID_VAL_MEMBER(fsid, i) (fsid.val[i]) +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL */ + +/* linux/exportfs.h */ +#ifndef FILEID_INVALID +# define FILEID_INVALID 0xff +#endif + +#endif /* LAPI_FANOTIFY_H__ */ diff --git a/ltp/include/lapi/fcntl.h b/ltp/include/lapi/fcntl.h new file mode 100644 index 0000000000000000000000000000000000000000..7c050248892e26ebeb28b86277b1ff47b9dc5ff2 --- /dev/null +++ b/ltp/include/lapi/fcntl.h @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014 Cyril Hrubis + * Copyright (c) Linux Test Project, 2014-2023 + */ + +#ifndef LAPI_FCNTL_H__ +#define LAPI_FCNTL_H__ + +#include "config.h" +#include +#include + +/* NOTE: #define _GNU_SOURCE if you need O_DIRECT in tests */ + +#ifndef O_CLOEXEC +# define O_CLOEXEC 02000000 +#endif + +#ifndef SOCK_CLOEXEC +# define SOCK_CLOEXEC O_CLOEXEC +#endif + +#ifndef SOCK_NONBLOCK +# define SOCK_NONBLOCK O_NONBLOCK +#endif + +#ifndef O_TMPFILE +# define O_TMPFILE (020000000 | O_DIRECTORY) +#endif + +#ifndef F_DUPFD_CLOEXEC +# define F_DUPFD_CLOEXEC 1030 +#endif + +#ifndef F_SETPIPE_SZ +# define F_SETPIPE_SZ 1031 +#endif + +#ifndef F_GETPIPE_SZ +# define F_GETPIPE_SZ 1032 +#endif + +/* + * Set/Get seals + */ +#ifndef F_ADD_SEALS +# define F_ADD_SEALS (1033) +#endif + +#ifndef F_GET_SEALS +# define F_GET_SEALS (1034) +#endif + +#ifndef F_SEAL_SEAL +# define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ +#endif + +#ifndef F_SEAL_SHRINK +# define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ +#endif +#ifndef F_SEAL_GROW +# define F_SEAL_GROW 0x0004 /* prevent file from growing */ +#endif +#ifndef F_SEAL_WRITE +# define F_SEAL_WRITE 0x0008 /* prevent writes */ +#endif + +#ifndef F_OWNER_PGRP +# define F_OWNER_PGRP 2 +#endif + +#ifndef F_OFD_GETLK +# define F_OFD_GETLK 36 +#endif + +#ifndef F_OFD_SETLK +# define F_OFD_SETLK 37 +#endif + +#ifndef F_OFD_SETLKW +# define F_OFD_SETLKW 38 +#endif + +#ifndef AT_FDCWD +# define AT_FDCWD -100 +#endif + +#ifndef AT_SYMLINK_NOFOLLOW +# define AT_SYMLINK_NOFOLLOW 0x100 +#endif + +#ifndef AT_REMOVEDIR +# define AT_REMOVEDIR 0x200 +#endif + +#ifndef AT_HANDLE_FID +# define AT_HANDLE_FID AT_REMOVEDIR +#endif + +#ifndef AT_SYMLINK_FOLLOW +# define AT_SYMLINK_FOLLOW 0x400 +#endif + +#ifndef AT_NO_AUTOMOUNT +# define AT_NO_AUTOMOUNT 0x800 +#endif + +#ifndef AT_EMPTY_PATH +# define AT_EMPTY_PATH 0x1000 +#endif + +#ifndef AT_STATX_SYNC_AS_STAT +# define AT_STATX_SYNC_AS_STAT 0x0000 +#endif + +#ifndef AT_STATX_FORCE_SYNC +# define AT_STATX_FORCE_SYNC 0x2000 +#endif + +#ifndef AT_STATX_DONT_SYNC +# define AT_STATX_DONT_SYNC 0x4000 +#endif + +#ifndef AT_STATX_SYNC_TYPE +# define AT_STATX_SYNC_TYPE 0x6000 +#endif + +#ifndef O_NOATIME +# define O_NOATIME 01000000 +#endif + +#ifndef O_PATH +# ifdef __sparc__ +# define O_PATH 0x1000000 +# else +# define O_PATH 010000000 +# endif +#endif + +#ifndef FALLOC_FL_KEEP_SIZE +# define FALLOC_FL_KEEP_SIZE 1 +#endif + +#ifndef RENAME_NOREPLACE +# define RENAME_NOREPLACE (1 << 0) +#endif + +#ifndef RENAME_EXCHANGE +# define RENAME_EXCHANGE (1 << 1) +#endif + +#ifndef RENAME_WHITEOUT +# define RENAME_WHITEOUT (1 << 2) +#endif + +#ifndef F_LINUX_SPECIFIC_BASE +#define F_LINUX_SPECIFIC_BASE 1024 +#endif + +#ifndef F_CREATED_QUERY +#define F_CREATED_QUERY (F_LINUX_SPECIFIC_BASE + 4) +#endif + +/* splice, vmsplice, tee */ + +#ifndef SPLICE_F_NONBLOCK +# define SPLICE_F_NONBLOCK 2 +#endif + +#ifndef MAX_HANDLE_SZ +# define MAX_HANDLE_SZ 128 +#endif + +#define TST_OPEN_NEEDS_MODE(oflag) \ + (((oflag) & O_CREAT) != 0 || ((oflag) & O_TMPFILE) == O_TMPFILE) + +#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/ltp/include/lapi/ficlone.h b/ltp/include/lapi/ficlone.h new file mode 100644 index 0000000000000000000000000000000000000000..22167331314cf8162f720dd38081fd0f19329a77 --- /dev/null +++ b/ltp/include/lapi/ficlone.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 Andrea Cervesato + * Copyright (C) 2024 Cyril Hrubis + */ + +#ifndef LAPI_FICLONE_H__ +#define LAPI_FICLONE_H__ + +#include "config.h" +#include +#include + +#ifndef HAVE_STRUCT_FILE_CLONE_RANGE +struct file_clone_range { + int64_t src_fd; + uint64_t src_offset; + uint64_t src_length; + uint64_t dest_offset; +}; +#endif + +#ifndef FICLONE +# define FICLONE _IOW(0x94, 9, int) +#endif + +#ifndef FICLONERANGE +# define FICLONERANGE _IOW(0x94, 13, struct file_clone_range) +#endif + +#endif /* LAPI_FICLONE_H__ */ diff --git a/ltp/include/lapi/fnmatch.h b/ltp/include/lapi/fnmatch.h new file mode 100644 index 0000000000000000000000000000000000000000..3bfd6e71e22d89f8f1c4c48674170d94788aedfb --- /dev/null +++ b/ltp/include/lapi/fnmatch.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Linaro Limited. All rights reserved. + * Author: Rafael David Tinoco + */ + +#ifndef LAPI_FNMATCH_H__ +#define LAPI_FNMATCH_H__ + +#ifndef FNM_EXTMATCH +#define FNM_EXTMATCH 0 +#endif + +#endif /* LAPI_FNMATCH_H__ */ diff --git a/ltp/include/lapi/fs.h b/ltp/include/lapi/fs.h new file mode 100644 index 0000000000000000000000000000000000000000..8261ca41dab7d01ea5e7dc9d65e3d5604013cd46 --- /dev/null +++ b/ltp/include/lapi/fs.h @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Referred from linux kernel include/uapi/linux/fs.h + * Copyright (c) 2019 Petr Vorel + * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 + * Email: code@zilogic.com + */ + +#ifndef LAPI_FS_H__ +#define LAPI_FS_H__ + +#include "config.h" +#ifndef HAVE_MOUNT_SETATTR +# include +#endif + +#include +#include +#include "lapi/abisize.h" + +#ifndef FS_IOC_GETFLAGS +# define FS_IOC_GETFLAGS _IOR('f', 1, long) +#endif + +#ifndef FS_IOC_SETFLAGS +# define FS_IOC_SETFLAGS _IOW('f', 2, long) +#endif + +#ifndef FS_COMPR_FL +# define FS_COMPR_FL 0x00000004 /* Compress file */ +#endif + +#ifndef FS_IMMUTABLE_FL +# define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#endif + +#ifndef FS_APPEND_FL +# define FS_APPEND_FL 0x00000020 /* writes to file may only append */ +#endif + +#ifndef FS_NODUMP_FL +# define FS_NODUMP_FL 0x00000040 /* do not dump file */ +#endif + +#ifndef FS_VERITY_FL +# define FS_VERITY_FL 0x00100000 /* Verity protected inode */ +#endif + +/* + * Helper function to get MAX_LFS_FILESIZE. + * Missing PAGE_SHIFT on some libc prevents defining MAX_LFS_FILESIZE. + * + * 64 bit: macro taken from kernel from include/linux/fs.h + * 32 bit: own implementation + */ +static inline long long tst_max_lfs_filesize(void) +{ +#ifdef TST_ABI64 + return LLONG_MAX; +#else + long page_size = getpagesize(); + long long ret = ULONG_MAX; + + while (page_size >>= 1) + ret <<= 1; + + return ret; +#endif +} + +#endif /* LAPI_FS_H__ */ diff --git a/ltp/include/lapi/fsmount.h b/ltp/include/lapi/fsmount.h new file mode 100644 index 0000000000000000000000000000000000000000..1783272a00a1a049031cacbb417239123450a0e4 --- /dev/null +++ b/ltp/include/lapi/fsmount.h @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2021-2022 + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_FSMOUNT_H__ +#define LAPI_FSMOUNT_H__ + +#include "config.h" +#include +#include + +#if !defined(HAVE_FSOPEN) && defined(HAVE_LINUX_MOUNT_H) +# include +#else +# include +#endif + +#include "lapi/fcntl.h" +#include "lapi/syscalls.h" + +/* + * Mount attributes. + */ +#ifndef MOUNT_ATTR_RDONLY +# define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */ +#endif +#ifndef MOUNT_ATTR_NOSUID +# define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */ +#endif +#ifndef MOUNT_ATTR_NODEV +# define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */ +#endif +#ifndef MOUNT_ATTR_NOEXEC +# define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */ +#endif +#ifndef MOUNT_ATTR_NODIRATIME +# define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */ +#endif +#ifndef MOUNT_ATTR_NOSYMFOLLOW +# define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks */ +#endif + +#ifndef ST_NOSYMFOLLOW +# define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */ +#endif + +#ifndef HAVE_STRUCT_MOUNT_ATTR +/* + * mount_setattr() + */ +struct mount_attr { + uint64_t attr_set; + uint64_t attr_clr; + uint64_t propagation; + uint64_t userns_fd; +}; +#endif + +#ifndef HAVE_FSOPEN +static inline int fsopen(const char *fsname, unsigned int flags) +{ + return tst_syscall(__NR_fsopen, fsname, flags); +} +#endif /* HAVE_FSOPEN */ + +#ifndef HAVE_FSCONFIG +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 +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 +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 +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); +} +#endif /* HAVE_MOVE_MOUNT */ + +#ifndef HAVE_OPEN_TREE +static inline int open_tree(int dirfd, const char *pathname, unsigned int flags) +{ + return tst_syscall(__NR_open_tree, dirfd, pathname, flags); +} +#endif /* HAVE_OPEN_TREE */ + +#ifndef HAVE_MOUNT_SETATTR +static inline int mount_setattr(int dirfd, const char *from_pathname, unsigned int flags, + struct mount_attr *attr, size_t size) +{ + return tst_syscall(__NR_mount_setattr, dirfd, from_pathname, flags, + attr, size); +} +#endif /* HAVE_MOUNT_SETATTR */ + +/* + * New headers added in kernel after 5.2 release, create them for old userspace. +*/ + +#ifndef MOVE_MOUNT_BENEATH +# define MOVE_MOUNT_BENEATH 0x00000200 +#endif + +#ifndef OPEN_TREE_CLONE + +/* + * open_tree() flags. + */ +#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ +#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ + +/* + * move_mount() flags. + */ +#define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */ +#define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */ +#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */ +#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */ +#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */ +#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */ +#define MOVE_MOUNT__MASK 0x00000377 + +/* + * fsopen() flags. + */ +#define FSOPEN_CLOEXEC 0x00000001 + +/* + * fspick() flags. + */ +#define FSPICK_CLOEXEC 0x00000001 +#define FSPICK_SYMLINK_NOFOLLOW 0x00000002 +#define FSPICK_NO_AUTOMOUNT 0x00000004 +#define FSPICK_EMPTY_PATH 0x00000008 + +/* + * The type of fsconfig() call made. + */ +enum fsconfig_command { + FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */ + FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */ + FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */ + FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */ + FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */ + FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */ + FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */ + FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */ +}; + +/* + * fsmount() flags. + */ +#define FSMOUNT_CLOEXEC 0x00000001 + +/* + * Mount attributes. + */ +#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */ +#define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */ +#define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */ +#define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */ +#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */ +#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */ +#define MOUNT_ATTR_NOATIME 0x00000010 /* - Do not update access times. */ +#define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */ +#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */ + +#endif /* OPEN_TREE_CLONE */ + +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 */ + 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 /* LAPI_FSMOUNT_H__ */ diff --git a/ltp/include/lapi/fsverity.h b/ltp/include/lapi/fsverity.h new file mode 100644 index 0000000000000000000000000000000000000000..3a33ca83181f9744fcb777d73c16c7746cbfdcd2 --- /dev/null +++ b/ltp/include/lapi/fsverity.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Dai Shili + */ +#ifndef LAPI_FSVERITY_H__ +#define LAPI_FSVERITY_H__ + +#include "config.h" +#include +#include + +#ifdef HAVE_LINUX_FSVERITY_H +#include +#endif + +#ifndef FS_VERITY_HASH_ALG_SHA256 +# define FS_VERITY_HASH_ALG_SHA256 1 +#endif + +#ifndef HAVE_STRUCT_FSVERITY_ENABLE_ARG +struct fsverity_enable_arg { + uint32_t version; + uint32_t hash_algorithm; + uint32_t block_size; + uint32_t salt_size; + uint64_t salt_ptr; + uint32_t sig_size; + uint32_t __reserved1; + uint64_t sig_ptr; + uint64_t __reserved2[11]; +}; +#endif + +#ifndef FS_IOC_ENABLE_VERITY +# define FS_IOC_ENABLE_VERITY _IOW('f', 133, struct fsverity_enable_arg) +#endif + +#endif diff --git a/ltp/include/lapi/futex.h b/ltp/include/lapi/futex.h new file mode 100644 index 0000000000000000000000000000000000000000..a05fcb89ca969d0c6009def90e215670a8e065ea --- /dev/null +++ b/ltp/include/lapi/futex.h @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Linux Test Project + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +#ifndef LAPI_FUTEX_H__ +#define LAPI_FUTEX_H__ + +#include +#include "config.h" + +typedef volatile uint32_t futex_t; + +#if !defined(SYS_futex) && defined(SYS_futex_time64) +#define SYS_futex SYS_futex_time64 +#endif + +#ifdef HAVE_LINUX_FUTEX_H +# include +#else +#include + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_FD 2 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_LOCK_PI 6 +#define FUTEX_UNLOCK_PI 7 +#define FUTEX_TRYLOCK_PI 8 +#define FUTEX_WAIT_BITSET 9 +#define FUTEX_WAKE_BITSET 10 +#define FUTEX_WAIT_REQUEUE_PI 11 +#define FUTEX_CMP_REQUEUE_PI 12 +#define FUTEX_LOCK_PI2 13 + +#define FUTEX_PRIVATE_FLAG 128 +#define FUTEX_CLOCK_REALTIME 256 +#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) + +#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) +#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG) +#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG) +#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_LOCK_PI2_PRIVATE (FUTEX_LOCK_PI2 | FUTEX_PRIVATE_FLAG) +#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ + FUTEX_PRIVATE_FLAG) +#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ + FUTEX_PRIVATE_FLAG) + +/* + * Support for robust futexes: the kernel cleans up held futexes at + * thread exit time. + */ + +/* + * Per-lock list entry - embedded in user-space locks, somewhere close + * to the futex field. (Note: user-space uses a double-linked list to + * achieve O(1) list add and remove, but the kernel only needs to know + * about the forward link) + * + * NOTE: this structure is part of the syscall ABI, and must not be + * changed. + */ +struct robust_list { + struct robust_list *next; +}; + +/* + * Per-thread list head: + * + * NOTE: this structure is part of the syscall ABI, and must only be + * changed if the change is first communicated with the glibc folks. + * (When an incompatible change is done, we'll increase the structure + * size, which glibc will detect) + */ +struct robust_list_head { + /* + * The head of the list. Points back to itself if empty: + */ + struct robust_list list; + + /* + * This relative offset is set by user-space, it gives the kernel + * the relative position of the futex field to examine. This way + * we keep userspace flexible, to freely shape its data-structure, + * without hardcoding any particular offset into the kernel: + */ + long futex_offset; + + /* + * The death of the thread may race with userspace setting + * up a lock's links. So to handle this race, userspace first + * sets this field to the address of the to-be-taken lock, + * then does the lock acquire, and then adds itself to the + * list, and then clears this field. Hence the kernel will + * always have full knowledge of all locks that the thread + * _might_ have taken. We check the owner TID in any case, + * so only truly owned locks will be handled. + */ + struct robust_list *list_op_pending; +}; + +/* + * Are there any waiters for this robust futex: + */ +#define FUTEX_WAITERS 0x80000000 + +/* + * The kernel signals via this bit that a thread holding a futex + * has exited without unlocking the futex. The kernel also does + * a FUTEX_WAKE on such futexes, after setting the bit, to wake + * up any possible waiters: + */ +#define FUTEX_OWNER_DIED 0x40000000 + +/* + * The rest of the robust-futex field is for the TID: + */ +#define FUTEX_TID_MASK 0x3fffffff + +/* + * This limit protects against a deliberately circular list. + * (Not worth introducing an rlimit for it) + */ +#define ROBUST_LIST_LIMIT 2048 + +/* + * bitset with all bits set for the FUTEX_xxx_BITSET OPs to request a + * match of any bit. + */ +#define FUTEX_BITSET_MATCH_ANY 0xffffffff + + +#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ +#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ +#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ +#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */ +#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */ + +#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */ + +#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */ +#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */ +#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */ +#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */ +#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */ +#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */ + +/* FUTEX_WAKE_OP will perform atomically + int oldval = *(int *)UADDR2; + *(int *)UADDR2 = oldval OP OPARG; + if (oldval CMP CMPARG) + wake UADDR2; */ + +#define FUTEX_OP(op, oparg, cmp, cmparg) \ + (((op & 0xf) << 28) | ((cmp & 0xf) << 24) \ + | ((oparg & 0xfff) << 12) | (cmparg & 0xfff)) + +#endif /* HAVE_LINUX_FUTEX_H */ + +#ifndef HAVE_STRUCT_FUTEX_WAITV +/* + * Flags to specify the bit length of the futex word for futex2 syscalls. + * Currently, only 32 is supported. + */ +#define FUTEX_32 2 + +/* + * Max numbers of elements in a futex_waitv array + */ +#define FUTEX_WAITV_MAX 128 + +/** + * struct futex_waitv - A waiter for vectorized wait + * @val: Expected value at uaddr + * @uaddr: User address to wait on + * @flags: Flags for this waiter + * @__reserved: Reserved member to preserve data alignment. Should be 0. + */ +struct futex_waitv { + uint64_t val; + uint64_t uaddr; + uint32_t flags; + uint32_t __reserved; +}; +#endif /* HAVE_STRUCT_FUTEX_WAITV */ + +#endif /* LAPI_FUTEX_H__ */ diff --git a/ltp/include/lapi/getrandom.h b/ltp/include/lapi/getrandom.h new file mode 100644 index 0000000000000000000000000000000000000000..8d5b90ee935c73df5c9548e6aa9d3a4650c6d43a --- /dev/null +++ b/ltp/include/lapi/getrandom.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Linux Test Project + */ + +#ifndef LAPI_GETRANDOM_H__ +#define LAPI_GETRANDOM_H__ + +#include "config.h" + +#ifdef HAVE_SYS_RANDOM_H +# include +#else +# include +#endif + +#include "lapi/syscalls.h" + +/* + * Flags for getrandom(2) + * + * GRND_NONBLOCK Don't block and return EAGAIN instead + * GRND_RANDOM Use the /dev/random pool instead of /dev/urandom + */ + +#ifndef GRND_NONBLOCK +# define GRND_NONBLOCK 0x0001 +#endif + +#ifndef GRND_RANDOM +# define GRND_RANDOM 0x0002 +#endif + +#ifndef HAVE_SYS_RANDOM_H +static inline int getrandom(void *buf, size_t buflen, unsigned int flags) +{ + return tst_syscall(SYS_getrandom, buf, buflen, flags); +} +#endif + +#endif /* LAPI_GETRANDOM_H__ */ diff --git a/ltp/include/lapi/if_addr.h b/ltp/include/lapi/if_addr.h new file mode 100644 index 0000000000000000000000000000000000000000..0f7e44784e9905c8fc570a933d6abb0f587cb428 --- /dev/null +++ b/ltp/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/ltp/include/lapi/if_alg.h b/ltp/include/lapi/if_alg.h new file mode 100644 index 0000000000000000000000000000000000000000..466957e9ed98473bab3f9f3c27886a5139e964fa --- /dev/null +++ b/ltp/include/lapi/if_alg.h @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2019 Google LLC + */ + +#ifndef LAPI_IF_ALG_H__ +#define LAPI_IF_ALG_H__ + +#ifdef HAVE_LINUX_IF_ALG_H +# include +#endif +# include + +#ifndef HAVE_STRUCT_SOCKADDR_ALG +struct sockaddr_alg { + uint16_t salg_family; + uint8_t salg_type[14]; + uint32_t salg_feat; + 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 + +#ifndef ALG_SET_KEY +# define ALG_SET_KEY 1 +#endif + +#ifndef ALG_SET_IV +# define ALG_SET_IV 2 +#endif + +#ifndef ALG_SET_OP +# define ALG_SET_OP 3 +#endif + +#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/ltp/include/lapi/if_ether.h b/ltp/include/lapi/if_ether.h new file mode 100644 index 0000000000000000000000000000000000000000..536d1863a093ee3b225902725f4973813b866762 --- /dev/null +++ b/ltp/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/ltp/include/lapi/if_packet.h b/ltp/include/lapi/if_packet.h new file mode 100644 index 0000000000000000000000000000000000000000..8c6c2e0e2f6c55e8cff39699221de9e68c835759 --- /dev/null +++ b/ltp/include/lapi/if_packet.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. + * Author: Jinhui huang + */ + +#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 +#endif + +#ifndef PACKET_FANOUT_ROLLOVER +# 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__ */ diff --git a/ltp/include/lapi/init_module.h b/ltp/include/lapi/init_module.h new file mode 100644 index 0000000000000000000000000000000000000000..ba0d2b266bcd2ec095a1e6cd15c5c380188cbede --- /dev/null +++ b/ltp/include/lapi/init_module.h @@ -0,0 +1,25 @@ +// 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 "tst_test.h" +#include "lapi/syscalls.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); +} + +#endif /* LAPI_INIT_MODULE_H__ */ diff --git a/ltp/include/lapi/io_pgetevents.h b/ltp/include/lapi/io_pgetevents.h new file mode 100644 index 0000000000000000000000000000000000000000..4ab13a6d461bd11a3f12b01703678b35618ca7a7 --- /dev/null +++ b/ltp/include/lapi/io_pgetevents.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_IO_PGETEVENTS_H__ +#define LAPI_IO_PGETEVENTS_H__ + +#include +#include + +#include "config.h" +#include "lapi/syscalls.h" + +#ifdef HAVE_LIBAIO +#include + +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); +} + +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 /* LAPI_IO_PGETEVENTS_H__ */ diff --git a/ltp/include/lapi/io_uring.h b/ltp/include/lapi/io_uring.h new file mode 100644 index 0000000000000000000000000000000000000000..c05517595f2f99f4cb243cccc38254c290273a6e --- /dev/null +++ b/ltp/include/lapi/io_uring.h @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 ARM. All rights reserved. + * Copyright (c) 2020 Petr Vorel + * + * Mostly copied/adapted from + */ + +#ifndef LAPI_IO_URING_H__ +#define LAPI_IO_URING_H__ + +#include +#include +#include +#include +#include + +#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) + */ +struct io_uring_sqe { + uint8_t opcode; /* type of operation for this sqe */ + uint8_t flags; /* IOSQE_ flags */ + uint16_t ioprio; /* ioprio for the request */ + int32_t fd; /* file descriptor to do IO on */ + union { + uint64_t off; /* offset into file */ + uint64_t addr2; + }; + uint64_t addr; /* pointer to buffer or iovecs */ + uint32_t len; /* buffer size or number of iovecs */ + union { + __kernel_rwf_t rw_flags; + uint32_t fsync_flags; + uint16_t poll_events; + uint32_t sync_range_flags; + uint32_t msg_flags; + uint32_t timeout_flags; + uint32_t accept_flags; + uint32_t cancel_flags; + uint32_t open_flags; + uint32_t statx_flags; + uint32_t fadvise_advice; + }; + uint64_t user_data; /* data to be passed back at completion time */ + union { + struct { + /* index into fixed buffers, if used */ + uint16_t buf_index; + /* personality to use, if used */ + uint16_t personality; + }; + uint64_t __pad2[3]; + }; +}; + +enum { + IOSQE_FIXED_FILE_BIT, + IOSQE_IO_DRAIN_BIT, + IOSQE_IO_LINK_BIT, +}; + +/* + * sqe->flags + */ +/* use fixed fileset */ +#define IOSQE_FIXED_FILE (1U << IOSQE_FIXED_FILE_BIT) +/* issue after inflight IO */ +#define IOSQE_IO_DRAIN (1U << IOSQE_IO_DRAIN_BIT) +/* links next sqe */ +#define IOSQE_IO_LINK (1U << IOSQE_IO_LINK_BIT) + +/* + * io_uring_setup() flags + */ +#define IORING_SETUP_IOPOLL (1U << 0) /* io_context is polled */ +#define IORING_SETUP_SQPOLL (1U << 1) /* SQ poll thread */ +#define IORING_SETUP_SQ_AFF (1U << 2) /* sq_thread_cpu is valid */ +#define IORING_SETUP_CQSIZE (1U << 3) /* app defines CQ size */ +#define IORING_SETUP_CLAMP (1U << 4) /* clamp SQ/CQ ring sizes */ +#define IORING_SETUP_ATTACH_WQ (1U << 5) /* attach to existing wq */ + +enum { + IORING_OP_NOP, + IORING_OP_READV, + IORING_OP_WRITEV, + IORING_OP_FSYNC, + IORING_OP_READ_FIXED, + IORING_OP_WRITE_FIXED, + IORING_OP_POLL_ADD, + IORING_OP_POLL_REMOVE, + IORING_OP_SYNC_FILE_RANGE, + IORING_OP_SENDMSG, + IORING_OP_RECVMSG, + IORING_OP_TIMEOUT, + IORING_OP_TIMEOUT_REMOVE, + IORING_OP_ACCEPT, + IORING_OP_ASYNC_CANCEL, + IORING_OP_LINK_TIMEOUT, + IORING_OP_CONNECT, + IORING_OP_FALLOCATE, + IORING_OP_OPENAT, + IORING_OP_CLOSE, + IORING_OP_FILES_UPDATE, + IORING_OP_STATX, + IORING_OP_READ, + IORING_OP_WRITE, + IORING_OP_FADVISE, + IORING_OP_MADVISE, + IORING_OP_SEND, + IORING_OP_RECV, + IORING_OP_OPENAT2, + IORING_OP_EPOLL_CTL, + + /* this goes last, obviously */ + IORING_OP_LAST, +}; + +/* + * sqe->fsync_flags + */ +#define IORING_FSYNC_DATASYNC (1U << 0) + +/* + * sqe->timeout_flags + */ +#define IORING_TIMEOUT_ABS (1U << 0) + +/* + * IO completion data structure (Completion Queue Entry) + */ +struct io_uring_cqe { + uint64_t user_data; /* sqe->data submission passed back */ + int32_t res; /* result code for this event */ + uint32_t flags; +}; + +/* + * Magic offsets for the application to mmap the data it needs + */ +#define IORING_OFF_SQ_RING 0ULL +#define IORING_OFF_CQ_RING 0x8000000ULL +#define IORING_OFF_SQES 0x10000000ULL + +/* + * Filled with the offset for mmap(2) + */ +struct io_sqring_offsets { + uint32_t head; + uint32_t tail; + uint32_t ring_mask; + uint32_t ring_entries; + uint32_t flags; + uint32_t dropped; + uint32_t array; + uint32_t resv1; + uint64_t resv2; +}; + +/* + * sq_ring->flags + */ +#define IORING_SQ_NEED_WAKEUP (1U << 0) /* needs io_uring_enter wakeup */ + +struct io_cqring_offsets { + uint32_t head; + uint32_t tail; + uint32_t ring_mask; + uint32_t ring_entries; + uint32_t overflow; + uint32_t cqes; + uint64_t resv[2]; +}; + +/* + * io_uring_enter(2) flags + */ +#define IORING_ENTER_GETEVENTS (1U << 0) +#define IORING_ENTER_SQ_WAKEUP (1U << 1) + +/* + * Passed in for io_uring_setup(2). Copied back with updated info on success + */ +struct io_uring_params { + uint32_t sq_entries; + uint32_t cq_entries; + uint32_t flags; + uint32_t sq_thread_cpu; + uint32_t sq_thread_idle; + uint32_t features; + uint32_t wq_fd; + uint32_t resv[3]; + struct io_sqring_offsets sq_off; + struct io_cqring_offsets cq_off; +}; + +/* + * io_uring_params->features flags + */ +#define IORING_FEAT_SINGLE_MMAP (1U << 0) +#define IORING_FEAT_NODROP (1U << 1) +#define IORING_FEAT_SUBMIT_STABLE (1U << 2) +#define IORING_FEAT_RW_CUR_POS (1U << 3) +#define IORING_FEAT_CUR_PERSONALITY (1U << 4) + +/* + * io_uring_register(2) opcodes and arguments + */ +#define IORING_REGISTER_BUFFERS 0 +#define IORING_UNREGISTER_BUFFERS 1 +#define IORING_REGISTER_FILES 2 +#define IORING_UNREGISTER_FILES 3 +#define IORING_REGISTER_EVENTFD 4 +#define IORING_UNREGISTER_EVENTFD 5 +#define IORING_REGISTER_FILES_UPDATE 6 +#define IORING_REGISTER_EVENTFD_ASYNC 7 +#define IORING_REGISTER_PROBE 8 +#define IORING_REGISTER_PERSONALITY 9 +#define IORING_UNREGISTER_PERSONALITY 10 + +struct io_uring_files_update { + uint32_t offset; + uint32_t resv; + uint64_t __attribute__((aligned(8))) fds; +}; + +#define IO_URING_OP_SUPPORTED (1U << 0) + +struct io_uring_probe_op { + uint8_t op; + uint8_t resv; + uint16_t flags; /* IO_URING_OP_* flags */ + uint32_t resv2; +}; + +struct io_uring_probe { + uint8_t last_op; /* last opcode supported */ + uint8_t ops_len; /* length of ops[] array below */ + uint16_t resv; + uint32_t resv2[3]; + struct io_uring_probe_op ops[0]; +}; + +#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 +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); +} +#endif /* HAVE_IO_URING_REGISTER */ + + +#ifndef HAVE_IO_URING_SETUP +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 +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 */ + +static inline void io_uring_setup_supported_by_kernel(void) +{ + long ret; + ret = syscall(__NR_io_uring_setup, NULL, 0); + if (ret != -1) { + SAFE_CLOSE(ret); + return; + } + + if (errno == ENOSYS) { + if ((tst_kvercmp(5, 1, 0)) < 0) { + tst_brk(TCONF, + "Test not supported on kernel version < v5.1"); + } + tst_brk(TCONF, "CONFIG_IO_URING not set?"); + } +} + +#endif /* LAPI_IO_URING_H__ */ diff --git a/ltp/include/lapi/ioctl.h b/ltp/include/lapi/ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..d0f8bf2547b35df525716ae796daa3b577fa2ccb --- /dev/null +++ b/ltp/include/lapi/ioctl.h @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + * Copyright (c) 2020 Petr Vorel + */ + +#ifndef LAPI_IOCTL_H__ +#define LAPI_IOCTL_H__ + +#include "config.h" +#include +#include + +/* musl not including it in */ +#include + +#ifndef TIOCVHANGUP +# define TIOCVHANGUP 0x5437 +#endif + +#ifndef HAVE_STRUCT_TERMIO +# ifndef NCC +# ifdef __powerpc__ +# define NCC 10 +# else +# define NCC 8 +# endif +# endif /* NCC */ + +struct termio + { + unsigned short int c_iflag; /* input mode flags */ + unsigned short int c_oflag; /* output mode flags */ + unsigned short int c_cflag; /* control mode flags */ + unsigned short int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; +#endif /* HAVE_STRUCT_TERMIO */ + +#ifndef HAVE_STRUCT_PROCMAP_QUERY +#define PROCFS_IOCTL_MAGIC 'f' +#define PROCMAP_QUERY _IOWR(PROCFS_IOCTL_MAGIC, 17, struct procmap_query) +enum procmap_query_flags { + /* + * VMA permission flags. + * + * Can be used as part of procmap_query.query_flags field to look up + * only VMAs satisfying specified subset of permissions. E.g., specifying + * PROCMAP_QUERY_VMA_READABLE only will return both readable and read/write VMAs, + * while having PROCMAP_QUERY_VMA_READABLE | PROCMAP_QUERY_VMA_WRITABLE will only + * return read/write VMAs, though both executable/non-executable and + * private/shared will be ignored. + * + * PROCMAP_QUERY_VMA_* flags are also returned in procmap_query.vma_flags + * field to specify actual VMA permissions. + */ + PROCMAP_QUERY_VMA_READABLE = 0x01, + PROCMAP_QUERY_VMA_WRITABLE = 0x02, + PROCMAP_QUERY_VMA_EXECUTABLE = 0x04, + PROCMAP_QUERY_VMA_SHARED = 0x08, + /* + * Query modifier flags. + * + * By default VMA that covers provided address is returned, or -ENOENT + * is returned. With PROCMAP_QUERY_COVERING_OR_NEXT_VMA flag set, closest + * VMA with vma_start > addr will be returned if no covering VMA is + * found. + * + * PROCMAP_QUERY_FILE_BACKED_VMA instructs query to consider only VMAs that + * have file backing. Can be combined with PROCMAP_QUERY_COVERING_OR_NEXT_VMA + * to iterate all VMAs with file backing. + */ + PROCMAP_QUERY_COVERING_OR_NEXT_VMA = 0x10, + PROCMAP_QUERY_FILE_BACKED_VMA = 0x20, +}; + +struct procmap_query { + /* Query struct size, for backwards/forward compatibility */ + uint64_t size; + /* + * Query flags, a combination of enum procmap_query_flags values. + * Defines query filtering and behavior, see enum procmap_query_flags. + * + * Input argument, provided by user. Kernel doesn't modify it. + */ + uint64_t query_flags; /* in */ + /* + * Query address. By default, VMA that covers this address will + * be looked up. PROCMAP_QUERY_* flags above modify this default + * behavior further. + * + * Input argument, provided by user. Kernel doesn't modify it. + */ + uint64_t query_addr; /* in */ + /* VMA starting (inclusive) and ending (exclusive) address, if VMA is found. */ + uint64_t vma_start; /* out */ + uint64_t vma_end; /* out */ + /* VMA permissions flags. A combination of PROCMAP_QUERY_VMA_* flags. */ + uint64_t vma_flags; /* out */ + /* VMA backing page size granularity. */ + uint64_t vma_page_size; /* out */ + /* + * VMA file offset. If VMA has file backing, this specifies offset + * within the file that VMA's start address corresponds to. + * Is set to zero if VMA has no backing file. + */ + uint64_t vma_offset; /* out */ + /* Backing file's inode number, or zero, if VMA has no backing file. */ + uint64_t inode; /* out */ + /* Backing file's device major/minor number, or zero, if VMA has no backing file. */ + uint32_t dev_major; /* out */ + uint32_t dev_minor; /* out */ + /* + * If set to non-zero value, signals the request to return VMA name + * (i.e., VMA's backing file's absolute path, with " (deleted)" suffix + * appended, if file was unlinked from FS) for matched VMA. VMA name + * can also be some special name (e.g., "[heap]", "[stack]") or could + * be even user-supplied with prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME). + * + * Kernel will set this field to zero, if VMA has no associated name. + * Otherwise kernel will return actual amount of bytes filled in + * user-supplied buffer (see vma_name_addr field below), including the + * terminating zero. + * + * If VMA name is longer that user-supplied maximum buffer size, + * -E2BIG error is returned. + * + * If this field is set to non-zero value, vma_name_addr should point + * to valid user space memory buffer of at least vma_name_size bytes. + * If set to zero, vma_name_addr should be set to zero as well + */ + uint32_t vma_name_size; /* in/out */ + /* + * If set to non-zero value, signals the request to extract and return + * VMA's backing file's build ID, if the backing file is an ELF file + * and it contains embedded build ID. + * + * Kernel will set this field to zero, if VMA has no backing file, + * backing file is not an ELF file, or ELF file has no build ID + * embedded. + * + * Build ID is a binary value (not a string). Kernel will set + * build_id_size field to exact number of bytes used for build ID. + * If build ID is requested and present, but needs more bytes than + * user-supplied maximum buffer size (see build_id_addr field below), + * -E2BIG error will be returned. + * + * If this field is set to non-zero value, build_id_addr should point + * to valid user space memory buffer of at least build_id_size bytes. + * If set to zero, build_id_addr should be set to zero as well + */ + uint32_t build_id_size; /* in/out */ + /* + * User-supplied address of a buffer of at least vma_name_size bytes + * for kernel to fill with matched VMA's name (see vma_name_size field + * description above for details). + * + * Should be set to zero if VMA name should not be returned. + */ + uint64_t vma_name_addr; /* in */ + /* + * User-supplied address of a buffer of at least build_id_size bytes + * for kernel to fill with matched VMA's ELF build ID, if available + * (see build_id_size field description above for details). + * + * Should be set to zero if build ID should not be returned. + */ + uint64_t build_id_addr; /* in */ +}; +#endif /* HAVE_STRUCT_PROCMAP_QUERY */ + +#endif /* LAPI_IOCTL_H__ */ diff --git a/ltp/include/lapi/ioctl_ns.h b/ltp/include/lapi/ioctl_ns.h new file mode 100644 index 0000000000000000000000000000000000000000..9c81d5ce20f299e8e8d6565317c608f805dc74c9 --- /dev/null +++ b/ltp/include/lapi/ioctl_ns.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com + */ + +#ifndef LAPI_IOCTL_NS_H__ +#define LAPI_IOCTL_NS_H__ + +#include + +#ifndef NSIO +#define NSIO 0xb7 +#endif +#ifndef NS_GET_PARENT +#define NS_GET_PARENT _IO(NSIO, 0x2) +#endif +#ifndef NS_GET_OWNER_UID +#define NS_GET_OWNER_UID _IO(NSIO, 0x4) +#endif +#ifndef NS_GET_USERNS +#define NS_GET_USERNS _IO(NSIO, 0x1) +#endif +#ifndef NS_GET_NSTYPE +#define NS_GET_NSTYPE _IO(NSIO, 0x3) +#endif + + +#endif /* LAPI_IOCTL_NS_H__ */ diff --git a/ltp/include/lapi/ioprio.h b/ltp/include/lapi/ioprio.h new file mode 100644 index 0000000000000000000000000000000000000000..871aa0278e75a42c7a1bc63867559c0f4fe3dcf0 --- /dev/null +++ b/ltp/include/lapi/ioprio.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2019 Linus Walleij + */ + +#ifndef LAPI_IOPRIO_H__ +#define LAPI_IOPRIO_H__ + +#include "config.h" + +#ifdef HAVE_LINUX_IOPRIO_H +# include +#else + +enum { + IOPRIO_CLASS_NONE = 0, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + +enum { + IOPRIO_WHO_PROCESS = 1, + IOPRIO_WHO_PGRP, + IOPRIO_WHO_USER, +}; + +# define IOPRIO_CLASS_SHIFT (13) +# define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) + +# define IOPRIO_PRIO_CLASS(data) ((data) >> IOPRIO_CLASS_SHIFT) +# define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) + +#endif + +/* The RT and BE I/O priority classes have 8 priority levels 0..7 */ +#ifdef IOPRIO_NR_LEVELS +# define IOPRIO_PRIO_NUM IOPRIO_NR_LEVELS +#else +# define IOPRIO_PRIO_NUM 8 +#endif + +#ifndef IOPRIO_PRIO_LEVEL +# define IOPRIO_PRIO_LEVEL(data) ((data) & IOPRIO_PRIO_MASK) +#endif + +#endif /* LAPI_IOPRIO_H__ */ diff --git a/ltp/include/lapi/iovec.h b/ltp/include/lapi/iovec.h new file mode 100644 index 0000000000000000000000000000000000000000..8d9fe1036ebc50994e4e53b456eeb586332c83d3 --- /dev/null +++ b/ltp/include/lapi/iovec.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014 Cyril Hrubis + */ + +#ifndef LAPI_IOVEC_H__ +#define LAPI_IOVEC_H__ + +#include "config.h" + +#if !defined(HAVE_STRUCT_IOVEC) +struct iovec { + void *iov_base; + size_t iov_len; +}; +#else +# include +#endif + +#endif /* LAPI_IOVEC_H__ */ diff --git a/ltp/include/lapi/ip_tables.h b/ltp/include/lapi/ip_tables.h new file mode 100644 index 0000000000000000000000000000000000000000..d0ed33324863e942fa2aceff4adef9f17b83958a --- /dev/null +++ b/ltp/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/ltp/include/lapi/ipc.h b/ltp/include/lapi/ipc.h new file mode 100644 index 0000000000000000000000000000000000000000..5645c8817c2153c5f19e1c3d1a69bfb3b3137f95 --- /dev/null +++ b/ltp/include/lapi/ipc.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Arm Ltd. + */ +#ifndef LAPI_IPC_H__ +#define LAPI_IPC_H__ + +#include + +#ifndef IPC_INFO +# define IPC_INFO 3 +#endif + +#endif /* LAPI_IPC_H__ */ diff --git a/ltp/include/lapi/ipcbuf.h b/ltp/include/lapi/ipcbuf.h new file mode 100644 index 0000000000000000000000000000000000000000..ee0a9bafb0040ad1e905e103e0cccb77db111e0f --- /dev/null +++ b/ltp/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/ltp/include/lapi/kcmp.h b/ltp/include/lapi/kcmp.h new file mode 100644 index 0000000000000000000000000000000000000000..9fa1be888618d780ce9b0c90b21f615422576941 --- /dev/null +++ b/ltp/include/lapi/kcmp.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Cedric Hnyda + */ + +#ifndef LAPI_KCMP_H__ +#define LAPI_KCMP_H__ + +#include +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef HAVE_ENUM_KCMP_TYPE + +enum kcmp_type { + KCMP_FILE, + KCMP_VM, + KCMP_FILES, + KCMP_FS, + KCMP_SIGHAND, + KCMP_IO, + KCMP_SYSVSEM, + KCMP_TYPES, +}; + +#else + +# include + +#endif + +#ifndef HAVE_KCMP + +static inline int kcmp(int pid1, int pid2, int type, int fd1, int fd2) +{ + return tst_syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2); +} + +#endif + +#endif /* LAPI_KCMP_H__ */ diff --git a/ltp/include/lapi/keyctl.h b/ltp/include/lapi/keyctl.h new file mode 100644 index 0000000000000000000000000000000000000000..e08b8f13221a23e8af8f63d2cd2baba692631804 --- /dev/null +++ b/ltp/include/lapi/keyctl.h @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + */ + +#ifndef LAPI_KEYCTL_H__ +#define LAPI_KEYCTL_H__ + +#include "config.h" + +#if defined(HAVE_KEYUTILS_H) && defined(HAVE_LIBKEYUTILS) +# include +#else +# ifdef HAVE_LINUX_KEYCTL_H +# include +# endif /* HAVE_LINUX_KEYCTL_H */ + +# include +# include +# include "lapi/syscalls.h" +typedef int32_t key_serial_t; + +static inline key_serial_t add_key(const char *type, + const char *description, + const void *payload, + size_t plen, + key_serial_t ringid) +{ + return tst_syscall(__NR_add_key, + type, description, payload, plen, ringid); +} + +static inline key_serial_t request_key(const char *type, + const char *description, + const char *callout_info, + key_serial_t destringid) +{ + return tst_syscall(__NR_request_key, + type, description, callout_info, destringid); +} + +static inline long keyctl(int cmd, ...) +{ + va_list va; + unsigned long arg2, arg3, arg4, arg5; + + va_start(va, cmd); + arg2 = va_arg(va, unsigned long); + arg3 = va_arg(va, unsigned long); + arg4 = va_arg(va, unsigned long); + arg5 = va_arg(va, unsigned long); + va_end(va); + + return tst_syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); +} + +static inline key_serial_t keyctl_join_session_keyring(const char *name) { + return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name); +} + +#endif /* defined(HAVE_KEYUTILS_H) && defined(HAVE_LIBKEYUTILS) */ + +/* special process keyring shortcut IDs */ +#ifndef KEY_SPEC_THREAD_KEYRING +# define KEY_SPEC_THREAD_KEYRING -1 +#endif + +#ifndef KEY_SPEC_PROCESS_KEYRING +# define KEY_SPEC_PROCESS_KEYRING -2 +#endif + +#ifndef KEY_SPEC_SESSION_KEYRING +# define KEY_SPEC_SESSION_KEYRING -3 +#endif + +#ifndef KEY_SPEC_USER_KEYRING +# define KEY_SPEC_USER_KEYRING -4 +#endif + + +#ifndef KEY_SPEC_USER_SESSION_KEYRING +# define KEY_SPEC_USER_SESSION_KEYRING -5 +#endif + +/* request-key default keyrings */ +#ifndef KEY_REQKEY_DEFL_THREAD_KEYRING +# define KEY_REQKEY_DEFL_THREAD_KEYRING 1 +#endif + +#ifndef KEY_REQKEY_DEFL_SESSION_KEYRING +# define KEY_REQKEY_DEFL_SESSION_KEYRING 3 +#endif + +#ifndef KEY_REQKEY_DEFL_DEFAULT +# define KEY_REQKEY_DEFL_DEFAULT 0 +#endif + +/* keyctl commands */ +#ifndef KEYCTL_GET_KEYRING_ID +# define KEYCTL_GET_KEYRING_ID 0 +#endif + +#ifndef KEYCTL_JOIN_SESSION_KEYRING +# define KEYCTL_JOIN_SESSION_KEYRING 1 +#endif + +#ifndef KEYCTL_UPDATE +# define KEYCTL_UPDATE 2 +#endif + +#ifndef KEYCTL_REVOKE +# define KEYCTL_REVOKE 3 +#endif + +#ifndef KEYCTL_SETPERM +# define KEYCTL_SETPERM 5 +#endif + +#ifndef KEYCTL_DESCRIBE +# define KEYCTL_DESCRIBE 6 +#endif + +#ifndef KEYCTL_CLEAR +# define KEYCTL_CLEAR 7 +#endif + +#ifndef KEYCTL_UNLINK +# define KEYCTL_UNLINK 9 +#endif + +#ifndef KEYCTL_SEARCH +# define KEYCTL_SEARCH 10 +#endif + +#ifndef KEYCTL_READ +# define KEYCTL_READ 11 +#endif + +#ifndef KEYCTL_SET_REQKEY_KEYRING +# define KEYCTL_SET_REQKEY_KEYRING 14 +#endif + +#ifndef KEYCTL_SET_TIMEOUT +# define KEYCTL_SET_TIMEOUT 15 +#endif + +#ifndef KEYCTL_ASSUME_AUTHORITY +# define KEYCTL_ASSUME_AUTHORITY 16 +#endif + +#ifndef KEYCTL_GET_SECURITY +# define KEYCTL_GET_SECURITY 17 +#endif + +#ifndef KEYCTL_INVALIDATE +# define KEYCTL_INVALIDATE 21 +#endif + +#ifndef KEYCTL_GET_PERSISTENT +# define KEYCTL_GET_PERSISTENT 22 +#endif + +#ifndef KEYCTL_DH_COMPUTE +# define KEYCTL_DH_COMPUTE 23 +#endif + +#ifndef KEYCTL_WATCH_KEY +# define KEYCTL_WATCH_KEY 32 +#endif + +/* key permissions */ +#ifndef KEY_POS_VIEW +# define KEY_POS_VIEW 0x01000000 +# define KEY_POS_READ 0x02000000 +# define KEY_POS_WRITE 0x04000000 +# define KEY_POS_SEARCH 0x08000000 +# define KEY_POS_LINK 0x10000000 +# define KEY_POS_SETATTR 0x20000000 +# define KEY_POS_ALL 0x3f000000 + +# define KEY_USR_VIEW 0x00010000 +# define KEY_USR_READ 0x00020000 +# define KEY_USR_WRITE 0x00040000 +# define KEY_USR_SEARCH 0x00080000 +# define KEY_USR_LINK 0x00100000 +# define KEY_USR_SETATTR 0x00200000 +# define KEY_USR_ALL 0x003f0000 + +# define KEY_GRP_VIEW 0x00000100 +# define KEY_GRP_READ 0x00000200 +# define KEY_GRP_WRITE 0x00000400 +# define KEY_GRP_SEARCH 0x00000800 +# define KEY_GRP_LINK 0x00001000 +# define KEY_GRP_SETATTR 0x00002000 +# define KEY_GRP_ALL 0x00003f00 + +# define KEY_OTH_VIEW 0x00000001 +# define KEY_OTH_READ 0x00000002 +# define KEY_OTH_WRITE 0x00000004 +# define KEY_OTH_SEARCH 0x00000008 +# define KEY_OTH_LINK 0x00000010 +# define KEY_OTH_SETATTR 0x00000020 +# define KEY_OTH_ALL 0x0000003f +#endif /* !KEY_POS_VIEW */ + +static inline long safe_keyctl(const char *file, const int lineno, + int cmd, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) +{ + long rval; + int failure = 0; + + rval = keyctl(cmd, arg2, arg3, arg4, arg5); + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "keyctl(%d, %lu, %lu, %lu, %lu)", + cmd, arg2, arg3, arg4, arg5); + } + + switch (cmd) { + case KEYCTL_GET_KEYRING_ID: + case KEYCTL_JOIN_SESSION_KEYRING: + case KEYCTL_DESCRIBE: + case KEYCTL_SEARCH: + case KEYCTL_READ: + case KEYCTL_SET_REQKEY_KEYRING: + case KEYCTL_GET_SECURITY: + case KEYCTL_GET_PERSISTENT: + case KEYCTL_DH_COMPUTE: + if (rval < 0) + failure = 1; + break; + case KEYCTL_ASSUME_AUTHORITY: + if ((!arg2 && rval) || (arg2 && rval < 0)) + failure = 1; + break; + default: + if (rval) + failure = 1; + break; + } + + if (failure) { + tst_brk_(file, lineno, TBROK, + "keyctl(%d, %lu, %lu, %lu, %lu) returned %ld", + cmd, arg2, arg3, arg4, arg5, rval); + } + + return rval; +} +#define SAFE_KEYCTL(cmd, arg2, arg3, arg4, arg5) \ + safe_keyctl(__FILE__, __LINE__, \ + (cmd), (arg2), (arg3), (arg4), (arg5)) + +#endif /* LAPI_KEYCTL_H__ */ diff --git a/ltp/include/lapi/landlock.h b/ltp/include/lapi/landlock.h new file mode 100644 index 0000000000000000000000000000000000000000..e579500ec26cdc0a568620bc35386f3d2b68952e --- /dev/null +++ b/ltp/include/lapi/landlock.h @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 SUSE LLC Andrea Cervesato + */ + +#ifndef LAPI_LANDLOCK_H__ +#define LAPI_LANDLOCK_H__ + +#include "config.h" +#include + +#ifdef HAVE_LINUX_LANDLOCK_H +# include +#endif + +#include "lapi/syscalls.h" + +struct tst_landlock_ruleset_attr_abi1 { + uint64_t handled_access_fs; +}; + +struct tst_landlock_ruleset_attr_abi4 { + uint64_t handled_access_fs; + uint64_t handled_access_net; +}; + +struct tst_landlock_ruleset_attr_abi6 { + uint64_t handled_access_fs; + uint64_t handled_access_net; + uint64_t scoped; +}; + +#ifndef HAVE_STRUCT_LANDLOCK_PATH_BENEATH_ATTR +struct landlock_path_beneath_attr +{ + uint64_t allowed_access; + int32_t parent_fd; +} __attribute__((packed)); +#endif + +#if !HAVE_DECL_LANDLOCK_RULE_PATH_BENEATH +# define LANDLOCK_RULE_PATH_BENEATH 1 +#endif + +#if !HAVE_DECL_LANDLOCK_RULE_NET_PORT +# define LANDLOCK_RULE_NET_PORT 2 +#endif + +#ifndef HAVE_STRUCT_LANDLOCK_NET_PORT_ATTR +struct landlock_net_port_attr { + uint64_t allowed_access; + uint64_t port; +}; +#endif + +#ifndef LANDLOCK_CREATE_RULESET_VERSION +# define LANDLOCK_CREATE_RULESET_VERSION (1U << 0) +#endif + +#ifndef LANDLOCK_ACCESS_FS_EXECUTE +# define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0) +#endif + +#ifndef LANDLOCK_ACCESS_FS_WRITE_FILE +# define LANDLOCK_ACCESS_FS_WRITE_FILE (1ULL << 1) +#endif + +#ifndef LANDLOCK_ACCESS_FS_READ_FILE +# define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2) +#endif + +#ifndef LANDLOCK_ACCESS_FS_READ_DIR +# define LANDLOCK_ACCESS_FS_READ_DIR (1ULL << 3) +#endif + +#ifndef LANDLOCK_ACCESS_FS_REMOVE_DIR +# define LANDLOCK_ACCESS_FS_REMOVE_DIR (1ULL << 4) +#endif + +#ifndef LANDLOCK_ACCESS_FS_REMOVE_FILE +# define LANDLOCK_ACCESS_FS_REMOVE_FILE (1ULL << 5) +#endif + +#ifndef LANDLOCK_ACCESS_FS_MAKE_CHAR +# define LANDLOCK_ACCESS_FS_MAKE_CHAR (1ULL << 6) +#endif + +#ifndef LANDLOCK_ACCESS_FS_MAKE_DIR +# define LANDLOCK_ACCESS_FS_MAKE_DIR (1ULL << 7) +#endif + +#ifndef LANDLOCK_ACCESS_FS_MAKE_REG +# define LANDLOCK_ACCESS_FS_MAKE_REG (1ULL << 8) +#endif + +#ifndef LANDLOCK_ACCESS_FS_MAKE_SOCK +# define LANDLOCK_ACCESS_FS_MAKE_SOCK (1ULL << 9) +#endif + +#ifndef LANDLOCK_ACCESS_FS_MAKE_FIFO +# define LANDLOCK_ACCESS_FS_MAKE_FIFO (1ULL << 10) +#endif + +#ifndef LANDLOCK_ACCESS_FS_MAKE_BLOCK +# define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11) +#endif + +#ifndef LANDLOCK_ACCESS_FS_MAKE_SYM +# define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12) +#endif + +#ifndef LANDLOCK_ACCESS_FS_REFER +# define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) +#endif + +#ifndef LANDLOCK_ACCESS_FS_TRUNCATE +# define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14) +#endif + +#ifndef LANDLOCK_ACCESS_FS_IOCTL_DEV +# define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15) +#endif + +#ifndef LANDLOCK_ACCESS_NET_BIND_TCP +# define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0) +#endif + +#ifndef LANDLOCK_ACCESS_NET_CONNECT_TCP +# define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1) +#endif + +#ifndef LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET +# define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET (1ULL << 0) +#endif + +#ifndef LANDLOCK_SCOPE_SIGNAL +# define LANDLOCK_SCOPE_SIGNAL (1ULL << 1) +#endif + +static inline int safe_landlock_create_ruleset(const char *file, const int lineno, + const void *attr, size_t size , uint32_t flags) +{ + int rval; + + rval = tst_syscall(__NR_landlock_create_ruleset, attr, size, flags); + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "landlock_create_ruleset(%p, %zi, %u)", + attr, size, flags); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid landlock_create_ruleset(%p, %lu, %u) return value %d", + attr, size, flags, rval); + } + + return rval; +} + +static inline int safe_landlock_add_rule(const char *file, const int lineno, + int ruleset_fd, int rule_type, const void *rule_attr, uint32_t flags) +{ + int rval; + + rval = tst_syscall(__NR_landlock_add_rule, + ruleset_fd, rule_type, rule_attr, flags); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "landlock_add_rule(%d, %d, %p, %u)", + ruleset_fd, rule_type, rule_attr, flags); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid landlock_add_rule(%d, %d, %p, %u) return value %d", + ruleset_fd, rule_type, rule_attr, flags, rval); + } + + return rval; +} + +static inline int safe_landlock_restrict_self(const char *file, const int lineno, + int ruleset_fd, int flags) +{ + int rval; + + rval = tst_syscall(__NR_landlock_restrict_self, ruleset_fd, flags); + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "landlock_restrict_self(%d, %u)", + ruleset_fd, flags); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid landlock_restrict_self(%d, %u) return value %d", + ruleset_fd, flags, rval); + } + + return rval; +} + +#define SAFE_LANDLOCK_CREATE_RULESET(attr, size, flags) \ + safe_landlock_create_ruleset(__FILE__, __LINE__, (attr), (size), (flags)) + +#define SAFE_LANDLOCK_ADD_RULE(ruleset_fd, rule_type, rule_attr, flags) \ + safe_landlock_add_rule(__FILE__, __LINE__, \ + (ruleset_fd), (rule_type), (rule_attr), (flags)) + +#define SAFE_LANDLOCK_RESTRICT_SELF(ruleset_fd, flags) \ + safe_landlock_restrict_self(__FILE__, __LINE__, (ruleset_fd), (flags)) + +#endif diff --git a/ltp/include/lapi/ldt.h b/ltp/include/lapi/ldt.h new file mode 100644 index 0000000000000000000000000000000000000000..d9233d09bee947a90d22538e2e3cf13dece64208 --- /dev/null +++ b/ltp/include/lapi/ldt.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2025 SUSE LLC Ricardo B. Marlière + */ + +#ifndef LAPI_LDT_H__ +#define LAPI_LDT_H__ + +#include "config.h" +#include "lapi/syscalls.h" + +#ifdef HAVE_ASM_LDT_H +#include +#else +struct user_desc { + unsigned int entry_number; + unsigned int base_addr; + unsigned int limit; + unsigned int seg_32bit : 1; + unsigned int contents : 2; + unsigned int read_exec_only : 1; + unsigned int limit_in_pages : 1; + unsigned int seg_not_present : 1; + unsigned int useable : 1; +#ifdef __x86_64__ + unsigned int lm : 1; +#endif /* __x86_64__ */ +}; +#endif /* HAVE_ASM_LDT_H */ + +static inline int modify_ldt(int func, const struct user_desc *ptr, + unsigned long bytecount) +{ + long rval; + + errno = 0; + rval = tst_syscall(__NR_modify_ldt, func, ptr, bytecount); + +#ifdef __x86_64__ + /* + * The kernel intentionally casts modify_ldt() return value + * to unsigned int to prevent sign extension to 64 bits. This may + * result in syscall() returning the value as is instead of setting + * errno and returning -1. + */ + if (rval > 0 && (int)rval < 0) { + tst_res(TINFO, + "WARNING: Libc mishandled modify_ldt() return value"); + errno = -(int)rval; + rval = -1; + } +#endif /* __x86_64__ */ + + return rval; +} + +static inline int safe_modify_ldt(const char *file, const int lineno, int func, + const struct user_desc *ptr, + unsigned long bytecount) +{ + int rval; + + rval = modify_ldt(func, ptr, bytecount); + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "modify_ldt(%d, %p, %lu)", func, ptr, bytecount); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "modify_ltd(%d, %p, %lu) invalid retval %i", func, ptr, + bytecount, rval); + } + + return rval; +} + +#define SAFE_MODIFY_LDT(func, ptr, bytecount) \ + safe_modify_ldt(__FILE__, __LINE__, (func), (ptr), (bytecount)) + +static inline int set_thread_area(const struct user_desc *u_info) +{ + return tst_syscall(__NR_set_thread_area, u_info); +} + +static inline int get_thread_area(const struct user_desc *u_info) +{ + return tst_syscall(__NR_get_thread_area, u_info); +} + +#endif /* LAPI_LDT_H__ */ diff --git a/ltp/include/lapi/loop.h b/ltp/include/lapi/loop.h new file mode 100644 index 0000000000000000000000000000000000000000..c663eea1ae523412f5f0605027a0d85284d7e67f --- /dev/null +++ b/ltp/include/lapi/loop.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ +#ifndef LAPI_LOOP_H__ +#define LAPI_LOOP_H__ + +#include "config.h" +#include +#include + +#ifndef LO_FLAGS_PARTSCAN +# define LO_FLAGS_PARTSCAN 8 +#endif + +#ifndef LO_FLAGS_DIRECT_IO +# define LO_FLAGS_DIRECT_IO 16 +#endif + +#ifndef LOOP_SET_CAPACITY +# define LOOP_SET_CAPACITY 0x4C07 +#endif + +#ifndef LOOP_SET_DIRECT_IO +# define LOOP_SET_DIRECT_IO 0x4C08 +#endif + +#ifndef LOOP_SET_BLOCK_SIZE +# 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/ltp/include/lapi/lsm.h b/ltp/include/lapi/lsm.h new file mode 100644 index 0000000000000000000000000000000000000000..72ca85f784282190b1db9fac3da79a562f93f43a --- /dev/null +++ b/ltp/include/lapi/lsm.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 SUSE LLC Andrea Cervesato + */ + +#ifndef LAPI_LSM_H__ +#define LAPI_LSM_H__ + +#include "config.h" + +#ifdef HAVE_LINUX_LSM_H +#include +#endif + +#include +#include "lapi/syscalls.h" + +#define CTX_DATA_SIZE 4096 + +#define LSM_CTX_SIZE(x) (sizeof(struct lsm_ctx) + x) +#define LSM_CTX_SIZE_DEFAULT LSM_CTX_SIZE(CTX_DATA_SIZE) + +#ifndef HAVE_STRUCT_LSM_CTX + +/** + * struct lsm_ctx - LSM context information + * @id: the LSM id number, see LSM_ID_XXX + * @flags: LSM specific flags + * @len: length of the lsm_ctx struct, @ctx and any other data or padding + * @ctx_len: the size of @ctx + * @ctx: the LSM context value + * + * The @len field MUST be equal to the size of the lsm_ctx struct + * plus any additional padding and/or data placed after @ctx. + * + * In all cases @ctx_len MUST be equal to the length of @ctx. + * If @ctx is a string value it should be nul terminated with + * @ctx_len equal to `strlen(@ctx) + 1`. Binary values are + * supported. + * + * The @flags and @ctx fields SHOULD only be interpreted by the + * LSM specified by @id; they MUST be set to zero/0 when not used. + */ +struct lsm_ctx { + uint64_t id; + uint64_t flags; + uint64_t len; + uint64_t ctx_len; + uint8_t ctx[]; +}; +#endif + +/* + * ID tokens to identify Linux Security Modules (LSMs) + * + * These token values are used to uniquely identify specific LSMs + * in the kernel as well as in the kernel's LSM userspace API. + */ +#ifndef LSM_ID_UNDEF +# define LSM_ID_UNDEF 0 +#endif + +#ifndef LSM_ID_CAPABILITY +# define LSM_ID_CAPABILITY 100 +#endif + +#ifndef LSM_ID_SELINUX +# define LSM_ID_SELINUX 101 +#endif + +#ifndef LSM_ID_SMACK +# define LSM_ID_SMACK 102 +#endif + +#ifndef LSM_ID_TOMOYO +# define LSM_ID_TOMOYO 103 +#endif + +#ifndef LSM_ID_APPARMOR +# define LSM_ID_APPARMOR 104 +#endif + +#ifndef LSM_ID_YAMA +# define LSM_ID_YAMA 105 +#endif + +#ifndef LSM_ID_LOADPIN +# define LSM_ID_LOADPIN 106 +#endif + +#ifndef LSM_ID_SAFESETID +# define LSM_ID_SAFESETID 107 +#endif + +#ifndef LSM_ID_LOCKDOWN +# define LSM_ID_LOCKDOWN 108 +#endif + +#ifndef LSM_ID_BPF +# define LSM_ID_BPF 109 +#endif + +#ifndef LSM_ID_LANDLOCK +# define LSM_ID_LANDLOCK 110 +#endif + +#ifndef LSM_ID_IMA +# define LSM_ID_IMA 111 +#endif + +#ifndef LSM_ID_EVM +# define LSM_ID_EVM 112 +#endif + +#ifndef LSM_ID_IPE +# define LSM_ID_IPE 113 +#endif + +/* + * LSM_ATTR_XXX definitions identify different LSM attributes + * which are used in the kernel's LSM userspace API. Support + * for these attributes vary across the different LSMs. None + * are required. + */ +#ifndef LSM_ATTR_UNDEF +# define LSM_ATTR_UNDEF 0 +#endif + +#ifndef LSM_ATTR_CURRENT +# define LSM_ATTR_CURRENT 100 +#endif + +#ifndef LSM_ATTR_EXEC +# define LSM_ATTR_EXEC 101 +#endif + +#ifndef LSM_ATTR_FSCREATE +# define LSM_ATTR_FSCREATE 102 +#endif + +#ifndef LSM_ATTR_KEYCREATE +# define LSM_ATTR_KEYCREATE 103 +#endif + +#ifndef LSM_ATTR_PREV +# define LSM_ATTR_PREV 104 +#endif + +#ifndef LSM_ATTR_SOCKCREATE +# define LSM_ATTR_SOCKCREATE 105 +#endif + +/* + * LSM_FLAG_XXX definitions identify special handling instructions + * for the API. + */ +#ifndef LSM_FLAG_SINGLE +# define LSM_FLAG_SINGLE 0x0001 +#endif + +static inline int lsm_get_self_attr(uint32_t attr, struct lsm_ctx *ctx, + uint32_t *size, uint32_t flags) +{ + return tst_syscall(__NR_lsm_get_self_attr, attr, ctx, size, flags); +} + +static inline int lsm_set_self_attr(uint32_t attr, struct lsm_ctx *ctx, + uint32_t size, uint32_t flags) +{ + return tst_syscall(__NR_lsm_set_self_attr, attr, ctx, size, flags); +} + +static inline int lsm_list_modules(uint64_t *ids, uint32_t *size, uint32_t flags) +{ + return tst_syscall(__NR_lsm_list_modules, ids, size, flags); +} +#endif diff --git a/ltp/include/lapi/membarrier.h b/ltp/include/lapi/membarrier.h new file mode 100644 index 0000000000000000000000000000000000000000..eda63cd8a71889e8e9a45fab9827b9f5175e77fd --- /dev/null +++ b/ltp/include/lapi/membarrier.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Linaro Limited. All rights reserved. + * Author: Rafael David Tinoco + */ + +#ifndef LAPI_MEMBARRIER_H__ +#define LAPI_MEMBARRIER_H__ + +/* + * Having is enough to know if the test should run or + * not, but it might not define all needed MEMBARRIER_CMD_* being tested, + * since its first versions included just a few commands. + */ + +enum membarrier_cmd { + MEMBARRIER_CMD_QUERY = 0, + MEMBARRIER_CMD_GLOBAL = (1 << 0), + MEMBARRIER_CMD_GLOBAL_EXPEDITED = (1 << 1), + MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = (1 << 2), + MEMBARRIER_CMD_PRIVATE_EXPEDITED = (1 << 3), + MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = (1 << 4), + MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 5), + MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 6), + + /* Alias for header backward compatibility. */ + MEMBARRIER_CMD_SHARED = MEMBARRIER_CMD_GLOBAL, +}; + +#endif /* LAPI_MEMBARRIER_H__ */ diff --git a/ltp/include/lapi/memfd.h b/ltp/include/lapi/memfd.h new file mode 100644 index 0000000000000000000000000000000000000000..57b6cd83d80c84abec5d0f38828a5bdba9073496 --- /dev/null +++ b/ltp/include/lapi/memfd.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017 Red Hat, Inc. + */ + +#ifndef LAPI_MEMFD_H__ +#define LAPI_MEMFD_H__ + +/* flags for memfd_create(2) (unsigned int) */ +#ifndef MFD_CLOEXEC +# define MFD_CLOEXEC 0x0001U +#endif +#ifndef MFD_ALLOW_SEALING +# define MFD_ALLOW_SEALING 0x0002U +#endif + +/* flags for memfd_create(3) and memfd_create(4) */ +#ifndef MFD_HUGETLB +#define MFD_HUGETLB 0x0004U +#endif + +#ifndef MFD_HUGE_64KB +#define MFD_HUGE_64KB (16 << 26) +#endif +#ifndef MFD_HUGE_512KB +#define MFD_HUGE_512KB (19 << 26) +#endif +#ifndef MFD_HUGE_2MB +#define MFD_HUGE_2MB (21 << 26) +#endif +#ifndef MFD_HUGE_8MB +#define MFD_HUGE_8MB (23 << 26) +#endif +#ifndef MFD_HUGE_16MB +#define MFD_HUGE_16MB (24 << 26) +#endif +#ifndef MFD_HUGE_256MB +#define MFD_HUGE_256MB (28 << 26) +#endif +#ifndef MFD_HUGE_1GB +#define MFD_HUGE_1GB (30 << 26) +#endif +#ifndef MFD_HUGE_2GB +#define MFD_HUGE_2GB (31 << 26) +#endif +#ifndef MFD_HUGE_16GB +#define MFD_HUGE_16GB (34 << 26) +#endif + +#endif /* LAPI_MEMFD_H__ */ diff --git a/ltp/include/lapi/mlock2.h b/ltp/include/lapi/mlock2.h new file mode 100644 index 0000000000000000000000000000000000000000..7b180eadad005ff151c4eaa748441bf9f6775bf3 --- /dev/null +++ b/ltp/include/lapi/mlock2.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. + * Author: Xiao Yang + */ + +#ifndef LAPI_MLOCK2_H__ +#define LAPI_MLOCK2_H__ + +#include + +#ifndef MLOCK_ONFAULT +# define MLOCK_ONFAULT 0x01 +#endif + +#endif /* LAPI_MLOCK2_H__ */ diff --git a/ltp/include/lapi/mman.h b/ltp/include/lapi/mman.h new file mode 100644 index 0000000000000000000000000000000000000000..edd517c6e0ebad98f01530b9ac2a7c90cdcaced8 --- /dev/null +++ b/ltp/include/lapi/mman.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 SUSE LLC Andrea Cervesato + */ + +#ifndef LAPI_MMAN_H__ +#define LAPI_MMAN_H__ + +#include +#include +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef HAVE_STRUCT_CACHESTAT_RANGE +struct cachestat_range { + uint64_t off; + uint64_t len; +}; +#endif + +#ifndef HAVE_STRUCT_CACHESTAT +struct cachestat { + uint64_t nr_cache; + uint64_t nr_dirty; + uint64_t nr_writeback; + uint64_t nr_evicted; + uint64_t nr_recently_evicted; +}; +#endif + +#ifndef HAVE_CACHESTAT +/* + * cachestat: wrapper function of cachestat + * + * Returns: It returns status of cachestat syscall + */ +static inline int cachestat(int fd, struct cachestat_range *cstat_range, + struct cachestat *cstat, unsigned int flags) +{ + return tst_syscall(__NR_cachestat, fd, cstat_range, cstat, flags); +} +#endif + +#endif /* LAPI_MMAN_H__ */ diff --git a/ltp/include/lapi/mmap.h b/ltp/include/lapi/mmap.h new file mode 100644 index 0000000000000000000000000000000000000000..248b64564b4c418a0b7fb41edd8fcc31245d6a6f --- /dev/null +++ b/ltp/include/lapi/mmap.h @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Fujitsu Ltd. + * Author: Guangwen Feng + */ + +#ifndef LAPI_MMAP_H__ +#define LAPI_MMAP_H__ + +#include "config.h" +#include + +#ifndef MAP_SHARED_VALIDATE +# define MAP_SHARED_VALIDATE 0x03 +#endif + +#ifndef MAP_HUGETLB +# define MAP_HUGETLB 0x40000 +#endif + +#ifndef MADV_REMOVE +# define MADV_REMOVE 9 +#endif + +#ifndef MADV_DONTFORK +# define MADV_DONTFORK 10 +#endif + +#ifndef MADV_DOFORK +# define MADV_DOFORK 11 +#endif + +#ifndef MADV_HWPOISON +# define MADV_HWPOISON 100 +#endif + +#ifndef MADV_SOFT_OFFLINE +# define MADV_SOFT_OFFLINE 101 +#endif + +#ifndef MADV_GUARD_INSTALL +# define MADV_GUARD_INSTALL 102 +#endif + +#ifndef MADV_GUARD_REMOVE +# define MADV_GUARD_REMOVE 103 +#endif + +#ifndef MADV_MERGEABLE +# define MADV_MERGEABLE 12 +#endif + +#ifndef MADV_UNMERGEABLE +# define MADV_UNMERGEABLE 13 +#endif + +#ifndef MADV_HUGEPAGE +# define MADV_HUGEPAGE 14 +#endif + +#ifndef MADV_NOHUGEPAGE +# define MADV_NOHUGEPAGE 15 +#endif + +#ifndef MADV_DONTDUMP +# define MADV_DONTDUMP 16 +#endif + +#ifndef MADV_DODUMP +# define MADV_DODUMP 17 +#endif + +#ifndef MADV_FREE +# define MADV_FREE 8 +#endif + +#ifndef MADV_WIPEONFORK +# define MADV_WIPEONFORK 18 +# define MADV_KEEPONFORK 19 +#endif + +#ifndef MADV_COLD +# define MADV_COLD 20 +#endif + +#ifndef MADV_PAGEOUT +# define MADV_PAGEOUT 21 +#endif + +#ifndef MAP_DROPPABLE +# define MAP_DROPPABLE 0x08 +#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 +#else +# include +# define MMAP_GRANULARITY getpagesize() +#endif /* HAVE_SYS_SHM_H */ + +#endif /* LAPI_MMAP_H__ */ diff --git a/ltp/include/lapi/mount.h b/ltp/include/lapi/mount.h new file mode 100644 index 0000000000000000000000000000000000000000..aea6bca77ac0c52cbccb892cbd0a205994ab19be --- /dev/null +++ b/ltp/include/lapi/mount.h @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2015-2025 + * Copyright (c) 2015 Cui Bixuan + * Copyright (C) 2024 SUSE LLC Andrea Cervesato + */ + +#ifndef LAPI_MOUNT_H__ +#define LAPI_MOUNT_H__ + +#include "config.h" +#include + +/* + * NOTE: conflicts with , therefore not added + * although some definitions from it are used. + */ +#include + +#ifndef MS_REC +# define MS_REC 16384 +#endif + +#ifndef MS_PRIVATE +# define MS_PRIVATE (1<<18) +#endif + +#ifndef MS_STRICTATIME +# define MS_STRICTATIME (1 << 24) +#endif + +#ifndef MNT_DETACH +# define MNT_DETACH 2 +#endif + +#ifndef MNT_EXPIRE +# define MNT_EXPIRE 4 +#endif + +#ifndef UMOUNT_NOFOLLOW +# define UMOUNT_NOFOLLOW 8 +#endif + +#ifndef MS_NOSYMFOLLOW +# define MS_NOSYMFOLLOW 256 +#endif + +#ifndef HAVE_STRUCT_MNT_ID_REQ +struct mnt_id_req { + uint32_t size; + uint32_t spare; + uint64_t mnt_id; + uint64_t param; +}; +#endif + +#ifndef HAVE_STRUCT_STATMOUNT +struct statmount { + uint32_t size; + uint32_t __spare1; + uint64_t mask; + uint32_t sb_dev_major; + uint32_t sb_dev_minor; + uint64_t sb_magic; + uint32_t sb_flags; + uint32_t fs_type; + uint64_t mnt_id; + uint64_t mnt_parent_id; + uint32_t mnt_id_old; + uint32_t mnt_parent_id_old; + uint64_t mnt_attr; + uint64_t mnt_propagation; + uint64_t mnt_peer_group; + uint64_t mnt_master; + uint64_t propagate_from; + uint32_t mnt_root; + uint32_t mnt_point; + uint64_t __spare2[50]; + char str[]; +}; +#endif + +#ifndef MNT_ID_REQ_SIZE_VER0 +# define MNT_ID_REQ_SIZE_VER0 24 +#endif + +#ifndef STATMOUNT_SB_BASIC +# define STATMOUNT_SB_BASIC 0x00000001U +#endif + +#ifndef STATMOUNT_MNT_BASIC +# define STATMOUNT_MNT_BASIC 0x00000002U +#endif + +#ifndef STATMOUNT_PROPAGATE_FROM +# define STATMOUNT_PROPAGATE_FROM 0x00000004U +#endif + +#ifndef STATMOUNT_MNT_ROOT +# define STATMOUNT_MNT_ROOT 0x00000008U +#endif + +#ifndef STATMOUNT_MNT_POINT +# define STATMOUNT_MNT_POINT 0x00000010U +#endif + +#ifndef STATMOUNT_FS_TYPE +# define STATMOUNT_FS_TYPE 0x00000020U +#endif + +#ifndef LSMT_ROOT +# define LSMT_ROOT 0xffffffffffffffff +#endif + +#endif /* LAPI_MOUNT_H__ */ diff --git a/ltp/include/lapi/msg.h b/ltp/include/lapi/msg.h new file mode 100644 index 0000000000000000000000000000000000000000..ab37cdaac29be7eafcd656390a8a73fcf6bd104c --- /dev/null +++ b/ltp/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/ltp/include/lapi/msgbuf.h b/ltp/include/lapi/msgbuf.h new file mode 100644 index 0000000000000000000000000000000000000000..9736b99bf4b6ef8d67756102d26662731107ee65 --- /dev/null +++ b/ltp/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/ltp/include/lapi/name_to_handle_at.h b/ltp/include/lapi/name_to_handle_at.h new file mode 100644 index 0000000000000000000000000000000000000000..7c76438ecec03231cacf870ba608609b9deadb7c --- /dev/null +++ b/ltp/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 "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/fcntl.h" +#include "tst_buffers.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/ltp/include/lapi/netinet_in.h b/ltp/include/lapi/netinet_in.h new file mode 100644 index 0000000000000000000000000000000000000000..e88485c5ca373a8810ed69722230963f00eb39d6 --- /dev/null +++ b/ltp/include/lapi/netinet_in.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Petr Vorel + */ + +#ifndef LAPI_IN_H__ +#define LAPI_IN_H__ + +#include + +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif + +#ifndef IPPROTO_UDPLITE +# define IPPROTO_UDPLITE 136 /* UDP-Lite (RFC 3828) */ +#endif + +#ifndef IP_BIND_ADDRESS_NO_PORT +# define IP_BIND_ADDRESS_NO_PORT 24 +#endif + +#endif /* LAPI_IN_H__ */ diff --git a/ltp/include/lapi/nf_tables.h b/ltp/include/lapi/nf_tables.h new file mode 100644 index 0000000000000000000000000000000000000000..9feb3a60ecd70113a655f975c92ce1c76985cbb4 --- /dev/null +++ b/ltp/include/lapi/nf_tables.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 SUSE LLC + */ + +#ifndef LAPI_NF_TABLES_H__ +#define LAPI_NF_TABLES_H__ + +#include + +#ifndef HAVE_DECL_NFTA_CHAIN_ID +# define NFTA_CHAIN_ID 11 +#endif + +#ifndef HAVE_DECL_NFTA_VERDICT_CHAIN_ID +# define NFTA_VERDICT_CHAIN_ID 3 +#endif + +#endif /* LAPI_NF_TABLES_H__ */ diff --git a/ltp/include/lapi/numaif.h b/ltp/include/lapi/numaif.h new file mode 100644 index 0000000000000000000000000000000000000000..4362b75c1a72b024da3ae81f8a4da80551b87870 --- /dev/null +++ b/ltp/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/ltp/include/lapi/openat2.h b/ltp/include/lapi/openat2.h new file mode 100644 index 0000000000000000000000000000000000000000..03327bdb77bc81cb708ff9c011499bc0a12529ce --- /dev/null +++ b/ltp/include/lapi/openat2.h @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar + */ + +#ifndef LAPI_OPENAT2_H__ +#define LAPI_OPENAT2_H__ + +#include +#include + +#include "lapi/syscalls.h" + +#include "config.h" + +#ifndef HAVE_OPENAT2 +/* + * Arguments for how openat2(2) should open the target path. If only @flags and + * @mode are non-zero, then openat2(2) operates very similarly to openat(2). + * + * However, unlike openat(2), unknown or invalid bits in @flags result in + * -EINVAL rather than being silently ignored. @mode must be zero unless one of + * {O_CREAT, O_TMPFILE} are set. + * + * @flags: O_* flags. + * @mode: O_CREAT/O_TMPFILE file mode. + * @resolve: RESOLVE_* flags. + */ +struct open_how { + uint64_t flags; + uint64_t mode; + uint64_t resolve; +}; + +/* how->resolve flags for openat2(2). */ +#define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings + (includes bind-mounts). */ +#define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style + "magic-links". */ +#define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks + (implies OEXT_NO_MAGICLINKS) */ +#define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like + "..", symlinks, and absolute + paths which escape the dirfd. */ +#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".." + be scoped inside the dirfd + (similar to chroot(2)). */ + +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); +} +#endif + +struct open_how_pad { + /* how should be kept as the first entry here */ + struct open_how how; + uint64_t pad; +}; + +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 */ + 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 /* LAPI_OPENAT2_H__ */ diff --git a/ltp/include/lapi/personality.h b/ltp/include/lapi/personality.h new file mode 100644 index 0000000000000000000000000000000000000000..2cbb5dceb73fc33a19a34651e760fcef8c58b62d --- /dev/null +++ b/ltp/include/lapi/personality.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Richard Palethorpe + */ + +/* In the Linux kernel and glibc enums are (mostly) used for the constants, + * but in musl macros are used. + */ + +#ifndef LAPI_PERSONALITY_H__ +#define LAPI_PERSONALITY_H__ + +#include + +#ifndef UNAME26 +# define UNAME26 0x0020000 +#endif + +#ifndef READ_IMPLIES_EXEC +# define READ_IMPLIES_EXEC 0x0400000 +#endif + +#endif /* LAPI_PERSONALITY_H__ */ diff --git a/ltp/include/lapi/pidfd.h b/ltp/include/lapi/pidfd.h new file mode 100644 index 0000000000000000000000000000000000000000..9ca8e5aa23626646ebb2f18880abd5e52298bfc6 --- /dev/null +++ b/ltp/include/lapi/pidfd.h @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +#ifndef LAPI_PIDFD_H__ +#define LAPI_PIDFD_H__ + +#include +#ifdef HAVE_SYS_PIDFD_H +# include +#endif +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef PIDFD_NONBLOCK +#define PIDFD_NONBLOCK O_NONBLOCK +#endif + +static inline void pidfd_send_signal_supported(void) +{ + /* allow the tests to fail early */ + tst_syscall(__NR_pidfd_send_signal); +} + +#ifndef HAVE_PIDFD_SEND_SIGNAL +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 + +static inline void pidfd_open_supported(void) +{ + /* allow the tests to fail early */ + tst_syscall(__NR_pidfd_open); +} + +#ifndef HAVE_PIDFD_OPEN +static inline int pidfd_open(pid_t pid, unsigned int flags) +{ + return tst_syscall(__NR_pidfd_open, pid, flags); +} +#endif + +static inline void pidfd_getfd_supported(void) +{ + /* allow the tests to fail early */ + tst_syscall(__NR_pidfd_getfd); +} + +#ifndef HAVE_PIDFD_GETFD +static inline int pidfd_getfd(int pidfd, int targetfd, unsigned int flags) +{ + return tst_syscall(__NR_pidfd_getfd, pidfd, targetfd, flags); +} +#endif + +#endif /* LAPI_PIDFD_H__ */ diff --git a/ltp/include/lapi/pkey.h b/ltp/include/lapi/pkey.h new file mode 100644 index 0000000000000000000000000000000000000000..eb9bf7fb461796375c54ca6bbee3383f838d0e09 --- /dev/null +++ b/ltp/include/lapi/pkey.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019-2024 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2019-2024 + */ + +#ifndef PKEYS_H__ +#define PKEYS_H__ + +#include "config.h" +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/mmap.h" + +#ifndef PKEY_DISABLE_ACCESS +# define PKEY_DISABLE_ACCESS 0x1 +# define PKEY_DISABLE_WRITE 0x2 +#endif + +#ifndef PKEY_DISABLE_EXECUTE +# define PKEY_DISABLE_EXECUTE 0x4 +#endif + +#ifndef HAVE_PKEY_MPROTECT +inline int pkey_mprotect(void *addr, size_t len, int prot, int pkey) +{ + return tst_syscall(__NR_pkey_mprotect, addr, len, prot, pkey); +} + +inline int pkey_alloc(unsigned int flags, unsigned int access_rights) +{ + return tst_syscall(__NR_pkey_alloc, flags, access_rights); +} + +inline int pkey_free(int pkey) +{ + return tst_syscall(__NR_pkey_free, pkey); +} +#endif /* HAVE_PKEY_MPROTECT */ + +static inline void check_pkey_support(void) +{ + int pkey = tst_syscall(__NR_pkey_alloc, 0, 0); + + if (pkey == -1) { + if (errno == ENOSYS) + tst_brk(TCONF, "pkey_alloc is not implemented"); + if (errno == EINVAL) + tst_brk(TCONF, "pku is not supported on this CPU"); + if (errno == ENOSPC) + tst_brk(TCONF, "pkeys are not available for test"); + } + + tst_syscall(__NR_pkey_free, pkey); +} + +#endif /* PKEYS_H__ */ diff --git a/ltp/include/lapi/posix_clocks.h b/ltp/include/lapi/posix_clocks.h new file mode 100644 index 0000000000000000000000000000000000000000..d16f182eb368bef47b038d781cb7319472b8a8d4 --- /dev/null +++ b/ltp/include/lapi/posix_clocks.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019, Linux Test Project + * Copyright (c) 2013 Cyril Hrubis + */ + +#include + +#ifndef LAPI_POSIX_CLOCKS_H__ +#define LAPI_POSIX_CLOCKS_H__ + +#define MAX_CLOCKS 16 + +#ifndef CLOCK_MONOTONIC_RAW +# define CLOCK_MONOTONIC_RAW 4 +#endif + +#ifndef CLOCK_REALTIME_COARSE +# define CLOCK_REALTIME_COARSE 5 +#endif + +#ifndef CLOCK_MONOTONIC_COARSE +# define CLOCK_MONOTONIC_COARSE 6 +#endif + +#ifndef CLOCK_BOOTTIME +# define CLOCK_BOOTTIME 7 +#endif + +#ifndef CLOCK_REALTIME_ALARM +# define CLOCK_REALTIME_ALARM 8 +#endif + +#ifndef CLOCK_BOOTTIME_ALARM +# define CLOCK_BOOTTIME_ALARM 9 +#endif + +#ifndef CLOCK_TAI +#define CLOCK_TAI 11 +#endif + +#endif /* LAPI_POSIX_CLOCKS_H__ */ diff --git a/ltp/include/lapi/posix_types.h b/ltp/include/lapi/posix_types.h new file mode 100644 index 0000000000000000000000000000000000000000..44f6697a9da998d381ac637dce3f67cb76e76d6f --- /dev/null +++ b/ltp/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/ltp/include/lapi/prctl.h b/ltp/include/lapi/prctl.h new file mode 100644 index 0000000000000000000000000000000000000000..8d3ef5c32ef5e2ee7742cc418b4ec40bee8cd661 --- /dev/null +++ b/ltp/include/lapi/prctl.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. + * Author: Xiao Yang + */ + +#ifndef LAPI_PRCTL_H__ +#define LAPI_PRCTL_H__ + +#include + +#ifndef PR_SET_NAME +# define PR_SET_NAME 15 +# define PR_GET_NAME 16 +#endif + +#ifndef PR_SET_SECCOMP +# define PR_GET_SECCOMP 21 +# define PR_SET_SECCOMP 22 +#endif + +#ifndef PR_SET_TSC +# define PR_GET_TSC 25 +# define PR_SET_TSC 26 +# define PR_TSC_ENABLE 1 +# define PR_TSC_SIGSEGV 2 +#endif + +#ifndef PR_SET_TIMERSLACK +# define PR_SET_TIMERSLACK 29 +# define PR_GET_TIMERSLACK 30 +#endif + +#ifndef PR_SET_CHILD_SUBREAPER +# define PR_SET_CHILD_SUBREAPER 36 +# define PR_GET_CHILD_SUBREAPER 37 +#endif + +#ifndef PR_SET_NO_NEW_PRIVS +# define PR_SET_NO_NEW_PRIVS 38 +# define PR_GET_NO_NEW_PRIVS 39 +#endif + +#ifndef PR_SET_THP_DISABLE +# define PR_SET_THP_DISABLE 41 +# define PR_GET_THP_DISABLE 42 +#endif + +#ifndef PR_CAP_AMBIENT +# define PR_CAP_AMBIENT 47 +# define PR_CAP_AMBIENT_IS_SET 1 +# define PR_CAP_AMBIENT_RAISE 2 +# define PR_CAP_AMBIENT_LOWER 3 +# define PR_CAP_AMBIENT_CLEAR_ALL 4 +#endif + +#ifndef PR_GET_SPECULATION_CTRL +# define PR_GET_SPECULATION_CTRL 52 +# define PR_SET_SPECULATION_CTRL 53 +#endif + +#endif /* LAPI_PRCTL_H__ */ diff --git a/ltp/include/lapi/quotactl.h b/ltp/include/lapi/quotactl.h new file mode 100644 index 0000000000000000000000000000000000000000..739a856163d5df31589940af9a02a7abf1d434c2 --- /dev/null +++ b/ltp/include/lapi/quotactl.h @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2021 FUJITSU LIMITED. All rights reserved + * Author: Xiao Yang + * 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 +#else +# include +struct if_nextdqblk { + uint64_t dqb_bhardlimit; + uint64_t dqb_bsoftlimit; + uint64_t dqb_curspace; + uint64_t dqb_ihardlimit; + uint64_t dqb_isoftlimit; + uint64_t dqb_curinodes; + uint64_t dqb_btime; + uint64_t dqb_itime; + uint32_t dqb_valid; + uint32_t dqb_id; +}; +#endif /* HAVE_STRUCT_IF_NEXTDQBLK */ + +#ifndef HAVE_STRUCT_FS_QUOTA_STATV +# include +struct fs_qfilestatv { + uint64_t qfs_ino; + uint64_t qfs_nblks; + uint32_t qfs_nextents; + uint32_t qfs_pad; +}; + +struct fs_quota_statv { + int8_t qs_version; + uint8_t qs_pad1; + uint16_t qs_flags; + uint32_t qs_incoredqs; + struct fs_qfilestatv qs_uquota; + struct fs_qfilestatv qs_gquota; + struct fs_qfilestatv qs_pquota; + int32_t qs_btimelimit; + int32_t qs_itimelimit; + int32_t qs_rtbtimelimit; + uint16_t qs_bwarnlimit; + uint16_t qs_iwarnlimit; + uint64_t qs_pad2[8]; +}; +# define FS_QSTATV_VERSION1 1 +#endif /* HAVE_STRUCT_FS_QUOTA_STATV */ + +#ifndef PRJQUOTA +# define PRJQUOTA 2 +#endif + +#ifndef Q_XQUOTARM +# define Q_XQUOTARM XQM_CMD(6) +#endif + +#ifndef Q_XGETQSTATV +# define Q_XGETQSTATV XQM_CMD(8) +#endif + +#ifndef Q_XGETNEXTQUOTA +# define Q_XGETNEXTQUOTA XQM_CMD(9) +#endif + +#ifndef Q_GETNEXTQUOTA +# 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/ltp/include/lapi/readdir.h b/ltp/include/lapi/readdir.h new file mode 100644 index 0000000000000000000000000000000000000000..ec82604a1e84b786d4c8c75716af0e58220af483 --- /dev/null +++ b/ltp/include/lapi/readdir.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014 Fujitsu Ltd. + * Author: Zeng Linggang + */ + +#ifndef LAPI_READDIR_H__ +#define LAPI_READDIR_H__ + +#include + +struct old_linux_dirent { + long d_ino; /* inode number */ + off_t d_off; /* offset to this old_linux_dirent */ + unsigned short d_reclen; /* length of this d_name */ + char d_name[NAME_MAX+1]; /* filename (null-terminated) */ +}; + +#endif /* LAPI_READDIR_H__ */ diff --git a/ltp/include/lapi/resource.h b/ltp/include/lapi/resource.h new file mode 100644 index 0000000000000000000000000000000000000000..fec03d83b89b5e0a9da1b4487f5a3263f0dea15e --- /dev/null +++ b/ltp/include/lapi/resource.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Red Hat Inc. All Rights Reserved. + * Author: Chunfu Wen + */ + +#ifndef LAPI_RESOURCE_H__ +#define LAPI_RESOURCE_H__ + +#define _LARGEFILE64_SOURCE + +#include +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef HAVE_STRUCT_RLIMIT64 +struct rlimit64 { + uint64_t rlim_cur; + uint64_t rlim_max; +}; +#endif + +static int setrlimit_u64(int resource, struct rlimit64 *rlim) +{ + return tst_syscall(__NR_prlimit64, 0, resource, rlim, NULL); +} + +#endif /* LAPI_RESOURCE_H__ */ diff --git a/ltp/include/lapi/rt_sigaction.h b/ltp/include/lapi/rt_sigaction.h new file mode 100644 index 0000000000000000000000000000000000000000..a42b690d0c1b2cf09fc2004909d3ffc6709d89e8 --- /dev/null +++ b/ltp/include/lapi/rt_sigaction.h @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2009 Cisco Systems, Inc. All Rights Reserved. + * Copyright (c) 2009 FUJITSU LIMITED. All Rights Reserved. + * Author: Liu Bo + * Author: Ngie Cooper + */ + +#ifndef LAPI_RT_SIGACTION_H__ +#define LAPI_RT_SIGACTION_H__ + +#include "ltp_signal.h" + +#define INVAL_SA_PTR ((void *)-1) + +#if defined(__mips__) +struct kernel_sigaction { + unsigned int sa_flags; + void (* k_sa_handler)(int); + sigset_t sa_mask; +}; +#else +struct kernel_sigaction { + void (* k_sa_handler)(int); + unsigned long sa_flags; + void (*sa_restorer) (void); + sigset_t sa_mask; +}; +#endif + +/* This macro marks if (struct sigaction) has .sa_restorer member */ +#if !defined(__ia64__) && !defined(__alpha__) && !defined(__hppa__) && !defined(__mips__) +# define HAVE_SA_RESTORER +#endif + +#ifdef __x86_64__ + +/* + * From asm/signal.h -- this value isn't exported anywhere outside of glibc and + * asm/signal.h and is only required for the rt_sig* function family because + * sigaction(2), et all, appends this if necessary to + * (struct sigaction).sa_flags. HEH. + * + * I do #undef though, just in case... + * + * Also, from .../arch/x86/kernel/signal.c:448 for v2.6.30 (something or + * other): + * + * x86-64 should always use SA_RESTORER. + * + * -- thus SA_RESTORER must always be defined along with + * (struct sigaction).sa_restorer for this architecture. + */ +#undef SA_RESTORER +#define SA_RESTORER 0x04000000 + +void (*restore_rt)(void); + +static void handler_h(int signal) +{ + return; +} + +/* Setup an initial signal handler for signal number = sig for x86_64. */ +static inline int sig_initial(int sig) +{ + int ret_code = -1; + struct sigaction act, oact; + + act.sa_handler = handler_h; + act.sa_flags = 0; + /* Clear out the signal set. */ + if (sigemptyset(&act.sa_mask) < 0) { + /* Add the signal to the mask set. */ + } else if (sigaddset(&act.sa_mask, sig) < 0) { + /* Set act.sa_restorer via syscall(2) */ + } else if (sigaction(sig, &act, &oact) < 0) { + /* Copy oact.sa_restorer via syscall(2) */ + } else if (sigaction(sig, &act, &oact) < 0) { + /* And voila -- we just tricked the kernel into giving us our + * restorer function! */ + } else { + restore_rt = oact.sa_restorer; + ret_code = 0; + } + + return ret_code; +} + +#endif /* __x86_64__ */ + +#ifdef __sparc__ +# if defined __arch64__ || defined __sparcv9 + +/* + * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c + */ + +extern char *__rt_sig_stub; + +static void __attribute__((used)) __rt_sigreturn_stub(void) +{ + __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t" + "ta 0x6d\n\t" + : /* no outputs */ + : "i" (__NR_rt_sigreturn)); +} + +# else /* sparc32 */ + +/* + * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c + */ + +extern char *__rt_sig_stub, *__sig_stub; + +static void __attribute__((used)) __rt_sigreturn_stub(void) +{ + __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t" + "ta 0x10\n\t" + : /* no outputs */ + : "i" (__NR_rt_sigreturn)); +} + +static void __attribute__((used)) __sigreturn_stub(void) +{ + __asm__ ("__sig_stub: mov %0, %%g1\n\t" + "ta 0x10\n\t" + : /* no outputs */ + : "i" (__NR_sigreturn)); +} + +# endif +#endif /* __sparc__ */ + +#ifdef __arc__ + +#undef SA_RESTORER +#define SA_RESTORER 0x04000000 + +/* + * based on uClibc/libc/sysdeps/linux/arc/sigaction.c + */ +static void +__attribute__ ((optimize("Os"))) __attribute__((used)) restore_rt(void) +{ + __asm__ ( + "mov r8, %0 \n\t" +#ifdef __ARCHS__ + "trap_s 0 \n\t" +#else + "trap0 \n\t" +#endif + : /* no outputs */ + : "i" (__NR_rt_sigreturn) + : "r8"); +} +#endif + +/* This is a wrapper for __NR_rt_sigaction syscall. + * act/oact values of INVAL_SA_PTR is used to pass + * an invalid pointer to syscall(__NR_rt_sigaction) + * + * Based on glibc/sysdeps/unix/sysv/linux/{...}/sigaction.c + */ + +static int ltp_rt_sigaction(int signum, const struct sigaction *act, + struct sigaction *oact, size_t sigsetsize) +{ + int ret; + struct kernel_sigaction kact, koact; + struct kernel_sigaction *kact_p = NULL; + struct kernel_sigaction *koact_p = NULL; + + if (act == INVAL_SA_PTR) { + kact_p = INVAL_SA_PTR; + } else if (act) { + kact.k_sa_handler = act->sa_handler; + memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t)); + kact.sa_flags = act->sa_flags; +#ifndef __mips__ + kact.sa_restorer = NULL; +#endif + kact_p = &kact; + } + + if (oact == INVAL_SA_PTR) + koact_p = INVAL_SA_PTR; + else if (oact) + koact_p = &koact; + +#ifdef __x86_64__ + sig_initial(signum); +#endif + +#if defined __x86_64__ || defined __arc__ + kact.sa_flags |= SA_RESTORER; + kact.sa_restorer = restore_rt; +#endif + +#ifdef __sparc__ + unsigned long stub = 0; +# if defined __arch64__ || defined __sparcv9 + stub = ((unsigned long) &__rt_sig_stub) - 8; +# else /* sparc32 */ + if ((kact.sa_flags & SA_SIGINFO) != 0) + stub = ((unsigned long) &__rt_sig_stub) - 8; + else + stub = ((unsigned long) &__sig_stub) - 8; +# endif +#endif + + +#ifdef __sparc__ + ret = tst_syscall(__NR_rt_sigaction, signum, + kact_p, koact_p, + stub, sigsetsize); +#else + ret = tst_syscall(__NR_rt_sigaction, signum, + kact_p, koact_p, + sigsetsize); +#endif + + if (ret >= 0) { + if (oact && (oact != INVAL_SA_PTR)) { + oact->sa_handler = koact.k_sa_handler; + memcpy(&oact->sa_mask, &koact.sa_mask, + sizeof(sigset_t)); + oact->sa_flags = koact.sa_flags; +#ifdef HAVE_SA_RESTORER + oact->sa_restorer = koact.sa_restorer; +#endif + } + } + + return ret; +} + +#endif /* LAPI_RT_SIGACTION_H__ */ diff --git a/ltp/include/lapi/rtnetlink.h b/ltp/include/lapi/rtnetlink.h new file mode 100644 index 0000000000000000000000000000000000000000..089bf1a0d7cf2e1f001cd4659772b34ed6288509 --- /dev/null +++ b/ltp/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/ltp/include/lapi/safe_rt_signal.h b/ltp/include/lapi/safe_rt_signal.h new file mode 100644 index 0000000000000000000000000000000000000000..952085608fc657f1458067a7a9d13081b49d328e --- /dev/null +++ b/ltp/include/lapi/safe_rt_signal.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018 Cyril Hrubis + */ + +#ifndef SAFE_RT_SIGNAL_H__ +#define SAFE_RT_SIGNAL_H__ + +#include +#include "lapi/rt_sigaction.h" + +static inline int safe_rt_sigaction(const char *file, const int lineno, + int signum, const struct sigaction *act, + struct sigaction *oact, size_t sigsetsize) +{ + int ret; + + ret = ltp_rt_sigaction(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; +} + +#define SAFE_RT_SIGACTION(signum, act, oldact, sigsetsize) \ + safe_rt_sigaction(__FILE__, __LINE__, signum, act, oldact, sigsetsize) + + +static inline int safe_rt_sigprocmask(const char *file, const int lineno, + int how, const sigset_t *set, + sigset_t *oldset, size_t sigsetsize) +{ + int ret; + + ret = tst_syscall(__NR_rt_sigprocmask, 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; +} + +#define SAFE_RT_SIGPROCMASK(how, set, oldset, sigsetsize) \ + safe_rt_sigprocmask(__FILE__, __LINE__, how, set, oldset, sigsetsize) + +#endif /* SAFE_RT_SIGNAL_H__ */ diff --git a/ltp/include/lapi/sched.h b/ltp/include/lapi/sched.h new file mode 100644 index 0000000000000000000000000000000000000000..36f1ecad93c2a0679d4a54d6b0021e8343380e96 --- /dev/null +++ b/ltp/include/lapi/sched.h @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Cui Bixuan + * Copyright (c) Linux Test Project, 2016-2022 + */ + +#ifndef LAPI_SCHED_H__ +#define LAPI_SCHED_H__ + +#include +#include +#include +#include +#include "config.h" +#include "lapi/syscalls.h" + +/* sched_attr is not defined in glibc < 2.41 */ +#ifndef SCHED_ATTR_SIZE_VER0 +struct sched_attr { + uint32_t size; + + uint32_t sched_policy; + uint64_t sched_flags; + + /* SCHED_NORMAL, SCHED_BATCH */ + int32_t sched_nice; + + /* SCHED_FIFO, SCHED_RR */ + uint32_t sched_priority; + + /* SCHED_DEADLINE (nsec) */ + uint64_t sched_runtime; + uint64_t sched_deadline; + uint64_t sched_period; +}; + +static inline int sched_setattr(pid_t pid, const struct sched_attr *attr, + unsigned int flags) +{ + return syscall(__NR_sched_setattr, pid, attr, 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); +} + +# define SCHED_ATTR_SIZE_VER0 48 /* sizeof first published struct */ +#endif + +#ifndef HAVE_CLONE3 +struct clone_args { + uint64_t __attribute__((aligned(8))) flags; + uint64_t __attribute__((aligned(8))) pidfd; + uint64_t __attribute__((aligned(8))) child_tid; + uint64_t __attribute__((aligned(8))) parent_tid; + uint64_t __attribute__((aligned(8))) exit_signal; + uint64_t __attribute__((aligned(8))) stack; + uint64_t __attribute__((aligned(8))) stack_size; + uint64_t __attribute__((aligned(8))) tls; + uint64_t __attribute__((aligned(8))) set_tid; + uint64_t __attribute__((aligned(8))) set_tid_size; + uint64_t __attribute__((aligned(8))) cgroup; +}; + +struct clone_args_minimal { + uint64_t __attribute__((aligned(8))) flags; + uint64_t __attribute__((aligned(8))) pidfd; + uint64_t __attribute__((aligned(8))) child_tid; + uint64_t __attribute__((aligned(8))) parent_tid; + uint64_t __attribute__((aligned(8))) exit_signal; + uint64_t __attribute__((aligned(8))) stack; + uint64_t __attribute__((aligned(8))) stack_size; + uint64_t __attribute__((aligned(8))) tls; +}; + +static inline int clone3(struct clone_args *args, size_t size) +{ + return tst_syscall(__NR_clone3, args, size); +} +#endif + +static inline void clone3_supported_by_kernel(void) +{ + if ((tst_kvercmp(5, 3, 0)) < 0) { + /* Check if the syscall is backported on an older kernel */ + tst_syscall(__NR_clone3, NULL, 0); + } +} + +#ifndef HAVE_GETCPU +static inline int getcpu(unsigned *cpu, unsigned *node) +{ + return tst_syscall(__NR_getcpu, cpu, node, NULL); +} +#endif + +#ifndef SCHED_DEADLINE +# define SCHED_DEADLINE 6 +#endif + +#ifndef CLONE_VM +# define CLONE_VM 0x00000100 +#endif + +#ifndef CLONE_FS +# define CLONE_FS 0x00000200 +#endif + +#ifndef CLONE_PIDFD +# define CLONE_PIDFD 0x00001000 +#endif + +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +#endif + +#ifndef CLONE_SYSVSEM +# define CLONE_SYSVSEM 0x00040000 +#endif + +#ifndef CLONE_NEWCGROUP +# define CLONE_NEWCGROUP 0x02000000 +#endif + +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif + +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif + +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif + +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +#endif + +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +#endif + +#ifndef CLONE_IO +# define CLONE_IO 0x80000000 +#endif + +#ifndef CLONE_NEWTIME +# define CLONE_NEWTIME 0x00000080 +#endif + +#ifndef CLONE_INTO_CGROUP +# define CLONE_INTO_CGROUP 0x200000000ULL +#endif + +#endif /* LAPI_SCHED_H__ */ diff --git a/ltp/include/lapi/sctp.h b/ltp/include/lapi/sctp.h new file mode 100644 index 0000000000000000000000000000000000000000..c4c1cc91fa0cac6e14eaea59c9097ceb3937403f --- /dev/null +++ b/ltp/include/lapi/sctp.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Oracle and/or its affiliates. + */ + +#ifndef LAPI_SCTP_H__ +#define LAPI_SCTP_H__ + +#ifdef HAVE_NETINET_SCTP_H +# include +#endif + +#ifndef SCTP_SOCKOPT_BINDX_ADD +# define SCTP_SOCKOPT_BINDX_ADD 100 +#endif + +#endif /* LAPI_SCTP_H__ */ diff --git a/ltp/include/lapi/seccomp.h b/ltp/include/lapi/seccomp.h new file mode 100644 index 0000000000000000000000000000000000000000..29819ba6fde4ca8a9b0b1864b2e962b46f26762f --- /dev/null +++ b/ltp/include/lapi/seccomp.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ +#ifndef LAPI_SECCOMP_H__ +#define LAPI_SECCOMP_H__ + +#include + +#ifdef HAVE_LINUX_SECCOMP_H +# include +#else +/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, ) */ +# define SECCOMP_MODE_DISABLED 0 +# define SECCOMP_MODE_STRICT 1 +# define SECCOMP_MODE_FILTER 2 + +# define SECCOMP_RET_KILL_THREAD 0x00000000U /* kill the thread */ +# define SECCOMP_RET_KILL SECCOMP_RET_KILL_THREAD +# define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ + +/** + * struct seccomp_data - the format the BPF program executes over. + * @nr: the system call number + * @arch: indicates system call convention as an AUDIT_ARCH_* value + * as defined in . + * @instruction_pointer: at the time of the system call. + * @args: up to 6 system call arguments always stored as 64-bit values + * regardless of the architecture. + */ +struct seccomp_data { + int nr; + uint32_t arch; + uint64_t instruction_pointer; + uint64_t args[6]; +}; + +#endif /* HAVE_LINUX_SECCOMP_H*/ +#endif /* LAPI_SECCOMP_H__ */ diff --git a/ltp/include/lapi/securebits.h b/ltp/include/lapi/securebits.h new file mode 100644 index 0000000000000000000000000000000000000000..1b4d003c2a4ada4c0e326b90ce2968a1a8c76b9e --- /dev/null +++ b/ltp/include/lapi/securebits.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ +#ifndef LAPI_SECUREBITS_H__ +#define LAPI_SECUREBITS_H__ + +# ifdef HAVE_LINUX_SECUREBITS_H +# include +# endif + +# ifndef SECBIT_NO_CAP_AMBIENT_RAISE +# define SECBIT_NO_CAP_AMBIENT_RAISE 6 +# endif + +#endif /* LAPI_SECUREBITS_H__ */ diff --git a/ltp/include/lapi/seek.h b/ltp/include/lapi/seek.h new file mode 100644 index 0000000000000000000000000000000000000000..7062ee8d47c3a9a695bac46a58686831fbe0b5b9 --- /dev/null +++ b/ltp/include/lapi/seek.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + */ + +#ifndef LAPI_SEEK_H__ +#define LAPI_SEEK_H__ + +#include + +#ifndef SEEK_DATA +# define SEEK_DATA 3 +#endif + +#ifndef SEEK_HOLE +# define SEEK_HOLE 4 +#endif + +#endif /* LAPI_SEEK_H__ */ diff --git a/ltp/include/lapi/sem.h b/ltp/include/lapi/sem.h new file mode 100644 index 0000000000000000000000000000000000000000..ba559d2f16588c6c210bee44285bba27958c3121 --- /dev/null +++ b/ltp/include/lapi/sem.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Linux Test Project + */ +#ifndef LAPI_SEM_H__ +#define LAPI_SEM_H__ + +#include + +#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) +/* union semun is defined by including */ +#else +/* according to X/OPEN we have to define it ourselves */ +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ + unsigned short *array; /* array for GETALL, SETALL */ + /* Linux specific part: */ + struct seminfo *__buf; /* buffer for IPC_INFO */ +}; +#endif + +#ifndef SEM_STAT_ANY +# define SEM_STAT_ANY 20 +#endif + +#ifndef SEMMSL +# define SEMMSL 32000 +#endif + +#endif /* LAPI_SEM_H__ */ diff --git a/ltp/include/lapi/sembuf.h b/ltp/include/lapi/sembuf.h new file mode 100644 index 0000000000000000000000000000000000000000..94a43a291e4ffdd1965cf8392ff8a670b104576d --- /dev/null +++ b/ltp/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/ltp/include/lapi/setns.h b/ltp/include/lapi/setns.h new file mode 100644 index 0000000000000000000000000000000000000000..2d0be88467a6f5e76a59ab0191e30d2e41b0080f --- /dev/null +++ b/ltp/include/lapi/setns.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + Copyright (c) 2020 Cyril Hrubis + */ + +#ifndef LAPI_SETNS_H__ +#define LAPI_SETNS_H__ + +#include "config.h" +#include "lapi/syscalls.h" +#include + +#ifndef HAVE_SETNS +static inline int setns(int fd, int nstype) +{ + return tst_syscall(__NR_setns, fd, nstype); +} +#endif + +#endif /* LAPI_SETNS_H__ */ diff --git a/ltp/include/lapi/shm.h b/ltp/include/lapi/shm.h new file mode 100644 index 0000000000000000000000000000000000000000..bb280fc44ef9005a107f15a39790be05275e339f --- /dev/null +++ b/ltp/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/ltp/include/lapi/shmbuf.h b/ltp/include/lapi/shmbuf.h new file mode 100644 index 0000000000000000000000000000000000000000..b0a0fa3d96553f864c93ea533f1d7e58e73dfb58 --- /dev/null +++ b/ltp/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/ltp/include/lapi/signal.h b/ltp/include/lapi/signal.h new file mode 100644 index 0000000000000000000000000000000000000000..6f4a7688139682b13f2bdb242635aa9bf16b8d7f --- /dev/null +++ b/ltp/include/lapi/signal.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Linaro Limited. All rights reserved. + * Author: Daniel Díaz + */ + +#ifndef LAPI_SIGNAL_H__ +#define LAPI_SIGNAL_H__ + +#include + +/* + * Some libc implementations might differ in the definitions they include. This + * covers those differences for all tests to successfully build. + */ + +#ifndef __SIGRTMIN +# define __SIGRTMIN 32 +#endif +#ifndef __SIGRTMAX +# define __SIGRTMAX (_NSIG - 1) +#endif + +#endif /* LAPI_SIGNAL_H__ */ diff --git a/ltp/include/lapi/socket.h b/ltp/include/lapi/socket.h new file mode 100644 index 0000000000000000000000000000000000000000..23e7ba6cfd2d0c2aa79b0f5b99ef1b3fc60a0950 --- /dev/null +++ b/ltp/include/lapi/socket.h @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +* Copyright (c) 2016 Fujitsu Ltd. +* Author: Xiao Yang +*/ + +#ifndef LAPI_SOCKET_H__ +#define LAPI_SOCKET_H__ + +#include "config.h" +#include + +#ifndef MSG_ZEROCOPY +# define MSG_ZEROCOPY 0x4000000 /* Use user data in kernel path */ +#endif + +#ifndef MSG_FASTOPEN +# define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */ +#endif + +#ifndef SO_REUSEPORT +# define SO_REUSEPORT 15 +#endif + +#ifndef SO_BUSY_POLL +# define SO_BUSY_POLL 46 +#endif + +#ifndef SO_ATTACH_BPF +# define SO_ATTACH_BPF 50 +#endif + +#ifndef SO_ZEROCOPY +# define SO_ZEROCOPY 60 +#endif + +#ifndef SOCK_DCCP +# define SOCK_DCCP 6 +#endif + +#ifndef SOCK_CLOEXEC +# define SOCK_CLOEXEC 02000000 +#endif + +#ifndef AF_ALG +# define AF_ALG 38 +#endif + +#ifndef SOL_SCTP +# define SOL_SCTP 132 +#endif + +#ifndef SOL_UDPLITE +# define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */ +#endif + +#ifndef SOL_DCCP +# define SOL_DCCP 269 +#endif + +#ifndef SOL_ALG +# define SOL_ALG 279 +#endif + +#ifndef SOL_TLS +# define SOL_TLS 282 +#endif + +#ifndef HAVE_STRUCT_MMSGHDR +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; +#endif + +#endif /* LAPI_SOCKET_H__ */ diff --git a/ltp/include/lapi/splice.h b/ltp/include/lapi/splice.h new file mode 100644 index 0000000000000000000000000000000000000000..191b22d2d6397d1efad5e2025be5a2c4370724dc --- /dev/null +++ b/ltp/include/lapi/splice.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2007 + * Copyright (c) 2014 Fujitsu Ltd. + */ + +#ifndef LAPI_SPLICE_H__ +#define LAPI_SPLICE_H__ + +#include "config.h" +#include "lapi/syscalls.h" + +#if !defined(HAVE_SPLICE) +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 /* LAPI_SPLICE_H__ */ diff --git a/ltp/include/lapi/stat.h b/ltp/include/lapi/stat.h new file mode 100644 index 0000000000000000000000000000000000000000..17b62ea98d6776fafc8713e710093f3c8cf41fc4 --- /dev/null +++ b/ltp/include/lapi/stat.h @@ -0,0 +1,297 @@ +//SPDX-License-Identifier: GPL-2.0-or-later +/* + * Referred from linux kernel -github/torvalds/linux/include/uapi/linux/fcntl.h + * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 + * Email: code@zilogic.com + */ + +#ifndef LAPI_STAT_H__ +#define LAPI_STAT_H__ + +#include +#include +#include +#include "lapi/syscalls.h" + +/* + * Timestamp structure for the timestamps in struct statx. + * + * tv_sec holds the number of seconds before (negative) or after (positive) + * 00:00:00 1st January 1970 UTC. + * + * tv_nsec holds a number of nanoseconds (0..999,999,999) after the tv_sec time. + * + * __reserved is held in case we need a yet finer resolution. + */ +#ifndef HAVE_STRUCT_STATX_TIMESTAMP +struct statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t __reserved; +}; +#endif + +/* + * Structures for the extended file attribute retrieval system call + * (statx()). + * + * The caller passes a mask of what they're specifically interested in as a + * parameter to statx(). What statx() actually got will be indicated in + * st_mask upon return. + * + * For each bit in the mask argument: + * + * - if the datum is not supported: + * + * - the bit will be cleared, and + * + * - the datum will be set to an appropriate fabricated value if one is + * available (eg. CIFS can take a default uid and gid), otherwise + * + * - the field will be cleared; + * + * - otherwise, if explicitly requested: + * + * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is + * set or if the datum is considered out of date, and + * + * - the field will be filled in and the bit will be set; + * + * - otherwise, if not requested, but available in approximate form without any + * effort, it will be filled in anyway, and the bit will be set upon return + * (it might not be up to date, however, and no attempt will be made to + * synchronise the internal state first); + * + * - otherwise the field and the bit will be cleared before returning. + * + * Items in STATX_BASIC_STATS may be marked unavailable on return, but they + * will have values installed for compatibility purposes so that stat() and + * co. can be emulated in userspace. + */ + #define LTP_DEFINE_STATX_STRUCT(x) \ + struct x { \ + uint32_t stx_mask; \ + uint32_t stx_blksize; \ + uint64_t stx_attributes; \ + uint32_t stx_nlink; \ + uint32_t stx_uid; \ + uint32_t stx_gid; \ + uint16_t stx_mode; \ + uint16_t __spare0[1]; \ + uint64_t stx_ino; \ + uint64_t stx_size; \ + uint64_t stx_blocks; \ + uint64_t stx_attributes_mask; \ + const struct statx_timestamp stx_atime; \ + const struct statx_timestamp stx_btime; \ + const struct statx_timestamp stx_ctime; \ + const struct statx_timestamp stx_mtime; \ + uint32_t stx_rdev_major; \ + uint32_t stx_rdev_minor; \ + uint32_t stx_dev_major; \ + uint32_t stx_dev_minor; \ + uint64_t stx_mnt_id; \ + uint32_t stx_dio_mem_align; \ + uint32_t stx_dio_offset_align; \ + uint64_t __spare3[12]; \ +}; + +LTP_DEFINE_STATX_STRUCT(statx_fallback); + +#ifndef HAVE_STRUCT_STATX +LTP_DEFINE_STATX_STRUCT(statx); +#endif + +/* + * This is the fallback statx that we pass to the safe_statx() syscall. + * The reason why we need it, is that statx struct is constantly changing + * inside the kernel and we need to extend its definition when structure + * changes in order to compile the tests. + */ +struct ltp_statx { + union { + struct statx buff; + struct statx_fallback data; + }; +}; + +#ifndef HAVE_STATX + +/* + * statx: wrapper function of statx + * + * Returns: It returns status of statx syscall + */ +static inline int statx(int dirfd, const char *pathname, unsigned int flags, + unsigned int mask, struct statx *st) +{ + return tst_syscall(__NR_statx, dirfd, pathname, flags, mask, st); +} +#endif + +/* + * Flags to be stx_mask + * + * Query request/result mask for statx() and struct statx::stx_mask. + * + * These bits should be set in the mask argument of statx() to request + * particular items when calling statx(). + */ +#ifndef STATX_TYPE +# define STATX_TYPE 0x00000001U +#endif + +#ifndef STATX_MODE +# define STATX_MODE 0x00000002U +#endif + +#ifndef STATX_NLINK +# define STATX_NLINK 0x00000004U +#endif + +#ifndef STATX_UID +# define STATX_UID 0x00000008U +#endif + +#ifndef STATX_GID +# define STATX_GID 0x00000010U +#endif + +#ifndef STATX_ATIME +# define STATX_ATIME 0x00000020U +#endif + +#ifndef STATX_MTIME +# define STATX_MTIME 0x00000040U +#endif + +#ifndef STATX_CTIME +# define STATX_CTIME 0x00000080U +#endif + +#ifndef STATX_INO +# define STATX_INO 0x00000100U +#endif + +#ifndef STATX_SIZE +# define STATX_SIZE 0x00000200U +#endif + +#ifndef STATX_BLOCKS +# define STATX_BLOCKS 0x00000400U +#endif + +#ifndef STATX_BASIC_STATS +# define STATX_BASIC_STATS 0x000007ffU +#endif + +#ifndef STATX_BTIME +# define STATX_BTIME 0x00000800U +#endif + +#ifndef STATX_MNT_ID +# define STATX_MNT_ID 0x00001000U +#endif + +#ifndef STATX_DIOALIGN +# define STATX_DIOALIGN 0x00002000U +#endif + +#ifndef STATX__RESERVED +# define STATX__RESERVED 0x80000000U +#endif + +/* + * Attributes to be found in stx_attributes and masked in stx_attributes_mask. + * + * These give information about the features or the state of a file that might + * be of use to ordinary userspace programs such as GUIs or ls rather than + * specialised tools. + * + * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS + * semantically. Where possible, the numerical value is picked to correspond + * also. + */ +#ifndef STATX_ATTR_COMPRESSED +# define STATX_ATTR_COMPRESSED 0x00000004 +#endif + +#ifndef STATX_ATTR_IMMUTABLE +# define STATX_ATTR_IMMUTABLE 0x00000010 +#endif + +#ifndef STATX_ATTR_APPEND +# define STATX_ATTR_APPEND 0x00000020 +#endif + +#ifndef STATX_ATTR_NODUMP +# define STATX_ATTR_NODUMP 0x00000040 +#endif + +#ifndef STATX_ATTR_ENCRYPTED +# define STATX_ATTR_ENCRYPTED 0x00000800 +#endif + +#ifndef STATX_ATTR_AUTOMOUNT +# define STATX_ATTR_AUTOMOUNT 0x00001000 +#endif + +#ifndef STATX_ATTR_MOUNT_ROOT +# define STATX_ATTR_MOUNT_ROOT 0x00002000 +#endif + +#ifndef STATX_ATTR_VERITY +# define STATX_ATTR_VERITY 0x00100000 +#endif + +#ifndef STATX_MNT_ID_UNIQUE +# define STATX_MNT_ID_UNIQUE 0x00004000U +#endif + +#define SAFE_FCHMODAT2(dfd, filename, mode, flags) \ + safe_fchmodat2(__FILE__, __LINE__, (dfd), (filename), (mode), (flags)) + +static inline int safe_fchmodat2(const char *file, const int lineno, + int dfd, const char *filename, mode_t mode, int flags) +{ + int ret; + + ret = tst_syscall(__NR_fchmodat2, dfd, filename, mode, flags); + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "syscall(__NR_fchmodat2,%d,%s,%d,%d) failed", + dfd, filename, mode, flags); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid syscall(__NR_fchmodat2,%d,%s,%d,%d) return value %d", + dfd, filename, mode, flags, ret); + } + + return ret; +} + +#define SAFE_STATX(dirfd, pathname, flags, mask, buf) \ + safe_statx(__FILE__, __LINE__, (dirfd), (pathname), (flags), (mask), (buf)) + +static inline int safe_statx(const char *file, const int lineno, + int dirfd, const char *pathname, int flags, unsigned int mask, + struct ltp_statx *buf) +{ + int rval; + + rval = statx(dirfd, pathname, flags, mask, &buf->buff); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "statx(%d,%s,%d,%u,%p) failed", dirfd, pathname, flags, mask, buf); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid statx(%d,%s,%d,%u,%p) return value %d", + dirfd, pathname, flags, mask, buf, + rval); + } + + return rval; +} + +#endif /* LAPI_STAT_H__ */ diff --git a/ltp/include/lapi/sync_file_range.h b/ltp/include/lapi/sync_file_range.h new file mode 100644 index 0000000000000000000000000000000000000000..b1d2b28276c0268527553917dd52b60eaa0316e2 --- /dev/null +++ b/ltp/include/lapi/sync_file_range.h @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2008 + */ + +#ifndef LAPI_SYNC_FILE_RANGE_H__ +#define LAPI_SYNC_FILE_RANGE_H__ + +#include +#include "config.h" +#include "lapi/syscalls.h" +#include "lapi/abisize.h" + +#if !defined(HAVE_SYNC_FILE_RANGE) + +/***************************************************************************** + * Wraper function to call sync_file_range system call + ******************************************************************************/ +static inline long sync_file_range(int fd, off64_t offset, off64_t nbytes, + unsigned int flags) +{ +#if (defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)) +# ifdef TST_ABI32 +# if __BYTE_ORDER == __BIG_ENDIAN + return tst_syscall(__NR_sync_file_range2, fd, flags, + (int)(offset >> 32), (int)offset, (int)(nbytes >> 32), + (int)nbytes); +# elif __BYTE_ORDER == __LITTLE_ENDIAN + return tst_syscall(__NR_sync_file_range2, fd, flags, (int)offset, + (int)(offset >> 32), nbytes, (int)(nbytes >> 32)); +# endif +# else + return tst_syscall(__NR_sync_file_range2, fd, flags, offset, nbytes); +# endif +#elif (defined(__s390__) || defined(__s390x__)) && defined(TST_ABI32) + return tst_syscall(__NR_sync_file_range, fd, (int)(offset >> 32), + (int)offset, (int)(nbytes >> 32), (int)nbytes, flags); +#elif defined(__mips__) && defined(TST_ABI32) +# if __BYTE_ORDER == __BIG_ENDIAN + return tst_syscall(__NR_sync_file_range, fd, 0, (int)(offset >> 32), + (int)offset, (int)(nbytes >> 32), (int)nbytes, flags); +# elif __BYTE_ORDER == __LITTLE_ENDIAN + return tst_syscall(__NR_sync_file_range, fd, 0, (int)offset, + (int)(offset >> 32), (int)nbytes, (int)(nbytes >> 32), flags); +# endif +#else + return tst_syscall(__NR_sync_file_range, fd, offset, nbytes, flags); +#endif +} +#endif + +#endif /* LAPI_SYNC_FILE_RANGE_H__ */ diff --git a/ltp/include/lapi/syncfs.h b/ltp/include/lapi/syncfs.h new file mode 100644 index 0000000000000000000000000000000000000000..5624832c1453048e25e8760265c4d149e9f6890f --- /dev/null +++ b/ltp/include/lapi/syncfs.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Linaro Limited. All rights reserved. + * Author: Sumit Garg + */ + +#ifndef LAPI_SYNCFS_H__ +#define LAPI_SYNCFS_H__ + +#include "config.h" +#include +#include "lapi/syscalls.h" + +#if !defined(HAVE_SYNCFS) +static inline int syncfs(int fd) +{ + return tst_syscall(__NR_syncfs, fd); +} +#endif + +#endif /* LAPI_SYNCFS_H__ */ diff --git a/ltp/include/lapi/syscalls/arc.in b/ltp/include/lapi/syscalls/arc.in new file mode 100644 index 0000000000000000000000000000000000000000..f680d4119c10f73e2f1b8938c3be4a7254965ed0 --- /dev/null +++ b/ltp/include/lapi/syscalls/arc.in @@ -0,0 +1,342 @@ +io_setup 0 +io_destroy 1 +io_submit 2 +io_cancel 3 +io_getevents 4 +setxattr 5 +lsetxattr 6 +fsetxattr 7 +getxattr 8 +lgetxattr 9 +fgetxattr 10 +listxattr 11 +llistxattr 12 +flistxattr 13 +removexattr 14 +lremovexattr 15 +fremovexattr 16 +getcwd 17 +lookup_dcookie 18 +eventfd2 19 +epoll_create1 20 +epoll_ctl 21 +epoll_pwait 22 +dup 23 +dup3 24 +fcntl64 25 +inotify_init1 26 +inotify_add_watch 27 +inotify_rm_watch 28 +ioctl 29 +ioprio_set 30 +ioprio_get 31 +flock 32 +mknodat 33 +mkdirat 34 +unlinkat 35 +symlinkat 36 +linkat 37 +renameat 38 +umount2 39 +mount 40 +pivot_root 41 +nfsservctl 42 +statfs64 43 +fstatfs64 44 +truncate64 45 +ftruncate64 46 +fallocate 47 +faccessat 48 +chdir 49 +fchdir 50 +chroot 51 +fchmod 52 +fchmodat 53 +fchownat 54 +fchown 55 +openat 56 +close 57 +vhangup 58 +pipe2 59 +quotactl 60 +getdents64 61 +llseek 62 +read 63 +write 64 +readv 65 +writev 66 +pread64 67 +pwrite64 68 +preadv 69 +pwritev 70 +sendfile64 71 +pselect6 72 +ppoll 73 +signalfd4 74 +vmsplice 75 +splice 76 +tee 77 +readlinkat 78 +fstatat64 79 +fstat64 80 +sync 81 +fsync 82 +fdatasync 83 +sync_file_range 84 +timerfd_create 85 +timerfd_settime 86 +timerfd_gettime 87 +utimensat 88 +acct 89 +capget 90 +capset 91 +personality 92 +exit 93 +exit_group 94 +waitid 95 +set_tid_address 96 +unshare 97 +futex 98 +set_robust_list 99 +get_robust_list 100 +nanosleep 101 +getitimer 102 +setitimer 103 +kexec_load 104 +init_module 105 +delete_module 106 +timer_create 107 +timer_gettime 108 +timer_getoverrun 109 +timer_settime 110 +timer_delete 111 +clock_settime 112 +clock_gettime 113 +clock_getres 114 +clock_nanosleep 115 +syslog 116 +ptrace 117 +sched_setparam 118 +sched_setscheduler 119 +sched_getscheduler 120 +sched_getparam 121 +sched_setaffinity 122 +sched_getaffinity 123 +sched_yield 124 +sched_get_priority_max 125 +sched_get_priority_min 126 +sched_rr_get_interval 127 +restart_syscall 128 +kill 129 +tkill 130 +tgkill 131 +sigaltstack 132 +rt_sigsuspend 133 +rt_sigaction 134 +rt_sigprocmask 135 +rt_sigpending 136 +rt_sigtimedwait 137 +rt_sigqueueinfo 138 +rt_sigreturn 139 +setpriority 140 +getpriority 141 +reboot 142 +setregid 143 +setgid 144 +setreuid 145 +setuid 146 +setresuid 147 +getresuid 148 +setresgid 149 +getresgid 150 +setfsuid 151 +setfsgid 152 +times 153 +setpgid 154 +getpgid 155 +getsid 156 +setsid 157 +getgroups 158 +setgroups 159 +uname 160 +sethostname 161 +setdomainname 162 +getrlimit 163 +setrlimit 164 +getrusage 165 +umask 166 +prctl 167 +getcpu 168 +gettimeofday 169 +settimeofday 170 +adjtimex 171 +getpid 172 +getppid 173 +getuid 174 +geteuid 175 +getgid 176 +getegid 177 +gettid 178 +sysinfo 179 +mq_open 180 +mq_unlink 181 +mq_timedsend 182 +mq_timedreceive 183 +mq_notify 184 +mq_getsetattr 185 +msgget 186 +msgctl 187 +msgrcv 188 +msgsnd 189 +semget 190 +semctl 191 +semtimedop 192 +semop 193 +shmget 194 +shmctl 195 +shmat 196 +shmdt 197 +socket 198 +socketpair 199 +bind 200 +listen 201 +accept 202 +connect 203 +getsockname 204 +getpeername 205 +sendto 206 +recvfrom 207 +setsockopt 208 +getsockopt 209 +shutdown 210 +sendmsg 211 +recvmsg 212 +readahead 213 +brk 214 +munmap 215 +mremap 216 +add_key 217 +request_key 218 +keyctl 219 +clone 220 +execve 221 +mmap2 222 +fadvise64_64 223 +swapon 224 +swapoff 225 +mprotect 226 +msync 227 +mlock 228 +munlock 229 +mlockall 230 +munlockall 231 +mincore 232 +madvise 233 +remap_file_pages 234 +mbind 235 +get_mempolicy 236 +set_mempolicy 237 +migrate_pages 238 +move_pages 239 +rt_tgsigqueueinfo 240 +perf_event_open 241 +accept4 242 +recvmmsg 243 +cacheflush 244 +arc_settls 245 +arc_gettls 246 +sysfs 247 +arc_usr_cmpxchg 248 +wait4 260 +prlimit64 261 +fanotify_init 262 +fanotify_mark 263 +name_to_handle_at 264 +open_by_handle_at 265 +clock_adjtime 266 +syncfs 267 +setns 268 +sendmmsg 269 +process_vm_readv 270 +process_vm_writev 271 +kcmp 272 +finit_module 273 +sched_setattr 274 +sched_getattr 275 +renameat2 276 +seccomp 277 +getrandom 278 +memfd_create 279 +bpf 280 +execveat 281 +userfaultfd 282 +membarrier 283 +mlock2 284 +copy_file_range 285 +preadv2 286 +pwritev2 287 +pkey_mprotect 288 +pkey_alloc 289 +pkey_free 290 +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 +io_uring_register 427 +open_tree 428 +move_mount 429 +fsopen 430 +fsconfig 431 +fsmount 432 +fspick 433 +pidfd_open 434 +clone3 435 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/arm.in b/ltp/include/lapi/syscalls/arm.in new file mode 100644 index 0000000000000000000000000000000000000000..32e48b2151afbf55a19e493518395e4265c670a0 --- /dev/null +++ b/ltp/include/lapi/syscalls/arm.in @@ -0,0 +1,415 @@ +restart_syscall 0 +exit 1 +fork 2 +read 3 +write 4 +open 5 +close 6 +creat 8 +link 9 +unlink 10 +execve 11 +chdir 12 +mknod 14 +chmod 15 +lchown 16 +lseek 19 +getpid 20 +mount 21 +setuid 23 +getuid 24 +ptrace 26 +pause 29 +access 33 +nice 34 +sync 36 +kill 37 +rename 38 +mkdir 39 +rmdir 40 +dup 41 +pipe 42 +times 43 +brk 45 +setgid 46 +getgid 47 +geteuid 49 +getegid 50 +acct 51 +umount2 52 +ioctl 54 +fcntl 55 +setpgid 57 +umask 60 +chroot 61 +ustat 62 +dup2 63 +getppid 64 +getpgrp 65 +setsid 66 +sigaction 67 +setreuid 70 +setregid 71 +sigsuspend 72 +sigpending 73 +sethostname 74 +setrlimit 75 +getrusage 77 +gettimeofday 78 +settimeofday 79 +getgroups 80 +setgroups 81 +symlink 83 +readlink 85 +uselib 86 +swapon 87 +reboot 88 +munmap 91 +truncate 92 +ftruncate 93 +fchmod 94 +fchown 95 +getpriority 96 +setpriority 97 +statfs 99 +fstatfs 100 +syslog 103 +setitimer 104 +getitimer 105 +stat 106 +lstat 107 +fstat 108 +vhangup 111 +wait4 114 +swapoff 115 +sysinfo 116 +fsync 118 +sigreturn 119 +clone 120 +setdomainname 121 +uname 122 +adjtimex 124 +mprotect 125 +sigprocmask 126 +init_module 128 +delete_module 129 +quotactl 131 +getpgid 132 +fchdir 133 +sysfs 135 +personality 136 +setfsuid 138 +setfsgid 139 +_llseek 140 +getdents 141 +_newselect 142 +flock 143 +msync 144 +readv 145 +writev 146 +getsid 147 +fdatasync 148 +_sysctl 149 +mlock 150 +munlock 151 +mlockall 152 +munlockall 153 +sched_setparam 154 +sched_getparam 155 +sched_setscheduler 156 +sched_getscheduler 157 +sched_yield 158 +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_rr_get_interval 161 +nanosleep 162 +mremap 163 +setresuid 164 +getresuid 165 +poll 168 +nfsservctl 169 +setresgid 170 +getresgid 171 +prctl 172 +rt_sigreturn 173 +rt_sigaction 174 +rt_sigprocmask 175 +rt_sigpending 176 +rt_sigtimedwait 177 +rt_sigqueueinfo 178 +rt_sigsuspend 179 +pread64 180 +pwrite64 181 +chown 182 +getcwd 183 +capget 184 +capset 185 +sigaltstack 186 +sendfile 187 +vfork 190 +ugetrlimit 191 +mmap2 192 +truncate64 193 +ftruncate64 194 +stat64 195 +lstat64 196 +fstat64 197 +lchown32 198 +getuid32 199 +getgid32 200 +geteuid32 201 +getegid32 202 +setreuid32 203 +setregid32 204 +getgroups32 205 +setgroups32 206 +fchown32 207 +setresuid32 208 +getresuid32 209 +setresgid32 210 +getresgid32 211 +chown32 212 +setuid32 213 +setgid32 214 +setfsuid32 215 +setfsgid32 216 +getdents64 217 +pivot_root 218 +mincore 219 +madvise 220 +fcntl64 221 +gettid 224 +readahead 225 +setxattr 226 +lsetxattr 227 +fsetxattr 228 +getxattr 229 +lgetxattr 230 +fgetxattr 231 +listxattr 232 +llistxattr 233 +flistxattr 234 +removexattr 235 +lremovexattr 236 +fremovexattr 237 +tkill 238 +sendfile64 239 +futex 240 +sched_setaffinity 241 +sched_getaffinity 242 +io_setup 243 +io_destroy 244 +io_getevents 245 +io_submit 246 +io_cancel 247 +exit_group 248 +lookup_dcookie 249 +epoll_create 250 +epoll_ctl 251 +epoll_wait 252 +remap_file_pages 253 +set_tid_address 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 +statfs64 266 +fstatfs64 267 +tgkill 268 +utimes 269 +arm_fadvise64_64 270 +pciconfig_iobase 271 +pciconfig_read 272 +pciconfig_write 273 +mq_open 274 +mq_unlink 275 +mq_timedsend 276 +mq_timedreceive 277 +mq_notify 278 +mq_getsetattr 279 +waitid 280 +socket 281 +bind 282 +connect 283 +listen 284 +accept 285 +getsockname 286 +getpeername 287 +socketpair 288 +send 289 +sendto 290 +recv 291 +recvfrom 292 +shutdown 293 +setsockopt 294 +getsockopt 295 +sendmsg 296 +recvmsg 297 +semop 298 +semget 299 +semctl 300 +msgsnd 301 +msgrcv 302 +msgget 303 +msgctl 304 +shmat 305 +shmdt 306 +shmget 307 +shmctl 308 +add_key 309 +request_key 310 +keyctl 311 +semtimedop 312 +vserver 313 +ioprio_set 314 +ioprio_get 315 +inotify_init 316 +inotify_add_watch 317 +inotify_rm_watch 318 +mbind 319 +get_mempolicy 320 +set_mempolicy 321 +openat 322 +mkdirat 323 +mknodat 324 +fchownat 325 +futimesat 326 +fstatat64 327 +unlinkat 328 +renameat 329 +linkat 330 +symlinkat 331 +readlinkat 332 +fchmodat 333 +faccessat 334 +pselect6 335 +ppoll 336 +unshare 337 +set_robust_list 338 +get_robust_list 339 +splice 340 +arm_sync_file_range 341 +sync_file_range2 341 +tee 342 +vmsplice 343 +move_pages 344 +getcpu 345 +epoll_pwait 346 +kexec_load 347 +utimensat 348 +signalfd 349 +timerfd_create 350 +eventfd 351 +fallocate 352 +timerfd_settime 353 +timerfd_gettime 354 +signalfd4 355 +eventfd2 356 +epoll_create1 357 +dup3 358 +pipe2 359 +inotify_init1 360 +preadv 361 +pwritev 362 +rt_tgsigqueueinfo 363 +perf_event_open 364 +recvmmsg 365 +accept4 366 +fanotify_init 367 +fanotify_mark 368 +prlimit64 369 +name_to_handle_at 370 +open_by_handle_at 371 +clock_adjtime 372 +syncfs 373 +sendmmsg 374 +setns 375 +process_vm_readv 376 +process_vm_writev 377 +kcmp 378 +finit_module 379 +sched_setattr 380 +sched_getattr 381 +renameat2 382 +seccomp 383 +getrandom 384 +memfd_create 385 +bpf 386 +execveat 387 +userfaultfd 388 +membarrier 389 +mlock2 390 +copy_file_range 391 +preadv2 392 +pwritev2 393 +pkey_mprotect 394 +pkey_alloc 395 +pkey_free 396 +statx 397 +rseq 398 +io_pgetevents 399 +migrate_pages 400 +kexec_file_load 401 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/arm64.in b/ltp/include/lapi/syscalls/arm64.in new file mode 100644 index 0000000000000000000000000000000000000000..be7e9df6480c065ff63345d55082b1a6b2532760 --- /dev/null +++ b/ltp/include/lapi/syscalls/arm64.in @@ -0,0 +1,318 @@ +io_setup 0 +io_destroy 1 +io_submit 2 +io_cancel 3 +io_getevents 4 +setxattr 5 +lsetxattr 6 +fsetxattr 7 +getxattr 8 +lgetxattr 9 +fgetxattr 10 +listxattr 11 +llistxattr 12 +flistxattr 13 +removexattr 14 +lremovexattr 15 +fremovexattr 16 +getcwd 17 +lookup_dcookie 18 +eventfd2 19 +epoll_create1 20 +epoll_ctl 21 +epoll_pwait 22 +dup 23 +dup3 24 +fcntl 25 +inotify_init1 26 +inotify_add_watch 27 +inotify_rm_watch 28 +ioctl 29 +ioprio_set 30 +ioprio_get 31 +flock 32 +mknodat 33 +mkdirat 34 +unlinkat 35 +symlinkat 36 +linkat 37 +renameat 38 +umount2 39 +mount 40 +pivot_root 41 +nfsservctl 42 +statfs 43 +fstatfs 44 +truncate 45 +ftruncate 46 +fallocate 47 +faccessat 48 +chdir 49 +fchdir 50 +chroot 51 +fchmod 52 +fchmodat 53 +fchownat 54 +fchown 55 +openat 56 +close 57 +vhangup 58 +pipe2 59 +quotactl 60 +getdents64 61 +lseek 62 +read 63 +write 64 +readv 65 +writev 66 +pread64 67 +pwrite64 68 +preadv 69 +pwritev 70 +sendfile 71 +pselect6 72 +ppoll 73 +signalfd4 74 +vmsplice 75 +splice 76 +tee 77 +readlinkat 78 +newfstatat 79 +fstat 80 +sync 81 +fsync 82 +fdatasync 83 +sync_file_range 84 +timerfd_create 85 +timerfd_settime 86 +timerfd_gettime 87 +utimensat 88 +acct 89 +capget 90 +capset 91 +personality 92 +exit 93 +exit_group 94 +waitid 95 +set_tid_address 96 +unshare 97 +futex 98 +set_robust_list 99 +get_robust_list 100 +nanosleep 101 +getitimer 102 +setitimer 103 +kexec_load 104 +init_module 105 +delete_module 106 +timer_create 107 +timer_gettime 108 +timer_getoverrun 109 +timer_settime 110 +timer_delete 111 +clock_settime 112 +clock_gettime 113 +clock_getres 114 +clock_nanosleep 115 +syslog 116 +ptrace 117 +sched_setparam 118 +sched_setscheduler 119 +sched_getscheduler 120 +sched_getparam 121 +sched_setaffinity 122 +sched_getaffinity 123 +sched_yield 124 +sched_get_priority_max 125 +sched_get_priority_min 126 +sched_rr_get_interval 127 +restart_syscall 128 +kill 129 +tkill 130 +tgkill 131 +sigaltstack 132 +rt_sigsuspend 133 +rt_sigaction 134 +rt_sigprocmask 135 +rt_sigpending 136 +rt_sigtimedwait 137 +rt_sigqueueinfo 138 +rt_sigreturn 139 +setpriority 140 +getpriority 141 +reboot 142 +setregid 143 +setgid 144 +setreuid 145 +setuid 146 +setresuid 147 +getresuid 148 +setresgid 149 +getresgid 150 +setfsuid 151 +setfsgid 152 +times 153 +setpgid 154 +getpgid 155 +getsid 156 +setsid 157 +getgroups 158 +setgroups 159 +uname 160 +sethostname 161 +setdomainname 162 +getrlimit 163 +setrlimit 164 +getrusage 165 +umask 166 +prctl 167 +getcpu 168 +gettimeofday 169 +settimeofday 170 +adjtimex 171 +getpid 172 +getppid 173 +getuid 174 +geteuid 175 +getgid 176 +getegid 177 +gettid 178 +sysinfo 179 +mq_open 180 +mq_unlink 181 +mq_timedsend 182 +mq_timedreceive 183 +mq_notify 184 +mq_getsetattr 185 +msgget 186 +msgctl 187 +msgrcv 188 +msgsnd 189 +semget 190 +semctl 191 +semtimedop 192 +semop 193 +shmget 194 +shmctl 195 +shmat 196 +shmdt 197 +socket 198 +socketpair 199 +bind 200 +listen 201 +accept 202 +connect 203 +getsockname 204 +getpeername 205 +sendto 206 +recvfrom 207 +setsockopt 208 +getsockopt 209 +shutdown 210 +sendmsg 211 +recvmsg 212 +readahead 213 +brk 214 +munmap 215 +mremap 216 +add_key 217 +request_key 218 +keyctl 219 +clone 220 +execve 221 +mmap 222 +fadvise64 223 +swapon 224 +swapoff 225 +mprotect 226 +msync 227 +mlock 228 +munlock 229 +mlockall 230 +munlockall 231 +mincore 232 +madvise 233 +remap_file_pages 234 +mbind 235 +get_mempolicy 236 +set_mempolicy 237 +migrate_pages 238 +move_pages 239 +rt_tgsigqueueinfo 240 +perf_event_open 241 +accept4 242 +recvmmsg 243 +wait4 260 +prlimit64 261 +fanotify_init 262 +fanotify_mark 263 +name_to_handle_at 264 +open_by_handle_at 265 +clock_adjtime 266 +syncfs 267 +setns 268 +sendmmsg 269 +process_vm_readv 270 +process_vm_writev 271 +kcmp 272 +finit_module 273 +sched_setattr 274 +sched_getattr 275 +renameat2 276 +seccomp 277 +getrandom 278 +memfd_create 279 +bpf 280 +execveat 281 +userfaultfd 282 +membarrier 283 +mlock2 284 +copy_file_range 285 +preadv2 286 +pwritev2 287 +pkey_mprotect 288 +pkey_alloc 289 +pkey_free 290 +statx 291 +io_pgetevents 292 +rseq 293 +kexec_file_load 294 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +memfd_secret 447 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/generate_arch.sh b/ltp/include/lapi/syscalls/generate_arch.sh new file mode 100755 index 0000000000000000000000000000000000000000..5d731794d6492a76c3ba39ac0117b60d8a374740 --- /dev/null +++ b/ltp/include/lapi/syscalls/generate_arch.sh @@ -0,0 +1,213 @@ +#!/bin/sh -eu +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2009-2024 +# Copyright (c) Marcin Juszkiewicz, 2023-2024 +# +# This is an adaptation of the update-tables.sh script, included in the +# syscalls-table project (https://github.com/hrw/syscalls-table) and released +# under the MIT license. +# +# Author: Andrea Cervesato + +if [ "$#" -eq "0" ]; then + echo "Please provide kernel sources:" + echo "" + echo "$0 path/to/Linux/kernel/sources" + echo "" + exit 1 +fi + +KERNELSRC="$1" + +# to keep sorting in order +export LC_ALL=C + +if [ ! -d "${KERNELSRC}" ]; then + echo "${KERNELSRC} is not a directory" + exit 1 +fi + +if [ ! -e "${KERNELSRC}/Makefile" ]; then + echo "No Makefile in ${KERNELSRC} directory" + exit 1 +fi + +TEMP="$(mktemp -d)" +KVER="$(make -C ${KERNELSRC} kernelversion -s)" + +SCRIPT_DIR="$(realpath $(dirname "$0"))" +SUPPORTED_ARCH="${SCRIPT_DIR}/supported-arch.txt" +LINUX_HEADERS="${TEMP}/headers" + +grab_syscall_names_from_tables() { + for tbl_file in $(find ${KERNELSRC}/arch -name syscall*.tbl); do + grep -E -v "(^#|^$|sys_ni_syscall)" $tbl_file | + awk '{ print $3 }' >>${TEMP}/syscall-names.tosort + done + + drop_bad_entries +} + +grab_syscall_names_from_unistd_h() { + grep -E -h "^#define __NR_" \ + ${LINUX_HEADERS}/usr/include/asm/unistd*.h \ + ${LINUX_HEADERS}/usr/include/asm-generic/unistd.h \ + >${TEMP}/syscall-names.tosort + + drop_bad_entries +} + +drop_bad_entries() { + grep -E -v "(unistd.h|NR3264|__NR_syscall|__SC_COMP|__NR_.*Linux|__NR_FAST)" \ + ${TEMP}/syscall-names.tosort | + grep -E -v "(__SYSCALL|SYSCALL_BASE|SYSCALL_MASK)" | + sed -e "s/#define\s*__NR_//g" -e "s/\s.*//g" | + sort -u >${TEMP}/syscall-names.txt +} + +generate_table() { + echo "- $arch" + + if [ "$bits" -eq "32" ]; then + extraflags="${extraflags} -D__BITS_PER_LONG=32" + fi + + local uppercase_arch=$(echo "$arch" | tr '[:lower:]' '[:upper:]') + + # ignore any error generated by gcc. We want to obtain all the + # available architecture syscalls for the current platform and to handle + # only supported architectures later on + gcc ${TEMP}/list-syscalls.c -U__LP64__ -U__ILP32__ -U__i386__ \ + -D${uppercase_arch} \ + -D__${arch}__ ${extraflags} \ + -I ${LINUX_HEADERS}/usr/include/ \ + -o ${TEMP}/list-syscalls || true + + ${TEMP}/list-syscalls >"${TEMP}/${arch}.in.tosort" + + sort -k2,2n "${TEMP}/${arch}.in.tosort" >"${TEMP}/${arch}.in" +} + +generate_list_syscalls_c() { + ( + printf " + #include + #include + + int main(void) + { + " + for syscall in $(cat ${TEMP}/syscall-names.txt); do + printf " + #ifdef __NR_$syscall + printf(\"$syscall %%d" + # i know the following print is ugly, but dash and bash + # treat double quoted strings in a different way and we + # really need to inject '\n' character in the C code + # rather than carriage return + printf '\\n' + printf "\", __NR_$syscall); + #endif + " + done + printf " return 0; + }" + ) >${TEMP}/list-syscalls.c +} + +export_headers() { + make -s -C ${KERNELSRC} ARCH=${arch} O=${LINUX_HEADERS} \ + headers_install >/dev/null 2>&1 +} + +do_all_tables() { + for archdir in ${KERNELSRC}/arch/*; do + arch=$(basename $archdir) + + bits=64 + extraflags= + + case ${arch} in + Kconfig) + continue + ;; + um) + continue + ;; + esac + + export_headers + grab_syscall_names_from_unistd_h + + case ${arch} in + arm) + bits=32 + arch=armoabi extraflags= generate_table + arch=arm extraflags=-D__ARM_EABI__ generate_table + ;; + loongarch) + # 32-bit variant of loongarch may appear + arch=loongarch64 extraflags=-D_LOONGARCH_SZLONG=64 generate_table + ;; + mips) + arch=mips64 extraflags=-D_MIPS_SIM=_MIPS_SIM_ABI64 generate_table + bits=32 + arch=mipso32 extraflags=-D_MIPS_SIM=_MIPS_SIM_ABI32 generate_table + arch=mips64n32 extraflags=-D_MIPS_SIM=_MIPS_SIM_NABI32 generate_table + ;; + powerpc) + generate_table + arch=powerpc64 generate_table + ;; + riscv) + arch=riscv64 extraflags=-D__LP64__ generate_table + bits=32 + arch=riscv32 extraflags=-D__SIZEOF_POINTER__=4 generate_table + ;; + s390) + bits=32 + generate_table + bits=64 + arch=s390x generate_table + ;; + sparc) + bits=32 + extraflags=-D__32bit_syscall_numbers__ generate_table + bits=64 + arch=sparc64 extraflags=-D__arch64__ generate_table + ;; + x86) + arch=x86_64 extraflags=-D__LP64__ generate_table + bits=32 + arch=i386 generate_table + arch=x32 extraflags=-D__ILP32__ generate_table + ;; + arc | csky | hexagon | m68k | microblaze | nios2 | openrisc | sh | xtensa) + bits=32 generate_table + ;; + *) + generate_table + ;; + esac + done +} + +copy_supported_arch() { + while IFS= read -r arch; do + if [ -f "${TEMP}/${arch}.in" ]; then + echo "- ${arch}" + cp "${TEMP}/${arch}.in" "${SCRIPT_DIR}/${arch}.in" + fi + done <${SUPPORTED_ARCH} +} + +echo "Temporary directory ${TEMP}" +echo "Extracting syscalls" + +grab_syscall_names_from_tables +generate_list_syscalls_c + +do_all_tables + +echo "Copying supported syscalls" +copy_supported_arch diff --git a/ltp/include/lapi/syscalls/generate_syscalls.sh b/ltp/include/lapi/syscalls/generate_syscalls.sh new file mode 100755 index 0000000000000000000000000000000000000000..b17c72ddf09cff4f55b7ef80856cd97862ce1317 --- /dev/null +++ b/ltp/include/lapi/syscalls/generate_syscalls.sh @@ -0,0 +1,109 @@ +#!/bin/sh -eu +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Generate the syscalls.h file, merging all architectures syscalls input file +# which are in the current folder and defined inside supported-arch.txt file. + +SYSCALLS_FILE="$1" + +if [ -z "${SYSCALLS_FILE}" ]; then + echo "Please provide the syscalls.h directory:" + echo "" + echo "$0 path/of/syscalls.h" + echo "" + exit 1 +fi + +SCRIPT_DIR="$(realpath $(dirname "$0"))" +SUPPORTED_ARCH="${SCRIPT_DIR}/supported-arch.txt" + +echo '// SPDX-License-Identifier: GPL-2.0-or-later +/************************************************ + * GENERATED FILE: DO NOT EDIT/PATCH THIS FILE * + * change your arch specific .in file instead * + ************************************************/ + +/* + * Here we stick all the ugly *fallback* logic for linux + * system call numbers (those __NR_ thingies). + */ + +#ifndef LAPI_SYSCALLS_H__ +#define LAPI_SYSCALLS_H__ + +#include +#include +#include + +#ifdef TST_TEST_H__ +#define TST_SYSCALL_BRK__(NR, SNR) ({ \ +tst_brk(TCONF, \ + "syscall(%d) " SNR " not supported on your arch", NR); \ +}) +#else +inline static void dummy_cleanup(void) {} + +#define TST_SYSCALL_BRK__(NR, SNR) ({ \ +tst_brkm(TCONF, dummy_cleanup, \ + "syscall(%d) " SNR " not supported on your arch", NR); \ +}) +#endif + +#define tst_syscall(NR, ...) ({ \ +intptr_t tst_ret; \ +if (NR == __LTP__NR_INVALID_SYSCALL) { \ + errno = ENOSYS; \ + tst_ret = -1; \ +} else { \ + tst_ret = syscall(NR, ##__VA_ARGS__); \ +} \ +if (tst_ret == -1 && errno == ENOSYS) { \ + TST_SYSCALL_BRK__(NR, #NR); \ +} \ +tst_ret; \ +}) + +#define __LTP__NR_INVALID_SYSCALL -1' >${SYSCALLS_FILE} + +while IFS= read -r arch; do + ( + echo + case ${arch} in + sparc64) echo "#if defined(__sparc__) && defined(__arch64__)" ;; + sparc) echo "#if defined(__sparc__) && !defined(__arch64__)" ;; + s390) echo "#if defined(__s390__) && !defined(__s390x__)" ;; + mips64n32) echo "#if defined(__mips__) && defined(_ABIN32)" ;; + mips64) echo "#if defined(__mips__) && defined(_ABI64)" ;; + mipso32) echo "#if defined(__mips__) && defined(_ABIO32) && _MIPS_SZLONG == 32" ;; + parisc) echo "#ifdef __hppa__" ;; + loongarch64) echo "#ifdef __loongarch__" ;; + arm64) echo "#ifdef __aarch64__" ;; + *) echo "#ifdef __${arch}__" ;; + esac + + while read -r line; do + set -- ${line} + syscall_nr="__NR_$1" + shift + + echo "# ifndef ${syscall_nr}" + echo "# define ${syscall_nr} $*" + echo "# endif" + done <"${SCRIPT_DIR}/${arch}.in" + echo "#endif" + echo + ) >>${SYSCALLS_FILE} +done <${SUPPORTED_ARCH} + +( + echo + echo "/* Common stubs */" + for num in $(awk '{print $1}' "${SCRIPT_DIR}/"*.in | sort -u); do + syscall_nr="__NR_${num}" + + echo "# ifndef ${syscall_nr}" + echo "# define ${syscall_nr} __LTP__NR_INVALID_SYSCALL" + echo "# endif" + done + echo "#endif" +) >>${SYSCALLS_FILE} diff --git a/ltp/include/lapi/syscalls/i386.in b/ltp/include/lapi/syscalls/i386.in new file mode 100644 index 0000000000000000000000000000000000000000..13f72e7950ded9393e665cb1a44fe955343f820c --- /dev/null +++ b/ltp/include/lapi/syscalls/i386.in @@ -0,0 +1,449 @@ +restart_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 +oldstat 18 +lseek 19 +getpid 20 +mount 21 +umount 22 +setuid 23 +getuid 24 +stime 25 +ptrace 26 +alarm 27 +oldfstat 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 +oldolduname 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 +select 82 +symlink 83 +oldlstat 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 +olduname 109 +iopl 110 +vhangup 111 +idle 112 +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 +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 +getsid 147 +fdatasync 148 +_sysctl 149 +mlock 150 +munlock 151 +mlockall 152 +munlockall 153 +sched_setparam 154 +sched_getparam 155 +sched_setscheduler 156 +sched_getscheduler 157 +sched_yield 158 +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_rr_get_interval 161 +nanosleep 162 +mremap 163 +setresuid 164 +getresuid 165 +query_module 167 +poll 168 +nfsservctl 169 +setresgid 170 +getresgid 171 +prctl 172 +rt_sigreturn 173 +rt_sigaction 174 +rt_sigprocmask 175 +rt_sigpending 176 +rt_sigtimedwait 177 +rt_sigqueueinfo 178 +rt_sigsuspend 179 +pread64 180 +pwrite64 181 +chown 182 +getcwd 183 +capget 184 +capset 185 +sigaltstack 186 +sendfile 187 +getpmsg 188 +putpmsg 189 +vfork 190 +ugetrlimit 191 +mmap2 192 +truncate64 193 +ftruncate64 194 +stat64 195 +lstat64 196 +fstat64 197 +lchown32 198 +getuid32 199 +getgid32 200 +geteuid32 201 +getegid32 202 +setreuid32 203 +setregid32 204 +getgroups32 205 +setgroups32 206 +fchown32 207 +setresuid32 208 +getresuid32 209 +setresgid32 210 +getresgid32 211 +chown32 212 +setuid32 213 +setgid32 214 +setfsuid32 215 +setfsgid32 216 +pivot_root 217 +mincore 218 +madvise 219 +getdents64 220 +fcntl64 221 +gettid 224 +readahead 225 +setxattr 226 +lsetxattr 227 +fsetxattr 228 +getxattr 229 +lgetxattr 230 +fgetxattr 231 +listxattr 232 +llistxattr 233 +flistxattr 234 +removexattr 235 +lremovexattr 236 +fremovexattr 237 +tkill 238 +sendfile64 239 +futex 240 +sched_setaffinity 241 +sched_getaffinity 242 +set_thread_area 243 +get_thread_area 244 +io_setup 245 +io_destroy 246 +io_getevents 247 +io_submit 248 +io_cancel 249 +fadvise64 250 +exit_group 252 +lookup_dcookie 253 +epoll_create 254 +epoll_ctl 255 +epoll_wait 256 +remap_file_pages 257 +set_tid_address 258 +timer_create 259 +timer_settime 260 +timer_gettime 261 +timer_getoverrun 262 +timer_delete 263 +clock_settime 264 +clock_gettime 265 +clock_getres 266 +clock_nanosleep 267 +statfs64 268 +fstatfs64 269 +tgkill 270 +utimes 271 +fadvise64_64 272 +vserver 273 +mbind 274 +get_mempolicy 275 +set_mempolicy 276 +mq_open 277 +mq_unlink 278 +mq_timedsend 279 +mq_timedreceive 280 +mq_notify 281 +mq_getsetattr 282 +kexec_load 283 +waitid 284 +add_key 286 +request_key 287 +keyctl 288 +ioprio_set 289 +ioprio_get 290 +inotify_init 291 +inotify_add_watch 292 +inotify_rm_watch 293 +migrate_pages 294 +openat 295 +mkdirat 296 +mknodat 297 +fchownat 298 +futimesat 299 +fstatat64 300 +unlinkat 301 +renameat 302 +linkat 303 +symlinkat 304 +readlinkat 305 +fchmodat 306 +faccessat 307 +pselect6 308 +ppoll 309 +unshare 310 +set_robust_list 311 +get_robust_list 312 +splice 313 +sync_file_range 314 +tee 315 +vmsplice 316 +move_pages 317 +getcpu 318 +epoll_pwait 319 +utimensat 320 +signalfd 321 +timerfd_create 322 +eventfd 323 +fallocate 324 +timerfd_settime 325 +timerfd_gettime 326 +signalfd4 327 +eventfd2 328 +epoll_create1 329 +dup3 330 +pipe2 331 +inotify_init1 332 +preadv 333 +pwritev 334 +rt_tgsigqueueinfo 335 +perf_event_open 336 +recvmmsg 337 +fanotify_init 338 +fanotify_mark 339 +prlimit64 340 +name_to_handle_at 341 +open_by_handle_at 342 +clock_adjtime 343 +syncfs 344 +sendmmsg 345 +setns 346 +process_vm_readv 347 +process_vm_writev 348 +kcmp 349 +finit_module 350 +sched_setattr 351 +sched_getattr 352 +renameat2 353 +seccomp 354 +getrandom 355 +memfd_create 356 +bpf 357 +execveat 358 +socket 359 +socketpair 360 +bind 361 +connect 362 +listen 363 +accept4 364 +getsockopt 365 +setsockopt 366 +getsockname 367 +getpeername 368 +sendto 369 +sendmsg 370 +recvfrom 371 +recvmsg 372 +shutdown 373 +userfaultfd 374 +membarrier 375 +mlock2 376 +copy_file_range 377 +preadv2 378 +pwritev2 379 +pkey_mprotect 380 +pkey_alloc 381 +pkey_free 382 +statx 383 +arch_prctl 384 +io_pgetevents 385 +rseq 386 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +memfd_secret 447 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/ia64.in b/ltp/include/lapi/syscalls/ia64.in new file mode 100644 index 0000000000000000000000000000000000000000..cd770bace8b311fa2844768fd2f997c85c759f3e --- /dev/null +++ b/ltp/include/lapi/syscalls/ia64.in @@ -0,0 +1,354 @@ +ni_syscall 1024 +exit 1025 +read 1026 +write 1027 +open 1028 +close 1029 +creat 1030 +link 1031 +unlink 1032 +execve 1033 +chdir 1034 +fchdir 1035 +utimes 1036 +mknod 1037 +chmod 1038 +chown 1039 +lseek 1040 +getpid 1041 +getppid 1042 +mount 1043 +umount2 1044 +setuid 1045 +getuid 1046 +geteuid 1047 +ptrace 1048 +access 1049 +sync 1050 +fsync 1051 +fdatasync 1052 +kill 1053 +rename 1054 +mkdir 1055 +rmdir 1056 +dup 1057 +pipe 1058 +times 1059 +brk 1060 +setgid 1061 +getgid 1062 +getegid 1063 +acct 1064 +ioctl 1065 +fcntl 1066 +umask 1067 +chroot 1068 +ustat 1069 +dup2 1070 +setreuid 1071 +setregid 1072 +getresuid 1073 +setresuid 1074 +getresgid 1075 +setresgid 1076 +getgroups 1077 +setgroups 1078 +getpgid 1079 +setpgid 1080 +setsid 1081 +getsid 1082 +sethostname 1083 +setrlimit 1084 +getrlimit 1085 +getrusage 1086 +gettimeofday 1087 +settimeofday 1088 +select 1089 +poll 1090 +symlink 1091 +readlink 1092 +uselib 1093 +swapon 1094 +swapoff 1095 +reboot 1096 +truncate 1097 +ftruncate 1098 +fchmod 1099 +fchown 1100 +getpriority 1101 +setpriority 1102 +statfs 1103 +fstatfs 1104 +gettid 1105 +semget 1106 +semop 1107 +semctl 1108 +msgget 1109 +msgsnd 1110 +msgrcv 1111 +msgctl 1112 +shmget 1113 +shmat 1114 +shmdt 1115 +shmctl 1116 +syslog 1117 +setitimer 1118 +getitimer 1119 +vhangup 1123 +lchown 1124 +remap_file_pages 1125 +wait4 1126 +sysinfo 1127 +clone 1128 +setdomainname 1129 +uname 1130 +adjtimex 1131 +init_module 1133 +delete_module 1134 +quotactl 1137 +bdflush 1138 +sysfs 1139 +personality 1140 +afs_syscall 1141 +setfsuid 1142 +setfsgid 1143 +getdents 1144 +flock 1145 +readv 1146 +writev 1147 +pread64 1148 +pwrite64 1149 +_sysctl 1150 +mmap 1151 +munmap 1152 +mlock 1153 +mlockall 1154 +mprotect 1155 +mremap 1156 +msync 1157 +munlock 1158 +munlockall 1159 +sched_getparam 1160 +sched_setparam 1161 +sched_getscheduler 1162 +sched_setscheduler 1163 +sched_yield 1164 +sched_get_priority_max 1165 +sched_get_priority_min 1166 +sched_rr_get_interval 1167 +nanosleep 1168 +nfsservctl 1169 +prctl 1170 +old_getpagesize 1171 +mmap2 1172 +pciconfig_read 1173 +pciconfig_write 1174 +perfmonctl 1175 +sigaltstack 1176 +rt_sigaction 1177 +rt_sigpending 1178 +rt_sigprocmask 1179 +rt_sigqueueinfo 1180 +rt_sigreturn 1181 +rt_sigsuspend 1182 +rt_sigtimedwait 1183 +getcwd 1184 +capget 1185 +capset 1186 +sendfile 1187 +getpmsg 1188 +putpmsg 1189 +socket 1190 +bind 1191 +connect 1192 +listen 1193 +accept 1194 +getsockname 1195 +getpeername 1196 +socketpair 1197 +send 1198 +sendto 1199 +recv 1200 +recvfrom 1201 +shutdown 1202 +setsockopt 1203 +getsockopt 1204 +sendmsg 1205 +recvmsg 1206 +pivot_root 1207 +mincore 1208 +madvise 1209 +stat 1210 +lstat 1211 +fstat 1212 +clone2 1213 +getdents64 1214 +getunwind 1215 +readahead 1216 +setxattr 1217 +lsetxattr 1218 +fsetxattr 1219 +getxattr 1220 +lgetxattr 1221 +fgetxattr 1222 +listxattr 1223 +llistxattr 1224 +flistxattr 1225 +removexattr 1226 +lremovexattr 1227 +fremovexattr 1228 +tkill 1229 +futex 1230 +sched_setaffinity 1231 +sched_getaffinity 1232 +set_tid_address 1233 +fadvise64 1234 +tgkill 1235 +exit_group 1236 +lookup_dcookie 1237 +io_setup 1238 +io_destroy 1239 +io_getevents 1240 +io_submit 1241 +io_cancel 1242 +epoll_create 1243 +epoll_ctl 1244 +epoll_wait 1245 +restart_syscall 1246 +semtimedop 1247 +timer_create 1248 +timer_settime 1249 +timer_gettime 1250 +timer_getoverrun 1251 +timer_delete 1252 +clock_settime 1253 +clock_gettime 1254 +clock_getres 1255 +clock_nanosleep 1256 +fstatfs64 1257 +statfs64 1258 +mbind 1259 +get_mempolicy 1260 +set_mempolicy 1261 +mq_open 1262 +mq_unlink 1263 +mq_timedsend 1264 +mq_timedreceive 1265 +mq_notify 1266 +mq_getsetattr 1267 +kexec_load 1268 +vserver 1269 +waitid 1270 +add_key 1271 +request_key 1272 +keyctl 1273 +ioprio_set 1274 +ioprio_get 1275 +move_pages 1276 +inotify_init 1277 +inotify_add_watch 1278 +inotify_rm_watch 1279 +migrate_pages 1280 +openat 1281 +mkdirat 1282 +mknodat 1283 +fchownat 1284 +futimesat 1285 +newfstatat 1286 +unlinkat 1287 +renameat 1288 +linkat 1289 +symlinkat 1290 +readlinkat 1291 +fchmodat 1292 +faccessat 1293 +pselect6 1294 +ppoll 1295 +unshare 1296 +splice 1297 +set_robust_list 1298 +get_robust_list 1299 +sync_file_range 1300 +tee 1301 +vmsplice 1302 +fallocate 1303 +getcpu 1304 +epoll_pwait 1305 +utimensat 1306 +signalfd 1307 +timerfd 1308 +eventfd 1309 +timerfd_create 1310 +timerfd_settime 1311 +timerfd_gettime 1312 +signalfd4 1313 +eventfd2 1314 +epoll_create1 1315 +dup3 1316 +pipe2 1317 +inotify_init1 1318 +preadv 1319 +pwritev 1320 +rt_tgsigqueueinfo 1321 +recvmmsg 1322 +fanotify_init 1323 +fanotify_mark 1324 +prlimit64 1325 +name_to_handle_at 1326 +open_by_handle_at 1327 +clock_adjtime 1328 +syncfs 1329 +setns 1330 +sendmmsg 1331 +process_vm_readv 1332 +process_vm_writev 1333 +accept4 1334 +finit_module 1335 +sched_setattr 1336 +sched_getattr 1337 +renameat2 1338 +getrandom 1339 +memfd_create 1340 +bpf 1341 +execveat 1342 +userfaultfd 1343 +membarrier 1344 +kcmp 1345 +mlock2 1346 +copy_file_range 1347 +preadv2 1348 +pwritev2 1349 +statx 1350 +io_pgetevents 1351 +perf_event_open 1352 +seccomp 1353 +pkey_mprotect 1354 +pkey_alloc 1355 +pkey_free 1356 +rseq 1357 +pidfd_send_signal 1448 +io_uring_setup 1449 +io_uring_enter 1450 +io_uring_register 1451 +open_tree 1452 +move_mount 1453 +fsopen 1454 +fsconfig 1455 +fsmount 1456 +fspick 1457 +pidfd_open 1458 +close_range 1460 +openat2 1461 +pidfd_getfd 1462 +faccessat2 1463 +epoll_pwait2 1465 +quotactl_fd 1467 +landlock_create_ruleset 1468 +landlock_add_rule 1469 +landlock_restrict_self 1470 +futex_waitv 1473 +cachestat 1475 +fchmodat2 1476 +mseal 1486 +statmount 1481 +listmount 1482 diff --git a/ltp/include/lapi/syscalls/loongarch64.in b/ltp/include/lapi/syscalls/loongarch64.in new file mode 100644 index 0000000000000000000000000000000000000000..2c1ecd7aeeb2fa4f38999bad144cfceee39a4a54 --- /dev/null +++ b/ltp/include/lapi/syscalls/loongarch64.in @@ -0,0 +1,314 @@ +io_setup 0 +io_destroy 1 +io_submit 2 +io_cancel 3 +io_getevents 4 +setxattr 5 +lsetxattr 6 +fsetxattr 7 +getxattr 8 +lgetxattr 9 +fgetxattr 10 +listxattr 11 +llistxattr 12 +flistxattr 13 +removexattr 14 +lremovexattr 15 +fremovexattr 16 +getcwd 17 +lookup_dcookie 18 +eventfd2 19 +epoll_create1 20 +epoll_ctl 21 +epoll_pwait 22 +dup 23 +dup3 24 +fcntl 25 +inotify_init1 26 +inotify_add_watch 27 +inotify_rm_watch 28 +ioctl 29 +ioprio_set 30 +ioprio_get 31 +flock 32 +mknodat 33 +mkdirat 34 +unlinkat 35 +symlinkat 36 +linkat 37 +umount2 39 +mount 40 +pivot_root 41 +nfsservctl 42 +statfs 43 +fstatfs 44 +truncate 45 +ftruncate 46 +fallocate 47 +faccessat 48 +chdir 49 +fchdir 50 +chroot 51 +fchmod 52 +fchmodat 53 +fchownat 54 +fchown 55 +openat 56 +close 57 +vhangup 58 +pipe2 59 +quotactl 60 +getdents64 61 +lseek 62 +read 63 +write 64 +readv 65 +writev 66 +pread64 67 +pwrite64 68 +preadv 69 +pwritev 70 +sendfile 71 +pselect6 72 +ppoll 73 +signalfd4 74 +vmsplice 75 +splice 76 +tee 77 +readlinkat 78 +newfstatat 79 +fstat 80 +sync 81 +fsync 82 +fdatasync 83 +sync_file_range 84 +timerfd_create 85 +timerfd_settime 86 +timerfd_gettime 87 +utimensat 88 +acct 89 +capget 90 +capset 91 +personality 92 +exit 93 +exit_group 94 +waitid 95 +set_tid_address 96 +unshare 97 +futex 98 +set_robust_list 99 +get_robust_list 100 +nanosleep 101 +getitimer 102 +setitimer 103 +kexec_load 104 +init_module 105 +delete_module 106 +timer_create 107 +timer_gettime 108 +timer_getoverrun 109 +timer_settime 110 +timer_delete 111 +clock_settime 112 +clock_gettime 113 +clock_getres 114 +clock_nanosleep 115 +syslog 116 +ptrace 117 +sched_setparam 118 +sched_setscheduler 119 +sched_getscheduler 120 +sched_getparam 121 +sched_setaffinity 122 +sched_getaffinity 123 +sched_yield 124 +sched_get_priority_max 125 +sched_get_priority_min 126 +sched_rr_get_interval 127 +restart_syscall 128 +kill 129 +tkill 130 +tgkill 131 +sigaltstack 132 +rt_sigsuspend 133 +rt_sigaction 134 +rt_sigprocmask 135 +rt_sigpending 136 +rt_sigtimedwait 137 +rt_sigqueueinfo 138 +rt_sigreturn 139 +setpriority 140 +getpriority 141 +reboot 142 +setregid 143 +setgid 144 +setreuid 145 +setuid 146 +setresuid 147 +getresuid 148 +setresgid 149 +getresgid 150 +setfsuid 151 +setfsgid 152 +times 153 +setpgid 154 +getpgid 155 +getsid 156 +setsid 157 +getgroups 158 +setgroups 159 +uname 160 +sethostname 161 +setdomainname 162 +getrusage 165 +umask 166 +prctl 167 +getcpu 168 +gettimeofday 169 +settimeofday 170 +adjtimex 171 +getpid 172 +getppid 173 +getuid 174 +geteuid 175 +getgid 176 +getegid 177 +gettid 178 +sysinfo 179 +mq_open 180 +mq_unlink 181 +mq_timedsend 182 +mq_timedreceive 183 +mq_notify 184 +mq_getsetattr 185 +msgget 186 +msgctl 187 +msgrcv 188 +msgsnd 189 +semget 190 +semctl 191 +semtimedop 192 +semop 193 +shmget 194 +shmctl 195 +shmat 196 +shmdt 197 +socket 198 +socketpair 199 +bind 200 +listen 201 +accept 202 +connect 203 +getsockname 204 +getpeername 205 +sendto 206 +recvfrom 207 +setsockopt 208 +getsockopt 209 +shutdown 210 +sendmsg 211 +recvmsg 212 +readahead 213 +brk 214 +munmap 215 +mremap 216 +add_key 217 +request_key 218 +keyctl 219 +clone 220 +execve 221 +mmap 222 +fadvise64 223 +swapon 224 +swapoff 225 +mprotect 226 +msync 227 +mlock 228 +munlock 229 +mlockall 230 +munlockall 231 +mincore 232 +madvise 233 +remap_file_pages 234 +mbind 235 +get_mempolicy 236 +set_mempolicy 237 +migrate_pages 238 +move_pages 239 +rt_tgsigqueueinfo 240 +perf_event_open 241 +accept4 242 +recvmmsg 243 +wait4 260 +prlimit64 261 +fanotify_init 262 +fanotify_mark 263 +name_to_handle_at 264 +open_by_handle_at 265 +clock_adjtime 266 +syncfs 267 +setns 268 +sendmmsg 269 +process_vm_readv 270 +process_vm_writev 271 +kcmp 272 +finit_module 273 +sched_setattr 274 +sched_getattr 275 +renameat2 276 +seccomp 277 +getrandom 278 +memfd_create 279 +bpf 280 +execveat 281 +userfaultfd 282 +membarrier 283 +mlock2 284 +copy_file_range 285 +preadv2 286 +pwritev2 287 +pkey_mprotect 288 +pkey_alloc 289 +pkey_free 290 +statx 291 +io_pgetevents 292 +rseq 293 +kexec_file_load 294 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/mips64.in b/ltp/include/lapi/syscalls/mips64.in new file mode 100644 index 0000000000000000000000000000000000000000..8be734158fb7840b7757a012b6ed823f29eb7ab9 --- /dev/null +++ b/ltp/include/lapi/syscalls/mips64.in @@ -0,0 +1,364 @@ +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 +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 +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 +landlock_create_ruleset 5444 +landlock_add_rule 5445 +landlock_restrict_self 5446 +process_mrelease 5448 +futex_waitv 5449 +set_mempolicy_home_node 5450 +cachestat 5451 +fchmodat2 5452 +map_shadow_stack 5453 +futex_wake 5454 +futex_wait 5455 +futex_requeue 5456 +statmount 5457 +listmount 5458 +lsm_get_self_attr 5459 +lsm_set_self_attr 5460 +lsm_list_modules 5461 +mseal 5462 diff --git a/ltp/include/lapi/syscalls/mips64n32.in b/ltp/include/lapi/syscalls/mips64n32.in new file mode 100644 index 0000000000000000000000000000000000000000..153fe50bf9a7c62978e458e1cb7225aa63b9edda --- /dev/null +++ b/ltp/include/lapi/syscalls/mips64n32.in @@ -0,0 +1,388 @@ +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 +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 +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 +landlock_create_ruleset 6444 +landlock_add_rule 6445 +landlock_restrict_self 6446 +process_mrelease 6448 +futex_waitv 6449 +set_mempolicy_home_node 6450 +cachestat 6451 +fchmodat2 6452 +map_shadow_stack 6453 +futex_wake 6454 +futex_wait 6455 +futex_requeue 6456 +statmount 6457 +listmount 6458 +lsm_get_self_attr 6459 +lsm_set_self_attr 6460 +lsm_list_modules 6461 +mseal 6462 diff --git a/ltp/include/lapi/syscalls/mipso32.in b/ltp/include/lapi/syscalls/mipso32.in new file mode 100644 index 0000000000000000000000000000000000000000..1ed74c1ecf281a3d208eded4a0dbd35fcc57e45f --- /dev/null +++ b/ltp/include/lapi/syscalls/mipso32.in @@ -0,0 +1,428 @@ +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 +lseek 4019 +getpid 4020 +mount 4021 +umount 4022 +setuid 4023 +getuid 4024 +stime 4025 +ptrace 4026 +alarm 4027 +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 +symlink 4083 +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 +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 +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 +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 +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 +landlock_create_ruleset 4444 +landlock_add_rule 4445 +landlock_restrict_self 4446 +process_mrelease 4448 +futex_waitv 4449 +set_mempolicy_home_node 4450 +cachestat 4451 +fchmodat2 4452 +map_shadow_stack 4453 +futex_wake 4454 +futex_wait 4455 +futex_requeue 4456 +statmount 4457 +listmount 4458 +lsm_get_self_attr 4459 +lsm_set_self_attr 4460 +lsm_list_modules 4461 +mseal 4462 diff --git a/ltp/include/lapi/syscalls/parisc.in b/ltp/include/lapi/syscalls/parisc.in new file mode 100644 index 0000000000000000000000000000000000000000..662bfea4428cf3b090b03632f2087251aaf3b513 --- /dev/null +++ b/ltp/include/lapi/syscalls/parisc.in @@ -0,0 +1,397 @@ +restart_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 +socket 17 +stat 18 +lseek 19 +getpid 20 +mount 21 +bind 22 +setuid 23 +getuid 24 +stime 25 +ptrace 26 +alarm 27 +fstat 28 +pause 29 +utime 30 +connect 31 +listen 32 +access 33 +nice 34 +accept 35 +sync 36 +kill 37 +rename 38 +mkdir 39 +rmdir 40 +dup 41 +pipe 42 +times 43 +getsockname 44 +brk 45 +setgid 46 +getgid 47 +signal 48 +geteuid 49 +getegid 50 +acct 51 +umount2 52 +getpeername 53 +ioctl 54 +fcntl 55 +socketpair 56 +setpgid 57 +send 58 +uname 59 +umask 60 +chroot 61 +ustat 62 +dup2 63 +getppid 64 +getpgrp 65 +setsid 66 +pivot_root 67 +sgetmask 68 +ssetmask 69 +setreuid 70 +setregid 71 +mincore 72 +sigpending 73 +sethostname 74 +setrlimit 75 +getrlimit 76 +getrusage 77 +gettimeofday 78 +settimeofday 79 +getgroups 80 +setgroups 81 +sendto 82 +symlink 83 +lstat 84 +readlink 85 +uselib 86 +swapon 87 +reboot 88 +mmap2 89 +mmap 90 +munmap 91 +truncate 92 +ftruncate 93 +fchmod 94 +fchown 95 +getpriority 96 +setpriority 97 +recv 98 +statfs 99 +fstatfs 100 +stat64 101 +syslog 103 +setitimer 104 +getitimer 105 +capget 106 +capset 107 +pread64 108 +pwrite64 109 +getcwd 110 +vhangup 111 +fstat64 112 +vfork 113 +wait4 114 +swapoff 115 +sysinfo 116 +shutdown 117 +fsync 118 +madvise 119 +clone 120 +setdomainname 121 +sendfile 122 +recvfrom 123 +adjtimex 124 +mprotect 125 +sigprocmask 126 +init_module 128 +delete_module 129 +quotactl 131 +getpgid 132 +fchdir 133 +sysfs 135 +personality 136 +setfsuid 138 +setfsgid 139 +_llseek 140 +getdents 141 +_newselect 142 +flock 143 +msync 144 +readv 145 +writev 146 +getsid 147 +fdatasync 148 +_sysctl 149 +mlock 150 +munlock 151 +mlockall 152 +munlockall 153 +sched_setparam 154 +sched_getparam 155 +sched_setscheduler 156 +sched_getscheduler 157 +sched_yield 158 +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_rr_get_interval 161 +nanosleep 162 +mremap 163 +setresuid 164 +getresuid 165 +sigaltstack 166 +poll 168 +setresgid 170 +getresgid 171 +prctl 172 +rt_sigreturn 173 +rt_sigaction 174 +rt_sigprocmask 175 +rt_sigpending 176 +rt_sigtimedwait 177 +rt_sigqueueinfo 178 +rt_sigsuspend 179 +chown 180 +setsockopt 181 +getsockopt 182 +sendmsg 183 +recvmsg 184 +semop 185 +semget 186 +semctl 187 +msgsnd 188 +msgrcv 189 +msgget 190 +msgctl 191 +shmat 192 +shmdt 193 +shmget 194 +shmctl 195 +lstat64 198 +truncate64 199 +ftruncate64 200 +getdents64 201 +fcntl64 202 +gettid 206 +readahead 207 +tkill 208 +sendfile64 209 +futex 210 +sched_setaffinity 211 +sched_getaffinity 212 +io_setup 215 +io_destroy 216 +io_getevents 217 +io_submit 218 +io_cancel 219 +exit_group 222 +lookup_dcookie 223 +epoll_create 224 +epoll_ctl 225 +epoll_wait 226 +remap_file_pages 227 +semtimedop 228 +mq_open 229 +mq_unlink 230 +mq_timedsend 231 +mq_timedreceive 232 +mq_notify 233 +mq_getsetattr 234 +waitid 235 +fadvise64_64 236 +set_tid_address 237 +setxattr 238 +lsetxattr 239 +fsetxattr 240 +getxattr 241 +lgetxattr 242 +fgetxattr 243 +listxattr 244 +llistxattr 245 +flistxattr 246 +removexattr 247 +lremovexattr 248 +fremovexattr 249 +timer_create 250 +timer_settime 251 +timer_gettime 252 +timer_getoverrun 253 +timer_delete 254 +clock_settime 255 +clock_gettime 256 +clock_getres 257 +clock_nanosleep 258 +tgkill 259 +mbind 260 +get_mempolicy 261 +set_mempolicy 262 +add_key 264 +request_key 265 +keyctl 266 +ioprio_set 267 +ioprio_get 268 +inotify_init 269 +inotify_add_watch 270 +inotify_rm_watch 271 +migrate_pages 272 +pselect6 273 +ppoll 274 +openat 275 +mkdirat 276 +mknodat 277 +fchownat 278 +futimesat 279 +fstatat64 280 +unlinkat 281 +renameat 282 +linkat 283 +symlinkat 284 +readlinkat 285 +fchmodat 286 +faccessat 287 +unshare 288 +set_robust_list 289 +get_robust_list 290 +splice 291 +sync_file_range 292 +tee 293 +vmsplice 294 +move_pages 295 +getcpu 296 +epoll_pwait 297 +statfs64 298 +fstatfs64 299 +kexec_load 300 +utimensat 301 +signalfd 302 +eventfd 304 +fallocate 305 +timerfd_create 306 +timerfd_settime 307 +timerfd_gettime 308 +signalfd4 309 +eventfd2 310 +epoll_create1 311 +dup3 312 +pipe2 313 +inotify_init1 314 +preadv 315 +pwritev 316 +rt_tgsigqueueinfo 317 +perf_event_open 318 +recvmmsg 319 +accept4 320 +prlimit64 321 +fanotify_init 322 +fanotify_mark 323 +clock_adjtime 324 +name_to_handle_at 325 +open_by_handle_at 326 +syncfs 327 +setns 328 +sendmmsg 329 +process_vm_readv 330 +process_vm_writev 331 +kcmp 332 +finit_module 333 +sched_setattr 334 +sched_getattr 335 +utimes 336 +renameat2 337 +seccomp 338 +getrandom 339 +memfd_create 340 +bpf 341 +execveat 342 +membarrier 343 +userfaultfd 344 +mlock2 345 +copy_file_range 346 +preadv2 347 +pwritev2 348 +statx 349 +io_pgetevents 350 +pkey_mprotect 351 +pkey_alloc 352 +pkey_free 353 +rseq 354 +kexec_file_load 355 +cacheflush 356 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/powerpc.in b/ltp/include/lapi/syscalls/powerpc.in new file mode 100644 index 0000000000000000000000000000000000000000..faaa75883a7d2a0b70ca0e8064b6c91dae21d20c --- /dev/null +++ b/ltp/include/lapi/syscalls/powerpc.in @@ -0,0 +1,439 @@ +restart_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 +oldstat 18 +lseek 19 +getpid 20 +mount 21 +umount 22 +setuid 23 +getuid 24 +stime 25 +ptrace 26 +alarm 27 +oldfstat 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 +oldolduname 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 +select 82 +symlink 83 +oldlstat 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 +olduname 109 +iopl 110 +vhangup 111 +idle 112 +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 +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 +getsid 147 +fdatasync 148 +_sysctl 149 +mlock 150 +munlock 151 +mlockall 152 +munlockall 153 +sched_setparam 154 +sched_getparam 155 +sched_setscheduler 156 +sched_getscheduler 157 +sched_yield 158 +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_rr_get_interval 161 +nanosleep 162 +mremap 163 +setresuid 164 +getresuid 165 +query_module 166 +poll 167 +nfsservctl 168 +setresgid 169 +getresgid 170 +prctl 171 +rt_sigreturn 172 +rt_sigaction 173 +rt_sigprocmask 174 +rt_sigpending 175 +rt_sigtimedwait 176 +rt_sigqueueinfo 177 +rt_sigsuspend 178 +pread64 179 +pwrite64 180 +chown 181 +getcwd 182 +capget 183 +capset 184 +sigaltstack 185 +sendfile 186 +getpmsg 187 +putpmsg 188 +vfork 189 +ugetrlimit 190 +readahead 191 +mmap2 192 +truncate64 193 +ftruncate64 194 +stat64 195 +lstat64 196 +fstat64 197 +pciconfig_read 198 +pciconfig_write 199 +pciconfig_iobase 200 +getdents64 202 +pivot_root 203 +fcntl64 204 +madvise 205 +mincore 206 +gettid 207 +tkill 208 +setxattr 209 +lsetxattr 210 +fsetxattr 211 +getxattr 212 +lgetxattr 213 +fgetxattr 214 +listxattr 215 +llistxattr 216 +flistxattr 217 +removexattr 218 +lremovexattr 219 +fremovexattr 220 +futex 221 +sched_setaffinity 222 +sched_getaffinity 223 +tuxcall 225 +sendfile64 226 +io_setup 227 +io_destroy 228 +io_getevents 229 +io_submit 230 +io_cancel 231 +set_tid_address 232 +fadvise64 233 +exit_group 234 +lookup_dcookie 235 +epoll_create 236 +epoll_ctl 237 +epoll_wait 238 +remap_file_pages 239 +timer_create 240 +timer_settime 241 +timer_gettime 242 +timer_getoverrun 243 +timer_delete 244 +clock_settime 245 +clock_gettime 246 +clock_getres 247 +clock_nanosleep 248 +swapcontext 249 +tgkill 250 +utimes 251 +statfs64 252 +fstatfs64 253 +fadvise64_64 254 +rtas 255 +migrate_pages 258 +mbind 259 +get_mempolicy 260 +set_mempolicy 261 +mq_open 262 +mq_unlink 263 +mq_timedsend 264 +mq_timedreceive 265 +mq_notify 266 +mq_getsetattr 267 +kexec_load 268 +add_key 269 +request_key 270 +keyctl 271 +waitid 272 +ioprio_set 273 +ioprio_get 274 +inotify_init 275 +inotify_add_watch 276 +inotify_rm_watch 277 +spu_run 278 +spu_create 279 +pselect6 280 +ppoll 281 +unshare 282 +splice 283 +tee 284 +vmsplice 285 +openat 286 +mkdirat 287 +mknodat 288 +fchownat 289 +futimesat 290 +fstatat64 291 +unlinkat 292 +renameat 293 +linkat 294 +symlinkat 295 +readlinkat 296 +fchmodat 297 +faccessat 298 +get_robust_list 299 +set_robust_list 300 +move_pages 301 +getcpu 302 +epoll_pwait 303 +utimensat 304 +signalfd 305 +timerfd_create 306 +eventfd 307 +sync_file_range2 308 +fallocate 309 +subpage_prot 310 +timerfd_settime 311 +timerfd_gettime 312 +signalfd4 313 +eventfd2 314 +epoll_create1 315 +dup3 316 +pipe2 317 +inotify_init1 318 +perf_event_open 319 +preadv 320 +pwritev 321 +rt_tgsigqueueinfo 322 +fanotify_init 323 +fanotify_mark 324 +prlimit64 325 +socket 326 +bind 327 +connect 328 +listen 329 +accept 330 +getsockname 331 +getpeername 332 +socketpair 333 +send 334 +sendto 335 +recv 336 +recvfrom 337 +shutdown 338 +setsockopt 339 +getsockopt 340 +sendmsg 341 +recvmsg 342 +recvmmsg 343 +accept4 344 +name_to_handle_at 345 +open_by_handle_at 346 +clock_adjtime 347 +syncfs 348 +sendmmsg 349 +setns 350 +process_vm_readv 351 +process_vm_writev 352 +finit_module 353 +kcmp 354 +sched_setattr 355 +sched_getattr 356 +renameat2 357 +seccomp 358 +getrandom 359 +memfd_create 360 +bpf 361 +execveat 362 +switch_endian 363 +userfaultfd 364 +membarrier 365 +mlock2 378 +copy_file_range 379 +preadv2 380 +pwritev2 381 +kexec_file_load 382 +statx 383 +pkey_alloc 384 +pkey_free 385 +pkey_mprotect 386 +rseq 387 +io_pgetevents 388 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/powerpc64.in b/ltp/include/lapi/syscalls/powerpc64.in new file mode 100644 index 0000000000000000000000000000000000000000..23b65e7840869c0cc08559324271b3b0d865ac01 --- /dev/null +++ b/ltp/include/lapi/syscalls/powerpc64.in @@ -0,0 +1,411 @@ +restart_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 +oldstat 18 +lseek 19 +getpid 20 +mount 21 +umount 22 +setuid 23 +getuid 24 +stime 25 +ptrace 26 +alarm 27 +oldfstat 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 +oldolduname 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 +select 82 +symlink 83 +oldlstat 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 +olduname 109 +iopl 110 +vhangup 111 +idle 112 +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 +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 +getsid 147 +fdatasync 148 +_sysctl 149 +mlock 150 +munlock 151 +mlockall 152 +munlockall 153 +sched_setparam 154 +sched_getparam 155 +sched_setscheduler 156 +sched_getscheduler 157 +sched_yield 158 +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_rr_get_interval 161 +nanosleep 162 +mremap 163 +setresuid 164 +getresuid 165 +query_module 166 +poll 167 +nfsservctl 168 +setresgid 169 +getresgid 170 +prctl 171 +rt_sigreturn 172 +rt_sigaction 173 +rt_sigprocmask 174 +rt_sigpending 175 +rt_sigtimedwait 176 +rt_sigqueueinfo 177 +rt_sigsuspend 178 +pread64 179 +pwrite64 180 +chown 181 +getcwd 182 +capget 183 +capset 184 +sigaltstack 185 +sendfile 186 +getpmsg 187 +putpmsg 188 +vfork 189 +ugetrlimit 190 +readahead 191 +pciconfig_read 198 +pciconfig_write 199 +pciconfig_iobase 200 +getdents64 202 +pivot_root 203 +madvise 205 +mincore 206 +gettid 207 +tkill 208 +setxattr 209 +lsetxattr 210 +fsetxattr 211 +getxattr 212 +lgetxattr 213 +fgetxattr 214 +listxattr 215 +llistxattr 216 +flistxattr 217 +removexattr 218 +lremovexattr 219 +fremovexattr 220 +futex 221 +sched_setaffinity 222 +sched_getaffinity 223 +tuxcall 225 +io_setup 227 +io_destroy 228 +io_getevents 229 +io_submit 230 +io_cancel 231 +set_tid_address 232 +fadvise64 233 +exit_group 234 +lookup_dcookie 235 +epoll_create 236 +epoll_ctl 237 +epoll_wait 238 +remap_file_pages 239 +timer_create 240 +timer_settime 241 +timer_gettime 242 +timer_getoverrun 243 +timer_delete 244 +clock_settime 245 +clock_gettime 246 +clock_getres 247 +clock_nanosleep 248 +swapcontext 249 +tgkill 250 +utimes 251 +statfs64 252 +fstatfs64 253 +rtas 255 +migrate_pages 258 +mbind 259 +get_mempolicy 260 +set_mempolicy 261 +mq_open 262 +mq_unlink 263 +mq_timedsend 264 +mq_timedreceive 265 +mq_notify 266 +mq_getsetattr 267 +kexec_load 268 +add_key 269 +request_key 270 +keyctl 271 +waitid 272 +ioprio_set 273 +ioprio_get 274 +inotify_init 275 +inotify_add_watch 276 +inotify_rm_watch 277 +spu_run 278 +spu_create 279 +pselect6 280 +ppoll 281 +unshare 282 +splice 283 +tee 284 +vmsplice 285 +openat 286 +mkdirat 287 +mknodat 288 +fchownat 289 +futimesat 290 +newfstatat 291 +unlinkat 292 +renameat 293 +linkat 294 +symlinkat 295 +readlinkat 296 +fchmodat 297 +faccessat 298 +get_robust_list 299 +set_robust_list 300 +move_pages 301 +getcpu 302 +epoll_pwait 303 +utimensat 304 +signalfd 305 +timerfd_create 306 +eventfd 307 +sync_file_range2 308 +fallocate 309 +subpage_prot 310 +timerfd_settime 311 +timerfd_gettime 312 +signalfd4 313 +eventfd2 314 +epoll_create1 315 +dup3 316 +pipe2 317 +inotify_init1 318 +perf_event_open 319 +preadv 320 +pwritev 321 +rt_tgsigqueueinfo 322 +fanotify_init 323 +fanotify_mark 324 +prlimit64 325 +socket 326 +bind 327 +connect 328 +listen 329 +accept 330 +getsockname 331 +getpeername 332 +socketpair 333 +send 334 +sendto 335 +recv 336 +recvfrom 337 +shutdown 338 +setsockopt 339 +getsockopt 340 +sendmsg 341 +recvmsg 342 +recvmmsg 343 +accept4 344 +name_to_handle_at 345 +open_by_handle_at 346 +clock_adjtime 347 +syncfs 348 +sendmmsg 349 +setns 350 +process_vm_readv 351 +process_vm_writev 352 +finit_module 353 +kcmp 354 +sched_setattr 355 +sched_getattr 356 +renameat2 357 +seccomp 358 +getrandom 359 +memfd_create 360 +bpf 361 +execveat 362 +switch_endian 363 +userfaultfd 364 +membarrier 365 +mlock2 378 +copy_file_range 379 +preadv2 380 +pwritev2 381 +kexec_file_load 382 +statx 383 +pkey_alloc 384 +pkey_free 385 +pkey_mprotect 386 +rseq 387 +io_pgetevents 388 +semtimedop 392 +semget 393 +semctl 394 +shmget 395 +shmctl 396 +shmat 397 +shmdt 398 +msgget 399 +msgsnd 400 +msgrcv 401 +msgctl 402 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/s390.in b/ltp/include/lapi/syscalls/s390.in new file mode 100644 index 0000000000000000000000000000000000000000..69d7408b7bdf0d9019d3c319cd52ff48022aca39 --- /dev/null +++ b/ltp/include/lapi/syscalls/s390.in @@ -0,0 +1,432 @@ +exit 1 +fork 2 +read 3 +write 4 +open 5 +close 6 +restart_syscall 7 +creat 8 +link 9 +unlink 10 +execve 11 +chdir 12 +time 13 +mknod 14 +chmod 15 +lchown 16 +lseek 19 +getpid 20 +mount 21 +umount 22 +setuid 23 +getuid 24 +stime 25 +ptrace 26 +alarm 27 +pause 29 +utime 30 +access 33 +nice 34 +sync 36 +kill 37 +rename 38 +mkdir 39 +rmdir 40 +dup 41 +pipe 42 +times 43 +brk 45 +setgid 46 +getgid 47 +signal 48 +geteuid 49 +getegid 50 +acct 51 +umount2 52 +ioctl 54 +fcntl 55 +setpgid 57 +umask 60 +chroot 61 +ustat 62 +dup2 63 +getppid 64 +getpgrp 65 +setsid 66 +sigaction 67 +setreuid 70 +setregid 71 +sigsuspend 72 +sigpending 73 +sethostname 74 +setrlimit 75 +getrlimit 76 +getrusage 77 +gettimeofday 78 +settimeofday 79 +getgroups 80 +setgroups 81 +symlink 83 +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 +statfs 99 +fstatfs 100 +ioperm 101 +socketcall 102 +syslog 103 +setitimer 104 +getitimer 105 +stat 106 +lstat 107 +fstat 108 +lookup_dcookie 110 +vhangup 111 +idle 112 +wait4 114 +swapoff 115 +sysinfo 116 +ipc 117 +fsync 118 +sigreturn 119 +clone 120 +setdomainname 121 +uname 122 +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 +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 +getsid 147 +fdatasync 148 +_sysctl 149 +mlock 150 +munlock 151 +mlockall 152 +munlockall 153 +sched_setparam 154 +sched_getparam 155 +sched_setscheduler 156 +sched_getscheduler 157 +sched_yield 158 +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_rr_get_interval 161 +nanosleep 162 +mremap 163 +setresuid 164 +getresuid 165 +query_module 167 +poll 168 +nfsservctl 169 +setresgid 170 +getresgid 171 +prctl 172 +rt_sigreturn 173 +rt_sigaction 174 +rt_sigprocmask 175 +rt_sigpending 176 +rt_sigtimedwait 177 +rt_sigqueueinfo 178 +rt_sigsuspend 179 +pread64 180 +pwrite64 181 +chown 182 +getcwd 183 +capget 184 +capset 185 +sigaltstack 186 +sendfile 187 +getpmsg 188 +putpmsg 189 +vfork 190 +ugetrlimit 191 +mmap2 192 +truncate64 193 +ftruncate64 194 +stat64 195 +lstat64 196 +fstat64 197 +lchown32 198 +getuid32 199 +getgid32 200 +geteuid32 201 +getegid32 202 +setreuid32 203 +setregid32 204 +getgroups32 205 +setgroups32 206 +fchown32 207 +setresuid32 208 +getresuid32 209 +setresgid32 210 +getresgid32 211 +chown32 212 +setuid32 213 +setgid32 214 +setfsuid32 215 +setfsgid32 216 +pivot_root 217 +mincore 218 +madvise 219 +getdents64 220 +fcntl64 221 +readahead 222 +sendfile64 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 +gettid 236 +tkill 237 +futex 238 +sched_setaffinity 239 +sched_getaffinity 240 +tgkill 241 +io_setup 243 +io_destroy 244 +io_getevents 245 +io_submit 246 +io_cancel 247 +exit_group 248 +epoll_create 249 +epoll_ctl 250 +epoll_wait 251 +set_tid_address 252 +fadvise64 253 +timer_create 254 +timer_settime 255 +timer_gettime 256 +timer_getoverrun 257 +timer_delete 258 +clock_settime 259 +clock_gettime 260 +clock_getres 261 +clock_nanosleep 262 +fadvise64_64 264 +statfs64 265 +fstatfs64 266 +remap_file_pages 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 +kexec_load 277 +add_key 278 +request_key 279 +keyctl 280 +waitid 281 +ioprio_set 282 +ioprio_get 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 +set_robust_list 304 +get_robust_list 305 +splice 306 +sync_file_range 307 +tee 308 +vmsplice 309 +move_pages 310 +getcpu 311 +epoll_pwait 312 +utimes 313 +fallocate 314 +utimensat 315 +signalfd 316 +timerfd 317 +eventfd 318 +timerfd_create 319 +timerfd_settime 320 +timerfd_gettime 321 +signalfd4 322 +eventfd2 323 +inotify_init1 324 +pipe2 325 +dup3 326 +epoll_create1 327 +preadv 328 +pwritev 329 +rt_tgsigqueueinfo 330 +perf_event_open 331 +fanotify_init 332 +fanotify_mark 333 +prlimit64 334 +name_to_handle_at 335 +open_by_handle_at 336 +clock_adjtime 337 +syncfs 338 +setns 339 +process_vm_readv 340 +process_vm_writev 341 +s390_runtime_instr 342 +kcmp 343 +finit_module 344 +sched_setattr 345 +sched_getattr 346 +renameat2 347 +seccomp 348 +getrandom 349 +memfd_create 350 +bpf 351 +s390_pci_mmio_write 352 +s390_pci_mmio_read 353 +execveat 354 +userfaultfd 355 +membarrier 356 +recvmmsg 357 +sendmmsg 358 +socket 359 +socketpair 360 +bind 361 +connect 362 +listen 363 +accept4 364 +getsockopt 365 +setsockopt 366 +getsockname 367 +getpeername 368 +sendto 369 +sendmsg 370 +recvfrom 371 +recvmsg 372 +shutdown 373 +mlock2 374 +copy_file_range 375 +preadv2 376 +pwritev2 377 +s390_guarded_storage 378 +statx 379 +s390_sthyi 380 +kexec_file_load 381 +io_pgetevents 382 +rseq 383 +pkey_mprotect 384 +pkey_alloc 385 +pkey_free 386 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +memfd_secret 447 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/s390x.in b/ltp/include/lapi/syscalls/s390x.in new file mode 100644 index 0000000000000000000000000000000000000000..fa98054c732787b62528c71f60b04de490b98958 --- /dev/null +++ b/ltp/include/lapi/syscalls/s390x.in @@ -0,0 +1,380 @@ +exit 1 +fork 2 +read 3 +write 4 +open 5 +close 6 +restart_syscall 7 +creat 8 +link 9 +unlink 10 +execve 11 +chdir 12 +mknod 14 +chmod 15 +lseek 19 +getpid 20 +mount 21 +umount 22 +ptrace 26 +alarm 27 +pause 29 +utime 30 +access 33 +nice 34 +sync 36 +kill 37 +rename 38 +mkdir 39 +rmdir 40 +dup 41 +pipe 42 +times 43 +brk 45 +signal 48 +acct 51 +umount2 52 +ioctl 54 +fcntl 55 +setpgid 57 +umask 60 +chroot 61 +ustat 62 +dup2 63 +getppid 64 +getpgrp 65 +setsid 66 +sigaction 67 +sigsuspend 72 +sigpending 73 +sethostname 74 +setrlimit 75 +getrusage 77 +gettimeofday 78 +settimeofday 79 +symlink 83 +readlink 85 +uselib 86 +swapon 87 +reboot 88 +readdir 89 +mmap 90 +munmap 91 +truncate 92 +ftruncate 93 +fchmod 94 +getpriority 96 +setpriority 97 +statfs 99 +fstatfs 100 +socketcall 102 +syslog 103 +setitimer 104 +getitimer 105 +stat 106 +lstat 107 +fstat 108 +lookup_dcookie 110 +vhangup 111 +idle 112 +wait4 114 +swapoff 115 +sysinfo 116 +ipc 117 +fsync 118 +sigreturn 119 +clone 120 +setdomainname 121 +uname 122 +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 +sysfs 135 +personality 136 +afs_syscall 137 +getdents 141 +select 142 +flock 143 +msync 144 +readv 145 +writev 146 +getsid 147 +fdatasync 148 +_sysctl 149 +mlock 150 +munlock 151 +mlockall 152 +munlockall 153 +sched_setparam 154 +sched_getparam 155 +sched_setscheduler 156 +sched_getscheduler 157 +sched_yield 158 +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_rr_get_interval 161 +nanosleep 162 +mremap 163 +query_module 167 +poll 168 +nfsservctl 169 +prctl 172 +rt_sigreturn 173 +rt_sigaction 174 +rt_sigprocmask 175 +rt_sigpending 176 +rt_sigtimedwait 177 +rt_sigqueueinfo 178 +rt_sigsuspend 179 +pread64 180 +pwrite64 181 +getcwd 183 +capget 184 +capset 185 +sigaltstack 186 +sendfile 187 +getpmsg 188 +putpmsg 189 +vfork 190 +getrlimit 191 +lchown 198 +getuid 199 +getgid 200 +geteuid 201 +getegid 202 +setreuid 203 +setregid 204 +getgroups 205 +setgroups 206 +fchown 207 +setresuid 208 +getresuid 209 +setresgid 210 +getresgid 211 +chown 212 +setuid 213 +setgid 214 +setfsuid 215 +setfsgid 216 +pivot_root 217 +mincore 218 +madvise 219 +getdents64 220 +readahead 222 +setxattr 224 +lsetxattr 225 +fsetxattr 226 +getxattr 227 +lgetxattr 228 +fgetxattr 229 +listxattr 230 +llistxattr 231 +flistxattr 232 +removexattr 233 +lremovexattr 234 +fremovexattr 235 +gettid 236 +tkill 237 +futex 238 +sched_setaffinity 239 +sched_getaffinity 240 +tgkill 241 +io_setup 243 +io_destroy 244 +io_getevents 245 +io_submit 246 +io_cancel 247 +exit_group 248 +epoll_create 249 +epoll_ctl 250 +epoll_wait 251 +set_tid_address 252 +fadvise64 253 +timer_create 254 +timer_settime 255 +timer_gettime 256 +timer_getoverrun 257 +timer_delete 258 +clock_settime 259 +clock_gettime 260 +clock_getres 261 +clock_nanosleep 262 +statfs64 265 +fstatfs64 266 +remap_file_pages 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 +kexec_load 277 +add_key 278 +request_key 279 +keyctl 280 +waitid 281 +ioprio_set 282 +ioprio_get 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 +newfstatat 293 +unlinkat 294 +renameat 295 +linkat 296 +symlinkat 297 +readlinkat 298 +fchmodat 299 +faccessat 300 +pselect6 301 +ppoll 302 +unshare 303 +set_robust_list 304 +get_robust_list 305 +splice 306 +sync_file_range 307 +tee 308 +vmsplice 309 +move_pages 310 +getcpu 311 +epoll_pwait 312 +utimes 313 +fallocate 314 +utimensat 315 +signalfd 316 +timerfd 317 +eventfd 318 +timerfd_create 319 +timerfd_settime 320 +timerfd_gettime 321 +signalfd4 322 +eventfd2 323 +inotify_init1 324 +pipe2 325 +dup3 326 +epoll_create1 327 +preadv 328 +pwritev 329 +rt_tgsigqueueinfo 330 +perf_event_open 331 +fanotify_init 332 +fanotify_mark 333 +prlimit64 334 +name_to_handle_at 335 +open_by_handle_at 336 +clock_adjtime 337 +syncfs 338 +setns 339 +process_vm_readv 340 +process_vm_writev 341 +s390_runtime_instr 342 +kcmp 343 +finit_module 344 +sched_setattr 345 +sched_getattr 346 +renameat2 347 +seccomp 348 +getrandom 349 +memfd_create 350 +bpf 351 +s390_pci_mmio_write 352 +s390_pci_mmio_read 353 +execveat 354 +userfaultfd 355 +membarrier 356 +recvmmsg 357 +sendmmsg 358 +socket 359 +socketpair 360 +bind 361 +connect 362 +listen 363 +accept4 364 +getsockopt 365 +setsockopt 366 +getsockname 367 +getpeername 368 +sendto 369 +sendmsg 370 +recvfrom 371 +recvmsg 372 +shutdown 373 +mlock2 374 +copy_file_range 375 +preadv2 376 +pwritev2 377 +s390_guarded_storage 378 +statx 379 +s390_sthyi 380 +kexec_file_load 381 +io_pgetevents 382 +rseq 383 +pkey_mprotect 384 +pkey_alloc 385 +pkey_free 386 +semtimedop 392 +semget 393 +semctl 394 +shmget 395 +shmctl 396 +shmat 397 +shmdt 398 +msgget 399 +msgsnd 400 +msgrcv 401 +msgctl 402 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +memfd_secret 447 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/sh.in b/ltp/include/lapi/syscalls/sh.in new file mode 100644 index 0000000000000000000000000000000000000000..2e584253c61d51b140c3b2f586e3c49e5740e7af --- /dev/null +++ b/ltp/include/lapi/syscalls/sh.in @@ -0,0 +1,426 @@ +restart_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 +oldstat 18 +lseek 19 +getpid 20 +mount 21 +umount 22 +setuid 23 +getuid 24 +stime 25 +ptrace 26 +alarm 27 +oldfstat 28 +pause 29 +utime 30 +access 33 +nice 34 +sync 36 +kill 37 +rename 38 +mkdir 39 +rmdir 40 +dup 41 +pipe 42 +times 43 +brk 45 +setgid 46 +getgid 47 +signal 48 +geteuid 49 +getegid 50 +acct 51 +umount2 52 +ioctl 54 +fcntl 55 +setpgid 57 +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 +symlink 83 +oldlstat 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 +statfs 99 +fstatfs 100 +socketcall 102 +syslog 103 +setitimer 104 +getitimer 105 +stat 106 +lstat 107 +fstat 108 +olduname 109 +vhangup 111 +wait4 114 +swapoff 115 +sysinfo 116 +ipc 117 +fsync 118 +sigreturn 119 +clone 120 +setdomainname 121 +uname 122 +cacheflush 123 +adjtimex 124 +mprotect 125 +sigprocmask 126 +init_module 128 +delete_module 129 +quotactl 131 +getpgid 132 +fchdir 133 +sysfs 135 +personality 136 +setfsuid 138 +setfsgid 139 +_llseek 140 +getdents 141 +_newselect 142 +flock 143 +msync 144 +readv 145 +writev 146 +getsid 147 +fdatasync 148 +_sysctl 149 +mlock 150 +munlock 151 +mlockall 152 +munlockall 153 +sched_setparam 154 +sched_getparam 155 +sched_setscheduler 156 +sched_getscheduler 157 +sched_yield 158 +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_rr_get_interval 161 +nanosleep 162 +mremap 163 +setresuid 164 +getresuid 165 +poll 168 +nfsservctl 169 +setresgid 170 +getresgid 171 +prctl 172 +rt_sigreturn 173 +rt_sigaction 174 +rt_sigprocmask 175 +rt_sigpending 176 +rt_sigtimedwait 177 +rt_sigqueueinfo 178 +rt_sigsuspend 179 +pread64 180 +pwrite64 181 +chown 182 +getcwd 183 +capget 184 +capset 185 +sigaltstack 186 +sendfile 187 +vfork 190 +ugetrlimit 191 +mmap2 192 +truncate64 193 +ftruncate64 194 +stat64 195 +lstat64 196 +fstat64 197 +lchown32 198 +getuid32 199 +getgid32 200 +geteuid32 201 +getegid32 202 +setreuid32 203 +setregid32 204 +getgroups32 205 +setgroups32 206 +fchown32 207 +setresuid32 208 +getresuid32 209 +setresgid32 210 +getresgid32 211 +chown32 212 +setuid32 213 +setgid32 214 +setfsuid32 215 +setfsgid32 216 +pivot_root 217 +mincore 218 +madvise 219 +getdents64 220 +fcntl64 221 +gettid 224 +readahead 225 +setxattr 226 +lsetxattr 227 +fsetxattr 228 +getxattr 229 +lgetxattr 230 +fgetxattr 231 +listxattr 232 +llistxattr 233 +flistxattr 234 +removexattr 235 +lremovexattr 236 +fremovexattr 237 +tkill 238 +sendfile64 239 +futex 240 +sched_setaffinity 241 +sched_getaffinity 242 +io_setup 245 +io_destroy 246 +io_getevents 247 +io_submit 248 +io_cancel 249 +fadvise64 250 +exit_group 252 +lookup_dcookie 253 +epoll_create 254 +epoll_ctl 255 +epoll_wait 256 +remap_file_pages 257 +set_tid_address 258 +timer_create 259 +timer_settime 260 +timer_gettime 261 +timer_getoverrun 262 +timer_delete 263 +clock_settime 264 +clock_gettime 265 +clock_getres 266 +clock_nanosleep 267 +statfs64 268 +fstatfs64 269 +tgkill 270 +utimes 271 +fadvise64_64 272 +mbind 274 +get_mempolicy 275 +set_mempolicy 276 +mq_open 277 +mq_unlink 278 +mq_timedsend 279 +mq_timedreceive 280 +mq_notify 281 +mq_getsetattr 282 +kexec_load 283 +waitid 284 +add_key 285 +request_key 286 +keyctl 287 +ioprio_set 288 +ioprio_get 289 +inotify_init 290 +inotify_add_watch 291 +inotify_rm_watch 292 +migrate_pages 294 +openat 295 +mkdirat 296 +mknodat 297 +fchownat 298 +futimesat 299 +fstatat64 300 +unlinkat 301 +renameat 302 +linkat 303 +symlinkat 304 +readlinkat 305 +fchmodat 306 +faccessat 307 +pselect6 308 +ppoll 309 +unshare 310 +set_robust_list 311 +get_robust_list 312 +splice 313 +sync_file_range 314 +tee 315 +vmsplice 316 +move_pages 317 +getcpu 318 +epoll_pwait 319 +utimensat 320 +signalfd 321 +timerfd_create 322 +eventfd 323 +fallocate 324 +timerfd_settime 325 +timerfd_gettime 326 +signalfd4 327 +eventfd2 328 +epoll_create1 329 +dup3 330 +pipe2 331 +inotify_init1 332 +preadv 333 +pwritev 334 +rt_tgsigqueueinfo 335 +perf_event_open 336 +fanotify_init 337 +fanotify_mark 338 +prlimit64 339 +socket 340 +bind 341 +connect 342 +listen 343 +accept 344 +getsockname 345 +getpeername 346 +socketpair 347 +send 348 +sendto 349 +recv 350 +recvfrom 351 +shutdown 352 +setsockopt 353 +getsockopt 354 +sendmsg 355 +recvmsg 356 +recvmmsg 357 +accept4 358 +name_to_handle_at 359 +open_by_handle_at 360 +clock_adjtime 361 +syncfs 362 +sendmmsg 363 +setns 364 +process_vm_readv 365 +process_vm_writev 366 +kcmp 367 +finit_module 368 +sched_getattr 369 +sched_setattr 370 +renameat2 371 +seccomp 372 +getrandom 373 +memfd_create 374 +bpf 375 +execveat 376 +userfaultfd 377 +membarrier 378 +mlock2 379 +copy_file_range 380 +preadv2 381 +pwritev2 382 +statx 383 +pkey_mprotect 384 +pkey_alloc 385 +pkey_free 386 +rseq 387 +sync_file_range2 388 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/sparc.in b/ltp/include/lapi/syscalls/sparc.in new file mode 100644 index 0000000000000000000000000000000000000000..fcdb9b812ee6844d4981550f3eeed7ff081852f8 --- /dev/null +++ b/ltp/include/lapi/syscalls/sparc.in @@ -0,0 +1,430 @@ +restart_syscall 0 +exit 1 +fork 2 +read 3 +write 4 +open 5 +close 6 +wait4 7 +creat 8 +link 9 +unlink 10 +execv 11 +chdir 12 +chown 13 +mknod 14 +chmod 15 +lchown 16 +brk 17 +perfctr 18 +lseek 19 +getpid 20 +capget 21 +capset 22 +setuid 23 +getuid 24 +vmsplice 25 +ptrace 26 +alarm 27 +sigaltstack 28 +pause 29 +utime 30 +lchown32 31 +fchown32 32 +access 33 +nice 34 +chown32 35 +sync 36 +kill 37 +stat 38 +sendfile 39 +lstat 40 +dup 41 +pipe 42 +times 43 +getuid32 44 +umount2 45 +setgid 46 +getgid 47 +signal 48 +geteuid 49 +getegid 50 +acct 51 +getgid32 53 +ioctl 54 +reboot 55 +mmap2 56 +symlink 57 +readlink 58 +execve 59 +umask 60 +chroot 61 +fstat 62 +fstat64 63 +getpagesize 64 +msync 65 +vfork 66 +pread64 67 +pwrite64 68 +geteuid32 69 +getegid32 70 +mmap 71 +setreuid32 72 +munmap 73 +mprotect 74 +madvise 75 +vhangup 76 +truncate64 77 +mincore 78 +getgroups 79 +setgroups 80 +getpgrp 81 +setgroups32 82 +setitimer 83 +ftruncate64 84 +swapon 85 +getitimer 86 +setuid32 87 +sethostname 88 +setgid32 89 +dup2 90 +setfsuid32 91 +fcntl 92 +select 93 +setfsgid32 94 +fsync 95 +setpriority 96 +socket 97 +connect 98 +accept 99 +getpriority 100 +rt_sigreturn 101 +rt_sigaction 102 +rt_sigprocmask 103 +rt_sigpending 104 +rt_sigtimedwait 105 +rt_sigqueueinfo 106 +rt_sigsuspend 107 +setresuid32 108 +getresuid32 109 +setresgid32 110 +getresgid32 111 +setregid32 112 +recvmsg 113 +sendmsg 114 +getgroups32 115 +gettimeofday 116 +getrusage 117 +getsockopt 118 +getcwd 119 +readv 120 +writev 121 +settimeofday 122 +fchown 123 +fchmod 124 +recvfrom 125 +setreuid 126 +setregid 127 +rename 128 +truncate 129 +ftruncate 130 +flock 131 +lstat64 132 +sendto 133 +shutdown 134 +socketpair 135 +mkdir 136 +rmdir 137 +utimes 138 +stat64 139 +sendfile64 140 +getpeername 141 +futex 142 +gettid 143 +getrlimit 144 +setrlimit 145 +pivot_root 146 +prctl 147 +pciconfig_read 148 +pciconfig_write 149 +getsockname 150 +inotify_init 151 +inotify_add_watch 152 +poll 153 +getdents64 154 +fcntl64 155 +inotify_rm_watch 156 +statfs 157 +fstatfs 158 +umount 159 +sched_set_affinity 160 +sched_get_affinity 161 +getdomainname 162 +setdomainname 163 +quotactl 165 +set_tid_address 166 +mount 167 +ustat 168 +setxattr 169 +lsetxattr 170 +fsetxattr 171 +getxattr 172 +lgetxattr 173 +getdents 174 +setsid 175 +fchdir 176 +fgetxattr 177 +listxattr 178 +llistxattr 179 +flistxattr 180 +removexattr 181 +lremovexattr 182 +sigpending 183 +query_module 184 +setpgid 185 +fremovexattr 186 +tkill 187 +exit_group 188 +uname 189 +init_module 190 +personality 191 +remap_file_pages 192 +epoll_create 193 +epoll_ctl 194 +epoll_wait 195 +ioprio_set 196 +getppid 197 +sigaction 198 +sgetmask 199 +ssetmask 200 +sigsuspend 201 +oldlstat 202 +uselib 203 +readdir 204 +readahead 205 +socketcall 206 +syslog 207 +lookup_dcookie 208 +fadvise64 209 +fadvise64_64 210 +tgkill 211 +waitpid 212 +swapoff 213 +sysinfo 214 +ipc 215 +sigreturn 216 +clone 217 +ioprio_get 218 +adjtimex 219 +sigprocmask 220 +create_module 221 +delete_module 222 +get_kernel_syms 223 +getpgid 224 +sysfs 226 +afs_syscall 227 +setfsuid 228 +setfsgid 229 +_newselect 230 +time 231 +splice 232 +stime 233 +statfs64 234 +fstatfs64 235 +_llseek 236 +mlock 237 +munlock 238 +mlockall 239 +munlockall 240 +sched_setparam 241 +sched_getparam 242 +sched_setscheduler 243 +sched_getscheduler 244 +sched_yield 245 +sched_get_priority_max 246 +sched_get_priority_min 247 +sched_rr_get_interval 248 +nanosleep 249 +mremap 250 +_sysctl 251 +getsid 252 +fdatasync 253 +nfsservctl 254 +sync_file_range 255 +clock_settime 256 +clock_gettime 257 +clock_getres 258 +clock_nanosleep 259 +sched_getaffinity 260 +sched_setaffinity 261 +timer_settime 262 +timer_gettime 263 +timer_getoverrun 264 +timer_delete 265 +timer_create 266 +vserver 267 +io_setup 268 +io_destroy 269 +io_submit 270 +io_cancel 271 +io_getevents 272 +mq_open 273 +mq_unlink 274 +mq_timedsend 275 +mq_timedreceive 276 +mq_notify 277 +mq_getsetattr 278 +waitid 279 +tee 280 +add_key 281 +request_key 282 +keyctl 283 +openat 284 +mkdirat 285 +mknodat 286 +fchownat 287 +futimesat 288 +fstatat64 289 +unlinkat 290 +renameat 291 +linkat 292 +symlinkat 293 +readlinkat 294 +fchmodat 295 +faccessat 296 +pselect6 297 +ppoll 298 +unshare 299 +set_robust_list 300 +get_robust_list 301 +migrate_pages 302 +mbind 303 +get_mempolicy 304 +set_mempolicy 305 +kexec_load 306 +move_pages 307 +getcpu 308 +epoll_pwait 309 +utimensat 310 +signalfd 311 +timerfd_create 312 +eventfd 313 +fallocate 314 +timerfd_settime 315 +timerfd_gettime 316 +signalfd4 317 +eventfd2 318 +epoll_create1 319 +dup3 320 +pipe2 321 +inotify_init1 322 +accept4 323 +preadv 324 +pwritev 325 +rt_tgsigqueueinfo 326 +perf_event_open 327 +recvmmsg 328 +fanotify_init 329 +fanotify_mark 330 +prlimit64 331 +name_to_handle_at 332 +open_by_handle_at 333 +clock_adjtime 334 +syncfs 335 +sendmmsg 336 +setns 337 +process_vm_readv 338 +process_vm_writev 339 +kern_features 340 +kcmp 341 +finit_module 342 +sched_setattr 343 +sched_getattr 344 +renameat2 345 +seccomp 346 +getrandom 347 +memfd_create 348 +bpf 349 +execveat 350 +membarrier 351 +userfaultfd 352 +bind 353 +listen 354 +setsockopt 355 +mlock2 356 +copy_file_range 357 +preadv2 358 +pwritev2 359 +statx 360 +io_pgetevents 361 +pkey_mprotect 362 +pkey_alloc 363 +pkey_free 364 +rseq 365 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/sparc64.in b/ltp/include/lapi/syscalls/sparc64.in new file mode 100644 index 0000000000000000000000000000000000000000..4256aaf77674ed0c00bbd092d7c715038e52f1c3 --- /dev/null +++ b/ltp/include/lapi/syscalls/sparc64.in @@ -0,0 +1,393 @@ +restart_syscall 0 +exit 1 +fork 2 +read 3 +write 4 +open 5 +close 6 +wait4 7 +creat 8 +link 9 +unlink 10 +execv 11 +chdir 12 +chown 13 +mknod 14 +chmod 15 +lchown 16 +brk 17 +perfctr 18 +lseek 19 +getpid 20 +capget 21 +capset 22 +setuid 23 +getuid 24 +vmsplice 25 +ptrace 26 +alarm 27 +sigaltstack 28 +pause 29 +utime 30 +access 33 +nice 34 +sync 36 +kill 37 +stat 38 +sendfile 39 +lstat 40 +dup 41 +pipe 42 +times 43 +umount2 45 +setgid 46 +getgid 47 +signal 48 +geteuid 49 +getegid 50 +acct 51 +memory_ordering 52 +ioctl 54 +reboot 55 +symlink 57 +readlink 58 +execve 59 +umask 60 +chroot 61 +fstat 62 +fstat64 63 +getpagesize 64 +msync 65 +vfork 66 +pread64 67 +pwrite64 68 +mmap 71 +munmap 73 +mprotect 74 +madvise 75 +vhangup 76 +mincore 78 +getgroups 79 +setgroups 80 +getpgrp 81 +setitimer 83 +swapon 85 +getitimer 86 +sethostname 88 +dup2 90 +fcntl 92 +select 93 +fsync 95 +setpriority 96 +socket 97 +connect 98 +accept 99 +getpriority 100 +rt_sigreturn 101 +rt_sigaction 102 +rt_sigprocmask 103 +rt_sigpending 104 +rt_sigtimedwait 105 +rt_sigqueueinfo 106 +rt_sigsuspend 107 +setresuid 108 +getresuid 109 +setresgid 110 +getresgid 111 +recvmsg 113 +sendmsg 114 +gettimeofday 116 +getrusage 117 +getsockopt 118 +getcwd 119 +readv 120 +writev 121 +settimeofday 122 +fchown 123 +fchmod 124 +recvfrom 125 +setreuid 126 +setregid 127 +rename 128 +truncate 129 +ftruncate 130 +flock 131 +lstat64 132 +sendto 133 +shutdown 134 +socketpair 135 +mkdir 136 +rmdir 137 +utimes 138 +stat64 139 +sendfile64 140 +getpeername 141 +futex 142 +gettid 143 +getrlimit 144 +setrlimit 145 +pivot_root 146 +prctl 147 +pciconfig_read 148 +pciconfig_write 149 +getsockname 150 +inotify_init 151 +inotify_add_watch 152 +poll 153 +getdents64 154 +inotify_rm_watch 156 +statfs 157 +fstatfs 158 +umount 159 +sched_set_affinity 160 +sched_get_affinity 161 +getdomainname 162 +setdomainname 163 +utrap_install 164 +quotactl 165 +set_tid_address 166 +mount 167 +ustat 168 +setxattr 169 +lsetxattr 170 +fsetxattr 171 +getxattr 172 +lgetxattr 173 +getdents 174 +setsid 175 +fchdir 176 +fgetxattr 177 +listxattr 178 +llistxattr 179 +flistxattr 180 +removexattr 181 +lremovexattr 182 +sigpending 183 +query_module 184 +setpgid 185 +fremovexattr 186 +tkill 187 +exit_group 188 +uname 189 +init_module 190 +personality 191 +remap_file_pages 192 +epoll_create 193 +epoll_ctl 194 +epoll_wait 195 +ioprio_set 196 +getppid 197 +sigaction 198 +sgetmask 199 +ssetmask 200 +sigsuspend 201 +oldlstat 202 +uselib 203 +readdir 204 +readahead 205 +socketcall 206 +syslog 207 +lookup_dcookie 208 +fadvise64 209 +fadvise64_64 210 +tgkill 211 +waitpid 212 +swapoff 213 +sysinfo 214 +ipc 215 +sigreturn 216 +clone 217 +ioprio_get 218 +adjtimex 219 +sigprocmask 220 +create_module 221 +delete_module 222 +get_kernel_syms 223 +getpgid 224 +sysfs 226 +afs_syscall 227 +setfsuid 228 +setfsgid 229 +_newselect 230 +splice 232 +stime 233 +statfs64 234 +fstatfs64 235 +_llseek 236 +mlock 237 +munlock 238 +mlockall 239 +munlockall 240 +sched_setparam 241 +sched_getparam 242 +sched_setscheduler 243 +sched_getscheduler 244 +sched_yield 245 +sched_get_priority_max 246 +sched_get_priority_min 247 +sched_rr_get_interval 248 +nanosleep 249 +mremap 250 +_sysctl 251 +getsid 252 +fdatasync 253 +nfsservctl 254 +sync_file_range 255 +clock_settime 256 +clock_gettime 257 +clock_getres 258 +clock_nanosleep 259 +sched_getaffinity 260 +sched_setaffinity 261 +timer_settime 262 +timer_gettime 263 +timer_getoverrun 264 +timer_delete 265 +timer_create 266 +vserver 267 +io_setup 268 +io_destroy 269 +io_submit 270 +io_cancel 271 +io_getevents 272 +mq_open 273 +mq_unlink 274 +mq_timedsend 275 +mq_timedreceive 276 +mq_notify 277 +mq_getsetattr 278 +waitid 279 +tee 280 +add_key 281 +request_key 282 +keyctl 283 +openat 284 +mkdirat 285 +mknodat 286 +fchownat 287 +futimesat 288 +fstatat64 289 +unlinkat 290 +renameat 291 +linkat 292 +symlinkat 293 +readlinkat 294 +fchmodat 295 +faccessat 296 +pselect6 297 +ppoll 298 +unshare 299 +set_robust_list 300 +get_robust_list 301 +migrate_pages 302 +mbind 303 +get_mempolicy 304 +set_mempolicy 305 +kexec_load 306 +move_pages 307 +getcpu 308 +epoll_pwait 309 +utimensat 310 +signalfd 311 +timerfd_create 312 +eventfd 313 +fallocate 314 +timerfd_settime 315 +timerfd_gettime 316 +signalfd4 317 +eventfd2 318 +epoll_create1 319 +dup3 320 +pipe2 321 +inotify_init1 322 +accept4 323 +preadv 324 +pwritev 325 +rt_tgsigqueueinfo 326 +perf_event_open 327 +recvmmsg 328 +fanotify_init 329 +fanotify_mark 330 +prlimit64 331 +name_to_handle_at 332 +open_by_handle_at 333 +clock_adjtime 334 +syncfs 335 +sendmmsg 336 +setns 337 +process_vm_readv 338 +process_vm_writev 339 +kern_features 340 +kcmp 341 +finit_module 342 +sched_setattr 343 +sched_getattr 344 +renameat2 345 +seccomp 346 +getrandom 347 +memfd_create 348 +bpf 349 +execveat 350 +membarrier 351 +userfaultfd 352 +bind 353 +listen 354 +setsockopt 355 +mlock2 356 +copy_file_range 357 +preadv2 358 +pwritev2 359 +statx 360 +io_pgetevents 361 +pkey_mprotect 362 +pkey_alloc 363 +pkey_free 364 +rseq 365 +semtimedop 392 +semget 393 +semctl 394 +shmget 395 +shmctl 396 +shmat 397 +shmdt 398 +msgget 399 +msgsnd 400 +msgrcv 401 +msgctl 402 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/syscalls/supported-arch.txt b/ltp/include/lapi/syscalls/supported-arch.txt new file mode 100644 index 0000000000000000000000000000000000000000..c5c5191ac08482d89f0a8c39dfae936538f58f7f --- /dev/null +++ b/ltp/include/lapi/syscalls/supported-arch.txt @@ -0,0 +1,18 @@ +arc +arm64 +arm +i386 +ia64 +loongarch64 +mips64n32 +mips64 +mipso32 +parisc +powerpc64 +powerpc +s390x +s390 +sh +sparc64 +sparc +x86_64 diff --git a/ltp/include/lapi/syscalls/x86_64.in b/ltp/include/lapi/syscalls/x86_64.in new file mode 100644 index 0000000000000000000000000000000000000000..e6c0a3b4047d60e0e372c023c8f6a9bab76697af --- /dev/null +++ b/ltp/include/lapi/syscalls/x86_64.in @@ -0,0 +1,375 @@ +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 +rt_sigreturn 15 +ioctl 16 +pread64 17 +pwrite64 18 +readv 19 +writev 20 +access 21 +pipe 22 +select 23 +sched_yield 24 +mremap 25 +msync 26 +mincore 27 +madvise 28 +shmget 29 +shmat 30 +shmctl 31 +dup 32 +dup2 33 +pause 34 +nanosleep 35 +getitimer 36 +alarm 37 +setitimer 38 +getpid 39 +sendfile 40 +socket 41 +connect 42 +accept 43 +sendto 44 +recvfrom 45 +sendmsg 46 +recvmsg 47 +shutdown 48 +bind 49 +listen 50 +getsockname 51 +getpeername 52 +socketpair 53 +setsockopt 54 +getsockopt 55 +clone 56 +fork 57 +vfork 58 +execve 59 +exit 60 +wait4 61 +kill 62 +uname 63 +semget 64 +semop 65 +semctl 66 +shmdt 67 +msgget 68 +msgsnd 69 +msgrcv 70 +msgctl 71 +fcntl 72 +flock 73 +fsync 74 +fdatasync 75 +truncate 76 +ftruncate 77 +getdents 78 +getcwd 79 +chdir 80 +fchdir 81 +rename 82 +mkdir 83 +rmdir 84 +creat 85 +link 86 +unlink 87 +symlink 88 +readlink 89 +chmod 90 +fchmod 91 +chown 92 +fchown 93 +lchown 94 +umask 95 +gettimeofday 96 +getrlimit 97 +getrusage 98 +sysinfo 99 +times 100 +ptrace 101 +getuid 102 +syslog 103 +getgid 104 +setuid 105 +setgid 106 +geteuid 107 +getegid 108 +setpgid 109 +getppid 110 +getpgrp 111 +setsid 112 +setreuid 113 +setregid 114 +getgroups 115 +setgroups 116 +setresuid 117 +getresuid 118 +setresgid 119 +getresgid 120 +getpgid 121 +setfsuid 122 +setfsgid 123 +getsid 124 +capget 125 +capset 126 +rt_sigpending 127 +rt_sigtimedwait 128 +rt_sigqueueinfo 129 +rt_sigsuspend 130 +sigaltstack 131 +utime 132 +mknod 133 +uselib 134 +personality 135 +ustat 136 +statfs 137 +fstatfs 138 +sysfs 139 +getpriority 140 +setpriority 141 +sched_setparam 142 +sched_getparam 143 +sched_setscheduler 144 +sched_getscheduler 145 +sched_get_priority_max 146 +sched_get_priority_min 147 +sched_rr_get_interval 148 +mlock 149 +munlock 150 +mlockall 151 +munlockall 152 +vhangup 153 +modify_ldt 154 +pivot_root 155 +_sysctl 156 +prctl 157 +arch_prctl 158 +adjtimex 159 +setrlimit 160 +chroot 161 +sync 162 +acct 163 +settimeofday 164 +mount 165 +umount2 166 +swapon 167 +swapoff 168 +reboot 169 +sethostname 170 +setdomainname 171 +iopl 172 +ioperm 173 +create_module 174 +init_module 175 +delete_module 176 +get_kernel_syms 177 +query_module 178 +quotactl 179 +nfsservctl 180 +getpmsg 181 +putpmsg 182 +afs_syscall 183 +tuxcall 184 +security 185 +gettid 186 +readahead 187 +setxattr 188 +lsetxattr 189 +fsetxattr 190 +getxattr 191 +lgetxattr 192 +fgetxattr 193 +listxattr 194 +llistxattr 195 +flistxattr 196 +removexattr 197 +lremovexattr 198 +fremovexattr 199 +tkill 200 +time 201 +futex 202 +sched_setaffinity 203 +sched_getaffinity 204 +set_thread_area 205 +io_setup 206 +io_destroy 207 +io_getevents 208 +io_submit 209 +io_cancel 210 +get_thread_area 211 +lookup_dcookie 212 +epoll_create 213 +epoll_ctl_old 214 +epoll_wait_old 215 +remap_file_pages 216 +getdents64 217 +set_tid_address 218 +restart_syscall 219 +semtimedop 220 +fadvise64 221 +timer_create 222 +timer_settime 223 +timer_gettime 224 +timer_getoverrun 225 +timer_delete 226 +clock_settime 227 +clock_gettime 228 +clock_getres 229 +clock_nanosleep 230 +exit_group 231 +epoll_wait 232 +epoll_ctl 233 +tgkill 234 +utimes 235 +vserver 236 +mbind 237 +set_mempolicy 238 +get_mempolicy 239 +mq_open 240 +mq_unlink 241 +mq_timedsend 242 +mq_timedreceive 243 +mq_notify 244 +mq_getsetattr 245 +kexec_load 246 +waitid 247 +add_key 248 +request_key 249 +keyctl 250 +ioprio_set 251 +ioprio_get 252 +inotify_init 253 +inotify_add_watch 254 +inotify_rm_watch 255 +migrate_pages 256 +openat 257 +mkdirat 258 +mknodat 259 +fchownat 260 +futimesat 261 +newfstatat 262 +unlinkat 263 +renameat 264 +linkat 265 +symlinkat 266 +readlinkat 267 +fchmodat 268 +faccessat 269 +pselect6 270 +ppoll 271 +unshare 272 +set_robust_list 273 +get_robust_list 274 +splice 275 +tee 276 +sync_file_range 277 +vmsplice 278 +move_pages 279 +utimensat 280 +epoll_pwait 281 +signalfd 282 +timerfd_create 283 +eventfd 284 +fallocate 285 +timerfd_settime 286 +timerfd_gettime 287 +accept4 288 +signalfd4 289 +eventfd2 290 +epoll_create1 291 +dup3 292 +pipe2 293 +inotify_init1 294 +preadv 295 +pwritev 296 +rt_tgsigqueueinfo 297 +perf_event_open 298 +recvmmsg 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 +getcpu 309 +process_vm_readv 310 +process_vm_writev 311 +kcmp 312 +finit_module 313 +sched_setattr 314 +sched_getattr 315 +renameat2 316 +seccomp 317 +getrandom 318 +memfd_create 319 +kexec_file_load 320 +bpf 321 +execveat 322 +userfaultfd 323 +membarrier 324 +mlock2 325 +copy_file_range 326 +preadv2 327 +pwritev2 328 +pkey_mprotect 329 +pkey_alloc 330 +pkey_free 331 +statx 332 +io_pgetevents 333 +rseq 334 +uretprobe 335 +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 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +memfd_secret 447 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 +cachestat 451 +fchmodat2 452 +map_shadow_stack 453 +futex_wake 454 +futex_wait 455 +futex_requeue 456 +statmount 457 +listmount 458 +lsm_get_self_attr 459 +lsm_set_self_attr 460 +lsm_list_modules 461 +mseal 462 diff --git a/ltp/include/lapi/tcp.h b/ltp/include/lapi/tcp.h new file mode 100644 index 0000000000000000000000000000000000000000..87c5636f6feda9b5acd56208ebdda53ea791afb3 --- /dev/null +++ b/ltp/include/lapi/tcp.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Petr Vorel + */ + +#ifndef LAPI_TCP_H__ +#define LAPI_TCP_H__ + +#include + +#ifndef TCP_FASTOPEN +# define TCP_FASTOPEN 23 +#endif + +#ifndef TCP_ULP +# define TCP_ULP 31 +#endif + +#ifndef TCP_FASTOPEN_CONNECT +# define TCP_FASTOPEN_CONNECT 30 /* Attempt FastOpen with connect */ +#endif + +#endif /* LAPI_TCP_H__ */ diff --git a/ltp/include/lapi/tee.h b/ltp/include/lapi/tee.h new file mode 100644 index 0000000000000000000000000000000000000000..8ba3c9be36f744e4e935d3711412104f96d29b19 --- /dev/null +++ b/ltp/include/lapi/tee.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2007 + * Copyright (c) 2014 Fujitsu Ltd. + */ + +#ifndef LAPI_TEE_H__ +#define LAPI_TEE_H__ + +#include "config.h" +#include "lapi/syscalls.h" + +#if !defined(HAVE_TEE) +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 /* LAPI_TEE_H__ */ diff --git a/ltp/include/lapi/termbits.h b/ltp/include/lapi/termbits.h new file mode 100644 index 0000000000000000000000000000000000000000..04f5148181ae00e1d54ed76796d9e56e7b656b6f --- /dev/null +++ b/ltp/include/lapi/termbits.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Linux Test Project + */ + +#ifndef LAPI_TERMBITS_H__ +#define LAPI_TERMBITS_H__ + +#ifndef EXTPROC +# define EXTPROC 0200000 +#endif + +#endif /* LAPI_TERMBITS_H__ */ diff --git a/ltp/include/lapi/timerfd.h b/ltp/include/lapi/timerfd.h new file mode 100644 index 0000000000000000000000000000000000000000..2613746ca541ef74fc60f66a720667fb6c51f5ac --- /dev/null +++ b/ltp/include/lapi/timerfd.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2007 + * Copyright (c) 2014 Fujitsu Ltd. + */ + +#ifndef LAPI_TIMERFD_H__ +#define LAPI_TIMERFD_H__ + +#include +#include "config.h" +#include "lapi/syscalls.h" + +#ifdef HAVE_SYS_TIMERFD_H +#include +#endif + +#if !defined(HAVE_TIMERFD_CREATE) +static inline int timerfd_create(int clockid, int flags) +{ + return tst_syscall(__NR_timerfd_create, clockid, flags); +} +#endif + +#if !defined(HAVE_TIMERFD_GETTIME) +static inline int timerfd_settime(int fd, int flags, + const struct itimerspec *new_value, + struct itimerspec *old_value) +{ + return tst_syscall(__NR_timerfd_settime, fd, flags, new_value, + old_value); +} +#endif + +#if !defined(HAVE_TIMERFD_SETTIME) +static inline int timerfd_gettime(int fd, struct itimerspec *curr_value) +{ + return tst_syscall(__NR_timerfd_gettime, fd, curr_value); +} +#endif + +#endif /* LAPI_TIMERFD_H__ */ diff --git a/ltp/include/lapi/timex.h b/ltp/include/lapi/timex.h new file mode 100644 index 0000000000000000000000000000000000000000..c2c9e4d8d43f234e00de1e49b60171ce1da30f9f --- /dev/null +++ b/ltp/include/lapi/timex.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +#ifndef LAPI_TIMEX_H__ +# define LAPI_TIMEX_H__ + +#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | \ + ADJ_ESTERROR | ADJ_STATUS | ADJ_TIMECONST | \ + ADJ_TICK) + +#ifndef ADJ_OFFSET_SS_READ +# define ADJ_OFFSET_SS_READ 0xa001 +#endif + +#ifndef ADJ_NANO +# define ADJ_NANO 0x2000 +#endif + +#ifndef STA_NANO +# define STA_NANO 0x2000 +#endif + +#ifndef ADJ_MICRO +# define ADJ_MICRO 0x1000 +#endif + +#endif/* LAPI_TIMEX_H__ */ diff --git a/ltp/include/lapi/tty.h b/ltp/include/lapi/tty.h new file mode 100644 index 0000000000000000000000000000000000000000..93a6254347c305341ed29b59119a4ae8864e9b48 --- /dev/null +++ b/ltp/include/lapi/tty.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Petr Vorel + */ + +#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__ */ diff --git a/ltp/include/lapi/udp.h b/ltp/include/lapi/udp.h new file mode 100644 index 0000000000000000000000000000000000000000..5c73dd36989c40c6dbb8b90d2f0c5bd8cd986b5d --- /dev/null +++ b/ltp/include/lapi/udp.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Oracle and/or its affiliates. + */ + +#ifndef LAPI_UDP_H__ +#define LAPI_UDP_H__ + +#include + +#ifndef UDPLITE_SEND_CSCOV +# define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */ +#endif +#ifndef UDPLITE_RECV_CSCOV +# define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */ +#endif + +#endif /* LAPI_UDP_H__ */ diff --git a/ltp/include/lapi/uinput.h b/ltp/include/lapi/uinput.h new file mode 100644 index 0000000000000000000000000000000000000000..bdd6f466f7c1ba09b829b3dda83e398ad7928b28 --- /dev/null +++ b/ltp/include/lapi/uinput.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Petr Vorel + */ + +#ifndef LAPI_UINPUT_H__ +#define LAPI_UINPUT_H__ + +#include + +#ifndef UI_GET_SYSNAME +# define UI_GET_SYSNAME(len) _IOC(_IOC_READ, UINPUT_IOCTL_BASE, 44, len) +#endif + +#endif /* LAPI_UINPUT_H__ */ diff --git a/ltp/include/lapi/uio.h b/ltp/include/lapi/uio.h new file mode 100644 index 0000000000000000000000000000000000000000..0ad2faacf8906ddab1911fefa48de52f5684e4ef --- /dev/null +++ b/ltp/include/lapi/uio.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. + * Author: Xiao Yang + */ + +#ifndef LAPI_PREADV2_H__ +#define LAPI_PREADV2_H__ + +#include +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef RWF_NOWAIT +# define RWF_NOWAIT 0x00000008 +#endif + + +/* LO_HI_LONG taken from glibc */ +# define LO_HI_LONG(val) (long) (val), (long) (((uint64_t) (val)) >> 32) + +#if !defined(HAVE_PREADV) +static inline ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, + off_t offset) +{ + return tst_syscall(__NR_preadv, fd, iov, iovcnt, LO_HI_LONG(offset)); +} +#endif + +#if !defined(HAVE_PWRITEV) +static inline ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, + off_t offset) +{ + return tst_syscall(__NR_pwritev, fd, iov, iovcnt, LO_HI_LONG(offset)); +} +#endif + +#if !defined(HAVE_PREADV2) +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 + +#if !defined(HAVE_PWRITEV2) +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 + +#undef LO_HI_LONG + +#endif /* LAPI_PREADV2_H__ */ diff --git a/ltp/include/lapi/userfaultfd.h b/ltp/include/lapi/userfaultfd.h new file mode 100644 index 0000000000000000000000000000000000000000..4d52b7c4bb9d4a495d79932dfd7bf0a9dc7aa214 --- /dev/null +++ b/ltp/include/lapi/userfaultfd.h @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2007 Davide Libenzi + * Copyright (C) 2015,2022 Red Hat, Inc. + * + * Mostly copied/adapted from + */ + +#ifndef LAPI_USERFAULTFD_H__ +#define LAPI_USERFAULTFD_H__ + +#include +#include +#include "lapi/syscalls.h" + +#ifdef HAVE_LINUX_USERFAULTFD_H +#include +#endif + +/* userfaultfd support was added in v4.1 */ +#ifndef UFFD_API +#define UFFD_API ((__u64)0xAA) + +/* + * Valid ioctl command number range with this API is from 0x00 to + * 0x3F. UFFDIO_API is the fixed number, everything else can be + * changed by implementing a different UFFD_API. If sticking to the + * same UFFD_API more ioctl can be added and userland will be aware of + * which ioctl the running kernel implements through the ioctl command + * bitmask written by the UFFDIO_API. + */ +#define _UFFDIO_REGISTER (0x00) +#define _UFFDIO_UNREGISTER (0x01) +#define _UFFDIO_WAKE (0x02) +#define _UFFDIO_COPY (0x03) +#define _UFFDIO_ZEROPAGE (0x04) +#define _UFFDIO_API (0x3F) + +/* userfaultfd ioctl ids */ +#define UFFDIO 0xAA +#define UFFDIO_API _IOWR(UFFDIO, _UFFDIO_API, \ + struct uffdio_api) +#define UFFDIO_REGISTER _IOWR(UFFDIO, _UFFDIO_REGISTER, \ + struct uffdio_register) +#define UFFDIO_UNREGISTER _IOR(UFFDIO, _UFFDIO_UNREGISTER, \ + struct uffdio_range) +#define UFFDIO_WAKE _IOR(UFFDIO, _UFFDIO_WAKE, \ + struct uffdio_range) +#define UFFDIO_COPY _IOWR(UFFDIO, _UFFDIO_COPY, \ + struct uffdio_copy) +#define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ + struct uffdio_zeropage) + +/* read() structure */ +struct uffd_msg { + __u8 event; + + __u8 reserved1; + __u16 reserved2; + __u32 reserved3; + + union { + struct { + __u64 flags; + __u64 address; + } pagefault; + + struct { + /* unused reserved fields */ + __u64 reserved1; + __u64 reserved2; + __u64 reserved3; + } reserved; + } arg; +} __packed; + +/* + * Start at 0x12 and not at 0 to be more strict against bugs. + */ +#define UFFD_EVENT_PAGEFAULT 0x12 + +/* flags for UFFD_EVENT_PAGEFAULT */ +#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ +#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */ + +struct uffdio_api { + /* userland asks for an API number and the features to enable */ + __u64 api; + /* + * Kernel answers below with the all available features for + * the API, this notifies userland of which events and/or + * which flags for each event are enabled in the current + * kernel. + * + * Note: UFFD_EVENT_PAGEFAULT and UFFD_PAGEFAULT_FLAG_WRITE + * are to be considered implicitly always enabled in all kernels as + * long as the uffdio_api.api requested matches UFFD_API. + */ + __u64 features; + + __u64 ioctls; +}; + +struct uffdio_range { + __u64 start; + __u64 len; +}; + +struct uffdio_register { + struct uffdio_range range; +#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0) +#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1) + __u64 mode; + + /* + * kernel answers which ioctl commands are available for the + * range, keep at the end as the last 8 bytes aren't read. + */ + __u64 ioctls; +}; + +struct uffdio_copy { + __u64 dst; + __u64 src; + __u64 len; + /* + * There will be a wrprotection flag later that allows to map + * pages wrprotected on the fly. And such a flag will be + * available if the wrprotection ioctl are implemented for the + * range according to the uffdio_register.ioctls. + */ +#define UFFDIO_COPY_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "copy" is written by the ioctl and must be at the end: the + * copy_from_user will not read the last 8 bytes. + */ + __s64 copy; +}; + +struct uffdio_zeropage { + struct uffdio_range range; +#define UFFDIO_ZEROPAGE_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "zeropage" is written by the ioctl and must be at the end: + * the copy_from_user will not read the last 8 bytes. + */ + __s64 zeropage; +}; +#endif /* UFFD_API */ + + +/* UFFD_USER_MODE_ONLY was added in v5.11 */ +#ifndef UFFD_USER_MODE_ONLY +#define UFFD_USER_MODE_ONLY 1 +#endif /* UFFD_USER_MODE_ONLY */ + + +/* UFFD_PAGEFAULT_FLAG_MINOR and UFFDIO_CONTINUE were added in v5.13 */ +#ifndef UFFD_PAGEFAULT_FLAG_MINOR +#define UFFD_FEATURE_MINOR_HUGETLBFS (1<<9) +#define UFFDIO_REGISTER_MODE_MINOR ((__u64)1<<2) + +#define _UFFDIO_CONTINUE (0x07) +#define UFFDIO_CONTINUE _IOWR(UFFDIO, _UFFDIO_CONTINUE, \ + struct uffdio_continue) + +struct uffdio_continue { + struct uffdio_range range; +#define UFFDIO_CONTINUE_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * Fields below here are written by the ioctl and must be at the end: + * the copy_from_user will not read past here. + */ + __s64 mapped; +}; +#endif /* UFFD_PAGEFAULT_FLAG_MINOR */ + + +/* UFFD_FEATURE_MINOR_SHMEM was added in v5.14 */ +#ifndef UFFD_FEATURE_MINOR_SHMEM +#define UFFD_FEATURE_MINOR_SHMEM (1<<10) +#endif /* UFFD_FEATURE_MINOR_SHMEM */ + +#endif /* LAPI_USERFAULTFD_H__ */ diff --git a/ltp/include/lapi/ustat.h b/ltp/include/lapi/ustat.h new file mode 100644 index 0000000000000000000000000000000000000000..218a53b14b000d6fdd09ba78f6d16ae5a102750b --- /dev/null +++ b/ltp/include/lapi/ustat.h @@ -0,0 +1,22 @@ +//SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef LAPI_USTAT_H__ +#define LAPI_USTAT_H__ + +#include "config.h" + +#include + +#ifdef HAVE_SYS_USTAT_H +# include +#elif HAVE_LINUX_TYPES_H +# include +struct ustat { + __kernel_daddr_t f_tfree; + ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; +#endif + +#endif /* LAPI_USTAT_H__ */ diff --git a/ltp/include/lapi/utime.h b/ltp/include/lapi/utime.h new file mode 100644 index 0000000000000000000000000000000000000000..a8085ae0a910831b83a9360274bbb99395ed29a6 --- /dev/null +++ b/ltp/include/lapi/utime.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + */ + +#ifndef LAPI_UTIME_H__ +#define LAPI_UTIME_H__ + +#ifndef UTIME_NOW +# define UTIME_NOW ((1l << 30) - 1l) +#endif + +#ifndef UTIME_OMIT +# define UTIME_OMIT ((1l << 30) - 2l) +#endif + +#endif /* LAPI_UTIME_H__ */ diff --git a/ltp/include/lapi/utsname.h b/ltp/include/lapi/utsname.h new file mode 100644 index 0000000000000000000000000000000000000000..f94d3e1e3298be748fe83a7093e7ec9d974ae48c --- /dev/null +++ b/ltp/include/lapi/utsname.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Petr Vorel + */ + +#ifndef LAPI_UTSNAME_H__ +#define LAPI_UTSNAME_H__ + +#ifdef HAVE_SYS_UTSNAME_H +# include +#endif + +#ifndef _UTSNAME_LENGTH +# define _UTSNAME_LENGTH 65 +#endif + +#ifndef _UTSNAME_DOMAIN_LENGTH +# define _UTSNAME_DOMAIN_LENGTH _UTSNAME_LENGTH +#endif + +#endif /* LAPI_UTSNAME_H__ */ diff --git a/ltp/include/lapi/vm_sockets.h b/ltp/include/lapi/vm_sockets.h new file mode 100644 index 0000000000000000000000000000000000000000..07884e538688569b5325b251fd629f20e44c1cdb --- /dev/null +++ b/ltp/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/ltp/include/lapi/vmsplice.h b/ltp/include/lapi/vmsplice.h new file mode 100644 index 0000000000000000000000000000000000000000..b6db77cb9e9bcad6960b572958fb73e3d4c6a24a --- /dev/null +++ b/ltp/include/lapi/vmsplice.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2007 + * Copyright (c) 2014 Cyril Hrubis + */ + +#ifndef LAPI_VMSPLICE_H__ +#define LAPI_VMSPLICE_H__ + +#include "config.h" +#include "lapi/syscalls.h" + +#include "lapi/iovec.h" + +#if !defined(HAVE_VMSPLICE) +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 /* LAPI_VMSPLICE_H__ */ diff --git a/ltp/include/lapi/watch_queue.h b/ltp/include/lapi/watch_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..438e62239f933ca5c87ddab248752baf121dd868 --- /dev/null +++ b/ltp/include/lapi/watch_queue.h @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + * + * This file is created to resolve conflicts between user space and kernel + * space fctnl.h declaration. linux/watch_queue.h is not handled, since + * user space fcntl.h redefines kernel space structures. + */ + +#ifndef LAPI_WATCH_QUEUE_H__ +#define LAPI_WATCH_QUEUE_H__ + +#include +#include "lapi/ioctl.h" +#include "lapi/fcntl.h" + +#define O_NOTIFICATION_PIPE O_EXCL /* Parameter to pipe2() selecting notification pipe */ + +#define IOC_WATCH_QUEUE_SET_SIZE _IO('W', 0x60) /* Set the size in pages */ +#define IOC_WATCH_QUEUE_SET_FILTER _IO('W', 0x61) /* Set the filter */ + +enum watch_notification_type { + WATCH_TYPE_META = 0, /* Special record */ + WATCH_TYPE_KEY_NOTIFY = 1, /* Key change event notification */ + WATCH_TYPE__NR = 2 +}; + +enum watch_meta_notification_subtype { + WATCH_META_REMOVAL_NOTIFICATION = 0, /* Watched object was removed */ + WATCH_META_LOSS_NOTIFICATION = 1, /* Data loss occurred */ +}; + +/* + * Notification record header. This is aligned to 64-bits so that subclasses + * can contain __u64 fields. + */ +struct watch_notification { + uint32_t type:24; /* enum watch_notification_type */ + uint32_t subtype:8; /* Type-specific subtype (filterable) */ + uint32_t info; +#define WATCH_INFO_LENGTH 0x0000007f /* Length of record */ +#define WATCH_INFO_LENGTH__SHIFT 0 +#define WATCH_INFO_ID 0x0000ff00 /* ID of watchpoint */ +#define WATCH_INFO_ID__SHIFT 8 +#define WATCH_INFO_TYPE_INFO 0xffff0000 /* Type-specific info */ +#define WATCH_INFO_TYPE_INFO__SHIFT 16 +#define WATCH_INFO_FLAG_0 0x00010000 /* Type-specific info, flag bit 0 */ +#define WATCH_INFO_FLAG_1 0x00020000 /* ... */ +#define WATCH_INFO_FLAG_2 0x00040000 +#define WATCH_INFO_FLAG_3 0x00080000 +#define WATCH_INFO_FLAG_4 0x00100000 +#define WATCH_INFO_FLAG_5 0x00200000 +#define WATCH_INFO_FLAG_6 0x00400000 +#define WATCH_INFO_FLAG_7 0x00800000 +}; + +/* + * Notification filtering rules (IOC_WATCH_QUEUE_SET_FILTER). + */ +struct watch_notification_type_filter { + uint32_t type; /* Type to apply filter to */ + uint32_t info_filter; /* Filter on watch_notification::info */ + uint32_t info_mask; /* Mask of relevant bits in info_filter */ + uint32_t subtype_filter[8]; /* Bitmask of subtypes to filter on */ +}; + +struct watch_notification_filter { + uint32_t nr_filters; /* Number of filters */ + uint32_t __reserved; /* Must be 0 */ + struct watch_notification_type_filter filters[]; +}; + + +/* + * Extended watch removal notification. This is used optionally if the type + * wants to indicate an identifier for the object being watched, if there is + * such. This can be distinguished by the length. + * + * type -> WATCH_TYPE_META + * subtype -> WATCH_META_REMOVAL_NOTIFICATION + */ +struct watch_notification_removal { + struct watch_notification watch; + uint64_t id; /* Type-dependent identifier */ +}; + +/* + * Type of key/keyring change notification. + */ +enum key_notification_subtype { + NOTIFY_KEY_INSTANTIATED = 0, /* Key was instantiated (aux is error code) */ + NOTIFY_KEY_UPDATED = 1, /* Key was updated */ + NOTIFY_KEY_LINKED = 2, /* Key (aux) was added to watched keyring */ + NOTIFY_KEY_UNLINKED = 3, /* Key (aux) was removed from watched keyring */ + NOTIFY_KEY_CLEARED = 4, /* Keyring was cleared */ + NOTIFY_KEY_REVOKED = 5, /* Key was revoked */ + NOTIFY_KEY_INVALIDATED = 6, /* Key was invalidated */ + NOTIFY_KEY_SETATTR = 7, /* Key's attributes got changed */ +}; + +/* + * Key/keyring notification record. + * - watch.type = WATCH_TYPE_KEY_NOTIFY + * - watch.subtype = enum key_notification_type + */ +struct key_notification { + struct watch_notification watch; + uint32_t key_id; /* The key/keyring affected */ + uint32_t aux; /* Per-type auxiliary data */ +}; + +#endif /* LAPI_WATCH_QUEUE_H__ */ diff --git a/ltp/include/lapi/xfrm.h b/ltp/include/lapi/xfrm.h new file mode 100644 index 0000000000000000000000000000000000000000..48503b7ef1bac5040b3c2861ad4b5620a9ed6e07 --- /dev/null +++ b/ltp/include/lapi/xfrm.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Linux Test Project + */ + +#ifndef LAPI_XFRM_H__ +#define LAPI_XFRM_H__ + +#ifndef XFRMNLGRP_NONE +# define XFRMNLGRP_NONE 0 +#endif + +#ifndef XFRM_MSG_GETPOLICY +# define XFRM_MSG_GETPOLICY 21 +#endif + +#endif /* LAPI_XFRM_H__ */ diff --git a/ltp/include/libmsgctl.h b/ltp/include/libmsgctl.h new file mode 100644 index 0000000000000000000000000000000000000000..e1afeab5f82d9e73227734e79c89a32fb85c8a24 --- /dev/null +++ b/ltp/include/libmsgctl.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * + * 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 would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __LIBMSGCTL_H__ +#define __LIBMSGCTL_H__ + +#define FAIL 1 +#define PASS 0 + +struct mbuffer { + long type; + struct { + char len; + char pbytes[99]; + } data; +}; + +int doreader(long key, int tid, long type, int child, int nreps); +int dowriter(long key, int tid, long type, int child, int nreps); +int fill_buffer(char *buf, char val, int size); +int verify(char *buf, char val, int size, int child); + +#endif /*__LIBMSGCTL_H__ */ diff --git a/ltp/include/libnewipc.h b/ltp/include/libnewipc.h new file mode 100644 index 0000000000000000000000000000000000000000..969c93292c8f12a18b300ebc163da13d212e9f8c --- /dev/null +++ b/ltp/include/libnewipc.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 Xiao Yang + * + * 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. + */ + +/* + * common definitions for the IPC system calls. + */ + +#ifndef __LIBNEWIPC_H +#define __LIBNEWIPC_H 1 + +#include +#include + +#define MSG_RD 0400 +#define MSG_WR 0200 +#define MSG_RW (MSG_RD | MSG_WR) +#define MSGSIZE 1024 +#define MSGTYPE 1 +#define NR_MSGQUEUES 16 + +#define SEM_RD 0400 +#define SEM_ALT 0200 +#define SEM_RA (SEM_RD | SEM_ALT) +#define PSEMS 10 + +#define SHM_RD 0400 +#define SHM_WR 0200 +#define SHM_RW (SHM_RD | SHM_WR) +#define SHM_SIZE 2048 +#define INT_SIZE 4 +#define MODE_MASK 0x01FF + +key_t getipckey(const char *file, const int lineno); +#define GETIPCKEY() \ + getipckey(__FILE__, __LINE__) + +int get_used_sysvipc(const char *file, const int lineno, const char *sysvipc_file); +#define GET_USED_QUEUES() \ + get_used_sysvipc(__FILE__, __LINE__, "/proc/sysvipc/msg") +#define GET_USED_SEGMENTS() \ + get_used_sysvipc(__FILE__, __LINE__, "/proc/sysvipc/shm") +#define GET_USED_ARRAYS() \ + get_used_sysvipc(__FILE__, __LINE__, "/proc/sysvipc/sem") + +void *probe_free_addr(const char *file, const int lineno); +#define PROBE_FREE_ADDR() \ + probe_free_addr(__FILE__, __LINE__) + +#endif /* newlibipc.h */ diff --git a/ltp/include/libsigwait.h b/ltp/include/libsigwait.h new file mode 100644 index 0000000000000000000000000000000000000000..2fca578b19aca8218cf915672bbb7e4053a71959 --- /dev/null +++ b/ltp/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/ltp/include/libswap.h b/ltp/include/libswap.h new file mode 100644 index 0000000000000000000000000000000000000000..6904e8f45b37f04017415c6e8d03c132ba8440a7 --- /dev/null +++ b/ltp/include/libswap.h @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) Linux Test Project, 2021-2024 + * Author: Stanislav Kholmanskikh + */ + +/** + * DOC: libltpswap + * + * Contains common content for all swapon/swapoff tests. + */ + +#ifndef __LIBSWAP_H__ +#define __LIBSWAP_H__ + +enum swapfile_method { + SWAPFILE_BY_SIZE, + SWAPFILE_BY_BLKS +}; + +/* + * Create a swapfile of a specified size or number of blocks. + */ +int make_swapfile(const char *file, const int lineno, + const char *swapfile, unsigned int num, + int safe, enum swapfile_method method); + +/** 65536 bytes is minimum for 64kb page size, let's use 1 MB */ +#define MINIMAL_SWAP_SIZE_MB 1 + +/** + * MAKE_SMALL_SWAPFILE - create small swap file. + * + * Macro to create small swap file. Size defined with MINIMAL_SWAP_SIZE_MB. + * + * @swapfile: swap filename. + */ +#define MAKE_SMALL_SWAPFILE(swapfile) \ + make_swapfile(__FILE__, __LINE__, swapfile, MINIMAL_SWAP_SIZE_MB, 0, \ + SWAPFILE_BY_SIZE) + +/** + * SAFE_MAKE_SMALL_SWAPFILE - create small swap file (safe version). + * + * Macro to create small swap file. Size defined with MINIMAL_SWAP_SIZE_MB. + * Includes safety checks to handle potential errors. + * + * @swapfile: swap filename. + */ +#define SAFE_MAKE_SMALL_SWAPFILE(swapfile) \ + make_swapfile(__FILE__, __LINE__, swapfile, MINIMAL_SWAP_SIZE_MB, 1, \ + SWAPFILE_BY_SIZE) + +/** + * MAKE_SWAPFILE_SIZE - create swap file (MB). + * + * Macro to create swap file, size specified in megabytes (MB). + * + * @swapfile: swap filename. + * @size: swap size in MB. + */ +#define MAKE_SWAPFILE_SIZE(swapfile, size) \ + make_swapfile(__FILE__, __LINE__, swapfile, size, 0, SWAPFILE_BY_SIZE) + +/** + * MAKE_SWAPFILE_BLKS - create swap file (blocks). + * + * Macro to create swap file, size specified in block numbers. + * + * @swapfile: swap filename. + * @blocks: number of blocks. + */ +#define MAKE_SWAPFILE_BLKS(swapfile, blocks) \ + make_swapfile(__FILE__, __LINE__, swapfile, blocks, 0, SWAPFILE_BY_BLKS) + +/** + * SAFE_MAKE_SWAPFILE_SIZE - create swap file (MB, safe version). + * + * Macro to safely create swap file, size specified in megabytes (MB). + * Includes safety checks to handle potential errors. + * + * @swapfile: swap file name. + * @size: swap size in MB. + */ +#define SAFE_MAKE_SWAPFILE_SIZE(swapfile, size) \ + make_swapfile(__FILE__, __LINE__, swapfile, size, 1, SWAPFILE_BY_SIZE) + +/** + * SAFE_MAKE_SWAPFILE_BLKS - create swap file (block, safe version) + * + * Macro to safely create swap file, size specified in block numbers. + * Includes safety checks to handle potential errors. + * + * @swapfile: swap file name. + * @blocks: number of blocks. + */ +#define SAFE_MAKE_SWAPFILE_BLKS(swapfile, blocks) \ + make_swapfile(__FILE__, __LINE__, swapfile, blocks, 1, SWAPFILE_BY_BLKS) + +/** + * is_swap_supported() - Check swapon/swapoff support. + * + * Check swapon/swapoff support status of filesystems or files + * we are testing on. + * + * @filename: swap file name. + * Return: true if swap is supported, false if not. + */ +bool is_swap_supported(const char *filename); + +/** + * tst_max_swapfiles() - Get kernel constant MAX_SWAPFILES value. + * + * Return: MAX_SWAPFILES value. + */ +int tst_max_swapfiles(void); + +/** + * tst_count_swaps() - Get the used swapfiles number. + * + * Return: used swapfiles number. + */ +int tst_count_swaps(void); + +#endif /* __LIBSWAP_H__ */ diff --git a/ltp/include/mk/automake.mk b/ltp/include/mk/automake.mk new file mode 100644 index 0000000000000000000000000000000000000000..a58f4042457c6c297cdda838f32f21a998d96230 --- /dev/null +++ b/ltp/include/mk/automake.mk @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Autotools include Makefile. +# Copyright (c) Linux Test Project, 2010-2024 +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +# Override these variables to use non-system available tools. +ACLOCAL ?= aclocal +AUTOCONF ?= autoconf +AUTOHEADER ?= autoheader +AUTOMAKE ?= automake + +AUTOCONFED_SUBDIRS = \ + testcases/open_posix_testsuite + +CLEAN_SUBDIRS = $(AUTOCONFED_SUBDIRS) include + +# We want to run this every single time to ensure that all of the prereq files +# are there. +.PHONY: testcases/open_posix_testsuite/configure +testcases/open_posix_testsuite/configure: + $(MAKE) -C $(@D) autotools + +.PHONY: autotools +autotools: aclocal autoconf autoheader automake $(addsuffix /configure,$(AUTOCONFED_SUBDIRS)) + +.PHONY: aclocal +aclocal: aclocal.m4 + +aclocal.m4: $(wildcard m4/*.m4) m4/ltp-version.m4 + $(ACLOCAL) -I m4 + +.PHONY: autoconf +autoconf: configure + +configure: configure.ac aclocal.m4 + $(AUTOCONF) + +.PHONY: autoheader +autoheader: configure.ac $(wildcard m4/*.m4) m4/ltp-version.m4 aclocal.m4 + $(AUTOHEADER) + +include: + mkdir -p "$@" + +m4/ltp-version.m4: VERSION + sed -n '1{s:LTP-:m4_define([LTP_VERSION],[:;s:$$:]):;p;q}' $< > $@ + +.PHONY: automake +AUTOMAKE_FILES := compile config.guess config.sub install-sh missing +automake: aclocal $(AUTOMAKE_FILES) +$(AUTOMAKE_FILES): m4/Makefile.in +m4/Makefile.in: m4/Makefile.am aclocal.m4 + $(AUTOMAKE) -c -a + +.PHONY: ac-clean ac-distclean ac-maintainer-clean +ac-clean:: + $(RM) -rf autom4te.cache + $(RM) -f config.log config.status + $(RM) -f m4/Makefile m4/ltp-version.m4 + for d in $(CLEAN_SUBDIRS); do \ + $(MAKE) -C "$(top_srcdir)/$$d" $@; \ + done + +ac-distclean:: ac-clean +ac-maintainer-clean:: ac-distclean + for d in $(CLEAN_SUBDIRS); do \ + $(MAKE) -C "$(top_srcdir)/$$d" $@; \ + done + $(RM) -f aclocal.m4 configure $(AUTOMAKE_FILES) m4/Makefile.in + +# Don't include config.h, or make will (rightfully) whine about overriding +# rules. +# +# This list should match the files in configure.ac. +# +AUTOGENERATED_FILES = \ + include/mk/config.mk \ + include/mk/config-openposix.mk \ + include/mk/features.mk \ + lib/ltp.pc \ + m4/Makefile + +distclean:: %: clean ac-distclean + for d in $(CLEAN_SUBDIRS); do \ + $(MAKE) -C "$(top_srcdir)/$$d" $@; \ + done + $(RM) -f $(AUTOGENERATED_FILES) + +maintainer-clean:: distclean ac-maintainer-clean + +$(AUTOGENERATED_FILES): $(top_builddir)/config.status + $(SHELL) $^ + +# This variable is automatically changed from help to all once someone has +# run configure, or the equivalent steps manually, as described in INSTALL. +$(abs_top_builddir)/include/mk/config.mk \ +$(abs_top_builddir)/include/mk/features.mk: + $(MAKE) -C $(top_srcdir) help; false diff --git a/ltp/include/mk/config-openposix.mk.in b/ltp/include/mk/config-openposix.mk.in new file mode 100644 index 0000000000000000000000000000000000000000..54422aec1bc62724ad831ae90f1272fd765b4cf2 --- /dev/null +++ b/ltp/include/mk/config-openposix.mk.in @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2016 +# Parameters from the top level configure +CC= @CC@ +CFLAGS+= @CFLAGS@ +LDLIBS+= @LIBS@ +LDFLAGS+= @LDFLAGS@ diff --git a/ltp/include/mk/config.mk.in b/ltp/include/mk/config.mk.in new file mode 100644 index 0000000000000000000000000000000000000000..4c3da304fc9dbc3c2aea2b41dd70ed7ea43f2b5e --- /dev/null +++ b/ltp/include/mk/config.mk.in @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2009-2024 +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +# See this page for more info about LEX*: +# http://www.gnu.org/software/hello/manual/autoconf/Particular-Programs.html + +# Application specifying variables. You should never have to change these. +AR := @AR@ +CC := @CC@ +LEX := @LEX@ +RANLIB := @RANLIB@ +OBJCOPY := @OBJCOPY@ +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@ +CRYPTO_LIBS := @CRYPTO_LIBS@ +LEXLIB := @LEXLIB@ +NUMA_LIBS := @NUMA_LIBS@ +SELINUX_LIBS := @SELINUX_LIBS@ +HAVE_RPC := @HAVE_RPC@ +LIBTIRPC_CFLAGS := @LIBTIRPC_CFLAGS@ +LIBTIRPC_LIBS := @LIBTIRPC_LIBS@ +KEYUTILS_LIBS := @KEYUTILS_LIBS@ +HAVE_FTS_H := @HAVE_FTS_H@ +LIBMNL_LIBS := @LIBMNL_LIBS@ +LIBMNL_CFLAGS := @LIBMNL_CFLAGS@ + +prefix := @prefix@ + +datarootdir := @datarootdir@ +includedir := @includedir@ +exec_prefix := @exec_prefix@ +bindir := @bindir@ +libdir := @libdir@ +mandir := @mandir@ + +CPPFLAGS := @CPPFLAGS@ +CFLAGS := @CFLAGS@ +LDLIBS := @LIBS@ +LDFLAGS := @LDFLAGS@ + +DEBUG_CFLAGS ?= -g + +# for -fstrict-aliasing see doc/developers/build_system.rst. +OPT_CFLAGS ?= -O2 -fno-strict-aliasing -pipe + +WCFLAGS ?= -Wall -W @GCC_WARN_OLDSTYLE@ + +STDCFLAGS ?= -std=gnu99 + +LDFLAGS += $(WLDFLAGS) +CFLAGS += $(DEBUG_CFLAGS) $(OPT_CFLAGS) $(WCFLAGS) $(STDCFLAGS) + +LTP_CFLAGS_NOPIE := @LTP_CFLAGS_NOPIE@ +LTP_CFLAGS_FFIXED_EBP := @LTP_CFLAGS_FFIXED_EBP@ + +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@ +LINUX_VERSION_PATCH := @LINUX_VERSION_PATCH@ +WITH_MODULES := @WITH_MODULES@ + +HOST_CPU := @HOST_CPU@ + +ifeq ($(strip $(prefix)),) +$(error you are using $$(prefix) incorrectly -- set it to $(abs_top_srcdir) if you want to build in the source tree) +endif + +export datarootdir includedir libdir mandir prefix diff --git a/ltp/include/mk/env_post.mk b/ltp/include/mk/env_post.mk new file mode 100644 index 0000000000000000000000000000000000000000..ab31da73af904796145c2133bde8ff4687669aad --- /dev/null +++ b/ltp/include/mk/env_post.mk @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Environment post-setup Makefile. +# Copyright (c) Linux Test Project, 2009-2025 +# Copyright (c) Cisco Systems Inc., 2009 +# Ngie Cooper, July 2009 + +ENV_PRE_LOADED ?= $(error You must load env_pre.mk before including this file) + +include $(top_srcdir)/include/mk/functions.mk + +ifndef ENV_POST_LOADED +ENV_POST_LOADED = 1 + +# Default source search path. Modify as necessary, but I would call that +# poor software design if you need more than one search directory, and +# would suggest creating a general purpose static library to that end. +vpath %.c $(abs_srcdir) +vpath %.S $(abs_srcdir) + +# For config.h, et all. +CPPFLAGS += -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/include/old/ + +LDFLAGS += -L$(top_builddir)/lib + +ifeq ($(ANDROID),1) +LDFLAGS += -L$(top_builddir)/lib/android_libpthread +LDFLAGS += -L$(top_builddir)/lib/android_librt +endif + +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) $(HOST_MAKE_TARGETS) *.o *.pyc .cache.mk *.dwo .*.dwo + +# Majority of the files end up in testcases/bin... +INSTALL_DIR ?= testcases/bin + +ifneq ($(filter-out install,$(MAKECMDGOALS)),$(MAKECMDGOALS)) + +ifeq ($(strip $(INSTALL_DIR)),) +INSTALL_DIR := $(error You must define INSTALL_DIR before including this file) +endif + +ifneq ($(strip $(prefix)),) +# Value specified by INSTALL_DIR isn't an absolute path, so let's tack on $(prefix). +ifneq ($(patsubst /%,,$(INSTALL_DIR)),) +INSTALL_DIR := $(prefix)/$(INSTALL_DIR) +endif + +# Glob any possible expressions, but make sure to zap the $(abs_srcdir) +# reference at the start of the filename instead of using $(notdir), so that +# way we don't accidentally nuke the relative path from $(abs_srcdir) that +# may have been set in the Makefile. +INSTALL_TARGETS := $(wildcard $(addprefix $(abs_srcdir)/,$(INSTALL_TARGETS))) +INSTALL_TARGETS := $(patsubst $(abs_srcdir)/%,%,$(INSTALL_TARGETS)) + +# The large majority of the files that we install are going to be apps and +# scripts, so let's chmod them like that. +INSTALL_MODE ?= 00775 + +$(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)))) + +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_HEADER_TARGETS ?= $(addprefix check-,$(notdir $(sort $(wildcard $(abs_srcdir)/*.h)))) +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,FILE_PATH_CHANGES +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/ltp/include/mk/env_pre.mk b/ltp/include/mk/env_pre.mk new file mode 100644 index 0000000000000000000000000000000000000000..46d6abecfb812637861d9032c4fd31ddec61bc22 --- /dev/null +++ b/ltp/include/mk/env_pre.mk @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Make pre-include environment Makefile. +# Copyright (c) Linux Test Project, 2009-2020 +# Copyright (c) Cisco Systems Inc., 2009 +# Ngie Cooper, September 2009 +# +# This Makefile must be included first. NO IF'S, AND'S, OR BUT'S. +# This sets the stage for all operations required within Makefiles. + +ifndef ENV_PRE_LOADED +ENV_PRE_LOADED = 1 + +# "out-of-build-tree" build. +BUILD_TREE_BUILDDIR_INSTALL := 1 +# "in-srcdir" build / install. +BUILD_TREE_SRCDIR_INSTALL := 2 +# "in-srcdir" build, non-srcdir install. +BUILD_TREE_NONSRCDIR_INSTALL := 3 +# configure not run. +BUILD_TREE_UNCONFIGURED := 4 + +# 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? +abs_top_srcdir := $(abspath $(top_srcdir)) + +# +# Where's the root object directory? +# +# Just in case it's not specified, set it to the top srcdir (because the user +# must not have wanted out of build tree support)... +# +top_builddir ?= $(top_srcdir) + +# We need the absolute path +abs_top_builddir := $(abspath $(top_builddir)) + +# Where's the root object directory? +builddir := . + +abs_builddir := $(CURDIR) + +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 +abs_srcdir := $(abspath $(abs_top_srcdir)/$(cwd_rel_from_top)) + +srcdir := $(strip $(subst $(abs_top_srcdir)/,,$(abs_srcdir))) + +ifeq ($(srcdir),) +srcdir := . +endif + +# If config.mk or features.mk doesn't exist it's not an error for some targets +# which are filtered below (e.g. clean). However these config files may be +# needed for those targets (eg. the open posix testsuite is not cleaned even if +# it's enabled by configure) thus it would be wise to do silent inclusion. +ifneq ("$(wildcard $(abs_top_builddir)/include/mk/config.mk)","") +include $(abs_top_builddir)/include/mk/config.mk +endif +ifneq ("$(wildcard $(abs_top_builddir)/include/mk/features.mk)","") +include $(abs_top_builddir)/include/mk/features.mk +endif + +# autotools, *clean, and help don't require config.mk, features.mk, etc... +ifeq ($(filter autotools %clean .gitignore gitignore.% help,$(MAKECMDGOALS)),) + +include $(abs_top_builddir)/include/mk/config.mk +include $(abs_top_builddir)/include/mk/features.mk + +# START out-of-build-tree check. +ifneq ($(abs_builddir),$(abs_srcdir)) +BUILD_TREE_STATE := $(BUILD_TREE_BUILDDIR_INSTALL) +else +# Else, not out of build tree.. + +# START srcdir build-tree install checks +ifeq ($(strip $(DESTDIR)$(prefix)),) +BUILD_TREE_STATE := $(BUILD_TREE_SRCDIR_INSTALL) +else # Empty $(DESTDIR)$(prefix) +ifeq ($(abs_top_srcdir),$(prefix)) +BUILD_TREE_STATE := $(BUILD_TREE_SRCDIR_INSTALL) +endif +# END srcdir build-tree install checks +endif +# END out-of-build-tree check. +endif + +# Is the build-tree configured yet? +ifeq ($(BUILD_TREE_STATE),) +ifneq ($(wildcard $(abs_top_builddir)/include/mk/config.mk),) +BUILD_TREE_STATE := $(BUILD_TREE_NONSRCDIR_INSTALL) +endif +endif + +.DEFAULT_GOAL := all + +endif # END autotools, *clean... + +BUILD_TREE_STATE ?= $(BUILD_TREE_UNCONFIGURED) + +# We can piece together where we're located in the source and object trees with +# 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/ltp/include/mk/features.mk.in b/ltp/include/mk/features.mk.in new file mode 100644 index 0000000000000000000000000000000000000000..fd93dc3763445dc3793ac50ef663e3df7b632e78 --- /dev/null +++ b/ltp/include/mk/features.mk.in @@ -0,0 +1,25 @@ +# Copyright (c) Linux Test Project, 2008-2025 +# SPDX-License-Identifier: GPL-2.0-or-later +# Ngie Cooper, October 2010 + +# Tools enable knobs +WITH_EXPECT := @WITH_EXPECT@ + +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 + +# Enable testcases/open_posix_testsuite's compile and install? +WITH_OPEN_POSIX_TESTSUITE := @WITH_OPEN_POSIX_TESTSUITE@ + +# Enable testcases/kernel/kvm compile and install? +WITH_KVM_TESTSUITE := @WITH_KVM_TESTSUITE@ diff --git a/ltp/include/mk/functions.mk b/ltp/include/mk/functions.mk new file mode 100644 index 0000000000000000000000000000000000000000..60dbed395ea9bdf5c844a6590b9b2883988a3f56 --- /dev/null +++ b/ltp/include/mk/functions.mk @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# A Makefile with a collection of reusable functions. +# Copyright (c) Linux Test Project, 2009-2020 +# Copyright (c) Cisco Systems Inc., 2009 +# Ngie Cooper, July 2009 + +# 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. +# +# 1 -> Target basename. +# 2 -> Source directory. +# 3 -> Destination directory. + +define generate_install_rule + +INSTALL_FILES += $$(abspath $$(DESTDIR)/$(3)/$(1)) + +$$(abspath $$(DESTDIR)/$(3)/$(1)): \ + $$(abspath $$(dir $$(DESTDIR)/$(3)/$(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 + +# +# Set SUBDIRS to the subdirectories where Makefiles were found. +# +define get_make_dirs +SUBDIRS ?= $$(subst $$(abs_srcdir)/,,$$(patsubst %/Makefile,%,$$(wildcard $$(abs_srcdir)/*/Makefile))) +SUBDIRS := $$(filter-out $$(FILTER_OUT_DIRS),$$(SUBDIRS)) +endef diff --git a/ltp/include/mk/generic_leaf_target.inc b/ltp/include/mk/generic_leaf_target.inc new file mode 100644 index 0000000000000000000000000000000000000000..7c685fea76e4957ac15ab0f52d4a18aae48977c2 --- /dev/null +++ b/ltp/include/mk/generic_leaf_target.inc @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Generic leaf rules include Makefile. +# Copyright (c) Linux Test Project, 2017-2022 +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +# +# generic_leaf_target +# +# Generate a set of basic targets (all, clean, install) for a leaf directory +# (no subdirectories). +# +# $(MAKE_DEPS) : What should we execute beforehand as a +# dependency of $(MAKE_TARGETS)? +# +# $(INSTALL_FILES) -> install +# +# Helpful variables are: +# +# $(MAKE_TARGETS) : What to execute as direct dependencies of +# all. +# 1. Defaults to the basename of the targets +# produced by the %.c -> % implicit pattern +# rules, e.g. the MAKE_TARGET in a directory +# like the following: +# +# $$ ls /bar +# foo.c +# +# Would be `foo'. Similarly, the following +# dir structure: +# +# $$ ls /bar +# foo.c zanzibar.c +# +# Would be `foo zanzibar'. +# +# 2. If you define MAKE_TARGETS as an empty +# string, this will override the defaults. +# I did this to avoid providing too much +# 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 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)? +# +# Also, if you wish to change the installation directory, from the set default +# (testcases/bin) you must do something like either one of the following items: +# +# Method A: +# +# INSTALL_DIR := /path/to/installdir/from/$(DESTDIR)/$(prefix) +# +# e.g. if I wanted to install my binaries in testcases/bin, I would do: +# +# INSTALL_DIR := testcases/bin +# +# in my calling Makefile. +# +# Or Method B: +# +# INSTALL_DIR := /path/to/installdir/from/$(DESTDIR) +# +# e.g. if I wanted to install my binaries in $(libdir) (which may not exist +# outside of $(prefix) right now, but could in the future), I could do the +# following: +# +# INSTALL_DIR := $(libdir) +# + +.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 -r $(CLEAN_TARGETS) + +$(INSTALL_FILES): | $(INSTALL_DEPS) + +install: $(INSTALL_FILES) + +$(CHECK_TARGETS): | $(CHECK_DEPS) +check: $(CHECK_HEADER_TARGETS) $(CHECK_TARGETS) $(SHELL_CHECK_TARGETS) + +# vim: syntax=make diff --git a/ltp/include/mk/generic_leaf_target.mk b/ltp/include/mk/generic_leaf_target.mk new file mode 100644 index 0000000000000000000000000000000000000000..c200803b554e87cad01ef77cdf975a8643af90ed --- /dev/null +++ b/ltp/include/mk/generic_leaf_target.mk @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Generic leaf include Makefile. +# Copyright (c) Linux Test Project, 2017 +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +include $(top_srcdir)/include/mk/env_post.mk +include $(top_srcdir)/include/mk/generic_leaf_target.inc diff --git a/ltp/include/mk/generic_trunk_target.inc b/ltp/include/mk/generic_trunk_target.inc new file mode 100644 index 0000000000000000000000000000000000000000..f9db7896a93a75882117b7cdc6ed22ad7653854d --- /dev/null +++ b/ltp/include/mk/generic_trunk_target.inc @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2010-2021 +# Generic trunk rules include Makefile. +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +# +# generic_trunk_target +# +# Generate a set of recursive targets to apply over a trunk directory (has +# directories) -- optionally with a set of trunk-based files. +# +# All variables in this canned define are essentially the same as +# generic_leaf_target, with the exception that the install flow for local +# targets is: +# +# $(INSTALL_FILES) -> trunk-install -> install (recursive) +# +# All recursive targets are traverse SUBDIRS as defined by the user, or if +# undefined, defaults to any subdirectories where Makefile's are contained +# within. +# +# generic_trunk_target specific variables are: +# +# RECURSIVE_TARGETS : a list of targets to apply over an entire +# directory tree. This defaults to +# `all install'. +# +# See generic_leaf_target, generic_target_env_setup, and get_make_dirs for +# more details and design notes. +# + +include $(top_srcdir)/include/mk/functions.mk + +RECURSIVE_TARGETS ?= all install check + +$(eval $(get_make_dirs)) + +.PHONY: $(RECURSIVE_TARGETS) $(addprefix trunk-,$(RECURSIVE_TARGETS)) + +$(SUBDIRS): %: + mkdir -m 00755 -p "$@" + +$(MAKE_TARGETS): | $(MAKE_DEPS) + +trunk-all: $(MAKE_TARGETS) + +trunk-clean:: | $(SUBDIRS) + $(if $(strip $(CLEAN_TARGETS)),$(RM) -f $(CLEAN_TARGETS)) + +$(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... +.PHONY: $(filter-out $(RECURSIVE_TARGETS),all clean install) +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 + +install: trunk-install + +# Print out CURDIR to check for a recursion issue. +ifeq ($(strip $(SUBDIRS)),) + $(warning CURDIR is: $(CURDIR)) + $(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/ltp/include/mk/generic_trunk_target.mk b/ltp/include/mk/generic_trunk_target.mk new file mode 100644 index 0000000000000000000000000000000000000000..e25f7bce24236ceeeac2f619c3256ba1be5f749d --- /dev/null +++ b/ltp/include/mk/generic_trunk_target.mk @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Generic trunk include Makefile. +# Copyright (c) Linux Test Project, 2017 +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +include $(top_srcdir)/include/mk/env_post.mk +include $(top_srcdir)/include/mk/generic_trunk_target.inc diff --git a/ltp/include/mk/lib.mk b/ltp/include/mk/lib.mk new file mode 100644 index 0000000000000000000000000000000000000000..cefb28c25d6d0f9a247e4c838830578efe10d5eb --- /dev/null +++ b/ltp/include/mk/lib.mk @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2009-2019 +# Copyright (C) Cyril Hrubis 2012 +# Copyright (c) Cisco Systems Inc., 2009 +# Ngie Cooper, July 2009 + +# Makefile to include for libraries. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/sparse.mk + +INSTALL_DIR := $(libdir) + +# An extension of generic_leaf_target, strictly for libraries. +.PHONY: install_headers + +ifndef LIB +ifndef INTERNAL_LIB +$(error You must define LIB or INTERNAL_LIB when including this Makefile) +endif +endif + +install_headers: $(addprefix $(DESTDIR)/$(includedir)/,$(notdir $(HEADER_FILES))) + +INSTALL_MODE ?= 00664 + +# Hide the LIB target for internal libs on install +ifneq ($(MAKECMDGOALS),install) +LIB ?= $(INTERNAL_LIB) +endif + +MAKE_TARGETS += $(LIB) + +LIBSRCS ?= $(wildcard $(abs_srcdir)/*.c) +LIBSRCS := $(sort $(LIBSRCS)) +LIBSRCS := $(abspath $(LIBSRCS)) +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 \ + 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/ltp/include/mk/man.mk b/ltp/include/mk/man.mk new file mode 100644 index 0000000000000000000000000000000000000000..a642dfb35de2ef2202f2214e06fc4375f8804c51 --- /dev/null +++ b/ltp/include/mk/man.mk @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2010-2017 +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +ifeq ($(strip $(MANPREFIX)),) +$(error $$(MANPREFIX) not defined) +endif + +include $(top_srcdir)/include/mk/env_pre.mk + +INSTALL_DIR := $(mandir)/man$(MANPREFIX) + +INSTALL_MODE := 00644 + +INSTALL_TARGETS ?= *.$(MANPREFIX) + +MAKE_TARGETS := + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/include/mk/module.mk b/ltp/include/mk/module.mk new file mode 100644 index 0000000000000000000000000000000000000000..10914084cfa7b5a7a9c4460d4e35363c68b0cd7a --- /dev/null +++ b/ltp/include/mk/module.mk @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. +# Copyright (c) Linux Test Project, 2014-2021 +# Author: Alexey Kodanev +# +# Include it to build kernel modules. +# REQ_VERSION_MAJOR and REQ_VERSION_PATCH must be defined beforehand. + +$(if $(REQ_VERSION_MAJOR),,$(error You must define REQ_VERSION_MAJOR)) +$(if $(REQ_VERSION_PATCH),,$(error You must define REQ_VERSION_MINOR)) + +ifeq ($(WITH_MODULES),no) +SKIP := 1 +else +ifeq ($(LINUX_VERSION_MAJOR)$(LINUX_VERSION_PATCH),) +SKIP := 1 +else +SKIP ?= $(shell \ + [ "$(LINUX_VERSION_MAJOR)" -gt "$(REQ_VERSION_MAJOR)" ] || \ + [ "$(LINUX_VERSION_MAJOR)" -eq "$(REQ_VERSION_MAJOR)" -a \ + "$(LINUX_VERSION_PATCH)" -ge "$(REQ_VERSION_PATCH)" ]; echo $$?) +endif +endif + +ifneq ($(SKIP),0) +MAKE_TARGETS := $(filter-out %.ko, $(MAKE_TARGETS)) +endif + +ifneq ($(filter install clean,$(MAKECMDGOALS)),) +MAKE_TARGETS := $(filter-out %.ko, $(MAKE_TARGETS)) +MAKE_TARGETS += $(sort $(wildcard *.ko)) +endif + +CLEAN_TARGETS += .dep_modules *.mod built-in.a + +CHECK_TARGETS := $(filter-out %.ko, $(CHECK_TARGETS)) + +MODULE_SOURCES := $(patsubst %.ko,%.c,$(filter %.ko, $(MAKE_TARGETS))) + +# Ignoring the exit status of commands is done to be forward compatible with +# kernel internal API changes. The user-space test will return TCONF, if it +# doesn't find the module (i.e. it wasn't built either due to kernel-devel +# missing or module build failure). +%.ko: %.c .dep_modules ; + +.dep_modules: $(MODULE_SOURCES) + @echo "Building modules: $(MODULE_SOURCES)" + -$(MAKE) -C $(LINUX_DIR) M=$(abs_srcdir) + rm -rf *.mod.c *.o *.ko.unsigned modules.order .tmp* .*.ko .*.cmd Module.symvers + @touch .dep_modules diff --git a/ltp/include/mk/rules.mk b/ltp/include/mk/rules.mk new file mode 100644 index 0000000000000000000000000000000000000000..c7da6d37f9ba54872069bdd809ab1461443d28ef --- /dev/null +++ b/ltp/include/mk/rules.mk @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2020-2022 + +target_rel_dir := $(if $(cwd_rel_from_top),$(cwd_rel_from_top)/,) + +%.o: %.S +ifdef VERBOSE + $(AS) $(ASFLAGS) -c -o $@ $< +else + @$(AS) $(ASFLAGS) -c -o $@ $< + @echo AS $(target_rel_dir)$@ +endif + +%.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: $(CHECK_HEADER_TARGETS) +$(CHECK_HEADER_TARGETS): check-%.h: %.h +ifdef VERBOSE + -$(CHECK_NOFLAGS) $< +else + @echo CHECK $(target_rel_dir)$< + @-$(CHECK_NOFLAGS) $< +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/ltp/include/mk/sparse.mk b/ltp/include/mk/sparse.mk new file mode 100644 index 0000000000000000000000000000000000000000..3390672c156ee1789e91b40afd31903d39fa4f96 --- /dev/null +++ b/ltp/include/mk/sparse.mk @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2021 +# 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/ltp/include/mk/testcases.mk b/ltp/include/mk/testcases.mk new file mode 100644 index 0000000000000000000000000000000000000000..2609535ce718c980ab2cb851874000482e1c5c04 --- /dev/null +++ b/ltp/include/mk/testcases.mk @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2009-2024 +# Ngie Cooper, July 2009 + +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 + +LIBLTP_DIR := $(abs_top_builddir)/lib + +LIBLTP := $(LIBLTP_DIR)/libltp.a + +$(APICMDS_DIR)/tst_kvercmp: $(APICMDS_DIR) + $(MAKE) -C "$^" -f "$(abs_top_srcdir)/tools/apicmds/Makefile" all + +$(LIBLTP): $(LIBLTP_DIR) + $(MAKE) -C "$^" -f "$(abs_top_srcdir)/lib/Makefile" all + +MAKE_DEPS := $(LIBLTP) + +INSTALL_DIR := testcases/bin + +LDLIBS += -lltp + +ifdef LTPLIBS + +LTPLIBS_DIRS = $(addprefix $(abs_top_builddir)/libs/, $(LTPLIBS)) +LTPLIBS_FILES = $(addsuffix .a, $(addprefix $(abs_top_builddir)/libs/, $(foreach LIB,$(LTPLIBS),$(LIB)/lib$(LIB)))) + +MAKE_DEPS += $(LTPLIBS_FILES) + +.PHONY: $(LTPLIBS_FILES) + +$(LTPLIBS_FILES): $(LTPLIBS_DIRS) + +$(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/, $(LTPLIBS)) + +endif + +$(LTPLIBS_DIRS) $(APICMDS_DIR) $(LIBLTP_DIR): %: + mkdir -p "$@" diff --git a/ltp/include/old/ltp_cpuid.h b/ltp/include/old/ltp_cpuid.h new file mode 100644 index 0000000000000000000000000000000000000000..6bd553708bc2f0f50d42c2d5f73d01fbcdc500b0 --- /dev/null +++ b/ltp/include/old/ltp_cpuid.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012-2013 The Chromium OS Authors. All rights reserved. + * + * Licensed under the BSD 3-clause. + */ + +#ifndef __LTP_CPUID_H__ +#define __LTP_CPUID_H__ + +static inline void cpuid(unsigned int info, unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ +#if defined(__i386__) || defined(__x86_64__) + unsigned int _eax = info, _ebx, _ecx, _edx; + asm volatile( +# ifdef __i386__ + "xchg %%ebx, %%esi;" /* save ebx (for PIC) */ + "cpuid;" + "xchg %%esi, %%ebx;" /* restore ebx & pass to caller */ + : "=S" (_ebx), +# else + "cpuid;" + : "=b" (_ebx), +# endif + "+a" (_eax), "=c" (_ecx), "=d" (_edx) + : /* inputs: eax is handled above */ + ); + if (eax) *eax = _eax; + if (ebx) *ebx = _ebx; + if (ecx) *ecx = _ecx; + if (edx) *edx = _edx; +#endif +} + +#endif diff --git a/ltp/include/old/ltp_priv.h b/ltp/include/old/ltp_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..0a0ef70f334775a056b6b63335fb86189296b08e --- /dev/null +++ b/ltp/include/old/ltp_priv.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013 Cyril Hrubis chrubis@suse.cz + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * 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. + */ + +#ifndef __LTP_PRIV_H__ +#define __LTP_PRIV_H__ + +#include +#include "tst_defaults.h" + +/* environment variables for controlling tst_res verbosity */ +#define TOUT_VERBOSE_S "VERBOSE" /* All test cases reported */ +#define TOUT_NOPASS_S "NOPASS" /* No pass test cases are reported */ +#define TOUT_DISCARD_S "DISCARD" /* No output is reported */ + +#define USC_ITERATION_ENV "USC_ITERATIONS" +#define USC_LOOP_WALLTIME "USC_LOOP_WALLTIME" +#define USC_NO_FUNC_CHECK "USC_NO_FUNC_CHECK" +#define USC_LOOP_DELAY "USC_LOOP_DELAY" + +const char *parse_opts(int ac, char **av, const option_t *user_optarr, void + (*uhf)(void)); + +/* Interface for rerouting to new lib calls from tst_res.c */ +extern void *tst_test; + +void tst_vbrk_(const char *file, const int lineno, int ttype, + const char *fmt, va_list va) __attribute__((noreturn)); + +void tst_brk_(const char *file, const int lineno, int ttype, + const char *msg, ...); + +void tst_vres_(const char *file, const int lineno, int ttype, + const char *fmt, va_list va); + +void tst_res_(const char *file, const int lineno, int ttype, + const char *msg, ...); + + +#define NO_NEWLIB_ASSERT(file, lineno) \ + if (tst_test) { \ + tst_brk_(file, lineno, TBROK, \ + "%s() executed from newlib!", __FUNCTION__); \ + } + +#endif /* __LTP_PRIV_H__ */ diff --git a/ltp/include/old/ltp_signal.h b/ltp/include/old/ltp_signal.h new file mode 100644 index 0000000000000000000000000000000000000000..02ee8349a8ac5faf640b65f0c7989b51f65d3804 --- /dev/null +++ b/ltp/include/old/ltp_signal.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009 Cisco Systems, Inc. All Rights Reserved. + * Copyright (c) 2009 FUJITSU LIMITED. All Rights Reserved. + * + * 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. + * + * Author: Liu Bo + * Author: Ngie Cooper + * + */ + +#ifndef __LTP_SIGNAL_H +#define __LTP_SIGNAL_H + +#include +#include +#include +#include "config.h" + +/* + * For all but __mips__: + * + * _COMPAT_NSIG / _COMPAT_NSIG_BPW == 2. + * + * For __mips__: + * + * _COMPAT_NSIG / _COMPAT_NSIG_BPW == 4. + * + * See asm/compat.h under the kernel source for more details. + * + * Multiply that by a fudge factor of 4 and you have your SIGSETSIZE. + */ +#if defined __mips__ +#define SIGSETSIZE 16 +#else +#define SIGSETSIZE (_NSIG / 8) +#endif + +#endif diff --git a/ltp/include/old/old_checkpoint.h b/ltp/include/old/old_checkpoint.h new file mode 100644 index 0000000000000000000000000000000000000000..f91fef9f6cc8ef9659753cfb449fb113c1ee2c50 --- /dev/null +++ b/ltp/include/old/old_checkpoint.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015-2016 Cyril Hrubis + * + * 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 . + */ + + /* + + Checkpoint - easy to use parent-child synchronization. + + Checkpoint is based on futexes (man futex). The library allocates a page of + shared memory for futexes and the id is an offset to it which gives the user + up to page_size/sizeof(uint32_t) checkpoint pairs. Up to INT_MAX processes + can sleep on single id and can be woken up by single wake. + + */ + +#ifndef OLD_CHECKPOINT__ +#define OLD_CHECKPOINT__ + +#include "test.h" +#include "tst_checkpoint_fn.h" + +#define TST_SAFE_CHECKPOINT_WAIT(cleanup_fn, id) \ + tst_safe_checkpoint_wait(__FILE__, __LINE__, cleanup_fn, id, 0); + +#define TST_SAFE_CHECKPOINT_WAIT2(cleanup_fn, id, msec_timeout) \ + tst_safe_checkpoint_wait(__FILE__, __LINE__, cleanup_fn, id, msec_timeout); + +#define TST_SAFE_CHECKPOINT_WAKE(cleanup_fn, id) \ + tst_safe_checkpoint_wake(__FILE__, __LINE__, cleanup_fn, id, 1); + +#define TST_SAFE_CHECKPOINT_WAKE2(cleanup_fn, id, nr_wake) \ + tst_safe_checkpoint_wake(__FILE__, __LINE__, cleanup_fn, id, nr_wake); + +#define TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup_fn, id) \ + tst_safe_checkpoint_wake(__FILE__, __LINE__, cleanup_fn, id, 1); \ + tst_safe_checkpoint_wait(__FILE__, __LINE__, cleanup_fn, id, 0); + +#endif /* OLD_CHECKPOINT__ */ diff --git a/ltp/include/old/old_device.h b/ltp/include/old/old_device.h new file mode 100644 index 0000000000000000000000000000000000000000..a6e9fea860c5e243ce492be9e059fd637af6dc8f --- /dev/null +++ b/ltp/include/old/old_device.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014-2016 Cyril Hrubis + * + * 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 . + */ + +#ifndef OLD_DEVICE_H__ +#define OLD_DEVICE_H__ + +/* + * Returns filesystem type to be used for the testing. Unless your test is + * designed for specific filesystem you should use this function to the tested + * filesystem. + * + * If TST_DEV_FS_TYPE is set the function returns it's content, + * otherwise default fs type hardcoded in the library is returned. + */ +const char *tst_dev_fs_type(void); + +/* + * Acquires test device. + * + * Can be used only once, i.e. you cannot get two different devices. + * + * Looks for LTP_DEV env variable first (which may be passed by the test + * driver or by a user) and returns just it's value if found. + * + * Otherwise creates a temp file and loop device. + * + * Note that you have to call tst_tmpdir() beforehand. + * + * Returns path to the device or NULL if it cannot be created. + * Call tst_release_device() when you're done. + */ +const char *tst_acquire_device_(void (cleanup_fn)(void), unsigned int size); + +const char *tst_acquire_device__(unsigned int size); + +static inline const char *tst_acquire_device(void (cleanup_fn)(void)) +{ + return tst_acquire_device_(cleanup_fn, 0); +} + +/* + * Acquire a loop device with specified temp filename. This function allows + * you to acquire multiple devices at the same time. LTP_DEV is ignored. + * If you call this function directly, use tst_detach_device() to release + * the devices. tst_release_device() will not work correctly. + * + * The return value points to a static buffer and additional calls of + * tst_acquire_loop_device() or tst_acquire_device() will overwrite it. + */ +const char *tst_acquire_loop_device(unsigned int size, const char *filename); + +/* + * @dev: device path returned by the tst_acquire_device() + */ +int tst_release_device(const char *dev); + +/* + * Cleanup function for tst_acquire_loop_device(). If you have acquired + * a device using tst_acquire_device(), use tst_release_device() instead. + * @dev: device path returned by the tst_acquire_loop_device() + */ +int tst_detach_device(const char *dev); + +/* + * Just like umount() but retries several times on failure. + * @path: Path to umount + */ +int tst_umount(const char *path); + +#endif /* OLD_DEVICE_H__ */ diff --git a/ltp/include/old/old_module.h b/ltp/include/old/old_module.h new file mode 100644 index 0000000000000000000000000000000000000000..f49c9937e7f2f81623de770e4d68fe5a1959a7df --- /dev/null +++ b/ltp/include/old/old_module.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) Linux Test Project, 2016-2024 + * + * 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 would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Alexey Kodanev + * + * These functions help to load and unload kernel modules in the tests. + * + * tst_module_load function already includes tst_module_exists function, + * which is checking the following possible module's locations: + * + * 1. Current working directory + * + * 2. LTP installation path (using env LTPROOT, which is usually /opt/ltp) + * + * 3. If tmp directory created, it'll look at the test start working directory + * + */ + +#ifndef TST_MODULE +#define TST_MODULE + +#include + +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); + +bool tst_module_signature_enforced_(void); +void tst_requires_module_signature_disabled_(void); + +/* + * Check module existence. + * + * @mod_name: module's file name. + * @mod_path: if it is not NULL, then tst_module_exists places the found + * module's path into the location pointed to by *mod_path. It must be freed + * with free() when it is no longer needed. + * + * In case of failure, test'll call cleanup_fn and exit with TCONF return value. + */ +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. + * + * @mod_name: module's file name. + * @argv: an array of pointers to null-terminated strings that represent the + * additional parameters to the module. The array of pointers must be + * terminated by a NULL pointer. If argv points to NULL, it will be ignored. + * + * In case of insmod failure, test will call cleanup_fn and exit with TBROK + * return value. + */ +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 + * cleanup_fn and exit with TBROK return value. + * + * @mod_name: can be module name or module's file name. + */ +static inline void tst_module_unload(void (cleanup_fn)(void), const char *mod_name) +{ + tst_module_unload_(cleanup_fn, mod_name); +} + +/** + * tst_requires_module_signature_disabled() - Check if enforced module signature. + * + * Module signature is enforced if module.sig_enforce=1 kernel parameter or + * CONFIG_MODULE_SIG_FORCE=y. + * + * return: Returns true if module signature is enforced false otherwise. + * + */ +static inline bool tst_module_signature_enforced(void) +{ + return tst_module_signature_enforced_(); +} + +/** + * tst_requires_module_signature_disabled() - Check if test needs to be skipped due + * enforced module signature. + * + * Skip test with tst_brk(TCONF) due module signature enforcement if + * module.sig_enforce=1 kernel parameter or CONFIG_MODULE_SIG_FORCE=y. + */ + +static inline void tst_requires_module_signature_disabled(void) +{ + tst_requires_module_signature_disabled_(); +} + +#endif /* TST_MODULE */ diff --git a/ltp/include/old/old_resource.h b/ltp/include/old/old_resource.h new file mode 100644 index 0000000000000000000000000000000000000000..46767f35c4429d3e55c9deafcac62fd0a21176ae --- /dev/null +++ b/ltp/include/old/old_resource.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 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. + */ + + /* + + Small helper for preparing files the test needs to copy before the testing. + + We need to support two scenarios. + + 1. Test is executed in local directory and this is also the place + we should look for files + + + 2. Test is executed after LTP has been installed, in this case we + look for env LTPROOT (usually /opt/ltp/) + + */ + +#ifndef TST_RESOURCE +#define TST_RESOURCE + +const char *tst_dataroot(void); + +/* + * Copy a file to the CWD. The destination is apended to CWD. + */ +#define TST_RESOURCE_COPY(cleanup_fn, filename, dest) \ + tst_resource_copy(__FILE__, __LINE__, (cleanup_fn), \ + (filename), (dest)) + +void tst_resource_copy(const char *file, const int lineno, + void (*cleanup_fn)(void), + const char *filename, const char *dest); + +#endif /* TST_RESOURCE */ diff --git a/ltp/include/old/old_safe_file_ops.h b/ltp/include/old/old_safe_file_ops.h new file mode 100644 index 0000000000000000000000000000000000000000..d6e2d29a96900297e1c803e6e1ed99cfeba2f8ae --- /dev/null +++ b/ltp/include/old/old_safe_file_ops.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012-2016 Cyril Hrubis + * + * 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 . + */ + + /* + + This code helps with file reading/writing files providing scanf/printf like + interface that opens and closes the file automatically. + + This kind of interface is especially useful for reading/writing values + from/to pseudo filesystems like procfs or sysfs. + + */ + +#ifndef SAFE_FILE_OPS +#define SAFE_FILE_OPS + +#include "safe_file_ops_fn.h" + +#define FILE_SCANF(path, fmt, ...) \ + file_scanf(__FILE__, __LINE__, \ + (path), (fmt), ## __VA_ARGS__) + +#define SAFE_FILE_SCANF(cleanup_fn, path, fmt, ...) \ + safe_file_scanf(__FILE__, __LINE__, (cleanup_fn), \ + (path), (fmt), ## __VA_ARGS__) + +#define FILE_LINES_SCANF(cleanup_fn, path, fmt, ...) \ + file_lines_scanf(__FILE__, __LINE__, (cleanup_fn), 0, \ + (path), (fmt), ## __VA_ARGS__) + +#define SAFE_FILE_LINES_SCANF(cleanup_fn, path, fmt, ...) \ + file_lines_scanf(__FILE__, __LINE__, (cleanup_fn), 1, \ + (path), (fmt), ## __VA_ARGS__) + +#define FILE_PRINTF(path, fmt, ...) \ + file_printf(__FILE__, __LINE__, \ + (path), (fmt), ## __VA_ARGS__) + +#define SAFE_FILE_PRINTF(cleanup_fn, path, fmt, ...) \ + safe_file_printf(__FILE__, __LINE__, (cleanup_fn), \ + (path), (fmt), ## __VA_ARGS__) + +#define SAFE_CP(cleanup_fn, src, dst) \ + safe_cp(__FILE__, __LINE__, (cleanup_fn), (src), (dst)) + +#define SAFE_TOUCH(cleanup_fn, pathname, mode, times) \ + safe_touch(__FILE__, __LINE__, (cleanup_fn), \ + (pathname), (mode), (times)) + +#endif /* SAFE_FILE_OPS */ diff --git a/ltp/include/old/old_safe_net.h b/ltp/include/old/old_safe_net.h new file mode 100644 index 0000000000000000000000000000000000000000..639094a94820825c780ce58af2d80964741bf499 --- /dev/null +++ b/ltp/include/old/old_safe_net.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015 Fujitsu Ltd. + * Copyright (c) 2016 Cyril Hrubis + * + * 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 . + */ + +#ifndef OLD_SAFE_NET_H__ +#define OLD_SAFE_NET_H__ + +#include +#include +#include +#include +#include + +#include "safe_net_fn.h" + +#define SAFE_SOCKET(cleanup_fn, domain, type, protocol) \ + safe_socket(__FILE__, __LINE__, (cleanup_fn), domain, type, protocol) + +#define SAFE_BIND(cleanup_fn, socket, address, address_len) \ + safe_bind(__FILE__, __LINE__, (cleanup_fn), socket, address, \ + address_len) + +#define SAFE_LISTEN(cleanup_fn, socket, backlog) \ + safe_listen(__FILE__, __LINE__, (cleanup_fn), socket, backlog) + +#define SAFE_CONNECT(cleanup_fn, sockfd, addr, addrlen) \ + safe_connect(__FILE__, __LINE__, (cleanup_fn), sockfd, addr, addrlen) + +#define SAFE_GETSOCKNAME(cleanup_fn, sockfd, addr, addrlen) \ + safe_getsockname(__FILE__, __LINE__, (cleanup_fn), sockfd, addr, \ + addrlen) + +#define TST_GET_UNUSED_PORT(cleanup_fn, family, type) \ + tst_get_unused_port(__FILE__, __LINE__, (cleanup_fn), family, type) + +#endif /* OLD_SAFE_NET_H__ */ diff --git a/ltp/include/old/old_safe_stdio.h b/ltp/include/old/old_safe_stdio.h new file mode 100644 index 0000000000000000000000000000000000000000..3508b2479d077bbfad9fda33824d6c289bef306b --- /dev/null +++ b/ltp/include/old/old_safe_stdio.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013-2016 Cyril Hrubis + * + * 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 . + */ + +#ifndef OLD_SAFE_STDIO_H__ +#define OLD_SAFE_STDIO_H__ + +#include + +#include "safe_stdio_fn.h" + +#define SAFE_FOPEN(cleanup_fn, path, mode) \ + safe_fopen(__FILE__, __LINE__, cleanup_fn, path, mode) + +#define SAFE_FCLOSE(cleanup_fn, f) \ + safe_fclose(__FILE__, __LINE__, cleanup_fn, f) + +#define SAFE_ASPRINTF(cleanup_fn, strp, fmt, ...) \ + safe_asprintf(__FILE__, __LINE__, cleanup_fn, strp, fmt, __VA_ARGS__) + +#define SAFE_POPEN(cleanup_fn, command, type) \ + safe_popen(__FILE__, __LINE__, cleanup_fn, command, type) + +#endif /* OLD_SAFE_STDIO_H__ */ diff --git a/ltp/include/old/old_tmpdir.h b/ltp/include/old/old_tmpdir.h new file mode 100644 index 0000000000000000000000000000000000000000..3e33bf043e2942676ebeb2fb59c9708c8ee00f19 --- /dev/null +++ b/ltp/include/old/old_tmpdir.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Cyril Hrubis + * + * 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 . + */ + +#ifndef OLD_TMPDIR_H__ +#define OLD_TMPDIR_H__ + +/* + * Create a unique temporary directory and chdir() to it. It expects the caller + * to have defined/initialized the TCID/TST_TOTAL global variables. + * The TESTDIR global variable will be set to the directory that gets used + * as the testing directory. + * + * NOTE: This function must be called BEFORE any activity that would require + * CLEANUP. If tst_tmpdir() fails, it cleans up afer itself and calls + * tst_exit() (i.e. does not return). + */ +void tst_tmpdir(void); + +/* + * Recursively remove the temporary directory created by tst_tmpdir(). + * This function is intended ONLY as a companion to tst_tmpdir(). + */ +void tst_rmdir(void); + +/* tst_get_tmpdir() + * + * Return a copy of the test temp directory as seen by LTP. This is for + * path-oriented tests like chroot, etc, that may munge the path a bit. + * + * FREE VARIABLE AFTER USE IF IT IS REUSED! + */ +char *tst_get_tmpdir(void); + +/* + * Returns path to the test temporary directory root (TMPDIR). + */ +const char *tst_get_tmpdir_root(void); + +/* + * Returns 1 if temp directory was created. + */ +int tst_tmpdir_created(void); + +/* declared in tst_tmpdir.c */ +const char *tst_get_startwd(void); + +#endif /* OLD_TMPDIR_H__ */ diff --git a/ltp/include/old/random_range.h b/ltp/include/old/random_range.h new file mode 100644 index 0000000000000000000000000000000000000000..22b3f932318c8d6328c302b819df188b4aaf07bb --- /dev/null +++ b/ltp/include/old/random_range.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +#ifndef _RANDOM_RANGE_H_ +#define _RANDOM_RANGE_H_ + +int parse_ranges ( char *, int, int, int, int (*)(), char **, char ** ); +int range_min ( char *, int ); +int range_max ( char *, int ); +int range_mult ( char *, int ); +long random_range ( int, int, int, char ** ); +long random_rangel ( long, long, long, char ** ); +long long random_rangell ( long long, long long, long long, char ** ); +void random_range_seed( long ); +long random_bit ( long ); + +#endif diff --git a/ltp/include/old/safe_macros.h b/ltp/include/old/safe_macros.h new file mode 100644 index 0000000000000000000000000000000000000000..fb1d7a110b57550f640ff36e24561978202d3453 --- /dev/null +++ b/ltp/include/old/safe_macros.h @@ -0,0 +1,340 @@ +/* + * Safe macros for commonly used syscalls to reduce code duplication in LTP + * testcases, and to ensure all errors are caught in said testcases as + * gracefully as possible. + * + * Also satiates some versions of gcc/glibc when the warn_unused_result + * attribute is applied to the function call. + * + * Licensed under the GPLv2. + */ + +#ifndef __TEST_H__ +#error "you must include test.h before this file" +#else + +#ifndef __SAFE_MACROS_H__ +#define __SAFE_MACROS_H__ + +#include "safe_macros_fn.h" +#include "old_safe_stdio.h" +#include "old_safe_net.h" + +#define SAFE_BASENAME(cleanup_fn, path) \ + safe_basename(__FILE__, __LINE__, (cleanup_fn), (path)) + +#define SAFE_CHDIR(cleanup_fn, path) \ + safe_chdir(__FILE__, __LINE__, (cleanup_fn), (path)) + +#define SAFE_CLOSE(cleanup_fn, fd) ({ \ + int ret = safe_close(__FILE__, __LINE__, (cleanup_fn), (fd)); \ + fd = -1; \ + ret; \ + }) + +#define SAFE_CREAT(cleanup_fn, pathname, mode) \ + safe_creat(__FILE__, __LINE__, cleanup_fn, (pathname), (mode)) + +#define SAFE_DIRNAME(cleanup_fn, path) \ + safe_dirname(__FILE__, __LINE__, (cleanup_fn), (path)) + +#define SAFE_GETCWD(cleanup_fn, buf, size) \ + safe_getcwd(__FILE__, __LINE__, (cleanup_fn), (buf), (size)) + +#define SAFE_GETPWNAM(cleanup_fn, name) \ + safe_getpwnam(__FILE__, __LINE__, cleanup_fn, (name)) + +#define SAFE_GETRUSAGE(cleanup_fn, who, usage) \ + safe_getrusage(__FILE__, __LINE__, (cleanup_fn), (who), (usage)) + +#define SAFE_MALLOC(cleanup_fn, size) \ + safe_malloc(__FILE__, __LINE__, (cleanup_fn), (size)) + +#define SAFE_MKDIR(cleanup_fn, pathname, mode) \ + safe_mkdir(__FILE__, __LINE__, (cleanup_fn), (pathname), (mode)) + +#define SAFE_RMDIR(cleanup_fn, pathname) \ + safe_rmdir(__FILE__, __LINE__, (cleanup_fn), (pathname)) + +#define SAFE_MUNMAP(cleanup_fn, addr, length) \ + safe_munmap(__FILE__, __LINE__, (cleanup_fn), (addr), (length)) + +#define SAFE_OPEN(cleanup_fn, pathname, oflags, ...) \ + safe_open(__FILE__, __LINE__, (cleanup_fn), (pathname), (oflags), \ + ##__VA_ARGS__) + +#define SAFE_PIPE(cleanup_fn, fildes) \ + safe_pipe(__FILE__, __LINE__, cleanup_fn, (fildes)) + +#define SAFE_READ(cleanup_fn, len_strict, fildes, buf, nbyte) \ + safe_read(__FILE__, __LINE__, cleanup_fn, (len_strict), (fildes), \ + (buf), (nbyte)) + +#define SAFE_SETEGID(cleanup_fn, egid) \ + safe_setegid(__FILE__, __LINE__, cleanup_fn, (egid)) + +#define SAFE_SETEUID(cleanup_fn, euid) \ + safe_seteuid(__FILE__, __LINE__, cleanup_fn, (euid)) + +#define SAFE_SETGID(cleanup_fn, gid) \ + safe_setgid(__FILE__, __LINE__, cleanup_fn, (gid)) + +#define SAFE_SETUID(cleanup_fn, uid) \ + safe_setuid(__FILE__, __LINE__, cleanup_fn, (uid)) + +#define SAFE_GETRESUID(cleanup_fn, ruid, euid, suid) \ + safe_getresuid(__FILE__, __LINE__, cleanup_fn, (ruid), (euid), (suid)) + +#define SAFE_GETRESGID(cleanup_fn, rgid, egid, sgid) \ + safe_getresgid(__FILE__, __LINE__, cleanup_fn, (rgid), (egid), (sgid)) + +#define SAFE_UNLINK(cleanup_fn, pathname) \ + safe_unlink(__FILE__, __LINE__, cleanup_fn, (pathname)) + +#define SAFE_LINK(cleanup_fn, oldpath, newpath) \ + safe_link(__FILE__, __LINE__, cleanup_fn, (oldpath), (newpath)) + +#define SAFE_LINKAT(cleanup_fn, olddirfd, oldpath, newdirfd, newpath, flags) \ + safe_linkat(__FILE__, __LINE__, cleanup_fn, (olddirfd), (oldpath), \ + (newdirfd), (newpath), (flags)) + +#define SAFE_READLINK(cleanup_fn, path, buf, bufsize) \ + safe_readlink(__FILE__, __LINE__, cleanup_fn, (path), (buf), (bufsize)) + +#define SAFE_SYMLINK(cleanup_fn, oldpath, newpath) \ + safe_symlink(__FILE__, __LINE__, cleanup_fn, (oldpath), (newpath)) + +#define SAFE_WRITE(cleanup_fn, len_strict, fildes, buf, nbyte) \ + safe_write(__FILE__, __LINE__, cleanup_fn, (len_strict), (fildes), \ + (buf), (nbyte)) + +#define SAFE_STRTOL(cleanup_fn, str, min, max) \ + safe_strtol(__FILE__, __LINE__, cleanup_fn, (str), (min), (max)) + +#define SAFE_STRTOUL(cleanup_fn, str, min, max) \ + safe_strtoul(__FILE__, __LINE__, cleanup_fn, (str), (min), (max)) + +#define SAFE_SYSCONF(cleanup_fn, name) \ + safe_sysconf(__FILE__, __LINE__, cleanup_fn, name) + +#define SAFE_CHMOD(cleanup_fn, path, mode) \ + safe_chmod(__FILE__, __LINE__, (cleanup_fn), (path), (mode)) + +#define SAFE_FCHMOD(cleanup_fn, fd, mode) \ + safe_fchmod(__FILE__, __LINE__, (cleanup_fn), (fd), (mode)) + +#define SAFE_CHOWN(cleanup_fn, path, owner, group) \ + safe_chown(__FILE__, __LINE__, (cleanup_fn), (path), (owner), (group)) + +#define SAFE_FCHOWN(cleanup_fn, fd, owner, group) \ + safe_fchown(__FILE__, __LINE__, (cleanup_fn), (fd), (owner), (group)) + +#define SAFE_WAIT(cleanup_fn, status) \ + safe_wait(__FILE__, __LINE__, (cleanup_fn), (status)) + +#define SAFE_WAITPID(cleanup_fn, pid, status, opts) \ + safe_waitpid(__FILE__, __LINE__, (cleanup_fn), (pid), (status), (opts)) + +#define SAFE_KILL(cleanup_fn, pid, sig) \ + safe_kill(__FILE__, __LINE__, (cleanup_fn), (pid), (sig)) + +#define SAFE_MEMALIGN(cleanup_fn, alignment, size) \ + safe_memalign(__FILE__, __LINE__, (cleanup_fn), (alignment), (size)) + +#define SAFE_MKFIFO(cleanup_fn, pathname, mode) \ + safe_mkfifo(__FILE__, __LINE__, (cleanup_fn), (pathname), (mode)) + +#define SAFE_RENAME(cleanup_fn, oldpath, newpath) \ + safe_rename(__FILE__, __LINE__, (cleanup_fn), (oldpath), (newpath)) + +#define SAFE_MOUNT(cleanup_fn, source, target, filesystemtype, \ + mountflags, data) \ + safe_mount(__FILE__, __LINE__, (cleanup_fn), (source), (target), \ + (filesystemtype), (mountflags), (data)) + +#define SAFE_UMOUNT(cleanup_fn, target) \ + safe_umount(__FILE__, __LINE__, (cleanup_fn), (target)) + +/* + * following functions are inline because the behaviour may depend on + * -D_FILE_OFFSET_BITS=64 compile flag + */ + +static inline void *safe_mmap(const char *file, const int lineno, + void (*cleanup_fn)(void), void *addr, size_t length, + int prot, int flags, int fd, off_t offset) +{ + void *rval; + + rval = mmap(addr, length, prot, flags, fd, offset); + if (rval == MAP_FAILED) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: mmap(%p,%zu,%d,%d,%d,%ld) failed", + file, lineno, addr, length, prot, flags, fd, + (long) offset); + } + + return rval; +} +#define SAFE_MMAP(cleanup_fn, addr, length, prot, flags, fd, offset) \ + safe_mmap(__FILE__, __LINE__, (cleanup_fn), (addr), (length), (prot), \ + (flags), (fd), (offset)) + +static inline int safe_ftruncate(const char *file, const int lineno, + void (cleanup_fn) (void), int fd, off_t length) +{ + int rval; + + rval = ftruncate(fd, length); + if (rval == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: ftruncate(%d,%ld) failed", + file, lineno, fd, (long)length); + } + + return rval; +} +#define SAFE_FTRUNCATE(cleanup_fn, fd, length) \ + safe_ftruncate(__FILE__, __LINE__, cleanup_fn, (fd), (length)) + +static inline int safe_truncate(const char *file, const int lineno, + void (cleanup_fn) (void), const char *path, off_t length) +{ + int rval; + + rval = truncate(path, length); + if (rval == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: truncate(%s,%ld) failed", + file, lineno, path, (long)length); + } + + return rval; +} +#define SAFE_TRUNCATE(cleanup_fn, path, length) \ + safe_truncate(__FILE__, __LINE__, cleanup_fn, (path), (length)) + +static inline int safe_stat(const char *file, const int lineno, + void (cleanup_fn)(void), const char *path, struct stat *buf) +{ + int rval; + + rval = stat(path, buf); + + if (rval == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: stat(%s,%p) failed", file, lineno, path, buf); + } + + return rval; +} +#define SAFE_STAT(cleanup_fn, path, buf) \ + safe_stat(__FILE__, __LINE__, (cleanup_fn), (path), (buf)) + +static inline int safe_fstat(const char *file, const int lineno, + void (cleanup_fn)(void), int fd, struct stat *buf) +{ + int rval; + + rval = fstat(fd, buf); + + if (rval == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: fstat(%d,%p) failed", file, lineno, fd, buf); + } + + return rval; +} +#define SAFE_FSTAT(cleanup_fn, fd, buf) \ + safe_fstat(__FILE__, __LINE__, (cleanup_fn), (fd), (buf)) + +static inline int safe_lstat(const char *file, const int lineno, + void (cleanup_fn)(void), const char *path, struct stat *buf) +{ + int rval; + + rval = lstat(path, buf); + + if (rval == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: lstat(%s,%p) failed", file, lineno, path, buf); + } + + return rval; +} +#define SAFE_LSTAT(cleanup_fn, path, buf) \ + safe_lstat(__FILE__, __LINE__, (cleanup_fn), (path), (buf)) + +static inline off_t safe_lseek(const char *file, const int lineno, + void (cleanup_fn)(void), int fd, off_t offset, int whence) +{ + off_t rval; + + rval = lseek(fd, offset, whence); + + if (rval == (off_t) -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: lseek(%d,%ld,%d) failed", + file, lineno, fd, (long)offset, whence); + } + + return rval; +} +#define SAFE_LSEEK(cleanup_fn, fd, offset, whence) \ + safe_lseek(__FILE__, __LINE__, cleanup_fn, (fd), (offset), (whence)) + +static inline int safe_getrlimit(const char *file, const int lineno, + void (cleanup_fn)(void), int resource, struct rlimit *rlim) +{ + int rval; + + rval = getrlimit(resource, rlim); + + if (rval == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: getrlimit(%d,%p) failed", + file, lineno, resource, rlim); + } + + return rval; +} +#define SAFE_GETRLIMIT(cleanup_fn, resource, rlim) \ + safe_getrlimit(__FILE__, __LINE__, (cleanup_fn), (resource), (rlim)) + +static inline int safe_setrlimit(const char *file, const int lineno, + void (cleanup_fn)(void), int resource, const struct rlimit *rlim) +{ + int rval; + + rval = setrlimit(resource, rlim); + + if (rval == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "%s:%d: setrlimit(%d,%p) failed", + file, lineno, resource, rlim); + } + + return rval; +} +#define SAFE_SETRLIMIT(cleanup_fn, resource, rlim) \ + safe_setrlimit(__FILE__, __LINE__, (cleanup_fn), (resource), (rlim)) + +#define SAFE_OPENDIR(cleanup_fn, name) \ + safe_opendir(__FILE__, __LINE__, (cleanup_fn), (name)) + +#define SAFE_CLOSEDIR(cleanup_fn, dirp) \ + safe_closedir(__FILE__, __LINE__, (cleanup_fn), (dirp)) + +#define SAFE_READDIR(cleanup_fn, dirp) \ + safe_readdir(__FILE__, __LINE__, (cleanup_fn), (dirp)) + + +#define SAFE_IOCTL(cleanup_fn, fd, request, ...) \ + ({int ret = ioctl(fd, request, __VA_ARGS__); \ + if (ret < 0) \ + tst_brkm(TBROK | TERRNO, cleanup_fn, \ + "ioctl(%i,%s,...) failed", fd, #request); \ + ret;}) + +#endif /* __SAFE_MACROS_H__ */ +#endif /* __TEST_H__ */ diff --git a/ltp/include/old/test.h b/ltp/include/old/test.h new file mode 100644 index 0000000000000000000000000000000000000000..306868fb542510a4bbf68e351d0b8c6dded13466 --- /dev/null +++ b/ltp/include/old/test.h @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2009-2013 Cyril Hrubis chrubis@suse.cz + */ + +#ifndef __TEST_H__ +#define __TEST_H__ + +#ifdef TST_TEST_H__ +# error Newlib tst_test.h already included +#endif /* TST_TEST_H__ */ + +#include +#include +#include +#include +#include +#include + +#include "usctest.h" + +#include "tst_common.h" +#include "old_safe_file_ops.h" +#include "old_checkpoint.h" +#include "tst_process_state.h" +#include "old_resource.h" +#include "tst_res_flags.h" +#include "tst_kvercmp.h" +#include "tst_fs.h" +#include "tst_pid.h" +#include "tst_cmd.h" +#include "tst_cpu.h" +#include "old_device.h" +#include "old_tmpdir.h" +#include "tst_minmax.h" +#include "tst_get_bad_addr.h" +#include "tst_path_has_mnt_flags.h" + +/* + * Ensure that NUMSIGS is defined. + * It should be defined in signal.h or sys/signal.h on + * UNICOS/mk and IRIX systems. On UNICOS systems, + * it is not defined, thus it is being set to UNICOS's NSIG. + * Note: IRIX's NSIG (signals are 1-(NSIG-1)) + * is not same meaning as UNICOS/UMK's NSIG (signals 1-NSIG) + */ +#ifndef NUMSIGS +#define NUMSIGS NSIG +#endif + + +/* defines for unexpected signal setup routine (set_usig.c) */ +#define FORK 1 /* SIGCHLD is to be ignored */ +#define NOFORK 0 /* SIGCHLD is to be caught */ +#define DEF_HANDLER SIG_ERR /* tells set_usig() to use default signal handler */ + +/* + * The following defines are used to control tst_res and t_result reporting. + */ + +#define TOUTPUT "TOUTPUT" /* The name of the environment variable */ + /* that can be set to one of the following */ + /* strings to control tst_res output */ + /* If not set, TOUT_VERBOSE_S is assumed */ + +/* + * Macro to use for making functions called only once in + * multi-threaded tests such as init or cleanup function. + * The first call to @name_fn function by any thread shall + * call the @exec_fn. Subsequent calls shall not call @exec_fn. + * *_fn functions must not take any arguments. + */ +#define TST_DECLARE_ONCE_FN(name_fn, exec_fn) \ + void name_fn(void) \ + { \ + static pthread_once_t ltp_once = PTHREAD_ONCE_INIT; \ + pthread_once(<p_once, exec_fn); \ + } + +/* + * lib/forker.c + */ +extern int Forker_pids[]; +extern int Forker_npids; + +typedef struct { + char *option; /* Valid option string (one option only) like "a:" */ + int *flag; /* Pointer to location to set true if option given */ + char **arg; /* Pointer to location to place argument, if needed */ +} option_t; + +/* lib/tst_parse_opts.c */ +void tst_parse_opts(int argc, char *argv[], const option_t *user_optarg, + void (*user_help)(void)); + +/* lib/tst_res.c */ +const char *strttype(int ttype); + +void tst_resm_(const char *file, const int lineno, int ttype, + const char *arg_fmt, ...) + __attribute__ ((format (printf, 4, 5))); +#define tst_resm(ttype, arg_fmt, ...) \ + tst_resm_(__FILE__, __LINE__, (ttype), \ + (arg_fmt), ##__VA_ARGS__) + +void tst_resm_hexd_(const char *file, const int lineno, int ttype, + const void *buf, size_t size, const char *arg_fmt, ...) + __attribute__ ((format (printf, 6, 7))); +#define tst_resm_hexd(ttype, buf, size, arg_fmt, ...) \ + tst_resm_hexd_(__FILE__, __LINE__, (ttype), (buf), (size), \ + (arg_fmt), ##__VA_ARGS__) + +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; + +#ifdef LTPLIB +# include "ltp_priv.h" +# define tst_brkm(flags, cleanup, fmt, ...) do { \ + if (tst_test) \ + tst_brk_(__FILE__, __LINE__, flags, fmt, ##__VA_ARGS__); \ + else \ + 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__); \ + } while (0) +#endif + +void tst_require_root(void); +void tst_exit(void) LTP_ATTRIBUTE_NORETURN; +void tst_old_flush(void); + +/* + * tst_old_flush() + fork + * NOTE: tst_fork() will reset T_exitval to 0 for child process. + */ +pid_t tst_fork(void); + +/* lib/tst_res.c */ +/* + * In case we need do real test work in child process parent process can use + * tst_record_childstatus() to make child process's test results propagated to + * parent process correctly. + * + * The child can use tst_resm(), tst_brkm() followed by the tst_exit() or + * plain old exit() (with TPASS, TFAIL and TBROK). + * + * WARNING: Be wary that the child cleanup function passed to tst_brkm() + * must clean only resources the child has allocated. E.g. the + * child cleanup is different function from the parent cleanup. + */ +void tst_record_childstatus(void (*cleanup)(void), pid_t child); + +extern int tst_count; + +/* lib/tst_sig.c */ +void tst_sig(int fork_flag, void (*handler)(), void (*cleanup)()); + +/* lib/tst_mkfs.c + * + * @dev: path to a device + * @fs_type: filesystem type + * @fs_opts: NULL or NULL terminated array of mkfs options + * @extra_opts: NULL or NULL terminated array of extra mkfs options which are + * passed after the device name. + */ +#define tst_mkfs(cleanup, dev, fs_type, fs_opts, extra_opts) \ + tst_mkfs_(__FILE__, __LINE__, cleanup, dev, fs_type, \ + fs_opts, extra_opts) +void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), + const char *dev, const char *fs_type, + const char *const fs_opts[], const char *const extra_opts[]); + +/* lib/tst_res.c + * tst_strsig converts signal's value to corresponding string. + * tst_strerrno converts errno to corresponding string. + */ +const char *tst_strsig(int sig); +const char *tst_strerrno(int err); + +#ifdef TST_USE_COMPAT16_SYSCALL +#define TCID_BIT_SUFFIX "_16" +#elif TST_USE_NEWER64_SYSCALL +#define TCID_BIT_SUFFIX "_64" +#else +#define TCID_BIT_SUFFIX "" +#endif +#define TCID_DEFINE(ID) char *TCID = (#ID TCID_BIT_SUFFIX) + +#endif /* __TEST_H__ */ diff --git a/ltp/include/old/tlibio.h b/ltp/include/old/tlibio.h new file mode 100644 index 0000000000000000000000000000000000000000..0fe9ce9debbc9f887ca5235f557596a9dda31e2e --- /dev/null +++ b/ltp/include/old/tlibio.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ + +#define LIO_IO_SYNC 00001 /* read/write */ +#define LIO_IO_ASYNC 00002 /* reada/writea/aio_write/aio_read */ +#define LIO_IO_SLISTIO 00004 /* single stride sync listio */ +#define LIO_IO_ALISTIO 00010 /* single stride async listio */ +#define LIO_IO_SYNCV 00020 /* single-buffer readv/writev */ +#define LIO_IO_SYNCP 00040 /* pread/pwrite */ + +#ifdef sgi +#define LIO_IO_ATYPES 00077 /* all io types */ +#define LIO_IO_TYPES 00061 /* all io types, non-async */ +#endif /* sgi */ +#if defined(__linux__) && !defined(__UCLIBC__) +#define LIO_IO_TYPES 00061 /* all io types */ +#define LIO_IO_ATYPES 00077 /* all io types */ +#endif +#if defined(__sun) || defined(__hpux) || defined(_AIX) || defined(__UCLIBC__) +#define LIO_IO_TYPES 00021 /* all io types except pread/pwrite */ +#endif /* linux */ +#ifdef CRAY +#define LIO_IO_TYPES 00017 /* all io types */ +#endif /* CRAY */ + +#ifndef LIO_IO_ATYPES +#define LIO_IO_ATYPES LIO_IO_TYPES +#endif + +#define LIO_WAIT_NONE 00010000 /* return asap -- use with care */ +#define LIO_WAIT_ACTIVE 00020000 /* spin looking at iosw fields, or EINPROGRESS */ +#define LIO_WAIT_RECALL 00040000 /* call recall(2)/aio_suspend(3) */ +#define LIO_WAIT_SIGPAUSE 00100000 /* call pause */ +#define LIO_WAIT_SIGACTIVE 00200000 /* spin waiting for signal */ +#if defined(sgi) || defined(__linux__) +#define LIO_WAIT_CBSUSPEND 00400000 /* aio_suspend waiting for callback */ +#define LIO_WAIT_SIGSUSPEND 01000000 /* aio_suspend waiting for signal */ +#define LIO_WAIT_ATYPES 01760000 /* all async wait types, except nowait */ +#define LIO_WAIT_TYPES 00020000 /* all sync wait types (sorta) */ +#endif /* sgi */ +#if defined(__sun) || defined(__hpux) || defined(_AIX) +#define LIO_WAIT_TYPES 00300000 /* all wait types, except nowait */ +#endif /* linux */ +#ifdef CRAY +#define LIO_WAIT_TYPES 00360000 /* all wait types, except nowait */ +#endif /* CRAY */ + +/* meta wait io */ +/* 00 000 0000 */ + +#if defined(sgi) || defined(__linux__) +/* all callback wait types */ +#define LIO_WAIT_CBTYPES (LIO_WAIT_CBSUSPEND) +/* all signal wait types */ +#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE|LIO_WAIT_SIGACTIVE|LIO_WAIT_SIGSUSPEND) +/* all aio_{read,write} or lio_listio */ +#define LIO_IO_ASYNC_TYPES (LIO_IO_ASYNC|LIO_IO_SLISTIO|LIO_IO_ALISTIO) +#endif /* sgi */ +#if defined(__sun) || defined(__hpux) || defined(_AIX) +/* all signal wait types */ +#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE) +#endif /* linux */ +#ifdef CRAY +/* all signal wait types */ +#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE|LIO_WAIT_SIGACTIVE) +#endif /* CRAY */ + +/* + * This bit provides a way to randomly pick an io type and wait method. + * lio_read_buffer() and lio_write_buffer() functions will call + * lio_random_methods() with the given method. + */ +#define LIO_RANDOM 010000000 + +/* + * This bit provides a way for the programmer to use async i/o with + * signals and to use their own signal handler. By default, + * the signal will only be given to the system call if the wait + * method is LIO_WAIT_SIGPAUSE or LIO_WAIT_SIGACTIVE. + * Whenever these wait methods are used, libio signal handler + * will be used. + */ +#define LIO_USE_SIGNAL 020000000 + +/* + * prototypes/structures for functions in the libio.c module. See comments + * in that module, or man page entries for information on the individual + * functions. + */ + +int stride_bounds(int offset, int stride, int nstrides, + int bytes_per_stride, int *min_byte, int *max_byte); + +int lio_set_debug(int level); +int lio_parse_io_arg1(char *string); +void lio_help1(char *prefex); +int lio_parse_io_arg2(char *string, char **badtoken); +void lio_help2(char *prefex); +int lio_write_buffer(int fd, int method, char *buffer, int size, + int sig, char **errmsg, long wrd); + +int lio_read_buffer(int fd, int method, char *buffer, int size, + int sig, char **errmsg, long wrd); +int lio_random_methods(long mask); + +#if CRAY +#include +int lio_wait4asyncio(int method, int fd, struct iosw **statptr); +int lio_check_asyncio(char *io_type, int size, struct iosw *status); +#endif /* CRAY */ +#if defined (sgi) +#include +int lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp); +int lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method); +#endif /* sgi */ +#if defined(__linux__) && !defined(__UCLIBC__) +#include +int lio_wait4asyncio(int method, int fd, struct aiocb *aiocbp); +int lio_check_asyncio(char *io_type, int size, struct aiocb *aiocbp, int method); +#endif + +/* + * Define the structure that contains the infomation that is used + * by the parsing and help functions. + */ +struct lio_info_type { + char *token; + int bits; + char *desc; +}; + + diff --git a/ltp/include/old/usctest.h b/ltp/include/old/usctest.h new file mode 100644 index 0000000000000000000000000000000000000000..b984c343fdd33625442b0d8e35d6e4f0825742b8 --- /dev/null +++ b/ltp/include/old/usctest.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Author: William Roske + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ + +#ifndef __USCTEST_H__ +#define __USCTEST_H__ + +/* For PATH_MAX */ +#include + +/*********************************************************************** + * The following globals are defined in parse_opts.c but must be + * externed here because they are used in the macros defined below. + ***********************************************************************/ +extern int STD_LOOP_COUNT; /* changed by -in to set loop count to n */ + +extern long TEST_RETURN; +extern int TEST_ERRNO; + +/*********************************************************************** + * TEST: calls a system call + * + * parameters: + * SCALL = system call and parameters to execute + * + ***********************************************************************/ +#define TEST(SCALL) \ + do { \ + errno = 0; \ + TEST_RETURN = SCALL; \ + TEST_ERRNO = errno; \ + } while (0) + +/*********************************************************************** + * TEST_PAUSE: Pause for SIGUSR1 if the pause flag is set. + * Just continue when signal comes in. + * + * parameters: + * none + * + ***********************************************************************/ +#define TEST_PAUSE usc_global_setup_hook(); +int usc_global_setup_hook(); + +/*********************************************************************** + * TEST_LOOPING now call the usc_test_looping function. + * The function will return 1 if the test should continue + * iterating. + * + ***********************************************************************/ +#define TEST_LOOPING usc_test_looping +int usc_test_looping(int counter); + +#endif /* __USCTEST_H__ */ diff --git a/ltp/include/parse_vdso.h b/ltp/include/parse_vdso.h new file mode 100644 index 0000000000000000000000000000000000000000..5212fc659e34268f918b4efd9900e55331dad5d3 --- /dev/null +++ b/ltp/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/ltp/include/safe_file_ops_fn.h b/ltp/include/safe_file_ops_fn.h new file mode 100644 index 0000000000000000000000000000000000000000..223fb0d687e789fa788164dea133d8d00c51f90d --- /dev/null +++ b/ltp/include/safe_file_ops_fn.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2012-2016 Cyril Hrubis + * + * 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 . + */ + +#ifndef SAFE_FILE_OPS_FN +#define SAFE_FILE_OPS_FN + +#include +#include + +#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. + */ +int file_scanf(const char *file, const int lineno, + const char *path, const char *fmt, ...) + __attribute__ ((format (scanf, 4, 5))); + +void safe_file_scanf(const char *file, const int lineno, + void (*cleanup_fn)(void), + const char *path, const char *fmt, ...) + __attribute__ ((format (scanf, 5, 6))); + +int file_lines_scanf(const char *file, const int lineno, + void (*cleanup_fn)(void), int strict, + const char *path, const char *fmt, ...) + __attribute__ ((format (scanf, 6, 7))); + +/* + * All-in-one function that lets you printf directly into a file. + */ +int file_printf(const char *file, const int lineno, + const char *path, const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); + +void safe_file_printf(const char *file, const int lineno, + void (*cleanup_fn)(void), + 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. + */ +int safe_cp(const char *file, const int lineno, + void (*cleanup_fn)(void), + const char *src, const char *dst); + +/* + * Safe function to touch a file. + * + * If the file (pathname) does not exist It will be created with + * the specified permission (mode) and the access/modification times (times). + * + * If mode is 0 then the file is created with (0666 & ~umask) + * permission or (if the file exists) the permission is not changed. + * + * 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. + */ +int safe_touch(const char *file, const int lineno, + void (*cleanup_fn)(void), + const char *pathname, + mode_t mode, const struct timespec times[2]); + +#endif /* SAFE_FILE_OPS_FN */ diff --git a/ltp/include/safe_macros_fn.h b/ltp/include/safe_macros_fn.h new file mode 100644 index 0000000000000000000000000000000000000000..d256091b76ad10b06b29e3fd5fad8853faa14c08 --- /dev/null +++ b/ltp/include/safe_macros_fn.h @@ -0,0 +1,202 @@ +/* + * Safe macros for commonly used syscalls to reduce code duplication in LTP + * testcases, and to ensure all errors are caught in said testcases as + * gracefully as possible. + * + * Also satiates some versions of gcc/glibc when the warn_unused_result + * attribute is applied to the function call. + * + * Licensed under the GPLv2. + */ + +#ifndef SAFE_MACROS_FN_H__ +#define SAFE_MACROS_FN_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* supported values for safe_write() len_strict parameter */ +enum safe_write_opts { + /* no length strictness, short writes are ok */ + SAFE_WRITE_ANY = 0, + + /* strict length, short writes raise TBROK */ + SAFE_WRITE_ALL = 1, + + /* retry/resume after short write */ + SAFE_WRITE_RETRY = 2, +}; + +char* safe_basename(const char *file, const int lineno, + void (*cleanup_fn)(void), char *path); + +int safe_chdir(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *path); + +int safe_close(const char *file, const int lineno, + void (*cleanup_fn)(void), int fildes); + +int safe_creat(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *pathname, mode_t mode); + +char* safe_dirname(const char *file, const int lineno, + void (*cleanup_fn)(void), char *path); + +char* safe_getcwd(const char *file, const int lineno, + void (*cleanup_fn)(void), char *buf, size_t size); + +struct passwd* safe_getpwnam(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *name); + +int safe_getrusage(const char *file, const int lineno, + void (*cleanup_fn)(void), int who, struct rusage *usage); + +void* safe_malloc(const char *file, const int lineno, + void (*cleanup_fn)(void), size_t size); + +int safe_mkdir(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *pathname, mode_t mode); + +int safe_rmdir(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *pathname); + + +int safe_munmap(const char *file, const int lineno, + void (*cleanup_fn)(void), void *addr, size_t length); + +int safe_open(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *pathname, int oflags, ...); + +int safe_pipe(const char *file, const int lineno, + void (*cleanup_fn)(void), int fildes[2]); + +ssize_t safe_read(const char *file, const int lineno, + void (*cleanup_fn)(void), char len_strict, int fildes, + void *buf, size_t nbyte); + +int safe_setegid(const char *file, const int lineno, + void (*cleanup_fn)(void), gid_t egid); + +int safe_seteuid(const char *file, const int lineno, + void (*cleanup_fn)(void), uid_t euid); + +int safe_setgid(const char *file, const int lineno, + void (*cleanup_fn)(void), gid_t gid); + +int safe_setuid(const char *file, const int lineno, + void (*cleanup_fn)(void), uid_t uid); + +int safe_getresuid(const char *file, const int lineno, + void (*cleanup_fn)(void), + uid_t *ruid, uid_t *euid, uid_t *suid); + +int safe_getresgid(const char *file, const int lineno, + void (*cleanup_fn)(void), + gid_t *rgid, gid_t *egid, gid_t *sgid); + +int safe_unlink(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *pathname); + +int safe_link(const char *file, const int lineno, + void (cleanup_fn)(void), const char *oldpath, + const char *newpath); + +int safe_linkat(const char *file, const int lineno, + void (cleanup_fn)(void), int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, int flags); + +ssize_t safe_readlink(const char *file, const int lineno, + void (cleanup_fn)(void), const char *path, + char *buf, size_t bufsize); + +int safe_symlink(const char *file, const int lineno, + void (cleanup_fn)(void), const char *oldpath, + const char *newpath); + +ssize_t safe_write(const char *file, const int lineno, + void (cleanup_fn)(void), enum safe_write_opts len_strict, + int fildes, const void *buf, size_t nbyte); + +long safe_strtol(const char *file, const int lineno, + void (cleanup_fn)(void), char *str, long min, long max); + +unsigned long safe_strtoul(const char *file, const int lineno, + void (cleanup_fn)(void), + char *str, unsigned long min, unsigned long max); + +float safe_strtof(const char *file, const int lineno, + void (cleanup_fn)(void), char *str, float min, float max); + +long safe_sysconf(const char *file, const int lineno, + void (cleanup_fn)(void), int name); + +int safe_chmod(const char *file, const int lineno, void (cleanup_fn)(void), + const char *path, mode_t mode); + +int safe_fchmod(const char *file, const int lineno, void (cleanup_fn)(void), + int fd, mode_t mode); + +int safe_chown(const char *file, const int lineno, void (cleanup_fn)(void), + const char *path, uid_t owner, gid_t group); + +int safe_fchown(const char *file, const int lineno, void (cleanup_fn)(void), + int fd, uid_t owner, gid_t group); + +pid_t safe_wait(const char *file, const int lineno, void (cleanup_fn)(void), + int *status); + +pid_t safe_waitpid(const char *file, const int lineno, void (cleanup_fn)(void), + pid_t pid, int *status, int opts); + +int safe_kill(const char *file, const int lineno, void (cleanup_fn)(void), + pid_t pid, int sig); + +void *safe_memalign(const char *file, const int lineno, + void (*cleanup_fn)(void), size_t alignment, size_t size); + +int safe_mkfifo(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *pathname, mode_t mode); + +int safe_rename(const char *file, const int lineno, void (*cleanup_fn)(void), + const char *oldpath, const char *newpath); + +int safe_mount(const char *file, const int lineno, void (*cleanup_fn)(void), + const char *source, const char *target, + const char *filesystemtype, unsigned long mountflags, + const void *data); + +int safe_umount(const char *file, const int lineno, void (*cleanup_fn)(void), + const char *target); + +DIR* safe_opendir(const char *file, const int lineno, void (cleanup_fn)(void), + const char *name); + +int safe_closedir(const char *file, const int lineno, void (cleanup_fn)(void), + DIR *dirp); + +struct dirent *safe_readdir(const char *file, const int lineno, + void (cleanup_fn)(void), + DIR *dirp); + +DIR* safe_opendir(const char *file, const int lineno, + void (cleanup_fn)(void), + const char *name); + +struct dirent *safe_readdir(const char *file, const int lineno, + void (cleanup_fn)(void), + DIR *dirp); + +int safe_closedir(const char *file, const int lineno, + void (cleanup_fn)(void), + DIR *dirp); + +#endif /* SAFE_MACROS_FN_H__ */ diff --git a/ltp/include/safe_net_fn.h b/ltp/include/safe_net_fn.h new file mode 100644 index 0000000000000000000000000000000000000000..6c63cb2cfa5df7735fd954c5e07b9577df247b54 --- /dev/null +++ b/ltp/include/safe_net_fn.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016 Cyril Hrubis + * Copyright (c) 2015 Fujitsu Ltd. + * + * 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 . + */ + +#ifndef SAFE_NET_FN_H__ +#define SAFE_NET_FN_H__ + +#include +#include +#include +#include +#include + +int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void), + int domain, int type, int protocol); + +int safe_socketpair(const char *file, const int lineno, int domain, int type, + int protocol, int sv[]); + +int safe_getsockopt(const char *file, const int lineno, int sockfd, int level, + int optname, void *optval, socklen_t *optlen); + +int safe_setsockopt(const char *file, const int lineno, int sockfd, int level, + int optname, const void *optval, socklen_t optlen); + +ssize_t safe_send(const char *file, const int lineno, char len_strict, + int sockfd, const void *buf, size_t len, int flags); + +ssize_t safe_sendto(const char *file, const int lineno, char len_strict, + int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); + +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); + +int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void), + int socket, const struct sockaddr *address, + socklen_t address_len); + +int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void), + int socket, int backlog); + +int safe_accept(const char *file, const int lineno, void (cleanup_fn)(void), + int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void), + int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +int safe_getsockname(const char *file, const int lineno, + void (cleanup_fn)(void), int sockfd, struct sockaddr *addr, + socklen_t *addrlen); + +int safe_gethostname(const char *file, const int lineno, + char *name, size_t size); + +int safe_sethostname(const char *file, const int lineno, + const char *name, size_t size); + +int tst_getsockport(const char *file, const int lineno, int sockfd); + +unsigned short tst_get_unused_port(const char *file, const int lineno, + void (cleanup_fn)(void), unsigned short family, int type); + +char *tst_sock_addr(const struct sockaddr *sa, socklen_t salen, char *res, + size_t len); + +#endif /* SAFE_NET_FN_H__ */ diff --git a/ltp/include/safe_stdio_fn.h b/ltp/include/safe_stdio_fn.h new file mode 100644 index 0000000000000000000000000000000000000000..3818a86571a6d9bc63fcf432c93683bb3298e5b2 --- /dev/null +++ b/ltp/include/safe_stdio_fn.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013-2016 Cyril Hrubis + * + * 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 . + */ + +#ifndef SAFE_STDIO_FN_H__ +#define SAFE_STDIO_FN_H__ + +#include + +FILE *safe_fopen(const char *file, const int lineno, void (cleanup_fn)(void), + const char *path, const char *mode); + +int safe_fclose(const char *file, const int lineno, void (cleanup_fn)(void), + FILE *f); + +int safe_asprintf(const char *file, const int lineno, void (cleanup_fn)(void), + char **strp, const char *fmt, ...); + +FILE *safe_popen(const char *file, const int lineno, void (cleanup_fn)(void), + const char *command, const char *type); + +#endif /* SAFE_STDIO_FN_H__ */ diff --git a/ltp/include/time64_variants.h b/ltp/include/time64_variants.h new file mode 100644 index 0000000000000000000000000000000000000000..fc52623c868a82f34945bb18aed20192df95a063 --- /dev/null +++ b/ltp/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/ltp/include/tst_af_alg.h b/ltp/include/tst_af_alg.h new file mode 100644 index 0000000000000000000000000000000000000000..5c307ed0695103e67aac2f56d7ef6ecbd0a0b704 --- /dev/null +++ b/ltp/include/tst_af_alg.h @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2019 Google LLC + * Copyright (c) Linux Test Project, 2021 + */ + +/** + * DOC: tst_af_alg.h -- Kernel crypto algorithms (AF_ALG) helpers + * + * Helpers for accessing kernel crypto algorithms via AF_ALG. + * + * See https://www.kernel.org/doc/html/latest/crypto/userspace-if.html + * for more information about AF_ALG. + */ + +#ifndef TST_AF_ALG_H +#define TST_AF_ALG_H + +#include "lapi/if_alg.h" +#include + +/** + * tst_alg_create() - Create an AF_ALG algorithm socket. + * + * This creates an AF_ALG algorithm socket that is initially not bound to any + * particular algorithm. On failure, tst_brk() is called with TCONF if the + * kernel doesn't support AF_ALG, otherwise TBROK. + * + * Return: a new AF_ALG algorithm socket + */ +int tst_alg_create(void); + +/** + * tst_alg_bind_addr() - Bind an AF_ALG algorithm socket to an algorithm. + * + * @algfd: An AF_ALG algorithm socket + * @addr: A structure which specifies the algorithm to use + * + * On failure, tst_brk() is called with TCONF if the kernel doesn't support the + * specified algorithm, otherwise TBROK. + */ +void tst_alg_bind_addr(int algfd, const struct sockaddr_alg *addr); + +/** + * tst_alg_bind() - Bind an AF_ALG algorithm socket to an algorithm. + * + * @algfd: An AF_ALG algorithm socket + * @algtype: The type of algorithm, such as "hash" or "skcipher" + * @algname: The name of the algorithm, such as "sha256" or "xts(aes)" + * + * Like tst_alg_bind_addr(), except this just takes in the algorithm type and + * name. The 'feat' and 'mask' fields are left 0. + * + * On failure, tst_brk() is called with TCONF if the kernel doesn't support the + * specified algorithm, otherwise TBROK. + */ +void tst_alg_bind(int algfd, const char *algtype, const char *algname); + +/** + * tst_try_alg() - Check for the availability of an algorithm. + * + * @algtype: The type of algorithm, such as "hash" or "skcipher" + * @algname: The name of the algorithm, such as "sha256" or "xts(aes)" + * + * Return: 0 if the algorithm is available, or errno if unavailable. + */ +int tst_try_alg(const char *algtype, const char *algname); + +/** + * tst_have_alg() - Check for the availability of an algorithm. + * + * @algtype: The type of algorithm, such as "hash" or "skcipher" + * @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); + +/** + * tst_require_alg() - Require the availability of an algorithm. + * + * @algtype: The type of algorithm, such as "hash" or "skcipher" + * @algname: The name of the algorithm, such as "sha256" or "xts(aes)" + * + * If the algorithm is unavailable, tst_brk() is called with TCONF. + * If another error occurs, tst_brk() is called with TBROK. + */ +void tst_require_alg(const char *algtype, const char *algname); + +/** + * tst_alg_setkey() - Assign a cryptographic key to an AF_ALG algorithm socket. + * + * @algfd: An AF_ALG algorithm socket + * @key: Pointer to the key. If NULL, a random key is generated. + * @keylen: Length of the key in bytes + * + * On failure, tst_brk() is called with TBROK. + */ +void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen); + +/** + * tst_alg_accept() - Create an AF_ALG request socket for the given algorithm socket. + * + * @algfd: An AF_ALG algorithm socket + * + * This creates a request socket for the given algorithm socket, which must be + * bound to an algorithm. The same algorithm socket can have many request + * sockets used concurrently to perform independent cryptographic operations, + * e.g. hashing or encryption/decryption. But the key, if any, that has been + * assigned to the algorithm is shared by all request sockets. + * + * On failure, tst_brk() is called with TBROK. + * + * Return: a new AF_ALG request socket + */ +int tst_alg_accept(int algfd); + +/** + * tst_alg_setup() - Set up an AF_ALG algorithm socket for the given algorithm w/ given key. + * + * @algtype: The type of algorithm, such as "hash" or "skcipher" + * @algname: The name of the algorithm, such as "sha256" or "xts(aes)" + * @key: The key to use (optional) + * @keylen: The length of the key in bytes (optional) + * + * This is a helper function which creates an AF_ALG algorithm socket, binds it + * to the specified algorithm, and optionally sets a key. If keylen is 0 then + * no key is set; otherwise if key is NULL a key of the given length is randomly + * generated and set; otherwise the given key is set. + * + * Return: the AF_ALG algorithm socket that was set up + */ +int tst_alg_setup(const char *algtype, const char *algname, + const uint8_t *key, unsigned int keylen); + +/** + * tst_alg_setup_reqfd() - Set up an AF_ALG request socket for the given algorithm w/ given key. + * + * @algtype: The type of algorithm, such as "hash" or "skcipher" + * @algname: The name of the algorithm, such as "sha256" or "xts(aes)" + * @key: The key to use (optional) + * @keylen: The length of the key in bytes (optional) + * + * This is like tst_alg_setup(), except this returns a request fd instead of the + * alg fd. The alg fd is closed, so it doesn't need to be kept track of. + * + * Return: the AF_ALG request socket that was set up + */ +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; +}; + +/** + * tst_alg_sendmsg() - Send some data to an AF_ALG request socket, including control data. + * @reqfd: An AF_ALG request socket + * @data: The data to send + * @datalen: The length of data in bytes + * @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/ltp/include/tst_ansi_color.h b/ltp/include/tst_ansi_color.h new file mode 100644 index 0000000000000000000000000000000000000000..376d4ad635ac2d0ea3dbe74ac4e9a79b1d337a13 --- /dev/null +++ b/ltp/include/tst_ansi_color.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2017 Petr Vorel + */ + +#ifndef TST_ANSI_COLOR_H__ +#define TST_ANSI_COLOR_H__ + +/* + * NOTE: these colors should match colors defined in tst_flag2color() in + * testcases/lib/tst_ansi_color.sh + */ + +#define ANSI_COLOR_BLUE "\033[1;34m" +#define ANSI_COLOR_GREEN "\033[1;32m" +#define ANSI_COLOR_MAGENTA "\033[1;35m" +#define ANSI_COLOR_RED "\033[1;31m" +#define ANSI_COLOR_WHITE "\033[1;37m" +#define ANSI_COLOR_YELLOW "\033[1;33m" + +#define ANSI_COLOR_RESET "\033[0m" + +char* tst_ttype2color(int ttype); +int tst_color_enabled(int fd); + +#endif /* TST_ANSI_COLOR_H__ */ diff --git a/ltp/include/tst_arch.h b/ltp/include/tst_arch.h new file mode 100644 index 0000000000000000000000000000000000000000..4a9473c6f1db39c0f63187e265bfc3baf4637d72 --- /dev/null +++ b/ltp/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/ltp/include/tst_assert.h b/ltp/include/tst_assert.h new file mode 100644 index 0000000000000000000000000000000000000000..dcb62dfeae9fa7fda405ed7b3d948c3b04a57553 --- /dev/null +++ b/ltp/include/tst_assert.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + * Copyright (c) 2020 Cyril Hrubis + */ +#ifndef TST_ASSERT_H__ +#define TST_ASSERT_H__ + +#define TST_ASSERT_INT(path, val) \ + tst_assert_int(__FILE__, __LINE__, path, val) + +/* + * Asserts that integer value stored in file pointed by path equals to the + * value passed to this function. This is mostly useful for asserting correct + * values in sysfs, procfs, etc. + */ +void tst_assert_int(const char *file, const int lineno, + const char *path, int val); + +#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 + * asserting correct field values in sysfs, procfs, etc. + */ + +void tst_assert_file_int(const char *file, const int lineno, + const char *path, const char *prefix, int val); + + +#define TST_ASSERT_STR(path, val) \ + tst_assert_str(__FILE__, __LINE__, path, val) + +/* + * Asserts that a string value stored in file pointed by path equals to the + * value passed to this function. This is mostly useful for asserting correct + * values in sysfs, procfs, etc. + */ +void tst_assert_str(const char *file, const int lineno, + const char *path, const char *val); + +#define TST_ASSERT_FILE_STR(path, prefix, val) \ + tst_assert_file_str(__FILE__, __LINE__, path, prefix, val) + +/* + * Asserts that a string value stored in the prefix field of file pointed by path + * equals to the value passed to this function. This is mostly useful for + * asserting correct field values in sysfs, procfs, etc. + */ +void tst_assert_file_str(const char *file, const int lineno, + const char *path, const char *prefix, const char *val); + +#endif /* TST_ASSERT_H__ */ diff --git a/ltp/include/tst_atomic.h b/ltp/include/tst_atomic.h new file mode 100644 index 0000000000000000000000000000000000000000..9d255bc4486c995cea904973ba0e0954884a1c1c --- /dev/null +++ b/ltp/include/tst_atomic.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2016 Cyril Hrubis + * Copyright (c) 2025 Li Wang + */ + +#ifndef TST_ATOMIC_H__ +#define TST_ATOMIC_H__ + +#include +#include "config.h" + +typedef int32_t tst_atomic_t; + +#if HAVE_ATOMIC_MEMORY_MODEL == 1 + +/* Use __atomic built-ins (GCC >= 4.7, Clang >= 3.1), with sequential consistency. */ + +static inline int tst_atomic_add_return(int32_t i, tst_atomic_t *v) +{ + return __atomic_add_fetch(v, i, __ATOMIC_SEQ_CST); +} + +static inline int32_t tst_atomic_load(tst_atomic_t *v) +{ + return __atomic_load_n(v, __ATOMIC_SEQ_CST); +} + +static inline void tst_atomic_store(int32_t i, tst_atomic_t *v) +{ + __atomic_store_n(v, i, __ATOMIC_SEQ_CST); +} + +#elif HAVE_SYNC_ADD_AND_FETCH == 1 + +/* Use __sync built-ins (GCC >= 4.1), with explicit memory barriers. */ + +static inline int tst_atomic_add_return(int32_t i, tst_atomic_t *v) +{ + return __sync_add_and_fetch(v, i); +} + +static inline int32_t tst_atomic_load(tst_atomic_t *v) +{ + tst_atomic_t ret; + + __sync_synchronize(); + ret = *v; + __sync_synchronize(); + return ret; +} + +static inline void tst_atomic_store(int32_t i, tst_atomic_t *v) +{ + __sync_synchronize(); + *v = i; + __sync_synchronize(); +} + +#else +# error "Your compiler does not support atomic operations (__atomic or __sync)" +#endif + +static inline int tst_atomic_inc(tst_atomic_t *v) +{ + return tst_atomic_add_return(1, v); +} + +static inline int tst_atomic_dec(tst_atomic_t *v) +{ + return tst_atomic_add_return(-1, v); +} + +#endif /* TST_ATOMIC_H__ */ diff --git a/ltp/include/tst_bitmap.h b/ltp/include/tst_bitmap.h new file mode 100644 index 0000000000000000000000000000000000000000..d294e3ec0a9da81ddeb35f5ddea8946de8c7f2a5 --- /dev/null +++ b/ltp/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/ltp/include/tst_bool_expr.h b/ltp/include/tst_bool_expr.h new file mode 100644 index 0000000000000000000000000000000000000000..894d219548207ac31634739b63205e6606609bde --- /dev/null +++ b/ltp/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/ltp/include/tst_buffers.h b/ltp/include/tst_buffers.h new file mode 100644 index 0000000000000000000000000000000000000000..bd1a112a25fff65a13c64965ce3d5e7df62f5490 --- /dev/null +++ b/ltp/include/tst_buffers.h @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Cyril Hrubis + */ + +/** + * DOC: Guarded buffers introduction + * + * Guarded buffer has a page with PROT_NONE allocated right before the start of + * the buffer and canary after the end of the buffer. That means that any + * memory access before the buffer ends with EFAULT or SEGFAULT and any write + * after the end of the buffer will be detected because it would overwrite the + * canaries. + * + * It should be used for all buffers passed to syscalls to make sure off-by-one + * buffer accesses does not happen. + */ + +#ifndef TST_BUFFERS_H__ +#define TST_BUFFERS_H__ + +/** + * struct tst_buffers - A guarded buffer description for allocator. + * + * Buffer description consist of a pointer to a pointer and buffer type/size + * encoded as a different structure members. + * + * @ptr: A pointer to the pointer to buffer. This is dereferenced and set by the + * allocator. + * @size: A buffer size in bytes. Only one of size and iov_sizes can be set. + * @iov_sizes: An -1 terminated array of sizes used to construct a + * struct iovec buffers. + * @str: If size is zero and iov_sizes is NULL this string is going to be + * copied into the buffer. + */ +struct tst_buffers { + void *ptr; + size_t size; + int *iov_sizes; + char *str; +}; + +/** + * tst_buffers_alloc() - Allocates buffers based on the tst_buffers structure. + * + * @bufs: A NULL terminated array of test buffer descriptions. + * + * This is called from the test library if the tst_test.bufs pointer is set. + */ +void tst_buffers_alloc(struct tst_buffers bufs[]); + +/** + * tst_strdup() - Copies a string into a newly allocated guarded buffer. + * + * @str: A string to be duplicated. + * return: A pointer to the string duplicated in a guarded buffer. + * + * Allocates a buffer with tst_alloc() and copies the string into it. + */ +char *tst_strdup(const char *str); + +/** + * tst_alloc() - Allocates a guarded buffer. + * + * @size: A size of the buffer. + * return: A newly allocated guarded buffer. + */ +void *tst_alloc(size_t size); + +/** + * tst_aprintf() - Printf into a newly allocated guarded buffer. + * + * @fmt: A printf-like format. + * @...: A printf-like parameters. + * return: A newly allocated buffer. + * + * Allocates a buffer with tst_alloc() then prints the data into it. + */ +char *tst_aprintf(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); + +/** + * tst_iovec_alloc() - Allocates a complete iovec structure. + * + * @sizes: A -1 terminated array of buffer sizes. + * return: Newly allocated iovec structure. + */ +struct iovec *tst_iovec_alloc(int sizes[]); + +/** + * tst_free_all() - Frees all allocated buffers. + * + * It's important to free all guarded buffers because the canaries after the + * buffer are checked only when the buffer is being freed. + * + * This is called at the end of the test automatically. + */ +void tst_free_all(void); + +#endif /* TST_BUFFERS_H__ */ diff --git a/ltp/include/tst_capability.h b/ltp/include/tst_capability.h new file mode 100644 index 0000000000000000000000000000000000000000..ccf4bd77b5d7f663f35f587ea2c0a7369070552e --- /dev/null +++ b/ltp/include/tst_capability.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2019 Richard Palethorpe + */ + +/** + * DOC: Capabilities introduction + * + * Limited capability operations without libcap. + */ + +#ifndef TST_CAPABILITY_H +#define TST_CAPABILITY_H + +#include + +#include "lapi/capability.h" + +/** + * enum tst_cap_act - A capability action masks. + * + * @TST_CAP_DROP: Drop capabilities. + * @TST_CAP_REQ: Add capabilities. + */ +enum tst_cap_act { + TST_CAP_DROP = 1, + TST_CAP_REQ = (1 << 1) +}; + +/** + * struct tst_cap_user_header - Kernel capget(), capset() syscall header. + * + * @version: A capability API version. + * @pid: A process to operate on. + */ +struct tst_cap_user_header { + uint32_t version; + int pid; +}; + +/** + * struct tst_cap_user_data - Kernel capset(), capget() syscall payload. + * + * @effective: A capability effective set. + * @permitted: A capability permitted set. + * @inheritable: A capability inheritable set. + */ +struct tst_cap_user_data { + uint32_t effective; + uint32_t permitted; + uint32_t inheritable; +}; + +/** + * struct tst_cap - A capability to alter. + * + * @action: What should we do, i.e. drop or add a capability. + * @id: A capability id. + * @name: A capability name. + * + * This structure is usually constructed with the TST_CAP() macro so that the + * name is created automatically. + */ +struct tst_cap { + uint32_t action; + uint32_t id; + char *name; +}; + +/** + * TST_CAP() - Create a struct tst_cap entry. + * + * @action: What should we do, i.e. drop or add capability. + * @capability: A capability id, e.g. CAP_BPF. + */ +#define TST_CAP(action, capability) {action, capability, #capability} + +/** + * tst_capget() - Get the capabilities as decided by hdr. + * + * @hdr: A capability user header stores a pid to operate on and which + * capability API version is used. + * @data: A memory to store the capabilities to. The memory pointed to by data + * should be large enough to store two structs. + * + * return: Returns 0 on success, -1 on a failure and sets errno. + */ +int tst_capget(struct tst_cap_user_header *hdr, + struct tst_cap_user_data *data); + +/** + * tst_capset() - Set the capabilities as decided by hdr and data + * + * @hdr: A capability user header stores a pid to operate on and which + * capability API version is used. + * @data: A memory to store the capabilities to. The memory pointed to by data + * should be large enough to store two structs. + * + * return: Returns 0 on success, -1 on a failure and sets errno. + */ +int tst_capset(struct tst_cap_user_header *hdr, + const struct tst_cap_user_data *data); + +/** + * tst_cap_action() - Add, check or remove a capability. + * + * @cap: An {} terminated array of capabilities to alter. + * + * It will attempt to drop or add capability to the effective set. It will + * try to detect if this is needed and whether it can or can't be done. If it + * clearly can not add a privilege to the effective set then it will return + * TCONF. However it may fail for some other reason and return TBROK. + * + * This only tries to change the effective set. Some tests may need to change + * the inheritable and ambient sets, so that child processes retain some + * capability. + */ +void tst_cap_action(struct tst_cap *cap); + + +/** + * tst_cap_setup() - Add, check or remove a capabilities. + * + * @cap: An {} terminated array of capabilities to alter. + * @action_mask: Decides which actions are done, i.e. only drop caps, add them + * or both. + * + * Takes a NULL terminated array of structs which describe whether some + * capabilities are needed or not and mask that determines subset of the + * actions to be performed. Loops over the array and if mask matches the + * element action it's passed to tst_cap_action(). + */ +void tst_cap_setup(struct tst_cap *cap, enum tst_cap_act action_mask); + +#endif /* TST_CAPABILITY_H */ diff --git a/ltp/include/tst_cgroup.h b/ltp/include/tst_cgroup.h new file mode 100644 index 0000000000000000000000000000000000000000..d2b5224a01e5110e6acdbde8ab78f78716041b26 --- /dev/null +++ b/ltp/include/tst_cgroup.h @@ -0,0 +1,259 @@ +// 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 + */ +/*\ + * 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_cg_ver { + TST_CG_V1 = 1, + TST_CG_V2 = 2, +}; + +/* This value is greater than ROOTS_MAX in tst_cgroup.c. */ +#define TST_CG_ROOTS_MAX 32 + +/* Used to specify CGroup hierarchy configuration options, allowing a + * test to request a particular CGroup structure. + */ +struct tst_cg_opts { + /* Call tst_brk with TCONF if the controller is not on this + * version. Defautls to zero to accept any version. + */ + enum tst_cg_ver needs_ver; + /* Pass in a specific pid to create and identify the test + * directory as opposed to the default pid of the calling process. + */ + int test_pid; + int needs_nsdelegate; +}; + +/* A Control Group in LTP's aggregated hierarchy */ +struct tst_cg_group; + +/* Populated with a reference to this tests's CGroup */ +extern const struct tst_cg_group *const tst_cg; +extern const struct tst_cg_group *const tst_cg_drain; + +/* Search the system for mounted cgroups and available + * controllers. Called automatically by tst_cg_require. + */ +void tst_cg_scan(void); +/* Print the config detected by tst_cg_scan and print the internal + * state associated with each controller. Output can be passed to + * tst_cg_load_config to configure the internal state to that of the + * config between program invocations. + */ +void tst_cg_print_config(void); + +/* Load the config printed out by tst_cg_print_config and configure the internal + * libary state to match the config. Used to allow tst_cg_cleanup to properly + * cleanup mounts and directories created by tst_cg_require between program + * invocations. + */ +void tst_cg_load_config(const char *const config); + +/* Ensure the specified controller is available in the test's default + * CGroup, mounting/enabling it if necessary. Usually this is not + * necessary use tst_test.needs_cgroup_ctrls instead. + */ +void tst_cg_require(const char *const ctrl_name, + const struct tst_cg_opts *const options) + __attribute__ ((nonnull)); + +/* Tear down any CGroups created by calls to tst_cg_require */ +void tst_cg_cleanup(void); + +/* Call this in setup after you call tst_cg_require and want to + * initialize tst_cg and tst_cg_drain. See tst_cg_require. + */ +void tst_cg_init(void); + +/* Create a descendant CGroup */ +struct tst_cg_group * +tst_cg_group_mk(const struct tst_cg_group *const parent, + const char *const group_name_fmt, ...) + __attribute__ ((nonnull, warn_unused_result, format (printf, 2, 3))); + +const char * +tst_cg_group_name(const struct tst_cg_group *const cg) + __attribute__ ((nonnull, warn_unused_result)); + +/* This call returns a fd pointing to a v2 directory */ +int tst_cg_group_unified_dir_fd(const struct tst_cg_group *const cg) + __attribute__ ((nonnull, warn_unused_result)); + +/* Remove a descendant CGroup */ +struct tst_cg_group * +tst_cg_group_rm(struct tst_cg_group *const cg) + __attribute__ ((nonnull, warn_unused_result)); + +#define TST_CG_VER(cg, ctrl_name) \ + tst_cg_ver(__FILE__, __LINE__, (cg), (ctrl_name)) + +enum tst_cg_ver tst_cg_ver(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const ctrl_name) + __attribute__ ((nonnull, warn_unused_result)); + +#define TST_CG_VER_IS_V1(cg, ctrl_name) \ + (TST_CG_VER((cg), (ctrl_name)) == TST_CG_V1) + +#define SAFE_CG_HAS(cg, file_name) \ + safe_cg_has(__FILE__, __LINE__, (cg), (file_name)) + +int safe_cg_has(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name) + __attribute__ ((nonnull, warn_unused_result)); + +#define SAFE_CG_READ(cg, file_name, out, len) \ + safe_cg_read(__FILE__, __LINE__, \ + (cg), (file_name), (out), (len)) + +ssize_t safe_cg_read(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + char *const out, const size_t len) + __attribute__ ((nonnull)); + +#define SAFE_CG_PRINTF(cg, file_name, fmt, ...) \ + safe_cg_printf(__FILE__, __LINE__, \ + (cg), (file_name), (fmt), __VA_ARGS__) + +#define SAFE_CG_PRINT(cg, file_name, str) \ + safe_cg_printf(__FILE__, __LINE__, (cg), (file_name), "%s", (str)) + +void safe_cg_printf(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + const char *const fmt, ...) + __attribute__ ((format (printf, 5, 6), nonnull)); + +#define SAFE_CG_OPEN(cg, file_name, flags, fds) \ + safe_cg_open(__FILE__, __LINE__, (cg), (file_name), (flags), (fds)) + +int safe_cg_open(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + int flags, int *fds) + __attribute__ ((nonnull)); + +#define SAFE_CG_FCHOWN(cg, file_name, owner, group) \ + safe_cg_fchown(__FILE__, __LINE__, (cg), (file_name), (owner), (group)) + +void safe_cg_fchown(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + uid_t owner, gid_t group) + __attribute__ ((nonnull)); + +#define SAFE_CG_SCANF(cg, file_name, fmt, ...) \ + safe_cg_scanf(__FILE__, __LINE__, \ + (cg), (file_name), (fmt), __VA_ARGS__) + +void safe_cg_scanf(const char *file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + const char *const fmt, ...) + __attribute__ ((format (scanf, 5, 6), nonnull)); + +#define SAFE_CG_LINES_SCANF(cg, file_name, fmt, ...) \ + safe_cg_lines_scanf(__FILE__, __LINE__, \ + (cg), (file_name), (fmt), __VA_ARGS__) + +void safe_cg_lines_scanf(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + const char *const fmt, ...) + __attribute__ ((format (scanf, 5, 6), nonnull)); + +#define SAFE_CG_OCCURSIN(cg, file_name, needle) \ + safe_cg_occursin(__FILE__, __LINE__, \ + (cg), (file_name), (needle)) + +int safe_cg_occursin(const char *file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + const char *const needle); + +int tst_cg_memory_recursiveprot(struct tst_cg_group *cg); + +#endif /* TST_CGROUP_H */ diff --git a/ltp/include/tst_checkpoint.h b/ltp/include/tst_checkpoint.h new file mode 100644 index 0000000000000000000000000000000000000000..f202dd03d85861cfed4dc60f2e4f4754d2ca7b40 --- /dev/null +++ b/ltp/include/tst_checkpoint.h @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016-2025 Cyril Hrubis + */ + +/** + * DOC: Checkpoints introduction + * + * Checkpoints implements a futex based synchronization primitive for threads + * and processes. When a process calls wait function its execution is suspended + * until wake is called for a corresponding checkpoint. Checkpoints are + * numbered from 0 and process can use at least hundred of them. + * + * In order to use checkpoints the test must set the tst_test.needs_checkpoints + * flag. + */ + +#ifndef TST_CHECKPOINT__ +#define TST_CHECKPOINT__ + +#include "tst_checkpoint_fn.h" + +/** + * TST_CHECKPOINT_WAIT() - Waits for a checkpoint. + * + * @id: A checkpoint id a positive integer. + * + * Suspends thread/process execution until it's woken up with a wake. The call + * does not wait indefinitely it gives up after 10 seconds. If an error + * happened or timeout was reached the function calls tst_brk(TBROK, ...) which + * exits the test. + */ +#define TST_CHECKPOINT_WAIT(id) \ + tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, 0) + +/** + * TST_CHECKPOINT_WAIT2() - Waits for a checkpoint. + * + * @id: A checkpoint id a positive integer. + * @msec_timeout: A timeout. + * + * Suspends thread/process execution until it's woken up with a wake. If an + * error happened or timeout was reached the function calls tst_brk(TBROK, ...) + * which exits the test. + */ +#define TST_CHECKPOINT_WAIT2(id, msec_timeout) \ + tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, msec_timeout) + +/** + * TST_CHECKPOINT_WAKE() - Wakes up a checkpoint. + * + * @id: A checkpoint id a positive integer. + * + * Wakes up a process suspended on a checkpoint and retries if there is no + * process suspended on the checkpoint yet. The call does not retry + * indefinitely but gives up after 10 seconds. If an error happened or timeout + * was reached the function calls tst_brk(TBROK, ...) which exits the test. + */ +#define TST_CHECKPOINT_WAKE(id) \ + tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, 1) + +/** + * TST_CHECKPOINT_WAKE2() - Wakes up several checkpoints. + * + * @id: A checkpoint id a positive integer. + * @nr_wake: A number of processes to wake. + * + * Wakes up nr_wake processes suspended on a checkpoint and retries if there + * wasn't enough process suspended on the checkpoint yet. The call does not + * retry indefinitely but gives up if it does not wake nr_wake processes after + * 10 seconds. If an error happened or timeout was reached the function calls + * tst_brk(TBROK, ...) which exits the test. + */ +#define TST_CHECKPOINT_WAKE2(id, nr_wake) \ + tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, nr_wake) + +/** + * TST_CHECKPOINT_WAKE_AND_WAIT() - Wakes up a checkpoint and immediately waits on it. + * + * @id: A checkpoint id a positive integer. + * + * This is a combination of TST_CHECKPOINT_WAKE() and TST_CHECKPOINT_WAIT(). + */ +#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); \ +} while (0) + +#endif /* TST_CHECKPOINT__ */ diff --git a/ltp/include/tst_checkpoint_fn.h b/ltp/include/tst_checkpoint_fn.h new file mode 100644 index 0000000000000000000000000000000000000000..e061e00b91c9d47b09a8eb904a3335586edc703b --- /dev/null +++ b/ltp/include/tst_checkpoint_fn.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015-2025 Cyril Hrubis + */ + +#ifndef TST_CHECKPOINT_FN__ +#define TST_CHECKPOINT_FN__ + +/* + * Waits for wakeup. + * + * @id: Checkpoint id, positive number + * @msec_timeout: Timeout in milliseconds, 0 == no timeout + */ +int tst_checkpoint_wait(unsigned int id, unsigned int msec_timeout); + +/* + * Wakes up sleeping process(es)/thread(s). + * + * @id: Checkpoint id, positive number + * @nr_wake: Number of processes/threads to wake up + * @msec_timeout: Timeout in milliseconds, 0 == no timeout + */ +int tst_checkpoint_wake(unsigned int id, unsigned int nr_wake, + unsigned int msec_timeout); + +void tst_safe_checkpoint_wait(const char *file, const int lineno, + void (*cleanup_fn)(void), unsigned int id, + unsigned int msec_timeout); + +void tst_safe_checkpoint_wake(const char *file, const int lineno, + void (*cleanup_fn)(void), unsigned int id, + unsigned int nr_wake); + +#endif /* TST_CHECKPOINT_FN__ */ diff --git a/ltp/include/tst_checksum.h b/ltp/include/tst_checksum.h new file mode 100644 index 0000000000000000000000000000000000000000..f062869de812171a0b1834a7957fefd89b4d52e7 --- /dev/null +++ b/ltp/include/tst_checksum.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. + */ + +#ifndef TST_CHECKSUM_H__ +#define TST_CHECKSUM_H__ + +#include +#include + +/* + * Generates CRC32c checksum. + */ +uint32_t tst_crc32c(uint8_t *buf, size_t buf_len); + +#endif diff --git a/ltp/include/tst_clocks.h b/ltp/include/tst_clocks.h new file mode 100644 index 0000000000000000000000000000000000000000..8b7f33d4f38737191d1ceaacbf1180d52a32799b --- /dev/null +++ b/ltp/include/tst_clocks.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2017 Cyril Hrubis + */ + +/* + * clock_gettime() and clock_getres() functions + */ + +#ifndef TST_CLOCKS__ +#define TST_CLOCKS__ + +int tst_clock_getres(clockid_t clk_id, struct timespec *res); + +int tst_clock_gettime(clockid_t clk_id, struct timespec *ts); + +int tst_clock_settime(clockid_t clk_id, struct timespec *ts); + +/* + * Converts clock id to a readable name. + */ +const char *tst_clock_name(clockid_t clk_id); + +/* + * Returns timestamp (seconds passed) for the specified clock. + * TBROKs on error. + */ +time_t tst_clock_get_timestamp(clockid_t clk_id); + +/* + * Returns current system time for file/IPC operations, which may slightly lag + * behind time() return values. Meant to be used as lower bound in atime/mtime + * checks. + * + * 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_fs_timestamp_start(void); + +/* + * Returns current system time for file/IPC operation, using clock + * which has higher precision. Meant to be used as higher bound in atime/mtime + * checks. + * + * The reason for separate start/end functions is to cover features like + * multigrain timestamps, which update atime/mtime using more precise clock. + */ +time_t tst_fs_timestamp_end(void); + +#endif /* TST_CLOCKS__ */ diff --git a/ltp/include/tst_clone.h b/ltp/include/tst_clone.h new file mode 100644 index 0000000000000000000000000000000000000000..a57d761ca56dc113dde81a0ed17f15e8f2e58924 --- /dev/null +++ b/ltp/include/tst_clone.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2016 Xiao Yang + */ + +#ifndef TST_CLONE_H__ +#define TST_CLONE_H__ + +#include + +#ifdef TST_TEST_H__ + +/* The parts of clone3's clone_args we support */ +struct tst_clone_args { + uint64_t flags; + uint64_t exit_signal; + uint64_t cgroup; +}; + +/* 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); +int ltp_clone7(unsigned long flags, int (*fn)(void *arg), void *arg, + size_t stack_size, void *stack, ...); +void *ltp_alloc_stack(size_t size); + +#define clone(...) (use_the_ltp_clone_functions__do_not_use_clone) + +#endif /* TST_CLONE_H__ */ diff --git a/ltp/include/tst_cmd.h b/ltp/include/tst_cmd.h new file mode 100644 index 0000000000000000000000000000000000000000..939825646051c5e58cca408b37ebb88f8008f40e --- /dev/null +++ b/ltp/include/tst_cmd.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2015-2016 Cyril Hrubis + */ + +#ifndef TST_CMD_H__ +#define TST_CMD_H__ + +enum tst_cmd_flags { + /* + * return the program exit code, otherwise it will call cleanup_fn() if the + * program exit code is not zero. + */ + TST_CMD_PASS_RETVAL = 1, + + /* exit with TCONF if program is not in path */ + TST_CMD_TCONF_ON_MISSING = 2, +}; + +/* + * vfork() + execvp() specified program. + * + * @param argv A list of two (at least program name + NULL) or more pointers that + * represent the argument list to the new program. The array of pointers + * must be terminated by a NULL pointer. + * @param stdout_fd File descriptor where to redirect stdout. Set -1 if + * redirection is not needed. + * @param stderr_fd File descriptor where to redirect stderr. Set -1 if + * redirection is not needed. + * @param flags enum tst_cmd_flags. + * @return The exit status of the program. + */ +int tst_cmd_fds_(void (cleanup_fn)(void), + const char *const argv[], + int stdout_fd, + int stderr_fd, + enum tst_cmd_flags flags); + +/* + * Executes tst_cmd_fds() and redirects its output to a file. + * + * @param stdout_path Path where to redirect stdout. Set NULL if redirection is + * not needed. + * @param stderr_path Path where to redirect stderr. Set NULL if redirection is + * not needed. + * @param flags enum tst_cmd_flags. + * @return The exit status of the program. + */ +int tst_cmd_(void (cleanup_fn)(void), + const char *const argv[], + const char *stdout_path, + const char *stderr_path, + enum tst_cmd_flags flags); + +#ifdef TST_TEST_H__ +static inline int tst_cmd_fds(const char *const argv[], + int stdout_fd, + int stderr_fd, + enum tst_cmd_flags flags) +{ + return tst_cmd_fds_(NULL, argv, + stdout_fd, stderr_fd, flags); +} + +static inline int tst_cmd(const char *const argv[], + const char *stdout_path, + const char *stderr_path, + enum tst_cmd_flags flags) +{ + return tst_cmd_(NULL, argv, + stdout_path, stderr_path, flags); +} +#else +static inline int tst_cmd_fds(void (cleanup_fn)(void), + const char *const argv[], + int stdout_fd, + int stderr_fd, + enum tst_cmd_flags flags) +{ + return tst_cmd_fds_(cleanup_fn, argv, + stdout_fd, stderr_fd, flags); +} + +static inline int tst_cmd(void (cleanup_fn)(void), + const char *const argv[], + const char *stdout_path, + const char *stderr_path, + enum tst_cmd_flags flags) +{ + return tst_cmd_(cleanup_fn, argv, + stdout_path, stderr_path, flags); +} +#endif + +/* Wrapper function for system(3), ignorcing SIGCHLD signal. + * @param command The command to be run. + */ +int tst_system(const char *command); + +#endif /* TST_CMD_H__ */ diff --git a/ltp/include/tst_common.h b/ltp/include/tst_common.h new file mode 100644 index 0000000000000000000000000000000000000000..473228149418fe66ed650595964694171f8ce1a8 --- /dev/null +++ b/ltp/include/tst_common.h @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + * Copyright (c) 2013 Stanislav Kholmanskikh + * Copyright (c) 2010 Ngie Cooper + * Copyright (c) 2008 Mike Frysinger + */ + +#ifndef TST_COMMON_H__ +#define TST_COMMON_H__ + +#define LTP_ATTRIBUTE_NORETURN __attribute__((noreturn)) +#define LTP_ATTRIBUTE_UNUSED __attribute__((unused)) +#define LTP_ATTRIBUTE_UNUSED_RESULT __attribute__((warn_unused_result)) + +#define LTP_VAR_USED(p) asm volatile("" :: "m"(p)); p + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +/* Round x to the next multiple of a. + * a should be a power of 2. + */ +#define LTP_ALIGN(x, a) __LTP_ALIGN_MASK(x, (typeof(x))(a) - 1) +#define __LTP_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + +/** + * TST_RETRY_FUNC() - Repeatedly retry a function with an increasing delay. + * @FUNC - The function which will be retried + * @ECHCK - Function/macro for validating @FUNC return value + * + * This macro will call @FUNC in a loop with a delay between retries. + * If ECHCK(ret) evaluates to non-zero, the loop ends. The delay between + * retries starts at one microsecond and is then doubled each iteration until + * it exceeds one second (the total time sleeping will be approximately one + * second as well). When the delay exceeds one second, the loop will end. + * The TST_RETRY_FUNC() macro returns the last value returned by @FUNC. + */ +#define TST_RETRY_FUNC(FUNC, ECHCK) \ + TST_RETRY_FN_EXP_BACKOFF(FUNC, ECHCK, 1) + +#define TST_RETRY_FN_EXP_BACKOFF(FUNC, ECHCK, MAX_DELAY) \ +({ unsigned int tst_delay_, tst_max_delay_; \ + typeof(FUNC) tst_ret_; \ + tst_delay_ = 1; \ + tst_max_delay_ = tst_multiply_timeout(MAX_DELAY * 1000000); \ + for (;;) { \ + errno = 0; \ + tst_ret_ = FUNC; \ + if (ECHCK(tst_ret_)) \ + break; \ + if (tst_delay_ < tst_max_delay_) { \ + usleep(tst_delay_); \ + tst_delay_ *= 2; \ + } else { \ + break; \ + } \ + } \ + tst_ret_; \ +}) + +/* + * Return value validation macros for TST_RETRY_FUNC(): + * TST_RETVAL_EQ0() - Check that value is equal to zero + */ +#define TST_RETVAL_EQ0(x) (!(x)) + +/* + * TST_RETVAL_NOTNULL() - Check that value is not equal to zero/NULL + */ +#define TST_RETVAL_NOTNULL(x) (!!(x)) + +/* + * TST_RETVAL_GE0() - Check that value is greater than or equal to zero + */ +#define TST_RETVAL_GE0(x) ((x) >= 0) + +#define TST_BUILD_BUG_ON(condition) \ + do { ((void)sizeof(char[1 - 2 * !!(condition)])); } while (0) + +#define TST_RES_SUPPORTS_TCONF_TDEBUG_TFAIL_TINFO_TPASS_TWARN(condition) \ + TST_BUILD_BUG_ON(condition) + +/* stringification */ +#define TST_TO_STR_(s) #s +#define TST_TO_STR(s) TST_TO_STR_(s) + +#endif /* TST_COMMON_H__ */ diff --git a/ltp/include/tst_coredump.h b/ltp/include/tst_coredump.h new file mode 100644 index 0000000000000000000000000000000000000000..e1f892544aa8c43b97eb6be50c7093494ac54c09 --- /dev/null +++ b/ltp/include/tst_coredump.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Red Hat, Inc. + */ + +#ifndef TST_COREDUMP__ +#define TST_COREDUMP__ + +/* + * If crash is expected, avoid dumping corefile. + * 1 is a special value, that disables core-to-pipe. + * At the same time it is small enough value for + * core-to-file, so it skips creating cores as well. + */ +void tst_no_corefile(int verbose); + +#endif /* TST_COREDUMP_H */ + diff --git a/ltp/include/tst_cpu.h b/ltp/include/tst_cpu.h new file mode 100644 index 0000000000000000000000000000000000000000..0724975f039c32f2342f46a2be3389e12f3e460c --- /dev/null +++ b/ltp/include/tst_cpu.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2015-2016 Cyril Hrubis + */ + +#ifndef TST_CPU_H__ +#define TST_CPU_H__ + +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); + +#endif /* TST_CPU_H__ */ diff --git a/ltp/include/tst_crypto.h b/ltp/include/tst_crypto.h new file mode 100644 index 0000000000000000000000000000000000000000..4511adf2241b76373cfbac146269bacef7fad598 --- /dev/null +++ b/ltp/include/tst_crypto.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2018 Richard Palethorpe + */ + +/** + * DOC: tst_crypto.h -- kernel's crypto layer helpers + * + * Helpers for interacting with kernel's crypto layer using the netlink + * interface. + */ + +#ifndef TST_CRYPTO_H +#define TST_CRYPTO_H + +#include "lapi/cryptouser.h" +#include "tst_netlink.h" + +/** + * tst_crypto_add_alg() - Add a crypto algorithm to a session. + * + * @ctx: Initialized netlink context + * @alg: The crypto algorithm or module to add. + * + * This requests a new crypto algorithm/engine/module to be initialized by the + * kernel. It sends the request contained in alg and then waits for a + * response. If sending the message or receiving the ack fails at the netlink + * level then tst_brk() with TBROK will be called. + * + * Return: On success it will return 0 otherwise it will return an inverted + * error code from the crypto layer. + */ +int tst_crypto_add_alg(struct tst_netlink_context *ctx, + const struct crypto_user_alg *alg); + +/** + * tst_crypto_del_alg() - Delete a crypto algorithm from a session. + * + * @ctx: Initialized netlink context + * @alg: The crypto algorithm to delete. + * @retries: Number of retries before giving up. Recommended value: 1000 + * + * Request that the kernel remove an existing crypto algorithm. This behaves + * in a similar way to tst_crypto_add_alg() except that it is the inverse + * operation and that it is not unusual for the crypto layer to return + * EBUSY. If EBUSY is returned then the function will internally retry the + * operation tst_crypto_session::retries times before giving up and returning + * EBUSY. + * + * Return: Either 0 or an inverted error code from the crypto layer. If called + * during cleanup it may return a positive ENODATA value from the LTP + * library, you don't need to log this error as it will already have + * been printed by tst_brk(). + */ +int tst_crypto_del_alg(struct tst_netlink_context *ctx, + const struct crypto_user_alg *alg, unsigned int retries); + +#endif /* TST_CRYPTO_H */ diff --git a/ltp/include/tst_defaults.h b/ltp/include/tst_defaults.h new file mode 100644 index 0000000000000000000000000000000000000000..083427b7e2d67c2b940e598e6e893bdc4953a73d --- /dev/null +++ b/ltp/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/ltp/include/tst_device.h b/ltp/include/tst_device.h new file mode 100644 index 0000000000000000000000000000000000000000..2597fb4e235e4e09f4e7a5cb87cb75f423ec3721 --- /dev/null +++ b/ltp/include/tst_device.h @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016-2019 Cyril Hrubis + * Copyright (c) Linux Test Project, 2019-2024 + */ + +#ifndef TST_DEVICE_H__ +#define TST_DEVICE_H__ + +#include +#include +#include + +struct tst_device { + const char *dev; + const char *fs_type; + uint64_t size; +}; + +/* + * Automatically initialized if test.needs_device is set. + */ +extern struct tst_device *tst_device; + +/* + * Just like umount() but retries several times on failure. + * @path: Path to umount + */ +int tst_umount(const char *path); + +/* + * Verifies if an earlier mount is successful or not. + * @path: Mount path to verify + */ +int tst_is_mounted(const char *path); +int tst_is_mounted_at_tmpdir(const char *path); + +/* + * Clears a first few blocks of the device. This is needed when device has + * already been formatted with a filesystems, subset of mkfs.foo utils aborts + * the operation if it finds a filesystem signature there. + * + * Note that this is called from tst_mkfs() automatically, so you probably will + * not need to use this from the test yourself. + */ +int tst_clear_device(const char *dev); + +/* + * Finds a free loop device for use and returns the free loopdev minor(-1 for no + * free loopdev). If path is non-NULL, it will be filled with free loopdev path. + * + */ +int tst_find_free_loopdev(char *path, size_t path_len); + +/* + * Attaches a file to a loop device. + * + * @dev_path Path to the loop device e.g. /dev/loop0 + * @file_path Path to a file e.g. disk.img + * @return Zero on success, non-zero otherwise. + */ +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_fd needs to be the + * last descriptor opened. Call to this function will close it, + * it is up to caller to open it again for further usage. + * + * @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); + +/* + * To avoid FS deferred IO metadata/cache interference, so we do syncfs + * simply before the tst_dev_bytes_written invocation. For easy to use, + * we create this inline function tst_dev_sync. + */ +int tst_dev_sync(int fd); + +/* + * Reads test block device stat file and returns the bytes written since the + * last call of this function. + * @dev: test block device + */ +unsigned long tst_dev_bytes_written(const char *dev); + +/* + * Find the file or path belongs to which block dev + * @path Path to find the backing dev + * @dev The buffer to store the block dev in + * @dev_size The length of the block dev buffer + */ +void tst_find_backing_dev(const char *path, char *dev, size_t dev_size); + +/* + * Stat the device mounted on a given path. + */ +void tst_stat_mount_dev(const char *const mnt_path, struct stat *const st); + +/* + * Returns the size of a physical device block size for the specific path + * @path Path to find the block size + * @return Size of the block size + */ +int tst_dev_block_size(const char *path); + +#endif /* TST_DEVICE_H__ */ diff --git a/ltp/include/tst_epoll.h b/ltp/include/tst_epoll.h new file mode 100644 index 0000000000000000000000000000000000000000..c5ffc07e3ea60b7741948268afd6378ac778828b --- /dev/null +++ b/ltp/include/tst_epoll.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 SUSE LLC + */ + +#include + +#ifndef TST_EPOLL_H +#define TST_EPOLL_H + +typedef int (*tst_on_epoll_fn)(void *, uint32_t); +struct tst_epoll_event_data { + tst_on_epoll_fn on_epoll; + void *self; +}; + +int safe_epoll_create1(const char *const file, const int lineno, + const int flags); + +#define SAFE_EPOLL_CREATE1(flags) \ + safe_epoll_create1(__FILE__, __LINE__, (flags)) + +int safe_epoll_ctl(const char *const file, const int lineno, + int epfd, int op, int fd, struct epoll_event *ev); + +#define SAFE_EPOLL_CTL(epfd, op, fd, ev) \ + safe_epoll_ctl(__FILE__, __LINE__, epfd, op, fd, ev) + +int safe_epoll_wait(const char *const file, const int lineno, + int epfd, struct epoll_event *events, + int maxevents, int timeout); + +#define SAFE_EPOLL_WAIT(epfd, events, maxevents, timeout)\ + safe_epoll_wait(__FILE__, __LINE__, epfd, events, maxevents, timeout) + +#endif diff --git a/ltp/include/tst_fd.h b/ltp/include/tst_fd.h new file mode 100644 index 0000000000000000000000000000000000000000..2183ea0687ef56bdc4e2660b0bc34ebd9289f601 --- /dev/null +++ b/ltp/include/tst_fd.h @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2023 Cyril Hrubis + */ + +#ifndef TST_FD_H__ +#define TST_FD_H__ + +enum tst_fd_type { + TST_FD_FILE, + TST_FD_PATH, + TST_FD_DIR, + TST_FD_DEV_ZERO, + TST_FD_PROC_MAPS, + TST_FD_PIPE_READ, + TST_FD_PIPE_WRITE, + TST_FD_UNIX_SOCK, + TST_FD_INET_SOCK, + TST_FD_EPOLL, + TST_FD_EVENTFD, + TST_FD_SIGNALFD, + TST_FD_TIMERFD, + TST_FD_PIDFD, + TST_FD_FANOTIFY, + TST_FD_INOTIFY, + TST_FD_USERFAULTFD, + TST_FD_PERF_EVENT, + TST_FD_IO_URING, + TST_FD_BPF_MAP, + TST_FD_FSOPEN, + TST_FD_FSPICK, + TST_FD_OPEN_TREE, + TST_FD_MEMFD, + TST_FD_MEMFD_SECRET, + TST_FD_MAX, +}; + +struct tst_fd { + enum tst_fd_type type; + int fd; + /* used by the library, do not touch! */ + long priv; +}; + +#define TST_FD_INIT {.type = TST_FD_FILE, .fd = -1} + +/* + * Advances the iterator to the next fd type, returns zero at the end. + */ +int tst_fd_next(struct tst_fd *fd); + +#define TST_FD_FOREACH(fd) \ + for (struct tst_fd fd = TST_FD_INIT; tst_fd_next(&fd); ) + +/* + * Returns human readable name for the file descriptor type. + */ +const char *tst_fd_desc(struct tst_fd *fd); + +#endif /* TST_FD_H__ */ diff --git a/ltp/include/tst_fs.h b/ltp/include/tst_fs.h new file mode 100644 index 0000000000000000000000000000000000000000..19c240e0720ad8e95a6567ad92ac4ef7c35f6f08 --- /dev/null +++ b/ltp/include/tst_fs.h @@ -0,0 +1,288 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2015-2017 Cyril Hrubis + * Copyright (c) Linux Test Project, 2017-2022 + */ + +#ifndef TST_FS_H__ +#define TST_FS_H__ + +/* man 2 statfs or kernel-source/include/uapi/linux/magic.h */ +#define TST_BTRFS_MAGIC 0x9123683E +#define TST_NFS_MAGIC 0x6969 +#define TST_RAMFS_MAGIC 0x858458f6 +#define TST_TMPFS_MAGIC 0x01021994 +#define TST_V9FS_MAGIC 0x01021997 +#define TST_XFS_MAGIC 0x58465342 +#define TST_EXT2_OLD_MAGIC 0xEF51 +/* ext2, ext3, ext4 have the same magic number */ +#define TST_EXT234_MAGIC 0xEF53 +#define TST_MINIX_MAGIC 0x137F +#define TST_MINIX_MAGIC2 0x138F +#define TST_MINIX2_MAGIC 0x2468 +#define TST_MINIX2_MAGIC2 0x2478 +#define TST_MINIX3_MAGIC 0x4D5A +#define TST_UDF_MAGIC 0x15013346 +#define TST_SYSV2_MAGIC 0x012FF7B6 +#define TST_SYSV4_MAGIC 0x012FF7B5 +#define TST_UFS_MAGIC 0x00011954 +#define TST_UFS2_MAGIC 0x19540119 +#define TST_F2FS_MAGIC 0xF2F52010 +#define TST_NILFS_MAGIC 0x3434 +#define TST_EXOFS_MAGIC 0x5DF5 +#define TST_OVERLAYFS_MAGIC 0x794c7630 +#define TST_FUSE_MAGIC 0x65735546 +#define TST_VFAT_MAGIC 0x4d44 /* AKA MSDOS */ +#define TST_EXFAT_MAGIC 0x2011BAB0UL + +/* fs/bcachefs/bcachefs_format.h */ +#define TST_BCACHE_MAGIC 0xca451a4e + +#include + +enum tst_fill_access_pattern { + TST_FILL_BLOCKS, + TST_FILL_RANDOM +}; + +enum { + TST_BYTES = 1, + TST_KB = 1024, + TST_MB = 1048576, + TST_GB = 1073741824, +}; + +#define OVL_BASE_MNTPOINT "mntpoint" +#define OVL_LOWER OVL_BASE_MNTPOINT"/lower" +#define OVL_UPPER OVL_BASE_MNTPOINT"/upper" +#define OVL_WORK OVL_BASE_MNTPOINT"/work" +#define OVL_MNT OVL_BASE_MNTPOINT"/ovl" + +/* + * @path: path is the pathname of any file within the mounted file system + * @mult: mult should be TST_KB, TST_MB or TST_GB + * the required free space is calculated by @size * @mult + */ +int tst_fs_has_free_(void (*cleanup)(void), const char *path, uint64_t size, + unsigned int mult); + +/* + * Returns filesystem magick for a given path. + * + * The expected usage is: + * + * if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC) { + * tst_brkm(TCONF, cleanup, + * "Test not supported on NFS filesystem"); + * } + * + * Or: + * + * long type; + * + * swtich ((type = tst_fs_type(cleanup, "."))) { + * case TST_NFS_MAGIC: + * case TST_TMPFS_MAGIC: + * case TST_RAMFS_MAGIC: + * tst_brkm(TCONF, cleanup, "Test not supported on %s filesystem", + * tst_fs_type_name(type)); + * break; + * } + */ +long tst_fs_type_(void (*cleanup)(void), const char *path); + +/* + * Returns filesystem name given magic. + */ +const char *tst_fs_type_name(long f_type); + +/* + * Try to get maximum number of hard links to a regular file inside the @dir. + * + * Note: This number depends on the filesystem @dir is on. + * + * The code uses link(2) to create hard links to a single file until it gets + * EMLINK or creates 65535 links. + * + * If limit is hit maximal 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 (succed to create 65535 without error) or if link() + * failed with ENOSPC or EDQUOT zero is returned previously created files are + * removed. + */ +int tst_fs_fill_hardlinks_(void (*cleanup) (void), const char *dir); + +/* + * Try to get maximum number of subdirectories in directory. + * + * Note: This number depends on the filesystem @dir is on. + * + * The code uses mkdir(2) to create directories in @dir until it gets EMLINK + * or creates 65535 directories. + * + * If limit is hit the maximal 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 link from parent dir). + * + * If no limit is hit or mkdir() failed with ENOSPC or EDQUOT zero is returned + * previously created directories are removed. + * + */ +int tst_fs_fill_subdirs_(void (*cleanup) (void), const char *dir); + +/* + * Checks if a given directory contains any entities, + * returns 1 if directory is empty, 0 otherwise + */ +int tst_dir_is_empty_(void (*cleanup)(void), const char *name, int verbose); + +/* + * Search $PATH for prog_name and fills buf with absolute path if found. + * + * Returns -1 on failure, either command was not found or buffer was too small. + */ +int tst_get_path(const char *prog_name, char *buf, size_t buf_len); + +/** + * tst_path_exists() - checks if path exists + * + * @fmt: A printf-like format used to construct the path. + * @...: A printf-like parameter list. + * return: Non-zero if path exists, zero otherwise. + */ +int tst_path_exists(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +/* + * Fill a file with specified pattern + * @fd: file descriptor + * @pattern: pattern + * @bs: block size + * @bcount: blocks count + */ +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 + * @pattern: pattern + * @bs: block size + * @bcount: blocks amount + */ +int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount); + +/* + * 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, +}; + +/* + * Returns if filesystem is supported and if driver is in kernel or FUSE. + * + * @fs_type A filesystem name to check the support for. + */ +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 filesystems to skip. + */ +int tst_fs_in_skiplist(const char *fs_type, const char *const *skiplist); + +/* + * Creates and writes to files on given path until write fails with ENOSPC + */ +void tst_fill_fs(const char *path, int verbose, enum tst_fill_access_pattern pattern); + +/* + * Check if FIBMAP ioctl is supported. + * Tests needs to set .needs_root = 1 in order to avoid EPERM. + * + * @return 0: FIBMAP is supported, 1: FIBMAP is *not* supported. + */ +int tst_fibmap(const char *filename); + +#ifdef TST_TEST_H__ +static inline long tst_fs_type(const char *path) +{ + return tst_fs_type_(NULL, path); +} + +static inline int tst_fs_has_free(const char *path, uint64_t size, + unsigned int mult) +{ + return tst_fs_has_free_(NULL, path, size, mult); +} + +static inline int tst_fs_fill_hardlinks(const char *dir) +{ + return tst_fs_fill_hardlinks_(NULL, dir); +} + +static inline int tst_fs_fill_subdirs(const char *dir) +{ + return tst_fs_fill_subdirs_(NULL, dir); +} + +static inline int tst_dir_is_empty(const char *name, int verbose) +{ + return tst_dir_is_empty_(NULL, name, verbose); +} +#else +static inline long tst_fs_type(void (*cleanup)(void), const char *path) +{ + return tst_fs_type_(cleanup, path); +} + +static inline int tst_fs_has_free(void (*cleanup)(void), const char *path, + uint64_t size, unsigned int mult) +{ + return tst_fs_has_free_(cleanup, path, size, mult); +} + +static inline int tst_fs_fill_hardlinks(void (*cleanup)(void), const char *dir) +{ + return tst_fs_fill_hardlinks_(cleanup, dir); +} + +static inline int tst_fs_fill_subdirs(void (*cleanup)(void), const char *dir) +{ + return tst_fs_fill_subdirs_(cleanup, dir); +} + +static inline int tst_dir_is_empty(void (*cleanup)(void), const char *name, int verbose) +{ + return tst_dir_is_empty_(cleanup, name, verbose); +} +#endif + +#endif /* TST_FS_H__ */ diff --git a/ltp/include/tst_fuzzy_sync.h b/ltp/include/tst_fuzzy_sync.h new file mode 100644 index 0000000000000000000000000000000000000000..b22364cab2bdcfbc62585dc6fd142d10489a0528 --- /dev/null +++ b/ltp/include/tst_fuzzy_sync.h @@ -0,0 +1,803 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2017-2018 Richard Palethorpe + */ +/** + * @file tst_fuzzy_sync.h + * Fuzzy Synchronisation - abbreviated to fzsync + * + * This library is intended to help reproduce race conditions by synchronising + * two threads at a given place by marking the range a race may occur + * in. Because the exact place where any race occurs is within the kernel, + * and therefore impossible to mark accurately, the library may add randomised + * delays to either thread in order to help find the exact race timing. + * + * Currently only two way races are explicitly supported, that is races + * involving two threads or processes. We refer to the main test thread as + * thread A and the child thread as thread B. + * + * In each thread you need a simple while- or for-loop which the tst_fzsync_* + * functions are called in. In the simplest case thread A will look something + * like: + * + * tst_fzsync_pair_reset(&pair, run_thread_b); + * while (tst_fzsync_run_a(&pair)) { + * // Perform some setup which must happen before the race + * tst_fzsync_start_race_a(&pair); + * // Do some dodgy syscall + * tst_fzsync_end_race_a(&pair); + * } + * + * Then in thread B (run_thread_b): + * + * while (tst_fzsync_run_b(&pair)) { + * tst_fzsync_start_race_b(&pair); + * // Do something which can race with the dodgy syscall in A + * tst_fzsync_end_race_b(&pair) + * } + * + * The calls to tst_fzsync_start/end_race and tst_fzsync_run_a/b block (at + * least) until both threads have enter them. These functions can only be + * called once for each iteration, but further synchronisation points can be + * added by calling tst_fzsync_wait_a() and tst_fzsync_wait_b() in each + * thread. + * + * The execution of the loops in threads A and B are bounded by both iteration + * count and time. A slow machine is likely to be limited by time and a fast + * one by iteration count. The user can use the -i parameter to run the test + * multiple times or LTP_TIMEOUT_MUL to give the test more time. + * + * It is possible to use the library just for tst_fzsync_pair_wait() to get a + * basic spin wait. However if you are actually testing a race condition then + * it is recommended to use tst_fzsync_start_race_a/b even if the + * randomisation is not needed. It provides some semantic information which + * may be useful in the future. + * + * For a usage example see testcases/cve/cve-2016-7117.c or just run + * 'git grep tst_fuzzy_sync.h' + * + * @sa tst_fzsync_pair + */ + +#include +#include +#include +#include +#include +#include "tst_atomic.h" +#include "tst_cpu.h" +#include "tst_timer.h" +#include "tst_safe_pthread.h" + +#ifndef TST_FUZZY_SYNC_H__ +#define TST_FUZZY_SYNC_H__ + +/* how much of exec time is sampling allowed to take */ +#define SAMPLING_SLICE 0.5f + +/** Some statistics for a variable */ +struct tst_fzsync_stat { + float avg; + float avg_dev; + float dev_ratio; +}; + +/** + * The state of a two way synchronisation or race. + * + * This contains all the necessary state for approximately synchronising two + * sections of code in different threads. + * + * Some of the fields can be configured before calling + * tst_fzsync_pair_reset(), however this is mainly for debugging purposes. If + * a test requires one of the parameters to be modified, we should consider + * finding a way of automatically selecting an appropriate value at runtime. + * + * Internal fields should only be accessed by library functions. + */ +struct tst_fzsync_pair { + /** + * The rate at which old diff samples are forgotten + * + * Defaults to 0.25. + */ + float avg_alpha; + /** Internal; Thread A start time */ + struct timespec a_start; + /** Internal; Thread B start time */ + struct timespec b_start; + /** Internal; Thread A end time */ + struct timespec a_end; + /** Internal; Thread B end time */ + struct timespec b_end; + /** Internal; Avg. difference between a_start and b_start */ + struct tst_fzsync_stat diff_ss; + /** Internal; Avg. difference between a_start and a_end */ + struct tst_fzsync_stat diff_sa; + /** Internal; Avg. difference between b_start and b_end */ + struct tst_fzsync_stat diff_sb; + /** Internal; Avg. difference between a_end and b_end */ + struct tst_fzsync_stat diff_ab; + /** Internal; Number of spins while waiting for the slower thread */ + int spins; + struct tst_fzsync_stat spins_avg; + /** + * Internal; Number of spins to use in the delay. + * + * A negative value delays thread A and a positive delays thread B. + */ + int delay; + int delay_bias; + /** + * Internal; The number of samples left or the sampling state. + * + * A positive value is the number of remaining mandatory + * samples. Zero or a negative indicate some other state. + */ + int sampling; + /** + * The Minimum number of statistical samples which must be collected. + * + * The minimum number of iterations which must be performed before a + * random delay can be calculated. Defaults to 1024. + */ + int min_samples; + /** + * The maximum allowed proportional average deviation. + * + * A value in the range (0, 1) which gives the maximum average + * deviation which must be attained before random delays can be + * calculated. + * + * It is a ratio of (average_deviation / total_time). The default is + * 0.1, so this allows an average deviation of at most 10%. + */ + float max_dev_ratio; + + /** Internal; Atomic counter used by fzsync_pair_wait() */ + tst_atomic_t a_cntr; + /** Internal; Atomic counter used by fzsync_pair_wait() */ + tst_atomic_t b_cntr; + /** Internal; Used by tst_fzsync_pair_exit() and fzsync_pair_wait() */ + tst_atomic_t exit; + /** Internal; The test time remaining on tst_fzsync_pair_reset() */ + float exec_time_start; + /** + * The maximum number of iterations to execute during the test + * + * Defaults to a large number, but not too large. + */ + int exec_loops; + /** Internal; The current loop index */ + 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 { \ + pair->param = (pair->param ? pair->param : def); \ + if (pair->param < low) \ + tst_brk(TBROK, #param " is less than the lower bound " #low); \ + if (pair->param > hi) \ + tst_brk(TBROK, #param " is more than the upper bound " #hi); \ + } while (0) +/** + * Ensures that any Fuzzy Sync parameters are properly set + * + * @relates tst_fzsync_pair + * + * Usually called from the setup function, it sets default parameter values or + * validates any existing non-defaults. + * + * @sa tst_fzsync_pair_reset() + */ +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_loops, 20, INT_MAX, 3000000); + + if (tst_ncpus_available() <= 1) + pair->yield_in_wait = 1; +} +#undef CHK + +/** + * Exit and join thread B if necessary. + * + * @relates tst_fzsync_pair + * + * Call this from your cleanup function. + */ +static inline void tst_fzsync_pair_cleanup(struct tst_fzsync_pair *pair) +{ + if (pair->thread_b) { + /* Revoke thread B if parent hits accidental break */ + if (!pair->exit) + tst_atomic_store(1, &pair->exit); + SAFE_PTHREAD_JOIN(pair->thread_b, NULL); + pair->thread_b = 0; + } +} + +/** + * Zero some stat fields + * + * @relates tst_fzsync_stat + */ +static inline void tst_init_stat(struct tst_fzsync_stat *s) +{ + s->avg = 0; + s->avg_dev = 0; +} + +/** + * Reset or initialise fzsync. + * + * @relates tst_fzsync_pair + * @param pair The state structure initialised with TST_FZSYNC_PAIR_INIT. + * @param run_b The function defining thread B or NULL. + * + * Call this from your main test function (thread A), just before entering the + * main loop. It will (re)set any variables needed by fzsync and (re)start + * thread B using the function provided. + * + * If you need to use fork or clone to start the second thread/process then + * you can pass NULL to run_b and handle starting and stopping thread B + * yourself. You may need to place tst_fzsync_pair in some shared memory as + * well. + * + * @sa tst_fzsync_pair_init() + */ +static inline void tst_fzsync_pair_reset(struct tst_fzsync_pair *pair, + void *(*run_b)(void *)) +{ + tst_fzsync_pair_cleanup(pair); + + tst_init_stat(&pair->diff_ss); + tst_init_stat(&pair->diff_sa); + tst_init_stat(&pair->diff_sb); + 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; + + pair->a_cntr = 0; + pair->b_cntr = 0; + pair->exit = 0; + if (run_b) + SAFE_PTHREAD_CREATE(&pair->thread_b, 0, run_b, 0); + + pair->exec_time_start = (float)tst_remaining_runtime(); +} + +/** + * Print stat + * + * @relates tst_fzsync_stat + */ +static inline void tst_fzsync_stat_info(struct tst_fzsync_stat stat, + char *unit, char *name) +{ + tst_res(TINFO, + "%1$-17s: { avg = %3$5.0f%2$s, avg_dev = %4$5.0f%2$s, dev_ratio = %5$.2f }", + name, unit, stat.avg, stat.avg_dev, stat.dev_ratio); +} + +/** + * Print some synchronisation statistics + * + * @relates tst_fzsync_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); + tst_fzsync_stat_info(pair->diff_ss, "ns", "start_a - start_b"); + tst_fzsync_stat_info(pair->diff_sa, "ns", "end_a - start_a"); + tst_fzsync_stat_info(pair->diff_sb, "ns", "end_b - start_b"); + tst_fzsync_stat_info(pair->diff_ab, "ns", "end_a - end_b"); + tst_fzsync_stat_info(pair->spins_avg, " ", "spins"); +} + +/** Wraps clock_gettime */ +static inline void tst_fzsync_time(struct timespec *t) +{ +#ifdef CLOCK_MONOTONIC_RAW + clock_gettime(CLOCK_MONOTONIC_RAW, t); +#else + clock_gettime(CLOCK_MONOTONIC, t); +#endif +} + +/** + * Exponential moving average + * + * @param alpha The preference for recent samples over old ones. + * @param sample The current sample + * @param prev_avg The average of the all the previous samples + * + * @return The average including the current sample. + */ +static inline float tst_exp_moving_avg(float alpha, + float sample, + float prev_avg) +{ + return alpha * sample + (1.0 - alpha) * prev_avg; +} + +/** + * Update a stat with a new sample + * + * @relates tst_fzsync_stat + */ +static inline void tst_upd_stat(struct tst_fzsync_stat *s, + float alpha, + float sample) +{ + s->avg = tst_exp_moving_avg(alpha, sample, s->avg); + s->avg_dev = tst_exp_moving_avg(alpha, + fabs(s->avg - sample), s->avg_dev); + s->dev_ratio = fabs(s->avg ? s->avg_dev / s->avg : 0); +} + +/** + * Update a stat with a new diff sample + * + * @relates tst_fzsync_stat + */ +static inline void tst_upd_diff_stat(struct tst_fzsync_stat *s, + float alpha, + struct timespec t1, + struct timespec t2) +{ + tst_upd_stat(s, alpha, tst_timespec_diff_ns(t1, t2)); +} + +/** + * Calculate various statistics and the delay + * + * This function helps create the fuzz in fuzzy sync. Imagine we have the + * following timelines in threads A and B: + * + * start_race_a + * ^ end_race_a (a) + * | ^ + * | | + * - --+------------------------+-- - - + * | Syscall A | Thread A + * - --+------------------------+-- - - + * - --+----------------+-------+-- - - + * | Syscall B | spin | Thread B + * - --+----------------+-------+-- - - + * | | + * ^ ^ + * start_race_b end_race_b + * + * Here we have synchronised the calls to syscall A and B with start_race_{a, + * b} so that they happen at approximately the same time in threads A and + * B. If the race condition occurs during the entry code for these two + * functions then we will quickly hit it. If it occurs during the exit code of + * B and mid way through A, then we will quickly hit it. + * + * However if the exit paths of A and B need to be aligned and (end_race_a - + * end_race_b) is large relative to the variation in call times, the + * probability of hitting the race condition is close to zero. To solve this + * scenario (and others) a randomised delay is introduced before the syscalls + * in A and B. Given enough time the following should happen where the exit + * paths are now synchronised: + * + * start_race_a + * ^ end_race_a (a) + * | ^ + * | | + * - --+------------------------+-- - - + * | Syscall A | Thread A + * - --+------------------------+-- - - + * - --+-------+----------------+-- - - + * | delay | Syscall B | Thread B + * - --+-------+----------------+-- - - + * | | + * ^ ^ + * start_race_b end_race_b + * + * The delay is not introduced immediately and the delay range is only + * calculated once the average relative deviation has dropped below some + * percentage of the total time. + * + * The delay range is chosen so that any point in Syscall A could be + * synchronised with any point in Syscall B using a value from the + * range. Because the delay range may be too large for a linear search, we use + * an evenly distributed random function to pick a value from it. + * + * The delay range goes from positive to negative. A negative delay will delay + * thread A and a positive one will delay thread B. The range is bounded by + * the point where the entry code to Syscall A is synchronised with the exit + * to Syscall B and the entry code to Syscall B is synchronised with the exit + * of A. + * + * In order to calculate the lower bound (the max delay of A) we can simply + * negate the execution time of Syscall B and convert it to a spin count. For + * the upper bound (the max delay of B), we just take the execution time of A + * and convert it to a spin count. + * + * In order to calculate spin count we need to know approximately how long a + * spin takes and divide the delay time with it. We find this by first + * counting how many spins one thread spends waiting for the other during + * end_race[1]. We also know when each syscall exits so we can take the + * difference between the exit times and divide it with the number of spins + * spent waiting. + * + * All the times and counts we use in the calculation are averaged over a + * variable number of iterations. There is an initial sampling period where we + * simply collect time and count samples then calculate their averages. When a + * minimum number of samples have been collected, and if the average deviation + * is below some proportion of the average sample magnitude, then the sampling + * period is ended. On all further iterations a random delay is calculated and + * applied, but the averages are not updated. + * + * [1] This assumes there is always a significant difference. The algorithm + * may fail to introduce a delay (when one is needed) in situations where + * Syscall A and B finish at approximately the same time. + * + * @relates tst_fzsync_pair + */ +static inline void tst_fzsync_pair_update(struct tst_fzsync_pair *pair) +{ + float alpha = pair->avg_alpha; + float per_spin_time, time_delay; + float max_dev = pair->max_dev_ratio; + int over_max_dev; + + pair->delay = pair->delay_bias; + + over_max_dev = pair->diff_ss.dev_ratio > max_dev + || pair->diff_sa.dev_ratio > max_dev + || pair->diff_sb.dev_ratio > max_dev + || pair->diff_ab.dev_ratio > max_dev + || pair->spins_avg.dev_ratio > max_dev; + + if (pair->sampling > 0 || over_max_dev) { + tst_upd_diff_stat(&pair->diff_ss, alpha, + pair->a_start, pair->b_start); + tst_upd_diff_stat(&pair->diff_sa, alpha, + pair->a_end, pair->a_start); + tst_upd_diff_stat(&pair->diff_sb, alpha, + pair->b_end, pair->b_start); + tst_upd_diff_stat(&pair->diff_ab, alpha, + pair->a_end, pair->b_end); + tst_upd_stat(&pair->spins_avg, alpha, pair->spins); + if (pair->sampling > 0 && --pair->sampling == 0) { + tst_res(TINFO, "Minimum sampling period ended"); + tst_fzsync_pair_info(pair); + } + } else if (fabsf(pair->diff_ab.avg) >= 1) { + 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)(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_fzsync_pair_info(pair); + pair->sampling = -1; + } + } else if (!pair->sampling) { + tst_res(TWARN, "Can't calculate random delay"); + tst_fzsync_pair_info(pair); + pair->sampling = -1; + } + + pair->spins = 0; +} + +/** + * Wait for the other thread + * + * @relates tst_fzsync_pair + * @param our_cntr The counter for the thread we are on + * @param other_cntr The counter for the thread we are synchronising with + * @param spins A pointer to the spin counter or NULL + * @param exit Exit flag when we need to break out of the wait loop + * + * Used by tst_fzsync_pair_wait_a(), tst_fzsync_pair_wait_b(), + * tst_fzsync_start_race_a(), etc. If the calling thread is ahead of the other + * thread, then it will spin wait. Unlike pthread_barrier_wait it will never + * use futex and can count the number of spins spent waiting. + * + * @return A non-zero value if the thread should continue otherwise the + * calling thread should exit. + */ +static inline void tst_fzsync_pair_wait(int *our_cntr, + int *other_cntr, + int *spins, + int *exit, + bool yield_in_wait) +{ + if (tst_atomic_inc(other_cntr) == INT_MAX) { + /* + * We are about to break the invariant that the thread with + * the lowest count is in front of the other. So we must wait + * here to ensure the other thread has at least reached the + * line above before doing that. If we are in rear position + * then our counter may already have been set to zero. + */ + if (yield_in_wait) { + while (tst_atomic_load(our_cntr) > 0 + && tst_atomic_load(our_cntr) < INT_MAX + && !tst_atomic_load(exit)) { + if (spins) + (*spins)++; + + sched_yield(); + } + } else { + while (tst_atomic_load(our_cntr) > 0 + && tst_atomic_load(our_cntr) < INT_MAX + && !tst_atomic_load(exit)) { + 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. + */ + if (yield_in_wait) { + while (tst_atomic_load(our_cntr) > 1 + && !tst_atomic_load(exit)) + sched_yield(); + } else { + while (tst_atomic_load(our_cntr) > 1 + && !tst_atomic_load(exit)) + ; + } + } else { + /* + * If our counter is less than the other thread's we are ahead + * of it and need to wait. + */ + if (yield_in_wait) { + while (tst_atomic_load(our_cntr) < + tst_atomic_load(other_cntr) + && !tst_atomic_load(exit)) { + if (spins) + (*spins)++; + sched_yield(); + } + } else { + while (tst_atomic_load(our_cntr) < + tst_atomic_load(other_cntr) + && !tst_atomic_load(exit)) { + if (spins) + (*spins)++; + } + } + } +} + +/** + * Wait in thread A + * + * @relates tst_fzsync_pair + * @sa tst_fzsync_pair_wait + */ +static inline void tst_fzsync_wait_a(struct tst_fzsync_pair *pair) +{ + tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, + NULL, &pair->exit, pair->yield_in_wait); +} + +/** + * Wait in thread B + * + * @relates tst_fzsync_pair + * @sa tst_fzsync_pair_wait + */ +static inline void tst_fzsync_wait_b(struct tst_fzsync_pair *pair) +{ + tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, + NULL, &pair->exit, pair->yield_in_wait); +} + +/** + * Decide whether to continue running thread A + * + * @relates tst_fzsync_pair + * + * Checks some values and decides whether it is time to break the loop of + * thread A. + * + * @return True to continue and false to break. + * @sa tst_fzsync_run_a + */ +static inline int tst_fzsync_run_a(struct tst_fzsync_pair *pair) +{ + float rem_p = 1 - tst_remaining_runtime() / pair->exec_time_start; + + if ((SAMPLING_SLICE < rem_p) && (pair->sampling > 0)) { + tst_res(TINFO, "Stopped sampling at %d (out of %d) samples, " + "sampling time reached 50%% of the total time limit", + pair->exec_loop, pair->min_samples); + pair->sampling = 0; + tst_fzsync_pair_info(pair); + } + + if (rem_p >= 1) { + tst_res(TINFO, + "Exceeded execution time, requesting exit"); + tst_atomic_store(1, &pair->exit); + } + + if (++pair->exec_loop > pair->exec_loops) { + tst_res(TINFO, + "Exceeded execution loops, requesting exit"); + tst_atomic_store(1, &pair->exit); + } + + tst_fzsync_wait_a(pair); + + if (pair->exit) { + tst_fzsync_pair_cleanup(pair); + return 0; + } + + return 1; +} + +/** + * Decide whether to continue running thread B + * + * @relates tst_fzsync_pair + * @sa tst_fzsync_run_a + */ +static inline int tst_fzsync_run_b(struct tst_fzsync_pair *pair) +{ + tst_fzsync_wait_b(pair); + return !tst_atomic_load(&pair->exit); +} + +/** + * Marks the start of a race region in thread A + * + * @relates tst_fzsync_pair + * + * This should be placed just before performing whatever action can cause a + * race condition. Usually it is placed just before a syscall and + * tst_fzsync_end_race_a() is placed just afterwards. + * + * A corresponding call to tst_fzsync_start_race_b() should be made in thread + * B. + * + * @return A non-zero value if the calling thread should continue to loop. If + * it returns zero then tst_fzsync_exit() has been called and you must exit + * the thread. + * + * @sa tst_fzsync_pair_update + */ +static inline void tst_fzsync_start_race_a(struct tst_fzsync_pair *pair) +{ + volatile int delay; + + tst_fzsync_pair_update(pair); + + tst_fzsync_wait_a(pair); + + delay = pair->delay; + if (pair->yield_in_wait) { + while (delay < 0) { + sched_yield(); + delay++; + } + } else { + while (delay < 0) + delay++; + } + + tst_fzsync_time(&pair->a_start); +} + +/** + * Marks the end of a race region in thread A + * + * @relates tst_fzsync_pair + * @sa tst_fzsync_start_race_a + */ +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, &pair->exit, pair->yield_in_wait); +} + +/** + * Marks the start of a race region in thread B + * + * @relates tst_fzsync_pair + * @sa tst_fzsync_start_race_a + */ +static inline void tst_fzsync_start_race_b(struct tst_fzsync_pair *pair) +{ + volatile int delay; + + tst_fzsync_wait_b(pair); + + delay = pair->delay; + if (pair->yield_in_wait) { + while (delay > 0) { + sched_yield(); + delay--; + } + } else { + while (delay > 0) + delay--; + } + + tst_fzsync_time(&pair->b_start); +} + +/** + * Marks the end of a race region in thread B + * + * @relates tst_fzsync_pair + * @sa tst_fzsync_start_race_a + */ +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, &pair->exit, pair->yield_in_wait); +} + +/** + * Add some amount to the delay bias + * + * @relates tst_fzsync_pair + * @param change The amount to add, can be negative + * + * A positive change delays thread B and a negative one delays thread + * A. + * + * It is intended to be used in tests where the time taken by syscall A and/or + * B are significantly affected by their chronological order. To the extent + * that the delay range will not include the correct values if too many of the + * initial samples are taken when the syscalls (or operations within the + * syscalls) happen in the wrong order. + * + * An example of this is cve/cve-2016-7117.c where a call to close() is racing + * with a call to recvmmsg(). If close() happens before recvmmsg() has chance + * to check if the file descriptor is open then recvmmsg() completes very + * quickly. If the call to close() happens once recvmmsg() has already checked + * the descriptor it takes much longer. The sample where recvmmsg() completes + * quickly is essentially invalid for our purposes. The test uses the simple + * heuristic of whether recvmmsg() returns EBADF, to decide if it should call + * tst_fzsync_pair_add_bias() to further delay syscall B. + */ +static inline void tst_fzsync_pair_add_bias(struct tst_fzsync_pair *pair, int change) +{ + if (pair->sampling > 0) + pair->delay_bias += change; +} + +#endif /* TST_FUZZY_SYNC_H__ */ diff --git a/ltp/include/tst_get_bad_addr.h b/ltp/include/tst_get_bad_addr.h new file mode 100644 index 0000000000000000000000000000000000000000..69d7402098f7c7480bc64df5a33e6a7042b67c85 --- /dev/null +++ b/ltp/include/tst_get_bad_addr.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. + * Author: Xiao Yang + */ + +#ifndef TST_GET_BAD_ADDR_H__ +#define TST_GET_BAD_ADDR_H__ + +/* Functions from lib/tst_get_bad_addr.c */ +void *tst_get_bad_addr(void (*cleanup_fn) (void)); + +#endif /* TST_GET_BAD_ADDR_H__ */ diff --git a/ltp/include/tst_hugepage.h b/ltp/include/tst_hugepage.h new file mode 100644 index 0000000000000000000000000000000000000000..6b865b2f20b3deb3197638cff45a7a34b77e7d0e --- /dev/null +++ b/ltp/include/tst_hugepage.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Red Hat, Inc. + */ + +#ifndef TST_HUGEPAGE__ +#define TST_HUGEPAGE__ + +#define PATH_HUGEPAGES "/sys/kernel/mm/hugepages/" +#define PATH_NR_HPAGES "/proc/sys/vm/nr_hugepages" +#define PATH_OC_HPAGES "/proc/sys/vm/nr_overcommit_hugepages" + +#define MEMINFO_HPAGE_TOTAL "HugePages_Total:" +#define MEMINFO_HPAGE_FREE "HugePages_Free:" +#define MEMINFO_HPAGE_RSVD "HugePages_Rsvd:" +#define MEMINFO_HPAGE_SURP "HugePages_Surp:" +#define MEMINFO_HPAGE_SIZE "Hugepagesize:" + +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 */ + +enum tst_hp_policy { + TST_REQUEST, + TST_NEEDS, +}; + +#define TST_NO_HUGEPAGES ((unsigned long)-1) + +struct tst_hugepage { + const unsigned long number; + enum tst_hp_policy policy; +}; + +/* + * 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. + * + * Note: this depend on the status of system memory fragmentation. + */ +unsigned long tst_reserve_hugepages(struct tst_hugepage *hp); + +/* + * This variable is used for recording the number of hugepages which system can + * provides. It will be equal to 'hpages' if tst_reserve_hugepages on success, + * otherwise set it to a number of hugepages that we were able to reserve. + * + * If system does not support hugetlb, then it will be set to 0. + */ +extern unsigned long tst_hugepages; + +#endif /* TST_HUGEPAGE_H */ diff --git a/ltp/include/tst_kconfig.h b/ltp/include/tst_kconfig.h new file mode 100644 index 0000000000000000000000000000000000000000..b0608498d7e837e2c7b847fbef23334dcf2605c9 --- /dev/null +++ b/ltp/include/tst_kconfig.h @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Cyril Hrubis + */ + +#ifndef TST_KCONFIG_H__ +#define TST_KCONFIG_H__ + +#include +#include + +/** + * Initialization helper macro for struct tst_kconfig_var. Requires + */ +#define TST_KCONFIG_INIT(confname) { \ + .id = confname, \ + .id_len = strlen(confname) \ +} + +struct tst_kconfig_var { + char id[64]; + unsigned int id_len; + char choice; + char *val; +}; + +/** + * + * 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 explicitly set/overridden with + * the KCONFIG_PATH environment variable as well. + * + * 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. + * + * After a call to this function each choice be set as follows: + * + * 'm' - config option set to m + * 'y' - config option set to y + * 'v' - config option set to other value + * 'n' - config option is not set + * 0 - config option not found + * + * 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 initialized tst_kconfig_var structures. + * @param vars_len Length of the vars array. + */ +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. 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 + * test or with an explicit value "CONFIG_FOO=bar" in which case the value has + * to match. + * + * @param kconfigs NULL-terminated array of config strings needed for the testrun. + */ +int tst_kconfig_check(const char *const kconfigs[]); + +/** + * Macro to prepare a tst_kcmdline_var structure with a given parameter name. + * + * It initializes the .key field with the provided name, sets the .value field + * to an empty string, and marks the parameter as not found (.found = false). + * + * This macro is typically used to prepopulate an array with configuration + * parameters before processing the actual command line arguments. + */ +#define TST_KCMDLINE_INIT(paraname) { \ + .key = paraname, \ + .value = "", \ + .found = false \ +} + +/** + * Structure for storing command-line parameter key and its corresponding + * value, and a flag indicating whether the parameter was found. + */ +struct tst_kcmdline_var { + const char *key; + char value[256]; + bool found; +}; + +/** + * Parses command-line parameters from /proc/cmdline and stores them in params array. + * params: The array of tst_kcmdline_var structures to be filled with parsed key-value pairs. + * params_len: The length of the params array, indicating how many parameters to parse. + */ +void tst_kcmdline_parse(struct tst_kcmdline_var params[], size_t params_len); + +/* + * tst_has_slow_kconfig() - Check if any performance-degrading kernel configs are enabled. + * + * This function iterates over the list of slow kernel configuration options + * (`tst_slow_kconfigs`) and checks if any of them are enabled in the running kernel. + * + * Return: + * - 1 if at least one slow kernel config is enabled. + * - 0 if none of the slow kernel configs are enabled. + */ +int tst_has_slow_kconfig(void); + +#endif /* TST_KCONFIG_H__ */ diff --git a/ltp/include/tst_kernel.h b/ltp/include/tst_kernel.h new file mode 100644 index 0000000000000000000000000000000000000000..63ecb19a4c2e7d2df934e37e36632269322c3576 --- /dev/null +++ b/ltp/include/tst_kernel.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) Linux Test Project, 2018-2024 + */ + +#ifndef TST_KERNEL_H__ +#define TST_KERNEL_H__ + +#include + +/** + * tst_kernel_bits() - Detect if running on 32bit or 64bit kernel. + * + * Return: 32 if the test process is running on 32bit kernel and 64 if on 64bit + * kernel. + */ +int tst_kernel_bits(void); + +/** + * tst_is_compat_mode() - Detect if running in compat mode. + * + * Detect if the test is 32bit binary executed on a 64bit kernel, + * i.e. we are testing the kernel compat layer. + * + * Return: non-zero if the test process is running in compat mode. + */ +int tst_is_compat_mode(void); + +/** + * tst_abi_bits() - Detect if compiled for required kernel ABI. + * + * @abi: kernel ABI bits (32 or 64). + * + * Return: true if compiled for required ABI or false otherwise. + */ +bool tst_abi_bits(int abi); + +/** + * tst_check_builtin_driver() - Check if the kernel module is built-in. + * + * @driver: the name of the driver. + * + * Return: 0 if builtin driver or -1 when driver is missing or config file not + * available. On Android *always* 0 (always expect the driver is available). + */ +int tst_check_builtin_driver(const char *driver); + +/** + * tst_check_driver() - Check support for the kernel module. + * + * Check support for the kernel module (both built-in and loadable). + * + * @driver: the name of the driver. + * + * Return: 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 *driver); + +/** + * tst_check_preempt_rt() - Check if the running kernel is RT. + * + * Check support for the kernel module (both built-in and loadable). + * + * Return: -1 if the kernel is RT, 0 otherwise. + */ +int tst_check_preempt_rt(void); + +#endif /* TST_KERNEL_H__ */ diff --git a/ltp/include/tst_kvercmp.h b/ltp/include/tst_kvercmp.h new file mode 100644 index 0000000000000000000000000000000000000000..fbefa0f793ac129089ec98d5ffb5931568b46701 --- /dev/null +++ b/ltp/include/tst_kvercmp.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2009-2016 Cyril Hrubis chrubis@suse.cz + */ + +#ifndef TST_KVERCMP_H__ +#define TST_KVERCMP_H__ + +/* + * The same as tst_kvercmp() but running kernel version is passed as parameter + * instead of utilizing uname(). + */ +int tst_kvcmp(const char *cur_kver, int r1, int r2, int r3); + +/* + * Parsers string into three integer version. + */ +int tst_parse_kver(const char *str_kver, int *v1, int *v2, int *v3); + +/* + * Returns distribution name parsed from kernel version string or NULL. + */ +const char *tst_kvcmp_distname(const char *cur_kver); + +/* + * Compares versions up to five version numbers long. + */ +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 same and positive if newer. + */ +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); + +#endif /* TST_KVERCMP_H__ */ diff --git a/ltp/include/tst_memutils.h b/ltp/include/tst_memutils.h new file mode 100644 index 0000000000000000000000000000000000000000..57c90c4a9ce1641612e00ec3cd1afbac09b8481d --- /dev/null +++ b/ltp/include/tst_memutils.h @@ -0,0 +1,74 @@ +/* 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); + +/* + * Read the value of SwapFree from /proc/meminfo. + */ +long long tst_available_swap(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); + +#define TST_PRINT_MEMINFO() safe_print_file(__FILE__, __LINE__, "/proc/meminfo") + +/** + * tst_mapping_in_range() - Returns true if there is a mapping provided range. + * + * @low: A lower address inside of the processe address space. + * @high: A higher address inside of the processe address space. + * + * return: Returns true if there is a mapping between low and high addresses in + * the process address space. + */ +int tst_mapping_in_range(unsigned long low, unsigned long high); + +#endif /* TST_MEMUTILS_H__ */ diff --git a/ltp/include/tst_minmax.h b/ltp/include/tst_minmax.h new file mode 100644 index 0000000000000000000000000000000000000000..1597fbc978f55208a99dba35cf86441e8e62c9a5 --- /dev/null +++ b/ltp/include/tst_minmax.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) Linux Test Project, 2020-2023 + */ + +#ifndef TST_MINMAX_H__ +#define TST_MINMAX_H__ + +#include + +#ifndef MIN +# define MIN(a, b) ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + (void) (&_a == &_b); \ + _a < _b ? _a : _b; \ +}) +#endif /* MIN */ + +#ifndef MAX +# define MAX(a, b) ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + (void) (&_a == &_b); \ + _a > _b ? _a : _b; \ +}) +#endif /* MAX */ + +#endif /* TST_MINMAX_H__ */ diff --git a/ltp/include/tst_mkfs.h b/ltp/include/tst_mkfs.h new file mode 100644 index 0000000000000000000000000000000000000000..9747a85e004907696056caacfa9f504904271c1c --- /dev/null +++ b/ltp/include/tst_mkfs.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2016 Cyril Hrubis + */ + +#ifndef TST_MKFS_H__ +#define TST_MKFS_H__ + +/* + * @dev: path to a device + * @fs_type: filesystem type + * @fs_opts: NULL or NULL terminated array of extra mkfs options + * @extra_opts: NULL or NULL terminated array of extra mkfs options which are + * passed after the device name. + */ +void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), + const char *dev, const char *fs_type, + const char *const fs_opts[], const char *const extra_opts[]); + +#define SAFE_MKFS(device, fs_type, fs_opts, extra_opts) \ + tst_mkfs_(__FILE__, __LINE__, NULL, device, fs_type, \ + fs_opts, extra_opts) + +#endif /* TST_MKFS_H__ */ diff --git a/ltp/include/tst_module.h b/ltp/include/tst_module.h new file mode 100644 index 0000000000000000000000000000000000000000..e55321d191bef6c78a770e893f287278aa5041e4 --- /dev/null +++ b/ltp/include/tst_module.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) Linux Test Project, 2016-2024 + * Alexey Kodanev + */ + +#ifndef TST_MODULE_H +#define TST_MODULE_H + +#include + +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); +} + +bool tst_module_signature_enforced_(void); + +static inline bool tst_module_signature_enforced(void) +{ + return tst_module_signature_enforced_(); +} + +void tst_requires_module_signature_disabled_(void); + +static inline void tst_requires_module_signature_disabled(void) +{ + tst_requires_module_signature_disabled_(); +} + +void tst_modprobe(const char *mod_name, char *const argv[]); +void tst_module_reload(const char *mod_name, char *const argv[]); + +#endif /* TST_MODULE_H */ diff --git a/ltp/include/tst_net.h b/ltp/include/tst_net.h new file mode 100644 index 0000000000000000000000000000000000000000..9d8b842dd68dcf9d0714b0479dbce57101c26d3d --- /dev/null +++ b/ltp/include/tst_net.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2019 Petr Vorel + */ + +#ifndef TST_NET_H_ +#define TST_NET_H_ + +#include +#include +#include +#include +#include + +void tst_get_in_addr(const char *ip_str, struct in_addr *ip); +void tst_get_in6_addr(const char *ip_str, struct in6_addr *ip6); + +/* + * Find valid connection address for a given bound socket + */ +socklen_t tst_get_connect_address(int sock, struct sockaddr_storage *addr); + +/* + * Initialize AF_INET/AF_INET6 socket address structure with address and port + */ +void tst_init_sockaddr_inet(struct sockaddr_in *sa, const char *ip_str, uint16_t port); +void tst_init_sockaddr_inet_bin(struct sockaddr_in *sa, uint32_t ip_val, uint16_t port); +void tst_init_sockaddr_inet6(struct sockaddr_in6 *sa, const char *ip_str, uint16_t port); +void tst_init_sockaddr_inet6_bin(struct sockaddr_in6 *sa, const struct in6_addr *ip_val, uint16_t port); + +void safe_getaddrinfo(const char *file, const int lineno, const char *src_addr, + const char *port, const struct addrinfo *hints, + struct addrinfo **addr_info); + +/* + * Create new network namespace for netdevice/socket tests. A test which calls + * tst_setup_netns() must declare the following entries in its struct tst_test: + * + * .needs_kconfigs = (const char *[]) { + * "CONFIG_USER_NS=y", + * "CONFIG_NET_NS=y", + * NULL + * }, + * .save_restore = (const struct tst_path_val[]) { + * {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + * {} + * }, + */ +void tst_setup_netns(void); + +#endif /* TST_NET_H_ */ diff --git a/ltp/include/tst_netdevice.h b/ltp/include/tst_netdevice.h new file mode 100644 index 0000000000000000000000000000000000000000..2394f9c7fd6f58cd390ac38e3426858ffe402f1f --- /dev/null +++ b/ltp/include/tst_netdevice.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2021 Linux Test Project + */ + +#ifndef TST_NETDEVICE_H +#define TST_NETDEVICE_H + +#include "tst_netlink.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, int strict, + const char *ifname1, const char *ifname2); +#define CREATE_VETH_PAIR(ifname1, ifname2) \ + tst_create_veth_pair(__FILE__, __LINE__, 1, (ifname1), (ifname2)) + +int tst_netdev_add_device(const char *file, const int lineno, int strict, + const char *ifname, const char *devtype); +#define NETDEV_ADD_DEVICE(ifname, devtype) \ + tst_netdev_add_device(__FILE__, __LINE__, 1, (ifname), (devtype)) + +int tst_netdev_remove_device(const char *file, const int lineno, int strict, + const char *ifname); +#define NETDEV_REMOVE_DEVICE(ifname) \ + tst_netdev_remove_device(__FILE__, __LINE__, 1, (ifname)) + +int tst_netdev_add_address(const char *file, const int lineno, int strict, + 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__, 1, (ifname), (family), \ + (address), (prefix), (addrlen), (flags)) + +int tst_netdev_add_address_inet(const char *file, const int lineno, int strict, + 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__, 1, (ifname), \ + (address), (prefix), (flags)) + +int tst_netdev_remove_address(const char *file, const int lineno, int strict, + 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__, 1, (ifname), (family), \ + (address), (addrlen)) + +int tst_netdev_remove_address_inet(const char *file, const int lineno, + int strict, const char *ifname, in_addr_t address); +#define NETDEV_REMOVE_ADDRESS_INET(ifname, address) \ + tst_netdev_remove_address_inet(__FILE__, __LINE__, 1, (ifname), \ + (address)) + +int tst_netdev_change_ns_fd(const char *file, const int lineno, int strict, + const char *ifname, int nsfd); +#define NETDEV_CHANGE_NS_FD(ifname, nsfd) \ + tst_netdev_change_ns_fd(__FILE__, __LINE__, 1, (ifname), (nsfd)) + +int tst_netdev_change_ns_pid(const char *file, const int lineno, int strict, + const char *ifname, pid_t nspid); +#define NETDEV_CHANGE_NS_PID(ifname, nspid) \ + tst_netdev_change_ns_pid(__FILE__, __LINE__, 1, (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, int strict, + 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__, 1, (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, int strict, + 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__, 1, (ifname), (srcaddr), \ + (srcprefix), (dstaddr), (dstprefix), (gateway)) + +/* + * Remove static entry from main routing table. + */ +int tst_netdev_remove_route(const char *file, const int lineno, int strict, + 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__, 1, (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, + int strict, 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__, 1, (ifname), \ + (srcaddr), (srcprefix), (dstaddr), (dstprefix), (gateway)) + +/* + * Add queueing discipline. Network interface name is optional. + */ +int tst_netdev_add_qdisc(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, const char *qd_kind, + const struct tst_netlink_attr_list *config); +#define NETDEV_ADD_QDISC(ifname, family, parent, handle, qd_kind, config) \ + tst_netdev_add_qdisc(__FILE__, __LINE__, 1, (ifname), (family), \ + (parent), (handle), (qd_kind), (config)) + +/* + * Remove queueing discipline. + */ +int tst_netdev_remove_qdisc(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, const char *qd_kind); +#define NETDEV_REMOVE_QDISC(ifname, family, parent, handle, qd_kind) \ + tst_netdev_remove_qdisc(__FILE__, __LINE__, 1, (ifname), (family), \ + (parent), (handle), (qd_kind)) + +/* + * Add traffic class to queueing discipline. Network interface name is + * optional. + */ +int tst_netdev_add_traffic_class(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, const char *qd_kind, + const struct tst_netlink_attr_list *config); +#define NETDEV_ADD_TRAFFIC_CLASS(ifname, parent, handle, qd_kind, config) \ + tst_netdev_add_traffic_class(__FILE__, __LINE__, 1, (ifname), \ + (parent), (handle), (qd_kind), (config)) + +int tst_netdev_remove_traffic_class(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, const char *qd_kind); +#define NETDEV_REMOVE_TRAFFIC_CLASS(ifname, parent, handle, qd_kind) \ + tst_netdev_remove_traffic_class(__FILE__, __LINE__, 1, (ifname), \ + (parent), (handle), (qd_kind)) + +/* + * Add traffic filter to queueing discipline. Protocol should be en ETH_P_* + * constant in host byte order. Network interface name is optional. + */ +int tst_netdev_add_traffic_filter(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, unsigned int protocol, unsigned int priority, + const char *f_kind, const struct tst_netlink_attr_list *config); +#define NETDEV_ADD_TRAFFIC_FILTER(ifname, parent, handle, protocol, priority, \ + f_kind, config) \ + tst_netdev_add_traffic_filter(__FILE__, __LINE__, 1, (ifname), \ + (parent), (handle), (protocol), (priority), (f_kind), (config)) + +#define NETDEV_ADD_TRAFFIC_FILTER_RET(ifname, parent, handle, protocol, \ + priority, f_kind, config) \ + tst_netdev_add_traffic_filter(__FILE__, __LINE__, 0, (ifname), \ + (parent), (handle), (protocol), (priority), (f_kind), (config)) + +int tst_netdev_remove_traffic_filter(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, unsigned int protocol, unsigned int priority, + const char *f_kind); +#define NETDEV_REMOVE_TRAFFIC_FILTER(ifname, parent, handle, protocol, \ + priority, f_kind) \ + tst_netdev_remove_traffic_filter(__FILE__, __LINE__, 1, (ifname), \ + (parent), (handle), (protocol), (priority), (f_kind)) + +#endif /* TST_NETDEVICE_H */ diff --git a/ltp/include/tst_netlink.h b/ltp/include/tst_netlink.h new file mode 100644 index 0000000000000000000000000000000000000000..7d96fd711e6cfdb0314d13b6eb410046b85fdb86 --- /dev/null +++ b/ltp/include/tst_netlink.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2021 Linux Test Project + */ + +#ifndef TST_NETLINK_H +#define TST_NETLINK_H + +#include + +struct tst_netlink_context; + +struct tst_netlink_attr_list { + unsigned short type; + const void *data; + ssize_t len; + const struct tst_netlink_attr_list *sublist; +}; + +struct tst_netlink_message { + struct nlmsghdr *header; + struct nlmsgerr *err; + void *payload; + size_t payload_size; +}; + +extern int tst_netlink_errno; + +/* Open a netlink socket */ +struct tst_netlink_context *tst_netlink_create_context(const char *file, + const int lineno, int protocol); +#define NETLINK_CREATE_CONTEXT(protocol) \ + tst_netlink_create_context(__FILE__, __LINE__, (protocol)) + +/* Free a tst_netlink_message array returned by tst_netlink_recv() */ +void tst_netlink_free_message(struct tst_netlink_message *msg); +#define NETLINK_FREE_MESSAGE tst_netlink_free_message + +/* Close netlink socket */ +void tst_netlink_destroy_context(const char *file, const int lineno, + struct tst_netlink_context *ctx); +#define NETLINK_DESTROY_CONTEXT(ctx) \ + tst_netlink_destroy_context(__FILE__, __LINE__, (ctx)) + +/* Send all messages in given buffer */ +int tst_netlink_send(const char *file, const int lineno, + struct tst_netlink_context *ctx); +#define NETLINK_SEND(ctx) tst_netlink_send(__FILE__, __LINE__, (ctx)) + +/* Send all messages in given buffer and validate kernel response */ +int tst_netlink_send_validate(const char *file, const int lineno, + struct tst_netlink_context *ctx); +#define NETLINK_SEND_VALIDATE(ctx) \ + tst_netlink_send_validate(__FILE__, __LINE__, (ctx)) + +/* Wait until data is available for reading from the netlink socket */ +int tst_netlink_wait(struct tst_netlink_context *ctx); +#define NETLINK_WAIT tst_netlink_wait + +/* + * Read from netlink socket and return an array of partially parsed messages. + * header == NULL indicates end of array. + */ +struct tst_netlink_message *tst_netlink_recv(const char *file, const int lineno, + struct tst_netlink_context *ctx); +#define NETLINK_RECV(ctx) tst_netlink_recv(__FILE__, __LINE__, (ctx)) + +/* Add new message to buffer */ +int tst_netlink_add_message(const char *file, const int lineno, + struct tst_netlink_context *ctx, const struct nlmsghdr *header, + const void *payload, size_t payload_size); +#define NETLINK_ADD_MESSAGE(ctx, header, payload, psize) \ + tst_netlink_add_message(__FILE__, __LINE__, (ctx), (header), \ + (payload), (psize)) + +/* Add arbitrary nlattr attribute to last message */ +int tst_netlink_add_attr(const char *file, const int lineno, + struct tst_netlink_context *ctx, unsigned short type, const void *data, + unsigned short len); +#define NETLINK_ADD_ATTR(ctx, type, data, len) \ + tst_netlink_add_attr(__FILE__, __LINE__, (ctx), (type), (data), (len)) + +/* Add string nlattr attribute to last message */ +int tst_netlink_add_attr_string(const char *file, const int lineno, + struct tst_netlink_context *ctx, unsigned short type, const char *data); +#define NETLINK_ADD_ATTR_STRING(ctx, type, data) \ + tst_netlink_add_attr_string(__FILE__, __LINE__, (ctx), (type), (data)) + +/* + * Add list of arbitrary nlattr attributes to last message. The list is + * terminated by attribute with negative length. Nested sublists are supported. + */ +int tst_netlink_add_attr_list(const char *file, const int lineno, + struct tst_netlink_context *ctx, + const struct tst_netlink_attr_list *list); +#define NETLINK_ADD_ATTR_LIST(ctx, list) \ + tst_netlink_add_attr_list(__FILE__, __LINE__, (ctx), (list)) + +/* Add arbitrary rtattr attribute to last message */ +int tst_rtnl_add_attr(const char *file, const int lineno, + struct tst_netlink_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 rtattr attribute to last message */ +int tst_rtnl_add_attr_string(const char *file, const int lineno, + struct tst_netlink_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 rtattr 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_netlink_context *ctx, + const struct tst_netlink_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_netlink_send(ctx); + * tst_netlink_wait(ctx); + * response = tst_netlink_recv(ctx); + * if (!tst_netlink_check_acks(ctx, response)) { ... } + * tst_netlink_free_message(response); + */ +int tst_netlink_check_acks(const char *file, const int lineno, + struct tst_netlink_context *ctx, struct tst_netlink_message *response); +#define NETLINK_CHECK_ACKS(ctx, response) \ + tst_netlink_check_acks(__FILE__, __LINE__, (ctx), (response)) + +#endif /* TST_NETLINK_H */ diff --git a/ltp/include/tst_numa.h b/ltp/include/tst_numa.h new file mode 100644 index 0000000000000000000000000000000000000000..a1f9616300074d50593d4c29ae27fefd4afedb5b --- /dev/null +++ b/ltp/include/tst_numa.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2018 Cyril Hrubis + */ + +#ifndef TST_NUMA_H__ +#define TST_NUMA_H__ + +#include + +/** + * struct tst_nodemap - Numa nodemap. + * + * @cnt: Number of nodes in map. + * @counters: Page allocation counters. + * @map: Array of numa ids. + */ +struct tst_nodemap { + unsigned int cnt; + unsigned int *counters; + unsigned int map[]; +}; + +/** + * tst_nodemap_reset_counters() - Clears numa counters. The counters are lazy-allocated on first call of this function. + * + * @nodes: Numa nodemap. + */ +void tst_nodemap_reset_counters(struct tst_nodemap *nodes); + +/** + * tst_nodemap_print_counters() - Prints pages allocated per each node. + * + * @nodes: Numa nodemap. + */ +void tst_nodemap_print_counters(struct tst_nodemap *nodes); + +/** + * tst_mempolicy_mode_name() - Returns a name for a mempolicy/mbind mode. + * + * @mode: Numa mempolicy mode. + * + * return: a name for a mempolicy/mbind mode. + */ +const char *tst_mempolicy_mode_name(int mode); + +/** + * tst_numa_map() - Maps pages into memory, if path is NULL the mapping is anonymous otherwise is backed by the file. + * + * @path: Path to a file, if not NULL mapping is file based. + * @size: Mapping size. + * + * return: a pointer to a mapped file. + */ +void *tst_numa_map(const char *path, size_t size); + +/** + * tst_numa_fault() - Writes to memory in order to get the pages faulted. + * + * @ptr: Start of the mapping. + * @size: Size of the mapping. + */ +static inline void tst_numa_fault(void *ptr, size_t size) +{ + memset(ptr, 'a', size); +} + +/** + * tst_numa_unmap() - Frees the memory. + * + * @ptr: Start of the mapping. + * @size: Size of the mapping. + */ +static inline void tst_numa_unmap(void *ptr, size_t size) +{ + SAFE_MUNMAP(ptr, size); +} + +/** + * tst_nodemap_count_pages() - Check which numa node resides each page. + * + * Check on which numa node resides each page of the mapping starting at ptr + * and continuing pages long and increases nodemap counters accordingly. + * + * @nodes: Nodemap with initialized counters. + * @ptr: Pointer to start of a mapping. + * @size: Size of the mapping. + */ +void tst_nodemap_count_pages(struct tst_nodemap *nodes, void *ptr, size_t size); + +/** + * tst_nodemap_free() - Frees nodemap. + * + * @nodes: Numa nodemap to be freed. + */ +void tst_nodemap_free(struct tst_nodemap *nodes); + +/** + * enum tst_numa_types - Bitflags for tst_get_nodemap() function. + * + * @TST_NUMA_ANY: general NUMA node. + * @TST_NUMA_MEM: NUMA memory node. + */ +enum tst_numa_types { + TST_NUMA_ANY = 0x00, + TST_NUMA_MEM = 0x01, +}; + +/** + * tst_get_nodemap() - Allocates and returns numa node map, which is an array of numa nodes which + * contain desired resources e.g. memory. + * + * @type: Bitflags of enum tst_numa_types specifying desired resources. + * @min_mem_kb: Minimal free RAM on memory nodes, if given node has less than + * requested amount of free+buffers memory it's not included in + * the resulting list of nodes. + * + * return: On success returns allocated and initialized struct tst_nodemap which contains + * array of numa node ids that contains desired resources. + */ +struct tst_nodemap *tst_get_nodemap(int type, size_t min_mem_kb); + +#endif /* TST_NUMA_H__ */ diff --git a/ltp/include/tst_parse.h b/ltp/include/tst_parse.h new file mode 100644 index 0000000000000000000000000000000000000000..167d416f407f01e49cda072f759bd446f202c15b --- /dev/null +++ b/ltp/include/tst_parse.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2015-2024 Cyril Hrubis + */ + +/** + * DOC: Option parsing functions + * + * Implements simple helpers on the top of the strtol() and strtod() for + * command line option parsing. + */ + +#ifndef TST_PARSE_H__ +#define TST_PARSE_H__ + +/** + * tst_parse_int() - Parse an integer from a string. + * + * @str: A string with an integer number. + * @val: A pointer to integer to store the result to. + * @min: A lower bound, pass INT_MIN for full range. + * @max: An upper bound, pass INT_MAX for full range. + * return: A zero if whole string was consumed and the value was within bounds, + * an errno otherwise. + */ +int tst_parse_int(const char *str, int *val, int min, int max); + +/** + * tst_parse_long() - Parse a long integer from a string. + * + * @str: A string with an integer number. + * @val: A pointer to long integer to store the result to. + * @min: A lower bound, pass LONG_MIN for full range. + * @max: An upper bound, pass LONG_MAX for full range. + * return: A zero if whole string was consumed and the value was within bounds, + * an errno otherwise. + */ +int tst_parse_long(const char *str, long *val, long min, long max); + +/** + * tst_parse_float() - Parse a floating point number from a string. + * + * @str: A string with a floating point number. + * @val: A pointer to float to store the result to. + * @min: A lower bound. + * @max: An upper bound. + * return: A zero if whole string was consumed and the value was within bounds, + * an errno otherwise. + */ +int tst_parse_float(const char *str, float *val, float min, float max); + +/** + * tst_parse_filesize() - Parse a file size from a string. + * + * @str: A string a positive number optionally followed by an unit, i.e. K, M, + * or G for kilobytes, megabytes and gigabytes. + * @val: A pointer to long long integer to store the size in bytes to. + * @min: A lower bound. + * @max: An upper bound. + * return: A zero if whole string was consumed and the value was within bounds, + * an errno otherwise. + */ +int tst_parse_filesize(const char *str, long long *val, long long min, long long max); + +#endif /* TST_PARSE_H__ */ diff --git a/ltp/include/tst_path_has_mnt_flags.h b/ltp/include/tst_path_has_mnt_flags.h new file mode 100644 index 0000000000000000000000000000000000000000..a9e1f40505cd4349a06ec32fbd6ee59febaaca1a --- /dev/null +++ b/ltp/include/tst_path_has_mnt_flags.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. + * Copyright (c) 2018 Cyril Hrubis + * Author: Xiao Yang + */ + +#ifndef TST_PATH_HAS_MNT_FLAGS_H__ +#define TST_PATH_HAS_MNT_FLAGS_H__ + +#ifdef TST_TEST_H__ +# define tst_path_has_mnt_flags(...) tst_path_has_mnt_flags_(NULL, __VA_ARGS__) +#else +# define tst_path_has_mnt_flags tst_path_has_mnt_flags_ +#endif + +/* lib/tst_path_has_mnt_flags.c + * + * Check whether a path is on a filesystem that is mounted with + * specified flags + * @path: path to file, if path is NULL tst_tmpdir is used. + * @flags: NULL or NULL terminated array of mount flags + * + * Return: 0..n - number of flags matched + */ +int tst_path_has_mnt_flags_(void (*cleanup_fn)(void), + const char *path, const char *flags[]); + +#endif /* TST_PATH_HAS_MNT_FLAGS_H__ */ diff --git a/ltp/include/tst_pid.h b/ltp/include/tst_pid.h new file mode 100644 index 0000000000000000000000000000000000000000..951138abc3a55765582f1c49d0a984a1d209a4db --- /dev/null +++ b/ltp/include/tst_pid.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2015-2016 Cyril Hrubis + */ + +#ifndef TST_PID_H__ +#define TST_PID_H__ + +#include + +/* + * Get a pid value not used by the OS + */ +pid_t tst_get_unused_pid_(void (*cleanup_fn)(void)); + +/* + * 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)); + +#ifdef TST_TEST_H__ +static inline pid_t tst_get_unused_pid(void) +{ + return tst_get_unused_pid_(NULL); +} + +static inline int tst_get_free_pids(void) +{ + return tst_get_free_pids_(NULL); +} +#else +static inline pid_t tst_get_unused_pid(void (*cleanup_fn)(void)) +{ + return tst_get_unused_pid_(cleanup_fn); +} + +static inline int tst_get_free_pids(void (*cleanup_fn)(void)) +{ + return tst_get_free_pids_(cleanup_fn); +} +#endif + +/* + * Direct getpid() syscall. Some glibc versions cache getpid() return value + * which can cause confusing issues for example in processes created by + * direct clone() syscall (without using the glibc wrapper). Use this function + * whenever the current process may be a child of the main test process. + */ +pid_t tst_getpid(void); + +/* + * Direct gettid() syscall. Some glibc versions cache gettid() return value + * which can cause confusing issues for example in processes created by + * direct clone() syscall (without using the glibc wrapper). Use this function + * whenever the current process may be a thread of the main test process. + */ +pid_t tst_gettid(void); + +#endif /* TST_PID_H__ */ diff --git a/ltp/include/tst_private.h b/ltp/include/tst_private.h new file mode 100644 index 0000000000000000000000000000000000000000..4c6479f4b33cafd5ffa33923ce38a3779caaa955 --- /dev/null +++ b/ltp/include/tst_private.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2019 Petr Vorel + * + * Internal helper functions for the shell library. Do not use directly + * in test programs. + */ + +#ifndef TST_PRIVATE_H_ +#define TST_PRIVATE_H_ + +#include +#include +#include "tst_defaults.h" + +#define MAX_IPV4_PREFIX 32 +#define MAX_IPV6_PREFIX 128 + +#define tst_res_comment(...) { \ + fprintf(stderr, "# "); \ + tst_res(__VA_ARGS__); } \ + + +#define tst_brk_comment(...) { \ + fprintf(stderr, "# "); \ + tst_brk(TCONF, __VA_ARGS__); } \ + +void tst_print_svar(const char *name, const char *val); +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 breaks if brk_nosupp is defined. + * 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 breaks if brk_nosupp is defined. + */ +int tst_check_cmd(const char *cmd, const int brk_nosupp); + +#endif diff --git a/ltp/include/tst_process_state.h b/ltp/include/tst_process_state.h new file mode 100644 index 0000000000000000000000000000000000000000..b1d83e10979aedc904dbcc4d5736285cb900987a --- /dev/null +++ b/ltp/include/tst_process_state.h @@ -0,0 +1,78 @@ +/* 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. + */ + +#ifndef TST_PROCESS_STATE__ +#define TST_PROCESS_STATE__ + +#include + +#ifdef 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 + */ +#define TST_PROCESS_STATE_WAIT(pid, state, msec_timeout) \ + tst_process_state_wait(__FILE__, __LINE__, NULL, \ + (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)) + +/* + * Waits for thread state change. + * + * The state is one of the following: + * + * R - running + * S - sleeping + * D - disk sleep + * T - stopped + * t - tracing stopped + * Z - zombie + * X - dead + */ +#define TST_THREAD_STATE_WAIT(tid, state, msec_timeout) \ + tst_thread_state_wait((tid), (state), (msec_timeout)) + +int tst_thread_state_wait(pid_t tid, const char state, + unsigned int msec_timeout); + +#else +/* + * The same as above but does not use tst_brkm() interface. + * + * This function is intended to be used from child processes. + * + * Returns zero on success, non-zero on failure. + */ +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) +#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); +int tst_process_exit_wait(pid_t pid, unsigned int msec_timeout); + +#endif /* TST_PROCESS_STATE__ */ diff --git a/ltp/include/tst_rand_data.h b/ltp/include/tst_rand_data.h new file mode 100644 index 0000000000000000000000000000000000000000..ba747d0f42879616c6bc4704eec1c4dbad33e8ba --- /dev/null +++ b/ltp/include/tst_rand_data.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) Linux Test Project, 2022 + */ + +#ifndef TST_RAND_DATA_H__ +#define TST_RAND_DATA_H__ + +#include + +/* Includes null byte */ +extern const size_t tst_rand_data_len; +/* statically defined random data */ +extern const char *const tst_rand_data; + +#endif diff --git a/ltp/include/tst_res_flags.h b/ltp/include/tst_res_flags.h new file mode 100644 index 0000000000000000000000000000000000000000..eb291b6bd3d2cd8dde46cfb3a72bbd2f7c7d96ae --- /dev/null +++ b/ltp/include/tst_res_flags.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) Linux Test Project, 2014 + */ + +#ifndef TST_RES_FLAGS_H +#define TST_RES_FLAGS_H + +/** + * enum tst_res_flags - Test result reporting flags. + * + * @TPASS: Reports a single success. Successes increment passed counter and + * show up in the test results. + * + * @TFAIL: Reports a single failure. Failures increment failure counter and + * show up in the test results. A failure occurs when test assertion + * is broken. + * + * @TBROK: Reports a single breakage. Breakages increment breakage counter and + * show up in the test results. Breakages are reported in cases where a + * test couldn't be executed due to an unexpected failure during the + * test setup. The TBROK status is mostly used with tst_brk() which + * exit the test immediately. The difference between TBROK and TCONF is + * that TCONF is used in cases where optional functionality is missing + * while TBROK is used in cases where something that is supposed to + * work is broken unexpectedly. + * + * @TWARN: Reports a single warning. Warnings increment a warning counter and + * show up in test results. Warnings are somewhere in the middle between + * TBROK and TCONF. Warnings usually appear when something that is + * supposed to be working is broken but the test can somehow continue. + * + * @TDEBUG: Prints additional debugging messages, it does not change the test result counters and + * the message is not displayed unless debugging is enabled with -D + * test command line parameter. + * + * @TINFO: Prints an additional information, it does not change the test result + * counters but unlike TDEBUG the message is always displayed. + * + * @TCONF: Reports unsupported configuration. When tests produce this result at + * least a subset of test was skipped, because it couldn't run. The + * usual reasons are, missing kernel modules or CONFIG options. + * Unsuitable CPU architecture, not enough memory, etc. + * + * @TERRNO: Combine bitwise with result flags to append errno to the output message. + * + * @TTERRNO: Combine bitwise with result flags to append error from TST_ERR to + * the message. The TST_TEST() macros store the errno into the + * TST_ERR global variable in order to make sure it's not change + * between the test is done and results are printed. + * + * @TRERRNO: Combine bitwise with result flags to errno from TST_RET variable + * to the message. The TST_TEST() macros store return value into the + * TST_RET global variable and quite a few, e.g. pthread functions, + * return the error value directly instead of storing it to the errno. + * + * A result flag with optional bitwise combination of errno flag are passed to + * the tst_res() and tst_brk() functions. Each message counts as a single test + * result and tests can produce arbitrary number of results, i.e. TPASS, TFAIL, + * TBROK, TWARN and TCONF messages. Each such message increases a result + * counter in a piece of shared memory, which means that reported results are + * accounted immediately even from child processes and there is no need for + * result propagation. + */ +enum tst_res_flags { + TPASS = 0, + TFAIL = 1, + TBROK = 2, + TWARN = 4, + TDEBUG = 8, + TINFO = 16, + TCONF = 32, + TERRNO = 0x100, + TTERRNO = 0x200, + TRERRNO = 0x400, +}; + +#define TTYPE_RESULT(ttype) ((ttype) & TTYPE_MASK) +#define TTYPE_MASK 0x3f + +#endif /* TST_RES_FLAGS_H */ diff --git a/ltp/include/tst_rtctime.h b/ltp/include/tst_rtctime.h new file mode 100644 index 0000000000000000000000000000000000000000..c2c282e90d3364cdd7fe657ebd15117c3710ff88 --- /dev/null +++ b/ltp/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/ltp/include/tst_safe_clocks.h b/ltp/include/tst_safe_clocks.h new file mode 100644 index 0000000000000000000000000000000000000000..5661ce57bf7c7b2b0eb3ada9d01049abdd99dab0 --- /dev/null +++ b/ltp/include/tst_safe_clocks.h @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019, Linux Test Project + * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 + * Email : code@zilogic.com + */ + +#ifndef TST_SAFE_CLOCKS_H__ +#define TST_SAFE_CLOCKS_H__ + +#include +#include +#include "tst_test.h" +#include "tst_clocks.h" +#include "lapi/syscalls.h" +#include "lapi/posix_clocks.h" + +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 == -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 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 == -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_settime(const char *file, const int lineno, + clockid_t clk_id, struct timespec *tp) +{ + int rval; + + rval = clock_settime(clk_id, tp); + + 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_timer_create(const char *file, const int lineno, + clockid_t clockid, struct sigevent *sevp, timer_t *timerid) +{ + 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; +} + +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 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)\ + safe_clock_getres(__FILE__, __LINE__, (clk_id), (res)) + +#define SAFE_CLOCK_GETTIME(clk_id, tp)\ + safe_clock_gettime(__FILE__, __LINE__, (clk_id), (tp)) + +#define SAFE_CLOCK_SETTIME(clk_id, tp)\ + safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp)) + +#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/ltp/include/tst_safe_file_at.h b/ltp/include/tst_safe_file_at.h new file mode 100644 index 0000000000000000000000000000000000000000..a1aa19fadc5850116e8c7eecfb0901826a627d36 --- /dev/null +++ b/ltp/include/tst_safe_file_at.h @@ -0,0 +1,79 @@ +// 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 +#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)) + +#define SAFE_FCHOWNAT(dirfd, path, owner, group, flags) \ + safe_fchownat(__FILE__, __LINE__, \ + (dirfd), (path), (owner), (group), (flags)) + +#define SAFE_FSTATAT(dirfd, path, statbuf, flags) \ + safe_fstatat(__FILE__, __LINE__, (dirfd), (path), (statbuf), (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)); + +int safe_fchownat(const char *const file, const int lineno, + const int dirfd, const char *const path, uid_t owner, + gid_t group, int flags) + __attribute__ ((nonnull)); + +int safe_fstatat(const char *const file, const int lineno, + const int dirfd, const char *const path, struct stat *statbuf, + int flags) + __attribute__ ((nonnull)); +#endif diff --git a/ltp/include/tst_safe_file_ops.h b/ltp/include/tst_safe_file_ops.h new file mode 100644 index 0000000000000000000000000000000000000000..0d8819594ab3f56662f0b51c1940587873db3d96 --- /dev/null +++ b/ltp/include/tst_safe_file_ops.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2012 Cyril Hrubis chrubis@suse.cz + */ + +#ifndef TST_SAFE_FILE_OPS +#define TST_SAFE_FILE_OPS + +#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__) + +#define FILE_LINES_SCANF(path, fmt, ...) \ + file_lines_scanf(__FILE__, __LINE__, NULL, 0,\ + (path), (fmt), ## __VA_ARGS__) + +#define SAFE_FILE_LINES_SCANF(path, fmt, ...) \ + file_lines_scanf(__FILE__, __LINE__, NULL, 1,\ + (path), (fmt), ## __VA_ARGS__) + +#define SAFE_READ_MEMINFO(item) \ + ({long tst_rval; \ + SAFE_FILE_LINES_SCANF("/proc/meminfo", item " %ld", \ + &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__) + +#define SAFE_FILE_PRINTF(path, fmt, ...) \ + 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)) + +#define SAFE_TOUCH(pathname, mode, times) \ + safe_touch(__FILE__, __LINE__, NULL, \ + (pathname), (mode), (times)) + +/* New API only functions */ + +/* helper functions to setup overlayfs mountpoint */ +void tst_create_overlay_dirs(void); +int tst_mount_overlay(const char *file, const int lineno, int strict); + +#define SAFE_MOUNT_OVERLAY() \ + ((void) tst_mount_overlay(__FILE__, __LINE__, 1)) + +#define TST_MOUNT_OVERLAY() \ + (tst_mount_overlay(__FILE__, __LINE__, 0) == 0) + +#endif /* TST_SAFE_FILE_OPS */ diff --git a/ltp/include/tst_safe_io_uring.h b/ltp/include/tst_safe_io_uring.h new file mode 100644 index 0000000000000000000000000000000000000000..cb26aec1e16c1030e39ee9e64565d5ba17588942 --- /dev/null +++ b/ltp/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/ltp/include/tst_safe_macros.h b/ltp/include/tst_safe_macros.h new file mode 100644 index 0000000000000000000000000000000000000000..19504beb57ad379c835a13ed5d35fe06e42a6ed6 --- /dev/null +++ b/ltp/include/tst_safe_macros.h @@ -0,0 +1,512 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2010-2024 Linux Test Project + * Copyright (c) 2011-2015 Cyril Hrubis + */ + +#ifndef TST_SAFE_MACROS_H__ +#define TST_SAFE_MACROS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "safe_stdio_fn.h" +#include "safe_macros_fn.h" +#include "tst_cmd.h" +#include "tst_safe_macros_inline.h" + +int safe_access(const char *filename, const int lineno, const char *pathname, + int mode); +#define SAFE_ACCESS(path, mode) \ + safe_access(__FILE__, __LINE__, (path), (mode)) + +#define SAFE_BASENAME(path) \ + safe_basename(__FILE__, __LINE__, NULL, (path)) + +#define SAFE_CHDIR(path) \ + safe_chdir(__FILE__, __LINE__, NULL, (path)) + +#define SAFE_CLOSE(fd) do { \ + safe_close(__FILE__, __LINE__, NULL, (fd)); \ + fd = -1; \ + } while (0) + +#define SAFE_CREAT(pathname, mode) \ + safe_creat(__FILE__, __LINE__, NULL, (pathname), (mode)) + +#define SAFE_CHROOT(path) \ + safe_chroot(__FILE__, __LINE__, (path)) +int safe_chroot(const char *file, const int lineno, const char *path); + +#define SAFE_DIRNAME(path) \ + safe_dirname(__FILE__, __LINE__, NULL, (path)) + +int safe_dup(const char *file, const int lineno, int oldfd); + +#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)) + +#define SAFE_GETPWNAM(name) \ + safe_getpwnam(__FILE__, __LINE__, NULL, (name)) + +#define SAFE_GETRUSAGE(who, usage) \ + safe_getrusage(__FILE__, __LINE__, NULL, (who), (usage)) + +#define SAFE_MALLOC(size) \ + safe_malloc(__FILE__, __LINE__, NULL, (size)) + +void *safe_calloc(const char *file, const int lineno, size_t nmemb, size_t size); + +#define SAFE_CALLOC(nmemb, size) \ + safe_calloc(__FILE__, __LINE__, (nmemb), (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)) + +#define SAFE_RMDIR(pathname) \ + safe_rmdir(__FILE__, __LINE__, NULL, (pathname)) + +#define SAFE_MUNMAP(addr, length) \ + safe_munmap(__FILE__, __LINE__, NULL, (addr), (length)) + +int safe_msync(const char *file, const int lineno, void *addr, + size_t length, int flags); + +#define SAFE_MSYNC(addr, length, flags) \ + safe_msync(__FILE__, __LINE__, (addr), (length), (flags)) + +#define SAFE_OPEN(pathname, oflags, ...) \ + safe_open(__FILE__, __LINE__, NULL, (pathname), (oflags), \ + ##__VA_ARGS__) + +#define SAFE_PIPE(fildes) \ + safe_pipe(__FILE__, __LINE__, NULL, (fildes)) + +int safe_pipe2(const char *file, const int lineno, int fildes[2], int flags); + +#define SAFE_PIPE2(fildes, flags) \ + safe_pipe2(__FILE__, __LINE__, (fildes), (flags)) + +#define SAFE_READ(len_strict, fildes, buf, nbyte) \ + safe_read(__FILE__, __LINE__, NULL, (len_strict), (fildes), (buf), (nbyte)) + +#define SAFE_SETEGID(egid) \ + safe_setegid(__FILE__, __LINE__, NULL, (egid)) + +#define SAFE_SETEUID(euid) \ + safe_seteuid(__FILE__, __LINE__, NULL, (euid)) + +#define SAFE_SETGID(gid) \ + safe_setgid(__FILE__, __LINE__, NULL, (gid)) + +#define SAFE_SETUID(uid) \ + safe_setuid(__FILE__, __LINE__, NULL, (uid)) + +int safe_setregid(const char *file, const int lineno, + gid_t rgid, gid_t egid); + +#define SAFE_SETREGID(rgid, egid) \ + safe_setregid(__FILE__, __LINE__, (rgid), (egid)) + +int safe_setreuid(const char *file, const int lineno, + uid_t ruid, uid_t euid); + +#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)) + +#define SAFE_GETRESGID(rgid, egid, sgid) \ + safe_getresgid(__FILE__, __LINE__, NULL, (rgid), (egid), (sgid)) + +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)) + +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)) + +#define SAFE_LINKAT(olddirfd, oldpath, newdirfd, newpath, flags) \ + safe_linkat(__FILE__, __LINE__, NULL, (olddirfd), (oldpath), \ + (newdirfd), (newpath), (flags)) + +#define SAFE_READLINK(path, buf, bufsize) \ + safe_readlink(__FILE__, __LINE__, NULL, (path), (buf), (bufsize)) + +#define SAFE_SYMLINK(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)) + +#define SAFE_STRTOL(str, min, max) \ + safe_strtol(__FILE__, __LINE__, NULL, (str), (min), (max)) + +#define SAFE_STRTOUL(str, min, max) \ + safe_strtoul(__FILE__, __LINE__, NULL, (str), (min), (max)) + +#define SAFE_STRTOF(str, min, max) \ + safe_strtof(__FILE__, __LINE__, NULL, (str), (min), (max)) + +#define SAFE_SYSCONF(name) \ + safe_sysconf(__FILE__, __LINE__, NULL, name) + +#define SAFE_CHMOD(path, mode) \ + safe_chmod(__FILE__, __LINE__, NULL, (path), (mode)) + +#define SAFE_FCHMOD(fd, mode) \ + safe_fchmod(__FILE__, __LINE__, NULL, (fd), (mode)) + +#define SAFE_CHOWN(path, owner, group) \ + safe_chown(__FILE__, __LINE__, NULL, (path), (owner), (group)) + +#define SAFE_FCHOWN(fd, owner, group) \ + safe_fchown(__FILE__, __LINE__, NULL, (fd), (owner), (group)) + +#define SAFE_WAIT(status) \ + safe_wait(__FILE__, __LINE__, NULL, (status)) + +#define SAFE_WAITPID(pid, status, opts) \ + safe_waitpid(__FILE__, __LINE__, NULL, (pid), (status), (opts)) + +#define SAFE_KILL(pid, sig) \ + safe_kill(__FILE__, __LINE__, NULL, (pid), (sig)) + +#define SAFE_MEMALIGN(alignment, size) \ + safe_memalign(__FILE__, __LINE__, NULL, (alignment), (size)) + +#define SAFE_MKFIFO(pathname, mode) \ + safe_mkfifo(__FILE__, __LINE__, NULL, (pathname), (mode)) + +#define SAFE_RENAME(oldpath, newpath) \ + safe_rename(__FILE__, __LINE__, NULL, (oldpath), (newpath)) + +#define SAFE_MOUNT(source, target, filesystemtype, \ + mountflags, data) \ + safe_mount(__FILE__, __LINE__, NULL, (source), (target), \ + (filesystemtype), (mountflags), (data)) + +#define SAFE_UMOUNT(target) \ + safe_umount(__FILE__, __LINE__, NULL, (target)) + +#define SAFE_OPENDIR(name) \ + safe_opendir(__FILE__, __LINE__, NULL, (name)) + +#define SAFE_CLOSEDIR(dirp) \ + safe_closedir(__FILE__, __LINE__, NULL, (dirp)) + +#define SAFE_READDIR(dirp) \ + safe_readdir(__FILE__, __LINE__, NULL, (dirp)) + +#define SAFE_IOCTL_(file, lineno, fd, request, ...) \ + ({int tst_ret_ = ioctl(fd, request, ##__VA_ARGS__); \ + tst_ret_ < 0 ? \ + 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 ? \ + tst_brk(TBROK | TERRNO, \ + "fcntl(%i,%s,...) failed", fd, #cmd), 0 \ + : tst_ret_;}) + +int safe_mprotect(const char *file, const int lineno, + char *addr, size_t len, int prot); + +#define SAFE_MPROTECT(addr, len, prot) \ + safe_mprotect(__FILE__, __LINE__, (addr), (len), (prot)) + +typedef void (*sighandler_t)(int); +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)) + +int safe_sigaction(const char *file, const int lineno, + int signum, const struct sigaction *act, + struct sigaction *oldact); +#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, \ + "execlp(%s, %s, ...) failed", file, arg); \ + } while (0) + +#define SAFE_EXECL(file, arg, ...) do { \ + execl((file), (arg), ##__VA_ARGS__); \ + tst_brk_(__FILE__, __LINE__, TBROK | TERRNO, \ + "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)) + +struct group *safe_getgrnam(const char *file, const int lineno, + const char *name); +#define SAFE_GETGRNAM(name) \ + safe_getgrnam(__FILE__, __LINE__, (name)) + +struct group *safe_getgrnam_fallback(const char *file, const int lineno, + const char *name, const char *fallback); +#define SAFE_GETGRNAM_FALLBACK(name, fallback) \ + safe_getgrnam_fallback(__FILE__, __LINE__, (name), (fallback)) + +struct group *safe_getgrgid(const char *file, const int lineno, gid_t gid); +#define SAFE_GETGRGID(gid) \ + safe_getgrgid(__FILE__, __LINE__, (gid)) + +ssize_t safe_getxattr(const char *file, const int lineno, const char *path, + const char *name, void *value, size_t size); +#define SAFE_GETXATTR(path, name, value, size) \ + safe_getxattr(__FILE__, __LINE__, (path), (name), (value), (size)) + +int safe_setxattr(const char *file, const int lineno, const char *path, + const char *name, const void *value, size_t size, int flags); +#define SAFE_SETXATTR(path, name, value, size, flags) \ + safe_setxattr(__FILE__, __LINE__, (path), (name), (value), (size), (flags)) + +int safe_lsetxattr(const char *file, const int lineno, const char *path, + const char *name, const void *value, size_t size, int flags); +#define SAFE_LSETXATTR(path, name, value, size, flags) \ + safe_lsetxattr(__FILE__, __LINE__, (path), (name), (value), (size), (flags)) + +int safe_fsetxattr(const char *file, const int lineno, int fd, const char *name, + const void *value, size_t size, int flags); +#define SAFE_FSETXATTR(fd, name, value, size, flags) \ + safe_fsetxattr(__FILE__, __LINE__, (fd), (name), (value), (size), (flags)) + +int safe_removexattr(const char *file, const int lineno, const char *path, + const char *name); +#define SAFE_REMOVEXATTR(path, name) \ + safe_removexattr(__FILE__, __LINE__, (path), (name)) + +int safe_lremovexattr(const char *file, const int lineno, const char *path, + const char *name); +#define SAFE_LREMOVEXATTR(path, name) \ + safe_lremovexattr(__FILE__, __LINE__, (path), (name)) + +int safe_fremovexattr(const char *file, const int lineno, int fd, + const char *name); +#define SAFE_FREMOVEXATTR(fd, name) \ + safe_fremovexattr(__FILE__, __LINE__, (fd), (name)) + +int safe_fsync(const char *file, const int lineno, int fd); +#define SAFE_FSYNC(fd) safe_fsync(__FILE__, __LINE__, (fd)) + +int safe_setsid(const char *file, const int lineno); +#define SAFE_SETSID() safe_setsid(__FILE__, __LINE__) + +int safe_mknod(const char *file, const int lineno, const char *pathname, + mode_t mode, dev_t dev); +#define SAFE_MKNOD(pathname, mode, dev) \ + safe_mknod(__FILE__, __LINE__, (pathname), (mode), (dev)) + +int safe_mlock(const char *file, const int lineno, const char *addr, + size_t len); +#define SAFE_MLOCK(addr, len) safe_mlock(__FILE__, __LINE__, (addr), (len)) + +int safe_munlock(const char *file, const int lineno, const char *addr, + size_t len); +#define SAFE_MUNLOCK(addr, len) safe_munlock(__FILE__, __LINE__, (addr), (len)) + +int safe_mincore(const char *file, const int lineno, void *start, + size_t length, unsigned char *vec); +#define SAFE_MINCORE(start, length, vec) \ + safe_mincore(__FILE__, __LINE__, (start), (length), (vec)) + +int safe_personality(const char *filename, unsigned int lineno, + unsigned long persona); +#define SAFE_PERSONALITY(persona) safe_personality(__FILE__, __LINE__, persona) + +int safe_pidfd_open(const char *filename, const int lineno, pid_t pid, + unsigned int flags); +#define SAFE_PIDFD_OPEN(pid, flags) \ + safe_pidfd_open(__FILE__, __LINE__, (pid), (flags)) + +#define SAFE_SETENV(name, value, overwrite) do { \ + if (setenv(name, value, overwrite)) { \ + tst_brk_(__FILE__, __LINE__, TBROK | TERRNO, \ + "setenv(%s, %s, %d) failed", \ + name, value, overwrite); \ + } \ + } while (0) + +int safe_unshare(const char *file, const int lineno, int flags); +#define SAFE_UNSHARE(flags) safe_unshare(__FILE__, __LINE__, (flags)) + +int safe_setns(const char *file, const int lineno, int fd, int nstype); +#define SAFE_SETNS(fd, nstype) safe_setns(__FILE__, __LINE__, (fd), (nstype)) + +/* + * SAFE_CMD() is a wrapper for tst_cmd(). It runs a command passed via argv[] + * and handles non-zero exit (exits with 'TBROK') and 'ENOENT' (the program not + * in '$PATH', exits with 'TCONF'). + * + * @param argv[] a 'NULL' terminated array of strings starting with the program + * name which is followed by optional arguments. + * @param stdout_path: path where to redirect stdout. Set NULL if redirection is + * not needed. + * @param stderr_path: path where to redirect stderr. Set NULL if redirection is + * not needed. + */ +void safe_cmd(const char *file, const int lineno, const char *const argv[], + const char *stdout_path, const char *stderr_path); +#define SAFE_CMD(argv, stdout_path, stderr_path) \ + safe_cmd(__FILE__, __LINE__, (argv), (stdout_path), (stderr_path)) +/* + * SAFE_PTRACE() treats any non-zero return value as error. Don't use it + * for requests like PTRACE_PEEK* or PTRACE_SECCOMP_GET_FILTER which use + * the return value to pass arbitrary data. + */ +long tst_safe_ptrace(const char *file, const int lineno, int req, pid_t pid, + void *addr, void *data); +#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)) + +void safe_print_file(const char *file, const int lineno, char *path); + +int safe_sscanf(const char *file, const int lineno, const char *restrict buffer, + const char *restrict format, ...); +#define SAFE_SSCANF(buffer, format, ...) \ + safe_sscanf(__FILE__, __LINE__, (buffer), (format), ##__VA_ARGS__) + +int safe_prctl(const char *file, const int lineno, + int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5); +#define SAFE_PRCTL(option, arg2, arg3, arg4, arg5) \ + safe_prctl(__FILE__, __LINE__, (option), (arg2), (arg3), (arg4), (arg5)) + +int safe_symlinkat(const char *file, const int lineno, + const char *oldpath, const int newdirfd, const char *newpath); + +#define SAFE_SYMLINKAT(oldpath, newdirfd, newpath) \ + safe_symlinkat(__FILE__, __LINE__, (oldpath), (newdirfd), (newpath)) + +ssize_t safe_readv(const char *file, const int lineno, char len_strict, + int fildes, const struct iovec *iov, int iovcnt); +#define SAFE_READV(len_strict, fildes, iov, iovcnt) \ + safe_readv(__FILE__, __LINE__, (len_strict), (fildes), \ + (iov), (iovcnt)) + +ssize_t safe_writev(const char *file, const int lineno, char len_strict, + int fildes, const struct iovec *iov, int iovcnt); +#define SAFE_WRITEV(len_strict, fildes, iov, iovcnt) \ + safe_writev(__FILE__, __LINE__, (len_strict), (fildes), \ + (iov), (iovcnt)) + +char *safe_ptsname(const char *const file, const int lineno, int masterfd); +#define SAFE_PTSNAME(masterfd) \ + safe_ptsname(__FILE__, __LINE__, (masterfd)) + +int safe_statvfs(const char *file, const int lineno, + const char *path, struct statvfs *buf); +#define SAFE_STATVFS(path, buf) \ + safe_statvfs(__FILE__, __LINE__, (path), (buf)) + +#endif /* TST_SAFE_MACROS_H__ */ diff --git a/ltp/include/tst_safe_macros_inline.h b/ltp/include/tst_safe_macros_inline.h new file mode 100644 index 0000000000000000000000000000000000000000..15b756860ed7515978207f894f199f4d3874e015 --- /dev/null +++ b/ltp/include/tst_safe_macros_inline.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2010-2024 Linux Test Project + * Copyright (c) 2011-2015 Cyril Hrubis + */ + +#ifndef TST_SAFE_MACROS_INLINE_H__ +#define TST_SAFE_MACROS_INLINE_H__ + +/* + * Following functions are inline because the behaviour may depend on + * -D_FILE_OFFSET_BITS=64 compile flag (type off_t or structures containing + * off_t fields), see man off_t(3type). + * + * Do not add other functions here. + */ + +static inline int safe_ftruncate(const char *file, const int lineno, + int fd, off_t length) +{ + int rval; + + rval = ftruncate(fd, length); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "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; +} + +#define SAFE_FTRUNCATE(fd, length) \ + safe_ftruncate(__FILE__, __LINE__, (fd), (length)) + +static inline int safe_posix_fadvise(const char *file, const int lineno, + int fd, off_t offset, off_t len, int advice) +{ + int rval; + + rval = posix_fadvise(fd, offset, len, advice); + + if (rval) + tst_brk_(file, lineno, TBROK, + "posix_fadvise(%d,%ld,%ld,%d) failed: %s", + fd, (long)offset, (long)len, advice, tst_strerrno(rval)); + + return rval; +} + +#define SAFE_POSIX_FADVISE(fd, offset, len, advice) \ + safe_posix_fadvise(__FILE__, __LINE__, (fd), (offset), (len), (advice)) + +static inline int safe_truncate(const char *file, const int lineno, + const char *path, off_t length) +{ + int rval; + + rval = truncate(path, length); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "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; +} + +#define SAFE_TRUNCATE(path, length) \ + safe_truncate(__FILE__, __LINE__, (path), (length)) + +static inline int safe_stat(const char *file, const int lineno, + const char *path, struct stat *buf) +{ + int rval; + + rval = stat(path, buf); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "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; +} + +#define SAFE_STAT(path, buf) \ + safe_stat(__FILE__, __LINE__, (path), (buf)) + +static inline int safe_fstat(const char *file, const int lineno, + int fd, struct stat *buf) +{ + int rval; + + rval = fstat(fd, buf); + + 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; +} +#define SAFE_FSTAT(fd, buf) \ + safe_fstat(__FILE__, __LINE__, (fd), (buf)) + +static inline int safe_lstat(const char *file, const int lineno, + const char *path, struct stat *buf) +{ + int rval; + + rval = lstat(path, buf); + + 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; +} +#define SAFE_LSTAT(path, buf) \ + safe_lstat(__FILE__, __LINE__, (path), (buf)) + +static inline int safe_statfs(const char *file, const int lineno, + const char *path, struct statfs *buf) +{ + int rval; + + rval = statfs(path, buf); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "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)) + +static inline off_t safe_lseek(const char *file, const int lineno, + int fd, off_t offset, int whence) +{ + off_t rval; + + rval = lseek(fd, offset, whence); + + if (rval == (off_t) -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "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; +} + +#define SAFE_LSEEK(fd, offset, whence) \ + safe_lseek(__FILE__, __LINE__, (fd), (offset), (whence)) + +static inline int safe_getrlimit(const char *file, const int lineno, + int resource, struct rlimit *rlim) +{ + int rval; + + rval = getrlimit(resource, rlim); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "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; +} + +#define SAFE_GETRLIMIT(resource, rlim) \ + safe_getrlimit(__FILE__, __LINE__, (resource), (rlim)) + +static inline int safe_setrlimit(const char *file, const int lineno, + int resource, const struct rlimit *rlim) +{ + int rval; + + rval = setrlimit(resource, rlim); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "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; +} + +#define SAFE_SETRLIMIT(resource, rlim) \ + safe_setrlimit(__FILE__, __LINE__, (resource), (rlim)) + +void tst_prot_to_str(const int prot, char *buf); + +static inline void *safe_mmap(const char *file, const int lineno, + void *addr, size_t length, int prot, int flags, int fd, off_t offset) +{ + void *rval; + char prot_buf[512]; + + tst_prot_to_str(prot, prot_buf); + + tst_res_(file, lineno, TDEBUG, + "mmap(%p, %zu, %s(%x), %d, %d, %lld)", + addr, length, prot_buf, prot, flags, fd, (long long int)offset); + + rval = mmap(addr, length, prot, flags, fd, offset); + if (rval == MAP_FAILED) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mmap(%p,%zu,%s(%x),%d,%d,%ld) failed", + addr, length, prot_buf, prot, flags, fd, (long) offset); + } + + return rval; +} + +#define SAFE_MMAP(addr, length, prot, flags, fd, offset) \ + safe_mmap(__FILE__, __LINE__, (addr), (length), (prot), \ + (flags), (fd), (offset)) + +#endif /* TST_SAFE_MACROS_INLINE_H__ */ diff --git a/ltp/include/tst_safe_net.h b/ltp/include/tst_safe_net.h new file mode 100644 index 0000000000000000000000000000000000000000..98f0256fd91f9d46328f6089e9c78f68132cc94e --- /dev/null +++ b/ltp/include/tst_safe_net.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2016 Cyril Hrubis + */ + +#ifndef TST_SAFE_NET_H__ +#define TST_SAFE_NET_H__ + +#include +#include +#include +#include +#include + +#include "safe_net_fn.h" +#include "tst_net.h" + +#define SAFE_SOCKET(domain, type, protocol) \ + safe_socket(__FILE__, __LINE__, NULL, domain, type, protocol) + +#define SAFE_SOCKETPAIR(domain, type, protocol, sv) \ + safe_socketpair(__FILE__, __LINE__, domain, type, protocol, sv) + +#define SAFE_GETSOCKOPT(fd, level, optname, optval, optlen) \ + safe_getsockopt(__FILE__, __LINE__, fd, level, optname, optval, optlen) + +#define SAFE_SETSOCKOPT(fd, level, optname, optval, optlen) \ + safe_setsockopt(__FILE__, __LINE__, fd, level, optname, optval, optlen) + +#define SAFE_SETSOCKOPT_INT(fd, l, n, val) \ + do { \ + int v = val; \ + safe_setsockopt(__FILE__, __LINE__, fd, l, n, &v, sizeof(v)); \ + } while (0) + +#define SAFE_SEND(strict, sockfd, buf, len, flags) \ + safe_send(__FILE__, __LINE__, strict, sockfd, buf, len, flags) + +#define SAFE_SENDTO(strict, fd, buf, len, flags, dest_addr, addrlen) \ + safe_sendto(__FILE__, __LINE__, strict, fd, buf, len, flags, \ + dest_addr, addrlen) + +#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) + +#define SAFE_BIND(socket, address, address_len) \ + safe_bind(__FILE__, __LINE__, NULL, socket, address, \ + address_len) + +#define SAFE_LISTEN(socket, backlog) \ + safe_listen(__FILE__, __LINE__, NULL, socket, backlog) + +#define SAFE_ACCEPT(sockfd, addr, addrlen) \ + safe_accept(__FILE__, __LINE__, NULL, sockfd, addr, addrlen) + +#define SAFE_CONNECT(sockfd, addr, addrlen) \ + safe_connect(__FILE__, __LINE__, NULL, sockfd, addr, addrlen) + +#define SAFE_GETSOCKNAME(sockfd, addr, addrlen) \ + safe_getsockname(__FILE__, __LINE__, NULL, sockfd, addr, \ + addrlen) + +#define SAFE_GETHOSTNAME(name, size) \ + safe_gethostname(__FILE__, __LINE__, name, size) + +#define SAFE_SETHOSTNAME(name, size) \ + safe_sethostname(__FILE__, __LINE__, name, size) + +#define TST_GETSOCKPORT(sockfd) \ + tst_getsockport(__FILE__, __LINE__, sockfd) + +#define TST_GET_UNUSED_PORT(family, type) \ + tst_get_unused_port(__FILE__, __LINE__, NULL, family, type) + +/* new API only */ + +#define SAFE_GETADDRINFO(src_addr, port, hints, addr_info) \ + safe_getaddrinfo(__FILE__, __LINE__, src_addr, port, hints, addr_info) + +#endif /* TST_SAFE_NET_H__ */ diff --git a/ltp/include/tst_safe_posix_ipc.h b/ltp/include/tst_safe_posix_ipc.h new file mode 100644 index 0000000000000000000000000000000000000000..e7892f2af8b6b3b92a949d99cce3e5b4dd01dcac --- /dev/null +++ b/ltp/include/tst_safe_posix_ipc.h @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017-2019 Petr Vorel pvorel@suse.cz + * Copyright (C) 2022 Andrea Cervesato andrea.cervesato@suse.com + */ + +#ifndef TST_SAFE_POSIX_IPC_H__ +#define TST_SAFE_POSIX_IPC_H__ + +#include +#include + +#define SAFE_MQ_OPEN(pathname, oflags, ...) \ + safe_mq_open(__FILE__, __LINE__, (pathname), (oflags), ##__VA_ARGS__) + +#define SAFE_MQ_CLOSE(mqdes) \ + safe_mq_close(__FILE__, __LINE__, (mqdes)) + +#define SAFE_MQ_NOTIFY(mqdes, sevp) \ + safe_mq_notify(__FILE__, __LINE__, (mqdes), (sevp)) + +#define SAFE_MQ_SEND(mqdes, msg_ptr, msg_len, msg_prio) \ + safe_mq_send(__FILE__, __LINE__, (mqdes), (msg_ptr), (msg_len), (msg_prio)) + +#define SAFE_MQ_UNLINK(name) \ + safe_mq_unlink(__FILE__, __LINE__, (name)) + +static inline int safe_mq_open(const char *file, const int lineno, + const char *pathname, int oflags, ...) +{ + va_list ap; + int rval; + mode_t mode; + struct mq_attr *attr; + + va_start(ap, oflags); + + /* Android's NDK's mode_t is smaller than an int, which results in + * SIGILL here when passing the mode_t type. + */ +#ifndef __ANDROID__ + mode = va_arg(ap, mode_t); +#else + mode = va_arg(ap, int); +#endif + + attr = va_arg(ap, struct mq_attr *); + + va_end(ap); + + rval = mq_open(pathname, oflags, mode, attr); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mq_open(%s,%d,%04o,%p) failed", pathname, oflags, + mode, attr); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid mq_open(%s) return value %d", pathname, rval); + } + + return rval; +} + +static inline int safe_mq_close(const char *file, const int lineno, + mqd_t __mqdes) +{ + int rval; + + rval = mq_close(__mqdes); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mq_close(%d) failed", __mqdes); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid mq_close(%d) return value %d", __mqdes, rval); + } + + return rval; +} + +static inline int safe_mq_unlink(const char *file, const int lineno, + const char* name) +{ + int rval; + + rval = mq_unlink(name); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mq_unlink(%s) failed", name); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid mq_unlink(%s) return value %d", name, rval); + } + + return rval; +} + +static inline int safe_mq_notify(const char *file, const int lineno, + mqd_t mqdes, const struct sigevent *sevp) +{ + int rval; + + rval = mq_notify(mqdes, sevp); + + if (rval == -1) + tst_brk_(file, lineno, TBROK | TERRNO, "mq_notify() failed"); + + return rval; +} + +static inline int safe_mq_send(const char *file, const int lineno, + mqd_t mqdes, const char *msg_ptr, + size_t msg_len, unsigned int msg_prio) +{ + int rval; + + rval = mq_send(mqdes, msg_ptr, msg_len, msg_prio); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mq_send(%d,%s,%zu,%d) failed", mqdes, msg_ptr, + msg_len, msg_prio); + } + + return rval; +} + +#endif /* TST_SAFE_POSIX_IPC_H__ */ diff --git a/ltp/include/tst_safe_prw.h b/ltp/include/tst_safe_prw.h new file mode 100644 index 0000000000000000000000000000000000000000..349fb46b427699c7efc227bfe21eaa475baa6d71 --- /dev/null +++ b/ltp/include/tst_safe_prw.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2010-2017 Linux Test Project + */ + +#ifndef TST_SAFE_PRW_H__ +#define TST_SAFE_PRW_H__ + +#include "lapi/uio.h" + +static inline ssize_t safe_pread(const char *file, const int lineno, + char len_strict, int fildes, void *buf, size_t nbyte, + off_t offset) +{ + ssize_t rval; + + rval = pread(fildes, buf, nbyte, offset); + + 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); + } 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; +} +#define SAFE_PREAD(len_strict, fildes, buf, nbyte, offset) \ + safe_pread(__FILE__, __LINE__, (len_strict), (fildes), \ + (buf), (nbyte), (offset)) + +static inline ssize_t safe_pwrite(const char *file, const int lineno, + char len_strict, int fildes, const void *buf, size_t nbyte, + off_t offset) +{ + ssize_t rval; + + 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); + } 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; +} +#define SAFE_PWRITE(len_strict, fildes, buf, nbyte, offset) \ + safe_pwrite(__FILE__, __LINE__, (len_strict), (fildes), \ + (buf), (nbyte), (offset)) + +static inline ssize_t safe_preadv(const char *file, const int lineno, + char len_strict, int fildes, const struct iovec *iov, int iovcnt, + off_t offset) +{ + ssize_t rval, nbyte; + int i; + + for (i = 0, nbyte = 0; i < iovcnt; i++) + nbyte += iov[i].iov_len; + + rval = preadv(fildes, iov, iovcnt, offset); + + if (rval == -1 || (len_strict && rval != nbyte)) { + tst_brk_(file, lineno, TBROK | TERRNO, + "preadv(%d,%p,%d,%lld) failed", + fildes, iov, iovcnt, (long long)offset); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid preadv(%d,%p,%d,%lld) return value %zd", + fildes, iov, iovcnt, (long long)offset, rval); + } + + return rval; +} +#define SAFE_PREADV(len_strict, fildes, iov, iovcnt, offset) \ + safe_preadv(__FILE__, __LINE__, (len_strict), (fildes), \ + (iov), (iovcnt), (offset)) + +static inline ssize_t safe_pwritev(const char *file, const int lineno, + char len_strict, int fildes, const struct iovec *iov, int iovcnt, + off_t offset) +{ + ssize_t rval, nbyte; + int i; + + for (i = 0, nbyte = 0; i < iovcnt; i++) + nbyte += iov[i].iov_len; + + rval = pwritev(fildes, iov, iovcnt, offset); + + if (rval == -1 || (len_strict && rval != nbyte)) { + tst_brk_(file, lineno, TBROK | TERRNO, + "pwritev(%d,%p,%d,%lld) failed", + fildes, iov, iovcnt, (long long)offset); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid pwritev(%d,%p,%d,%lld) return value %zd", + fildes, iov, iovcnt, (long long)offset, rval); + } + + return rval; +} +#define SAFE_PWRITEV(len_strict, fildes, iov, iovcnt, offset) \ + safe_pwritev(__FILE__, __LINE__, (len_strict), (fildes), \ + (iov), (iovcnt), (offset)) + +#endif /* SAFE_PRW_H__ */ diff --git a/ltp/include/tst_safe_pthread.h b/ltp/include/tst_safe_pthread.h new file mode 100644 index 0000000000000000000000000000000000000000..360b561b61f992bc8ea96d475ab113eec96ac737 --- /dev/null +++ b/ltp/include/tst_safe_pthread.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved. + */ + +#ifndef TST_SAFE_PTHREAD_H__ +#define TST_SAFE_PTHREAD_H__ + +/* + * Macro to use for making functions called only once in + * multi-threaded tests such as init or cleanup function. + * The first call to @name_fn function by any thread shall + * call the @exec_fn. Subsequent calls shall not call @exec_fn. + * *_fn functions must not take any arguments. + */ +#define TST_DECLARE_ONCE_FN(name_fn, exec_fn) \ + void name_fn(void) \ + { \ + static pthread_once_t ltp_once = PTHREAD_ONCE_INIT; \ + pthread_once(<p_once, exec_fn); \ + } + +int safe_pthread_create(const char *file, const int lineno, + pthread_t *thread_id, const pthread_attr_t *attr, + void *(*thread_fn)(void *), void *arg); +#define SAFE_PTHREAD_CREATE(thread_id, attr, thread_fn, arg) \ + safe_pthread_create(__FILE__, __LINE__, thread_id, attr, thread_fn, arg) + +int safe_pthread_join(const char *file, const int lineno, + pthread_t thread_id, void **retval); +#define SAFE_PTHREAD_JOIN(thread_id, retval) \ + safe_pthread_join(__FILE__, __LINE__, thread_id, retval) + +int safe_pthread_barrier_wait(const char *file, const int lineno, + pthread_barrier_t *barrier); +#define SAFE_PTHREAD_BARRIER_WAIT(barrier) \ + safe_pthread_barrier_wait(__FILE__, __LINE__, barrier); + +int safe_pthread_barrier_destroy(const char *file, const int lineno, + pthread_barrier_t *barrier); +#define SAFE_PTHREAD_BARRIER_DESTROY(barrier) \ + safe_pthread_barrier_destroy(__FILE__, __LINE__, barrier); + +int safe_pthread_barrier_init(const char *file, const int lineno, + pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned count); +#define SAFE_PTHREAD_BARRIER_INIT(barrier, attr, count) \ + safe_pthread_barrier_init(__FILE__, __LINE__, barrier, attr, count); + +int safe_pthread_cancel(const char *file, const int lineno, + pthread_t thread_id); +#define SAFE_PTHREAD_CANCEL(thread_id) \ + safe_pthread_cancel(__FILE__, __LINE__, thread_id); + +int safe_pthread_mutexattr_init(const char *file, const int lineno, + pthread_mutexattr_t *attr); +#define SAFE_PTHREAD_MUTEXATTR_INIT(attr) \ + safe_pthread_mutexattr_init(__FILE__, __LINE__, (attr)) + +int safe_pthread_mutexattr_destroy(const char *file, const int lineno, + pthread_mutexattr_t *attr); +#define SAFE_PTHREAD_MUTEXATTR_DESTROY(attr) \ + safe_pthread_mutexattr_destroy(__FILE__, __LINE__, (attr)) + +int safe_pthread_mutexattr_settype(const char *file, const int lineno, + pthread_mutexattr_t *attr, int type); +#define SAFE_PTHREAD_MUTEXATTR_SETTYPE(attr, type) \ + safe_pthread_mutexattr_settype(__FILE__, __LINE__, (attr), (type)) + +int safe_pthread_mutex_init(const char *file, const int lineno, + pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); +#define SAFE_PTHREAD_MUTEX_INIT(mutex, attr) \ + safe_pthread_mutex_init(__FILE__, __LINE__, (mutex), (attr)) + +int safe_pthread_mutex_destroy(const char *file, const int lineno, + pthread_mutex_t *mutex); +#define SAFE_PTHREAD_MUTEX_DESTROY(mutex) \ + safe_pthread_mutex_destroy(__FILE__, __LINE__, (mutex)) + +int safe_pthread_mutex_lock(const char *file, const int lineno, + pthread_mutex_t *mutex); +#define SAFE_PTHREAD_MUTEX_LOCK(mutex) \ + safe_pthread_mutex_lock(__FILE__, __LINE__, (mutex)) + +/* Terminates the test on any error other than EBUSY */ +int safe_pthread_mutex_trylock(const char *file, const int lineno, + pthread_mutex_t *mutex); +#define SAFE_PTHREAD_MUTEX_TRYLOCK(mutex) \ + safe_pthread_mutex_trylock(__FILE__, __LINE__, (mutex)) + +/* Terminates the test on any error other than ETIMEDOUT */ +int safe_pthread_mutex_timedlock(const char *file, const int lineno, + pthread_mutex_t *mutex, const struct timespec *abstime); +#define SAFE_PTHREAD_MUTEX_TIMEDLOCK(mutex, abstime) \ + safe_pthread_mutex_timedlock(__FILE__, __LINE__, (mutex), (abstime)) + +int safe_pthread_mutex_unlock(const char *file, const int lineno, + pthread_mutex_t *mutex); +#define SAFE_PTHREAD_MUTEX_UNLOCK(mutex) \ + safe_pthread_mutex_unlock(__FILE__, __LINE__, (mutex)) + +int safe_pthread_kill(const char *file, const int lineno, + pthread_t thread, int sig); +#define SAFE_PTHREAD_KILL(thread, sig) \ + safe_pthread_kill(__FILE__, __LINE__, (thread), (sig)) + +#endif /* TST_SAFE_PTHREAD_H__ */ diff --git a/ltp/include/tst_safe_stdio.h b/ltp/include/tst_safe_stdio.h new file mode 100644 index 0000000000000000000000000000000000000000..e4bff34da15c9116809fcf851cbf544a51e384ef --- /dev/null +++ b/ltp/include/tst_safe_stdio.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2013-2016 Cyril Hrubis + */ + +#ifndef TST_SAFE_STDIO_H__ +#define TST_SAFE_STDIO_H__ + +#include + +#include "safe_stdio_fn.h" + +#define SAFE_FOPEN(path, mode) \ + safe_fopen(__FILE__, __LINE__, NULL, path, mode) + +#define SAFE_FCLOSE(f) \ + safe_fclose(__FILE__, __LINE__, NULL, f) + +#define SAFE_ASPRINTF(strp, fmt, ...) \ + safe_asprintf(__FILE__, __LINE__, NULL, strp, fmt, __VA_ARGS__) + +#define SAFE_POPEN(command, type) \ + safe_popen(__FILE__, __LINE__, NULL, command, type) + +#endif /* TST_SAFE_STDIO_H__ */ diff --git a/ltp/include/tst_safe_sysv_ipc.h b/ltp/include/tst_safe_sysv_ipc.h new file mode 100644 index 0000000000000000000000000000000000000000..7804ce192ad6af9508ba1aba5427a4c1bf5ac41c --- /dev/null +++ b/ltp/include/tst_safe_sysv_ipc.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2017 Xiao yang + */ + +#ifndef TST_SAFE_SYSV_IPC_H__ +#define TST_SAFE_SYSV_IPC_H__ + +#include +#include +#include +#include +#include + +int safe_msgget(const char *file, const int lineno, key_t key, int msgflg); +#define SAFE_MSGGET(key, msgflg) \ + safe_msgget(__FILE__, __LINE__, (key), (msgflg)) + +int safe_msgsnd(const char *file, const int lineno, int msqid, const void *msgp, + size_t msgsz, int msgflg); +#define SAFE_MSGSND(msqid, msgp, msgsz, msgflg) \ + safe_msgsnd(__FILE__, __LINE__, (msqid), (msgp), (msgsz), (msgflg)) + +ssize_t safe_msgrcv(const char *file, const int lineno, int msqid, void *msgp, + size_t msgsz, long msgtyp, int msgflg); +#define SAFE_MSGRCV(msqid, msgp, msgsz, msgtyp, msgflg) \ + safe_msgrcv(__FILE__, __LINE__, (msqid), (msgp), (msgsz), (msgtyp), (msgflg)) + +int safe_msgctl(const char *file, const int lineno, int msqid, int cmd, + struct msqid_ds *buf); +#define SAFE_MSGCTL(msqid, cmd, buf) ({ \ + int tst_ret_ = safe_msgctl(__FILE__, __LINE__, (msqid), (cmd), (buf)); \ + (msqid) = ((cmd) == IPC_RMID ? -1 : (msqid)); \ + tst_ret_;}) + +int safe_shmget(const char *file, const int lineno, key_t key, size_t size, + int shmflg); +#define SAFE_SHMGET(key, size, shmflg) \ + safe_shmget(__FILE__, __LINE__, (key), (size), (shmflg)) + +void *safe_shmat(const char *file, const int lineno, int shmid, + const void *shmaddr, int shmflg); +#define SAFE_SHMAT(shmid, shmaddr, shmflg) \ + safe_shmat(__FILE__, __LINE__, (shmid), (shmaddr), (shmflg)) + +int safe_shmdt(const char *file, const int lineno, const void *shmaddr); +#define SAFE_SHMDT(shmaddr) safe_shmdt(__FILE__, __LINE__, (shmaddr)) + +int safe_shmctl(const char *file, const int lineno, int shmid, int cmd, + struct shmid_ds *buf); +#define SAFE_SHMCTL(shmid, cmd, buf) ({ \ + int tst_ret_ = safe_shmctl(__FILE__, __LINE__, (shmid), (cmd), (buf)); \ + (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/ltp/include/tst_safe_timerfd.h b/ltp/include/tst_safe_timerfd.h new file mode 100644 index 0000000000000000000000000000000000000000..526f128389e78e96b78f86c756c1c282e41fd76a --- /dev/null +++ b/ltp/include/tst_safe_timerfd.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Petr Vorel + */ + +#ifndef TST_SAFE_TIMERFD_H__ +#define TST_SAFE_TIMERFD_H__ + +#include "lapi/timerfd.h" + +int safe_timerfd_create(const char *file, const int lineno, + int clockid, int flags); + +#define SAFE_TIMERFD_CREATE(clockid, flags)\ + safe_timerfd_create(__FILE__, __LINE__, (clockid), (flags)) + +int safe_timerfd_gettime(const char *file, const int lineno, + int fd, struct itimerspec *curr_value); + +#define SAFE_TIMERFD_GETTIME(fd, curr_value)\ + safe_timerfd_gettime(__FILE__, __LINE__, (fd), (curr_value)) + +int safe_timerfd_settime(const char *file, const int lineno, + int fd, int flags, + const struct itimerspec *new_value, + struct itimerspec *old_value); + +#define SAFE_TIMERFD_SETTIME(fd, flags, new_value, old_value)\ + safe_timerfd_settime(__FILE__, __LINE__, (fd), (flags), (new_value), \ + (old_value)) + +#endif /* SAFE_TIMERFD_H__ */ diff --git a/ltp/include/tst_sched.h b/ltp/include/tst_sched.h new file mode 100644 index 0000000000000000000000000000000000000000..700afe3f200d8c7ade0775b669c5987a2aa1ff97 --- /dev/null +++ b/ltp/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/ltp/include/tst_security.h b/ltp/include/tst_security.h new file mode 100644 index 0000000000000000000000000000000000000000..5d91f8a98f104b0cafaaf2046bc0ceec06870606 --- /dev/null +++ b/ltp/include/tst_security.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) Linux Test Project, 2020-2024 + */ + +#ifndef TST_SECURITY_H__ +#define TST_SECURITY_H__ + +/* + * Detect whether FIPS enabled + * @return 0: FIPS not enabled, 1: FIPS enabled + */ +int tst_fips_enabled(void); + +int tst_lockdown_enabled(void); +int tst_secureboot_enabled(void); +int tst_selinux_enforcing(void); + +#endif /* TST_SECURITY_H__ */ diff --git a/ltp/include/tst_sig_proc.h b/ltp/include/tst_sig_proc.h new file mode 100644 index 0000000000000000000000000000000000000000..b85981e772029e4407069ba985b69e1b8f1e7747 --- /dev/null +++ b/ltp/include/tst_sig_proc.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2016 Linux Test Project + */ + +#ifndef TST_SIG_PROC_H__ +#define TST_SIG_PROC_H__ + +#include + +pid_t create_sig_proc(int sig, int count, unsigned int usec); + +#endif /* TST_SIG_PROC_H__ */ diff --git a/ltp/include/tst_sys_conf.h b/ltp/include/tst_sys_conf.h new file mode 100644 index 0000000000000000000000000000000000000000..a221a9a0daa0cc60cf09450aee134f2359499f38 --- /dev/null +++ b/ltp/include/tst_sys_conf.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2018 Jan Stancek + */ + +#ifndef TST_SYS_CONF_H__ +#define TST_SYS_CONF_H__ + +#define TST_SR_TCONF_MISSING 0x0 +#define TST_SR_TBROK_MISSING 0x1 +#define TST_SR_SKIP_MISSING 0x2 +#define TST_SR_TCONF_RO 0x0 +#define TST_SR_TBROK_RO 0x4 +#define TST_SR_SKIP_RO 0x8 +#define TST_SR_IGNORE_ERR 0x10 + +#define TST_SR_TCONF (TST_SR_TCONF_MISSING | TST_SR_TCONF_RO) +#define TST_SR_TBROK (TST_SR_TBROK_MISSING | TST_SR_TBROK_RO) +#define TST_SR_SKIP (TST_SR_SKIP_MISSING | TST_SR_SKIP_RO) + +struct tst_path_val { + const char *path; + const char *val; + unsigned int flags; +}; + +void tst_sys_conf_save_str(const char *path, const char *value); +int tst_sys_conf_save(const struct tst_path_val *conf); +void tst_sys_conf_restore(int verbose); +void tst_sys_conf_dump(void); + +int tst_read_bool_sys_param(const char *filename); + +/** + * TST_SYS_CONF_LONG_SET() - Writes a long int into a sys or proc file. + * + * @path: A path to a sysfs or a procfs file. + * @val: A long int value to be written to the file. + * @check: If non-zero the library reads the file back and checks that the + * value is the one we have written there. If not the library calls + * tst_brk(TBROK, ...). + * + * Sets a sysfs or procfs file and optionally checks that it was set correctly. + */ +#define TST_SYS_CONF_LONG_SET(path, val, check) \ + tst_sys_conf_long_set_(__FILE__, __LINE__, path, val, check) + +void tst_sys_conf_long_set_(const char *file, const int lineno, + const char *path, long val, int check); + + +/** + * TST_SYS_CONF_LONG_GET() - Reads a long int from sys or proc file. + * + * @path: A path to a sysfs or a procfs file. + * return: A value read from the file converted into a long. + * + * Gets a sysfs or procfs file value and converts it to long. + */ +#define TST_SYS_CONF_LONG_GET(path) \ + tst_sys_conf_long_get_(__FILE__, __LINE__, path) + +long tst_sys_conf_long_get_(const char *file, const int lineno, + const char *path); + +#endif diff --git a/ltp/include/tst_taint.h b/ltp/include/tst_taint.h new file mode 100644 index 0000000000000000000000000000000000000000..b2b201688595cdfaf812e4fe7acc1760330199eb --- /dev/null +++ b/ltp/include/tst_taint.h @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Michael Moese + */ + +/* Usage example + * + * ... + * #include "tst_test.h" + * .. + * static struct tst_test test = { + * ... + * .taint_check = TST_TAINT_W | TST_TAINT_D, + * ... + * }; + * + * void run(void) + * { + * ... + * . test code here + * ... + * if (tst_taint_check() != 0) + * tst_res(TFAIL, "kernel has issues"); + * else + * tst_res(TPASS, "kernel seems to be fine"); + * } + * + * + * + * 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__ +#define TST_TAINTED_H__ + +/* + * This are all 17 flags that are present in kernel 4.15 + * see kernel/panic.c in kernel sources + * + * Not all of them are valid in all kernel versions. + */ +#define TST_TAINT_G (1 << 0) /* a module with non-GPL license loaded */ +#define TST_TAINT_F (1 << 1) /* a module was force-loaded */ +#define TST_TAINT_S (1 << 2) /* SMP with Non-SMP kernel */ +#define TST_TAINT_R (1 << 3) /* module force unloaded */ +#define TST_TAINT_M (1 << 4) /* machine check error occurred */ +#define TST_TAINT_B (1 << 5) /* page-release function found bad page */ +#define TST_TAINT_U (1 << 6) /* user requested taint flag */ +#define TST_TAINT_D (1 << 7) /* kernel died recently - OOPS or BUG */ +#define TST_TAINT_A (1 << 8) /* ACPI table has been overwritten */ +#define TST_TAINT_W (1 << 9) /* a warning has been issued by kernel */ +#define TST_TAINT_C (1 << 10) /* driver from drivers/staging was loaded */ +#define TST_TAINT_I (1 << 11) /* working around BIOS/Firmware bug */ +#define TST_TAINT_O (1 << 12) /* out of tree module loaded */ +#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_T (1 << 17) /* kernel was built with the struct randomization plugin */ +#define TST_TAINT_N (1 << 18) /* an in-kernel test has been run */ + +/* + * 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 + * a warning or even reported it died. + * + * 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 TBROK is generated. + * + * The mask must not be zero. + */ +void tst_taint_init(unsigned int mask); + + +/* + * check if the tainted flags handed to tst_taint_init() are still not set + * during or after running the test. + * Calling this function is only allowed after tst_taint_init() was called, + * otherwise TBROK will be generated. + * + * returns 0 or a bitmask of the flags that currently tainted the kernel. + */ +unsigned int tst_taint_check(void); + + +#endif /* TST_TAINTED_H__ */ diff --git a/ltp/include/tst_test.h b/ltp/include/tst_test.h new file mode 100644 index 0000000000000000000000000000000000000000..9c21c17283fc1e5dce20647d96f88ca5c779c277 --- /dev/null +++ b/ltp/include/tst_test.h @@ -0,0 +1,754 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2015-2016 Cyril Hrubis + * Copyright (c) Linux Test Project, 2016-2024 + */ + +#ifndef TST_TEST_H__ +#define TST_TEST_H__ + +#ifdef __TEST_H__ +# error Oldlib test.h already included +#endif /* __TEST_H__ */ + +#include +#include +#include +#include +#include + +#include "tst_common.h" +#include "tst_res_flags.h" +#include "tst_parse.h" +#include "tst_test_macros.h" +#include "tst_checkpoint.h" +#include "tst_device.h" +#include "tst_mkfs.h" +#include "tst_fs.h" +#include "tst_pid.h" +#include "tst_cmd.h" +#include "tst_cpu.h" +#include "tst_process_state.h" +#include "tst_atomic.h" +#include "tst_kvercmp.h" +#include "tst_kernel.h" +#include "tst_minmax.h" +#include "tst_get_bad_addr.h" +#include "tst_path_has_mnt_flags.h" +#include "tst_sys_conf.h" +#include "tst_coredump.h" +#include "tst_buffers.h" +#include "tst_capability.h" +#include "tst_hugepage.h" +#include "tst_assert.h" +#include "tst_security.h" +#include "tst_taint.h" +#include "tst_memutils.h" +#include "tst_arch.h" +#include "tst_fd.h" +#include "tst_tmpdir.h" + +void tst_res_(const char *file, const int lineno, int ttype, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); + +/** + * tst_res() - Reports a test result. + * + * @ttype: An &enum tst_res_flags. + * @arg_fmt: A printf-like format. + * @...: A printf-like parameters. + * + * This is the main test reporting function. Each time this function is called + * with one of TPASS, TFAIL, TCONF, TBROK or TWARN a counter in page of shared + * memory is incremented. This means that there is no need to propagate test + * results from children and that results are accounted for once this function + * returns. The counters are incremented atomically which makes this function + * thread-safe. + */ +#define tst_res(ttype, arg_fmt, ...) \ + ({ \ + TST_RES_SUPPORTS_TCONF_TDEBUG_TFAIL_TINFO_TPASS_TWARN(\ + !((TTYPE_RESULT(ttype) ?: TCONF) & \ + (TCONF | TDEBUG | TFAIL | TINFO | TPASS | TWARN))); \ + tst_res_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__);\ + }) + +void tst_resm_hexd_(const char *file, const int lineno, int ttype, + const void *buf, size_t size, const char *arg_fmt, ...) + __attribute__ ((format (printf, 6, 7))); +/** + * tst_res_hexd() - Reports a test result along with hex dump of a buffer. + * + * This call is the same as tst_res() but includes a pointer and size of the + * buffer that is going to be printed in the output in a hexadecimal format. + * + * @ttype: An &enum tst_res_flags. + * @buf: A pointer to a buffer to print in hexadecimal format. + * @size: A size of the buffer. + * @arg_fmt: A printf-like format. + * @...: A printf-like parameters. + */ +#define tst_res_hexd(ttype, buf, size, arg_fmt, ...) \ + tst_resm_hexd_(__FILE__, __LINE__, (ttype), (buf), (size), \ + (arg_fmt), ##__VA_ARGS__) + +void tst_brk_(const char *file, const int lineno, int ttype, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); + +/** + * tst_brk() - Reports a breakage and exits the test or test process. + * + * @ttype: An &enum tst_res_flags. + * @arg_fmt: A printf-like format. + * @...: A printf-like parameters. + * + * Reports a single result and exits immediately. The call behaves differently + * based on the ttype parameter. For all ttype results but TBROK the call exits + * the current test process, i.e. increments test result counters and calls + * exit(0). + * + * The TBROK ttype is special that apart from exiting the current test process + * it also tells to the test library to exit immediately. When TBROK is + * triggered by any of the test processes the whole process group is killed so + * that there are no processes left after the library process exits. This also + * means that any subsequent test iterations are not executed, e.g. if a test + * runs for all filesystems and tst_brk() with TBROK is called, the test exits + * and does not attempt to continue a test iteration for the next filesystem. + * + * When test is in cleanup() function TBROK is converted into TWARN by the test + * library and we attempt to carry on with a cleanup even when tst_brk() was + * called. This makes it possible to use SAFE_FOO() macros in the test cleanup + * without interrupting the cleanup process on a failure. + */ +#define tst_brk(ttype, arg_fmt, ...) \ + tst_brk_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__) + +void tst_printf(const char *const fmt, ...) + __attribute__((nonnull(1), format (printf, 1, 2))); + +/** + * tst_flush() - Flushes the output file streams. + * + * There are rare cases when we want to flush the output file streams + * explicitly, e.g. before we do an action that may crash the test to ensure + * that the messages have been written out. + * + * This is also called by the SAFE_FORK() because otherwise each child would + * end up with the same copy of the file in it's memory and any messages in + * buffers would be multiplied. + */ +void tst_flush(void); + +pid_t safe_fork(const char *filename, unsigned int lineno); +/** + * SAFE_FORK() - Forks a test child. + * + * This call makes sure that output file streams are flushed and also handles + * errors from fork(). Use this instead of fork() whenever possible! + */ +#define SAFE_FORK() \ + safe_fork(__FILE__, __LINE__) + +#define TST_TRACE(expr) \ + ({int ret = expr; \ + ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; }) \ + +/** + * tst_strerrno() - Converts an errno number into a name. + * + * @err: An errno number. + * return: An errno name e.g. "EINVAL". + */ +const char *tst_strerrno(int err); + +/** + * tst_strsig() - Converts a signal number into a name. + * + * @sig: A signal number. + * return: A signal name e.g. "SIGINT". + */ +const char *tst_strsig(int sig); + + +/** + * tst_strstatus() - Returns string describing status as returned by wait(). + * + * WARNING: Not thread safe. + * + * @status: A status as returned by wait() + * return: A string description for the status e.g. "killed by SIGKILL". + */ +const char *tst_strstatus(int status); + +#include "tst_safe_macros.h" +#include "tst_safe_file_ops.h" +#include "tst_safe_net.h" +#include "tst_clone.h" +#include "tst_cgroup.h" + +/** + * tst_reap_children() - Waits for all child processes to exit. + * + * Wait for all children and exit with TBROK if any of them returned a non-zero + * exit status. + */ +void tst_reap_children(void); + +/** + * struct tst_option - Test command line option. + * + * @optstr: A short command line option, e.g. "a" or "a:". + * @arg: A pointer to store the option value to. + * @help: A help string for the option displayed when test is passed '-h' on + * the command-line. + */ +struct tst_option { + char *optstr; + char **arg; + char *help; +}; + +/** + * struct tst_tag - A test tag. + * + * @name: A tag name. + * @value: A tag value. + * + * This structure is used to encode pointers to upstream commits in regression + * tests as well as CVE numbers or any additional useful hints. + * + * The content of these tags is printed by the test on a failure to help the + * testers with debugging. + * + * The supported tags are: + * + * - "linux-git" with first 12 numbers from an upstream kernel git hash. + * - "CVE" with a CVE number e.g. "2000-1234". + * - "glibc-git" with first 12 numbers from an upstream glibc git hash. + * - "musl-git" with first 12 numbers from an upstream musl git hash. + * - "known-fail" a message describing something that is supposed to work but + * rather than that produces a longstanding failures. + */ +struct tst_tag { + const char *name; + const char *value; +}; + +extern unsigned int tst_variant; + +#define TST_UNLIMITED_TIMEOUT (-1) + +/** + * struct tst_ulimit_val - An ulimit resource and value. + * + * @resource: Which resource limits should be adjusted. See setrlimit(2) for + * the list of the RLIMIT_* constants. + * @rlim_cur: A limit value. + */ +struct tst_ulimit_val { + int resource; + rlim_t rlim_cur; +}; + +/** + * struct tst_fs - A file system type, mkfs and mount options + * + * @type: A filesystem type to use. + * + * @mkfs_opts: A NULL terminated array of options passed to mkfs in the case + * of 'tst_test.format_device'. These options are passed to mkfs + * before the device path. + * + * @mkfs_size_opt: An option passed to mkfs in the case of + * 'tst_test.format_device'. The device size in blocks is + * passed to mkfs after the device path and can be used to + * limit the file system not to use the whole block device. + * + * @mkfs_ver: mkfs tool version. The string format supports relational + * operators such as < > <= >= ==. + * + * @mnt_flags: MS_* flags passed to mount(2) when the test library mounts a + * device in the case of 'tst_test.mount_device'. + * + * @mnt_data: The data passed to mount(2) when the test library mounts a device + * in the case of 'tst_test.mount_device'. + * + * @min_kver: A minimum kernel version supporting the filesystem which has been + * created with mkfs. + */ +struct tst_fs { + const char *type; + + const char *const *mkfs_opts; + const char *mkfs_size_opt; + const char *mkfs_ver; + + unsigned int mnt_flags; + const void *mnt_data; + + const char *min_kver; +}; + +/** + * struct tst_test - A test description. + * + * @tcnt: A number of tests. If set the test() callback is called tcnt times + * and each time passed an increasing counter value. + * @options: An NULL optstr terminated array of struct tst_option. + * + * @min_kver: A minimal kernel version the test can run on. e.g. "3.10". + * + * @supported_archs: A NULL terminated array of architectures the test runs on + * e.g. {"x86_64, "x86", NULL}. Calls tst_is_on_arch() to + * check if current CPU architecture is supported and exits + * the test with TCONF if it's not. + * + * @tconf_msg: If set the test exits with TCONF right after entering the test + * library. This is used by the TST_TEST_TCONF() macro to disable + * tests at compile time. + * + * @needs_tmpdir: If set a temporary directory is prepared for the test inside + * $TMPDIR and the test $CWD is set to point to it. The content + * of the temporary directory is removed automatically after + * the test is finished. + * + * @needs_root: If set the test exit with TCONF unless it's executed under root + * user. + * + * @forks_child: Has to be set if the test intends to fork children. + * + * @needs_device: If set a block device is prepared for the test, the device + * path and size are set in the struct tst_device variable + * called tst_device. If $LTP_DEV variable exists in the test + * environment the test attempts to use that device first and + * only if that fails the test falls back to use loop devices. + * This flag implies needs_tmpdir flag because loop device + * backing files are created in the test temporary directory. + * + * @needs_checkpoints: Has to be set if the test wants to use checkpoint + * synchronization primitives. + * + * @needs_overlay: If set overlay file system is mounted on the top of the + * file system at tst_test.mntpoint. + * + * @format_device: Does all tst_test.needs_device would do and also formats + * the device with a file system as well. + * + * @mount_device: Does all tst_test.format_device would do and also mounts the + * device at tst_test.mntpoint. + * + * @needs_rofs: If set a read-only file system is mounted at tst_test.mntpoint. + * + * @child_needs_reinit: Has to be set if the test needs to call tst_reinit() + * from a process started by exec(). + * + * @runs_script: Implies child_needs_reinit and forks_child at the moment. + * + * @needs_devfs: If set the devfs is mounted at tst_test.mntpoint. This is + * needed for tests that need to create device files since tmpfs + * at /tmp is usually mounted with 'nodev' option. + * + * @restore_wallclock: Saves wall clock at the start of the test and restores + * it at the end with the help of monotonic timers. + * Testcases that modify system wallclock use this to + * restore the system to the previous state. + * + * @all_filesystems: If set the test is executed for all supported filesytems, + * i.e. file system that is supported by the kernel and has + * mkfs installed on the system.The file system is mounted at + * tst_test.mntpoint and file system details, e.g. type are set + * in the struct tst_device. Each execution is independent, + * that means that for each iteration tst_test.setup() is + * called at the test start and tst_test.cleanup() is called + * at the end and tst_brk() only exits test for a single + * file system. That especially means that calling + * tst_brk(TCONF, ...) in the test setup will skip the + * current file system. + * + * @skip_in_lockdown: Skip the test if kernel lockdown is enabled. + * + * @skip_in_secureboot: Skip the test if secureboot is enabled. + * + * @skip_in_compat: Skip the test if we are executing 32bit binary on a 64bit + * kernel, i.e. we are testing the kernel compat layer. + * + * @needs_abi_bits: Skip the test if runs on a different kernel ABI than + * requested (on 32bit instead of 64bit or vice versa). + * Possible values: 32, 64. + * + * @needs_hugetlbfs: If set hugetlbfs is mounted at tst_test.mntpoint. + * + * @skip_filesystems: A NULL terminated array of unsupported file systems. The + * test reports TCONF if the file system to be tested is + * present in the array. This is especially useful to filter + * out unsupported file system when tst_test.all_filesystems + * is enabled. + * + * @min_cpus: Minimal number of online CPUs the test needs to run. + * + * @min_mem_avail: Minimal amount of available RAM memory in megabytes required + * for the test to run. + * + * @min_swap_avail: Minimal amount of available swap memory in megabytes + * required for the test to run. + * + * @hugepages: An interface to reserve hugepages prior running the test. + * Request how many hugepages should be reserved in the global + * pool and also if having hugepages is required for the test run + * or not, i.e. if test should exit with TCONF if the requested + * amount of hugepages cannot be reserved. If TST_REQUEST is set + * the library will try it's best to reserve the hugepages and + * return the number of available hugepages in tst_hugepages, which + * may be 0 if there is no free memory or hugepages are not + * supported at all. If TST_NEEDS the requested hugepages are + * required for the test and the test exits if it couldn't be + * required. It can also be used to disable hugepages by setting + * .hugepages = {TST_NO_HUGEPAGES}. The test library restores the + * original poll allocations after the test has finished. + * + * @taint_check: If set the test fails if kernel is tainted during the test run. + * That means tst_taint_init() is called during the test setup + * and tst_taint_check() at the end of the test. If all_filesystems + * is set taint check will be performed after each iteration and + * testing will be terminated by TBROK if taint is detected. + * + * @test_variants: If set denotes number of test variant, the test is executed + * variants times each time with tst_variant set to different + * number. This allows us to run the same test for different + * settings. The intended use is to test different syscall + * wrappers/variants but the API is generic and does not limit + * usage in any way. + * + * @dev_min_size: A minimal device size in megabytes. + * + * @filesystems: A NULL type terminated array of per file system type + * parameters for mkfs and mount. If the first entry type is NULL + * it describes a default parameters for all file system tests. + * The rest of the entries the describes per file system type + * parameters. If tst_test.all_filesystems is set, the test runs + * for all filesystems and uses the array to lookup the mkfs + * and mount options. If tst_test.all_filesystems is not set + * the test iterates over file system types defined in the array. + * If there is only a single entry in the array with a NULL type, + * the test runs just once for the default file sytem i.e. + * $TST_FS_TYPE. + * + * @mntpoint: A mount point where the test library mounts requested file system. + * The directory is created by the library, the test must not create + * it itself. + * + * @timeout: Maximum allowable time in seconds for the entire duration of a test. + * By default, the timeout limits the total time for setup, single test + * function invocation, and cleanup phases. However, if .runtime is + * explicitly set and tst_remaining_runtime() is used in the test's + * main loop, the timeout then applies only to the setup and cleanup + * phases, as the runtime separately limits the main test execution. + * This ensures the test does not hang indefinitely, in the rare case + * that the test timeout cannot be accurately determined, it can be + * set to a sufficiently large value or TST_UNLIMITED_TIMEOUT to remove + * the limit. + * + * @runtime: Maximum runtime in seconds for the test's main execution loop. + * This should be set for tests that are expected to run longer + * than a few seconds and call tst_remaining_runtime() in their + * main loop to exit gracefully when the runtime is exceeded. + * Tests may finish sooner if their task completes (e.g., reaching + * a requested number of iterations) before the runtime runs out. + * The runtime is fixed and does not scale with timeout multipliers + * (e.g., TIMEOUT_MUL), ensuring consistent test duration across + * different environments (e.g., debug vs. stock kernels). + * + * @min_runtime: Optional lower bound (in seconds) applied after runtime is + * scaled by LTP_RUNTIME_MUL. If the scaled runtime is smaller + * than this value, it will be clamped up to min_runtime. + * This is useful for tests that require a minimum execution + * time to gather sufficient samples or trigger events (e.g., + * probabilistic or fuzzy synchronization tests). + * If not set, a default minimum of 1 second is enforced. + * + * @setup: Setup callback is called once at the start of the test in order to + * prepare the test environment. + * + * @cleanup: Cleanup callback is either called at the end of the test, or in a + * case that tst_brk() was called. That means that cleanup must be + * able to handle all possible states the test can be in. This + * usually means that we have to check if file descriptor was opened + * before we attempt to close it, etc. + * + * + * @test: A main test function, only one of the tst_test.test and test_all can + * be set. When this function is set the tst_test.tcnt must be set to a + * positive integer and this function will be executed tcnt times + * during a single test iteration. May be executed several times if test + * was passed '-i' or '-d' command line parameters. + * + * @test_all: A main test function, only one of the tst_test.test and test_all + * can be set. May be executed several times if test was passed '-i' + * or '-d' command line parameters. + * + * @scall: Internal only (timer measurement library). + * + * @sample: Internal only (timer measurement library). + * + * @resource_files: A NULL terminated array of filenames that will be copied + * to the test temporary directory from the LTP datafiles + * directory. + * + * @needs_drivers: A NULL terminated array of kernel modules required to run + * the test. The module has to be build in or present in order + * for the test to run. + * + * @save_restore: A {} terminated array of /proc or /sys files that should + * saved at the start of the test and restored at the end. See + * tst_sys_conf_save() and struct tst_path_val for details. + * + * @ulimit: A {} terminated array of process limits RLIMIT_* to be adjusted for + * the test. + * + * @needs_kconfigs: A NULL terminated array of kernel config options that are + * required for the test. All strings in the array have to be + * evaluated to true for the test to run. Boolean operators + * and parenthesis are supported, e.g. + * "CONFIG_X86_INTEL_UMIP=y | CONFIG_X86_UIMP=y" is evaluated + * to true if at least one of the options is present. + * + * @bufs: A description of guarded buffers to be allocated for the test. Guarded + * buffers are buffers with poisoned page allocated right before the start + * of the buffer and canary right after the end of the buffer. See + * struct tst_buffers and tst_buffer_alloc() for details. + * + * @caps: A {} terminated array of capabilities to change before the start of + * the test. See struct tst_cap and tst_cap_setup() for details. + * + * @tags: A {} terminated array of test tags. See struct tst_tag for details. + * + * @needs_cmds: A NULL terminated array of commands required for the test to run. + * + * @needs_cgroup_ver: If set the test will run only if the specified cgroup + * version is present on the system. + * + * @needs_cgroup_ctrls: A {} terminated array of cgroup controllers the test + * needs to run. + * + * @needs_cgroup_nsdelegate: If set test the will run only if cgroup2 is mounted + * with nsdelegate option. + */ + + struct tst_test { + unsigned int tcnt; + + struct tst_option *options; + + const char *min_kver; + + const char *const *supported_archs; + + const char *tconf_msg; + + unsigned int needs_tmpdir:1; + unsigned int needs_root:1; + unsigned int forks_child:1; + unsigned int needs_device:1; + unsigned int needs_checkpoints:1; + unsigned int needs_overlay:1; + unsigned int format_device:1; + unsigned int mount_device:1; + unsigned int needs_rofs:1; + unsigned int child_needs_reinit:1; + unsigned int runs_script:1; + unsigned int needs_devfs:1; + unsigned int restore_wallclock:1; + + unsigned int all_filesystems:1; + + unsigned int skip_in_lockdown:1; + unsigned int skip_in_secureboot:1; + unsigned int skip_in_compat:1; + + + int needs_abi_bits; + + unsigned int needs_hugetlbfs:1; + + const char *const *skip_filesystems; + + unsigned long min_cpus; + unsigned long min_mem_avail; + unsigned long min_swap_avail; + + struct tst_hugepage hugepages; + + unsigned int taint_check; + + unsigned int test_variants; + + unsigned int dev_min_size; + + struct tst_fs *filesystems; + + const char *mntpoint; + + int timeout; + int runtime; + int min_runtime; + + void (*setup)(void); + void (*cleanup)(void); + void (*test)(unsigned int test_nr); + void (*test_all)(void); + + const char *scall; + int (*sample)(int clk_id, long long usec); + + const char *const *resource_files; + const char * const *needs_drivers; + + const struct tst_path_val *save_restore; + + const struct tst_ulimit_val *ulimit; + + const char *const *needs_kconfigs; + + struct tst_buffers *bufs; + + struct tst_cap *caps; + + const struct tst_tag *tags; + + const char *const *needs_cmds; + + const enum tst_cg_ver needs_cgroup_ver; + + const char *const *needs_cgroup_ctrls; + + unsigned int needs_cgroup_nsdelegate:1; +}; + +/** + * tst_run_tcases() - Entry point to the test library. + * + * @argc: An argc that was passed to the main(). + * @argv: An argv that was passed to the main(). + * @self: The test description and callbacks packed in the struct tst_test + * structure. + * + * A main() function which calls this function is added to each test + * automatically by including the tst_test.h header. The test has to define the + * struct tst_test called test. + * + * This function does not return, i.e. calls exit() after the test has finished. + */ +void tst_run_tcases(int argc, char *argv[], struct tst_test *self) + __attribute__ ((noreturn)); + +#define IPC_ENV_VAR "LTP_IPC_PATH" + +/** + * tst_reinit() - Reinitialize the test library. + * + * In a cases where a test child process calls exec() it no longer can access + * the test library shared memory and therefore use the test reporting + * functions, checkpoint library, etc. This function re-initializes the test + * library so that it can be used again. + * + * @important The LTP_IPC_PATH variable must be passed to the program environment. + */ +void tst_reinit(void); + +/** + * tst_run_script() - Prepare the environment and execute a (shell) script. + * + * @script_name: A filename of the script. + * @params: A NULL terminated array of (shell) script parameters, pass NULL if + * none are needed. This what is passed starting from argv[1]. + * + * The (shell) script is executed with LTP_IPC_PATH in environment so that the + * binary helpers such as tst_res_ or tst_checkpoint work properly when executed + * from the script. This also means that the tst_test.runs_script flag needs to + * be set. + * + * A shell script has to source the tst_env.sh shell script at the start and + * after that it's free to use tst_res in the same way C code would use. + * + * Example shell script that reports success:: + * + * #!/bin/sh + * . tst_env.sh + * + * tst_res TPASS "Example test works" + * + * The call returns a pid in a case that you want to examine the return value + * of the script yourself. If you do not need to check the return value + * yourself you can use tst_reap_children() to wait for the completion. Or let + * the test library collect the child automatically, just be wary that the + * script and the test both runs concurently at the same time in this case. + * + * Return: A pid of the (shell) script process. + */ +int tst_run_script(const char *script_name, char *const params[]); + +/* + * Sets entire timeout in seconds. + */ +void tst_set_timeout(int timeout); + +unsigned int tst_multiply_timeout(unsigned int timeout); + +/* + * Returns remaining test runtime. Test that runs for more than a few seconds + * should check if they should exit by calling this function regularly. + * + * The function returns remaining runtime in seconds. If runtime was used up + * zero is returned. + */ +unsigned int tst_remaining_runtime(void); + +/* + * Sets maximal test runtime in seconds. + */ +void tst_set_runtime(int runtime); + +/* + * Create and open a random file inside the given dir path. + * It unlinks the file after opening and return file descriptor. + */ +int tst_creat_unlinked(const char *path, int flags, mode_t mode); + +/* + * Returns path to the test temporary directory root (TMPDIR). + */ +const char *tst_get_tmpdir_root(void); + +/* + * Validates exit status of child processes + */ +int tst_validate_children_(const char *file, const int lineno, + unsigned int count); +#define tst_validate_children(child_count) \ + tst_validate_children_(__FILE__, __LINE__, (child_count)) + +#ifndef TST_NO_DEFAULT_MAIN + +static struct tst_test test; + +int main(int argc, char *argv[]) +{ + tst_run_tcases(argc, argv, &test); +} + +#endif /* TST_NO_DEFAULT_MAIN */ + +/** + * TST_TEST_TCONF() - Exit tests with a TCONF message. + * + * @message: Error message (the reason to skip test). + * + * This macro is used in test that couldn't be compiled either because current + * CPU architecture is unsupported or because of missing development libraries. + */ +#define TST_TEST_TCONF(message) \ + static struct tst_test test = { .tconf_msg = message } \ + +#endif /* TST_TEST_H__ */ diff --git a/ltp/include/tst_test_macros.h b/ltp/include/tst_test_macros.h new file mode 100644 index 0000000000000000000000000000000000000000..be963ed94626ad430d880a032e7f5ff74b47b45e --- /dev/null +++ b/ltp/include/tst_test_macros.h @@ -0,0 +1,871 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015-2024 Cyril Hrubis + * Copyright (c) Linux Test Project, 2021-2024 + */ + +/** + * DOC: tst_test_macros.h -- helpers for testing syscalls + */ + +#ifndef TST_TEST_MACROS_H__ +#define TST_TEST_MACROS_H__ + +#include + +extern long TST_RET; +extern void *TST_RET_PTR; +extern int TST_ERR; +extern int TST_PASS; + +/** + * TEST() - Store syscall retval long and errno. + * + * @SCALL: Tested syscall e.g. write(fd, buf, len). + * + * This macro is a shortcut for storing an errno and a return value. The errno is + * cleared before the syscall is called and saved to a TST_ERR global variable + * right after the call returns. The return value is available in TST_RET + * global variable. + * + * The TST_ERR and TST_RET can be included into tst_res() messages with the + * TST_ERR and TTERRNO and TRERRNO flags. + * + * This macro is also used as a base for all the more specific variants e.g. + * TST_EXP_FAIL(). + */ +#define TEST(SCALL) \ + do { \ + errno = 0; \ + TST_RET = SCALL; \ + TST_ERR = errno; \ + } while (0) + +/** + * TESTPTR() - Store syscall retval pointer and errno. + * + * @SCALL: Tested syscall e.g. write(fd, buf, len). + * + * Sets TST_RET_PTR and TST_ERR. + * + * This is the same as TEST() macro the only difference is that the return + * value is a pointer which is stored into TST_RET_PTR instead. + */ +#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, SSCALL, ...) \ + ({ \ + TST_EXP_POSITIVE__(SCALL, SSCALL, ##__VA_ARGS__); \ + TST_RET; \ + }) + +/** + * TST_EXP_POSITIVE() - Test syscall, expect return value >= 0. + * + * @SCALL: Tested syscall. + * @...: A printf-like parameters. + * + * This macro calls the SCALL with a TEST() macro and additionaly prints pass + * or fail message. Apart from TST_ERR and TST_RET set by the TEST() macro + * TST_PASS global variable is set as well based on the outcome. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the first parameter + * is converted to a string and used instead. + */ +#define TST_EXP_POSITIVE(SCALL, ...) \ + ({ \ + TST_EXP_POSITIVE__(SCALL, #SCALL, ##__VA_ARGS__); \ + \ + if (TST_PASS) { \ + TST_MSGP_(TPASS, " returned %ld", \ + TST_RET, #SCALL, ##__VA_ARGS__); \ + } \ + \ + TST_RET; \ + }) + +/** + * TST_EXP_FD_SILENT() - Test syscall to return a file descriptor, silent variant. + * + * @SCALL: Tested syscall. + * @...: A printf-like parameters. + * + * Unlike TST_EXP_FD() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_FD_SILENT(SCALL, ...) TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__) + +/** + * TST_EXP_FD() - Test syscall to return a file descriptor. + * + * @SCALL: Tested syscall. + * @...: A printf-like parameters. + * + * This is a variant of the TST_EXP_POSSITIVE() for a more specific case that + * the returned value is a file descriptor. + */ +#define TST_EXP_FD(SCALL, ...) \ + ({ \ + TST_EXP_POSITIVE__(SCALL, #SCALL, ##__VA_ARGS__); \ + \ + if (TST_PASS) \ + TST_MSGP_(TPASS, " returned fd %ld", TST_RET, \ + #SCALL, ##__VA_ARGS__); \ + \ + TST_RET; \ + }) + +/** + * TST_EXP_FD_OR_FAIL() - Test syscall to return file descriptor or fail with + * expected errno. + * + * @SCALL: Tested syscall. + * @ERRNO: Expected errno or 0. + * @...: A printf-like parameters. + * + * Expect a file descriptor if errno is 0 otherwise expect a failure with + * expected errno. + * + * Internally it uses TST_EXP_FAIL() and TST_EXP_FD(). + */ +#define TST_EXP_FD_OR_FAIL(SCALL, ERRNO, ...) \ + ({ \ + if (ERRNO) \ + TST_EXP_FAIL(SCALL, ERRNO, ##__VA_ARGS__); \ + else \ + TST_EXP_FD(SCALL, ##__VA_ARGS__); \ + \ + TST_RET; \ + }) + +/** + * TST_EXP_PID_SILENT() - Test syscall to return PID, silent variant. + * + * @SCALL: Tested syscall. + * @...: A printf-like parameters. + * + * Unlike TST_EXP_PID() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_PID_SILENT(SCALL, ...) TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__) + +/** + * TST_EXP_PID() - Test syscall to return PID. + * + * @SCALL: Tested syscall. + * @...: A printf-like parameters. + * + * This is a variant of the TST_EXP_POSSITIVE() for a more specific case that + * the returned value is a pid. + */ +#define TST_EXP_PID(SCALL, ...) \ + ({ \ + TST_EXP_POSITIVE__(SCALL, #SCALL, ##__VA_ARGS__); \ + \ + if (TST_PASS) \ + TST_MSGP_(TPASS, " returned pid %ld", TST_RET, \ + #SCALL, ##__VA_ARGS__); \ + \ + TST_RET; \ + }) + +#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) + +/** + * TST_EXP_VAL_SILENT() - Test syscall to return specified value, silent variant. + * + * @SCALL: Tested syscall. + * @VAL: Expected return value. + * @...: A printf-like parameters. + * + * Unlike TST_EXP_VAL() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_VAL_SILENT(SCALL, VAL, ...) TST_EXP_VAL_SILENT_(SCALL, VAL, #SCALL, ##__VA_ARGS__) + +/** + * TST_EXP_VAL() - Test syscall to return specified value. + * + * @SCALL: Tested syscall. + * @VAL: Expected return value. + * @...: A printf-like parameters. + * + * This macro calls the SCALL with a TEST() macro and additionaly prints pass + * or fail message after comparing the returned value againts the expected + * value. Apart from TST_ERR and TST_RET set by the TEST() macro TST_PASS + * global variable is set as well based on the outcome. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the first parameter + * is converted to a string and used instead. + */ +#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_PTR_(SCALL, SSCALL, FAIL_PTR_VAL, ...) \ + do { \ + TESTPTR(SCALL); \ + \ + TST_PASS = 0; \ + \ + if (TST_RET_PTR == FAIL_PTR_VAL) { \ + 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) + +/** + * TST_EXP_PASS_SILENT() - Test syscall to return 0, silent variant. + * + * @SCALL: Tested syscall. + * @...: A printf-like parameters. + * + * Unlike TST_EXP_PASS() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_PASS_SILENT(SCALL, ...) TST_EXP_PASS_SILENT_(SCALL, #SCALL, ##__VA_ARGS__) + +/** + * TST_EXP_PASS() - Test syscall to return 0. + * + * @SCALL: Tested syscall. + * @...: A printf-like parameters. + * + * This macro calls the SCALL with a TEST() macro and additionaly prints pass + * or fail message after checking the return value againts zero. Apart from + * TST_ERR and TST_RET set by the TEST() macro TST_PASS global variable is set + * as well based on the outcome. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the first parameter + * is converted to a string and used instead. + */ +#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_PASS_PTR_(SCALL, SSCALL, FAIL_PTR_VAL, ...) \ + do { \ + TST_EXP_PASS_SILENT_PTR_(SCALL, SSCALL, \ + FAIL_PTR_VAL, ##__VA_ARGS__); \ + \ + if (TST_PASS) \ + TST_MSG_(TPASS, " passed", #SCALL, ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_PASS_PTR_VOID() - Test syscall to return a valid pointer. + * + * @SCALL: Tested syscall. + * @...: A printf-like parameters. + * + * This macro calls the SCALL with a TESTPTR() macro and additionaly prints + * pass or fail message after checking the return value against (void *)-1. + * Apart from TST_ERR and TST_RET_PTR set by the TESTPTR() macro TST_PASS + * global variable is set as well based on the outcome. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the first parameter + * is converted to a string and used instead. + */ +#define TST_EXP_PASS_PTR_VOID(SCALL, ...) \ + TST_EXP_PASS_PTR_(SCALL, #SCALL, (void *)-1, ##__VA_ARGS__); + +/* + * Returns true if err is in the exp_err array. + */ +bool tst_errno_in_set(int err, const int *exp_errs, int exp_errs_cnt); + +/* + * Fills in the buf with the errno names in the exp_err set. The buf must be at + * least 20 * exp_errs_cnt bytes long. + */ +const char *tst_errno_names(char *buf, const int *exp_errs, int exp_errs_cnt); + +#define TST_EXP_FAIL_SILENT_(PASS_COND, SCALL, SSCALL, ERRNOS, ERRNOS_CNT, ...)\ + 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_errno_in_set(TST_ERR, ERRNOS, ERRNOS_CNT)) { \ + TST_PASS = 1; \ + } else { \ + char tst_str_buf__[ERRNOS_CNT * 20]; \ + TST_MSGP_(TFAIL | TTERRNO, " expected %s", \ + tst_errno_names(tst_str_buf__, \ + ERRNOS, ERRNOS_CNT), \ + SSCALL, ##__VA_ARGS__); \ + } \ + } while (0) + +#define TST_EXP_FAIL_SILENT_PTR_(SCALL, SSCALL, FAIL_PTR_VAL, \ + ERRNOS, ERRNOS_CNT, ...) \ + do { \ + TESTPTR(SCALL); \ + \ + TST_PASS = 0; \ + \ + if (TST_RET_PTR != FAIL_PTR_VAL) { \ + TST_MSG_(TFAIL, " succeeded", SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + if (!tst_errno_in_set(TST_ERR, ERRNOS, ERRNOS_CNT)) { \ + char tst_str_buf__[ERRNOS_CNT * 20]; \ + TST_MSGP_(TFAIL | TTERRNO, " expected %s", \ + tst_errno_names(tst_str_buf__, \ + ERRNOS, ERRNOS_CNT), \ + SSCALL, ##__VA_ARGS__); \ + break; \ + } \ + \ + TST_PASS = 1; \ + \ + } while (0) + +#define TST_EXP_FAIL_PTR_(SCALL, SSCALL, FAIL_PTR_VAL, \ + ERRNOS, ERRNOS_CNT, ...) \ + do { \ + TST_EXP_FAIL_SILENT_PTR_(SCALL, SSCALL, FAIL_PTR_VAL, \ + ERRNOS, ERRNOS_CNT, ##__VA_ARGS__); \ + if (TST_PASS) \ + TST_MSG_(TPASS | TTERRNO, " ", SSCALL, ##__VA_ARGS__); \ + } while (0) + + +#define TST_EXP_FAIL_ARR_(SCALL, SSCALL, EXP_ERRS, EXP_ERRS_CNT, ...) \ + do { \ + TST_EXP_FAIL_SILENT_(TST_RET == 0, SCALL, SSCALL, \ + EXP_ERRS, EXP_ERRS_CNT, ##__VA_ARGS__); \ + if (TST_PASS) \ + TST_MSG_(TPASS | TTERRNO, " ", SSCALL, ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_FAIL() - Test syscall to fail with expected errno. + * + * @SCALL: Tested syscall. + * @EXP_ERR: Expected errno. + * @...: A printf-like parameters. + * + * This macro calls the SCALL with a TEST() macro and additionaly prints pass + * or fail message. The check passes if syscall has returned -1 and failed with + * the specified errno. + * + * The SCALL is supposed to return zero on success. For syscalls that return + * positive number on success TST_EXP_FAIL2() has to be used instead. + * + * Apart from TST_ERR and TST_RET set by the TEST() macro TST_PASS global + * variable is set as well based on the outcome. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the first parameter + * is converted to a string and used instead. + */ +#define TST_EXP_FAIL(SCALL, EXP_ERR, ...) \ + do { \ + int tst_exp_err__ = EXP_ERR; \ + TST_EXP_FAIL_ARR_(SCALL, #SCALL, &tst_exp_err__, 1, \ + ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_FAIL_ARR() - Test syscall to fail with expected errnos. + * + * @SCALL: Tested syscall. + * @EXP_ERRS: Array of expected errnos. + * @EXP_ERRS_CNT: Lenght of EXP_ERRS. + * @...: A printf-like parameters. + * + * This is a variant of TST_EXP_FAIL() with an array of possible errors. + */ +#define TST_EXP_FAIL_ARR(SCALL, EXP_ERRS, EXP_ERRS_CNT, ...) \ + TST_EXP_FAIL_ARR_(SCALL, #SCALL, EXP_ERRS, \ + EXP_ERRS_CNT, ##__VA_ARGS__); + +#define TST_EXP_FAIL2_ARR_(SCALL, SSCALL, EXP_ERRS, EXP_ERRS_CNT, ...) \ + do { \ + TST_EXP_FAIL_SILENT_(TST_RET >= 0, SCALL, SSCALL, \ + EXP_ERRS, EXP_ERRS_CNT, ##__VA_ARGS__); \ + if (TST_PASS) \ + TST_MSG_(TPASS | TTERRNO, " ", SSCALL, ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_FAIL2_ARR() - Test syscall to fail with expected errnos. + * + * @SCALL: Tested syscall. + * @EXP_ERRS: Array of expected errnos. + * @EXP_ERRS_CNT: Lenght of EXP_ERRS. + * @...: A printf-like parameters. + * + * This is a variant of TST_EXP_FAIL2() with an array of possible errors. + */ +#define TST_EXP_FAIL2_ARR(SCALL, EXP_ERRS, EXP_ERRS_CNT, ...) \ + TST_EXP_FAIL2_ARR_(SCALL, #SCALL, EXP_ERRS, \ + EXP_ERRS_CNT, ##__VA_ARGS__); + +/** + * TST_EXP_FAIL_PTR_NULL() - Test syscall to fail with expected errno and return a NULL pointer. + * + * @SCALL: Tested syscall. + * @EXP_ERR: Expected errno. + * @...: A printf-like parameters. + * + * This macro calls the SCALL with a TESTPTR() macro and additionaly prints + * pass or fail message after checking the return value against NULL and errno. + * + * Apart from TST_ERR and TST_RET_PTR set by the TESTPTR() macro TST_PASS + * global variable is set as well based on the outcome. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the first parameter + * is converted to a string and used instead. + */ +#define TST_EXP_FAIL_PTR_NULL(SCALL, EXP_ERR, ...) \ + do { \ + int tst_exp_err__ = EXP_ERR; \ + TST_EXP_FAIL_PTR_(SCALL, #SCALL, NULL, \ + &tst_exp_err__, 1, ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_FAIL_PTR_NULL_ARR() - Test syscall to fail with expected errnos and return a NULL pointer. + * + * @SCALL: Tested syscall. + * @EXP_ERRS: Array of expected errnos. + * @EXP_ERRS_CNT: Lenght of EXP_ERRS. + * @...: A printf-like parameters. + * + * This is a variant of TST_EXP_FAIL_PTR_NULL() with an array of possible + * errors. + */ +#define TST_EXP_FAIL_PTR_NULL_ARR(SCALL, EXP_ERRS, EXP_ERRS_CNT, ...) \ + TST_EXP_FAIL_PTR_(SCALL, #SCALL, NULL, \ + EXP_ERRS, EXP_ERRS_CNT, ##__VA_ARGS__); + + + +/** + * TST_EXP_FAIL_PTR_VOID() - Test syscall to fail with expected errno and return a (void *)-1 pointer. + * + * @SCALL: Tested syscall. + * @EXP_ERR: Expected errno. + * @...: A printf-like parameters. + * + * This macro calls the SCALL with a TESTPTR() macro and additionaly prints + * pass or fail message after checking the return value against (void *)-1 and + * errno. + * + * Apart from TST_ERR and TST_RET_PTR set by the TESTPTR() macro TST_PASS + * global variable is set as well based on the outcome. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the first parameter + * is converted to a string and used instead. + */ +#define TST_EXP_FAIL_PTR_VOID(SCALL, EXP_ERR, ...) \ + do { \ + int tst_exp_err__ = EXP_ERR; \ + TST_EXP_FAIL_PTR_(SCALL, #SCALL, (void *)-1, \ + &tst_exp_err__, 1, ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_FAIL_PTR_VOID_ARR() - Test syscall to fail with expected errnos and return a (void *)-1 pointer. + * + * @SCALL: Tested syscall. + * @EXP_ERRS: Array of expected errnos. + * @EXP_ERRS_CNT: Lenght of EXP_ERRS. + * @...: A printf-like parameters. + * + * This is a variant of TST_EXP_FAIL_PTR_VOID() with an array of possible + * errors. + */ +#define TST_EXP_FAIL_PTR_VOID_ARR(SCALL, EXP_ERRS, EXP_ERRS_CNT, ...) \ + TST_EXP_FAIL_PTR_(SCALL, #SCALL, (void *)-1, \ + EXP_ERRS, EXP_ERRS_CNT, ##__VA_ARGS__); + +/** + * TST_EXP_FAIL2() - Test syscall to fail with expected errno. + * + * @SCALL: Tested syscall. + * @EXP_ERR: Expected errno. + * @...: A printf-like parameters. + * + * This macro calls the SCALL with a TEST() macro and additionaly prints pass + * or fail message. The check passes if syscall has returned -1 and failed with + * the specified errno. + * + * The SCALL is supposed to return possitive number on success e.g. pid or file + * descriptor. For syscalls that return zero on success TST_EXP_FAIL() has to + * be used instead. + * + * Apart from TST_ERR and TST_RET set by the TEST() macro TST_PASS global + * variable is set as well based on the outcome. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the first parameter + * is converted to a string and used instead. + */ +#define TST_EXP_FAIL2(SCALL, EXP_ERR, ...) \ + do { \ + int tst_exp_err__ = EXP_ERR; \ + TST_EXP_FAIL2_ARR_(SCALL, #SCALL, &tst_exp_err__, 1, \ + ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_FAIL_SILENT() - Test syscall to fail with expected errno, silent variant. + * + * @SCALL: Tested syscall. + * @EXP_ERR: Expected errno. + * @...: A printf-like parameters. + * + * Unlike TST_EXP_FAIL() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_FAIL_SILENT(SCALL, EXP_ERR, ...) \ + do { \ + int tst_exp_err__ = EXP_ERR; \ + TST_EXP_FAIL_SILENT_(TST_RET == 0, SCALL, #SCALL, \ + &tst_exp_err__, 1, ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_FAIL2_SILENT() - Test syscall to fail with expected errno, silent variant. + * + * @SCALL: Tested syscall. + * @EXP_ERR: Expected errno. + * @...: A printf-like parameters. + * + * Unlike TST_EXP_FAIL2() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_FAIL2_SILENT(SCALL, EXP_ERR, ...) \ + do { \ + int tst_exp_err__ = EXP_ERR; \ + TST_EXP_FAIL_SILENT_(TST_RET >= 0, SCALL, #SCALL, \ + &tst_exp_err__, 1, ##__VA_ARGS__); \ + } while (0) + +/** + * TST_EXP_EXPR() - Check for expected expression. + * + * @EXPR: Expression to be tested. + * @...: A printf-like parameters. + * + * Reports a pass if expression evaluates to non-zero and a fail otherwise. + * + * The printf-like parameters can be optionally used to pass a description + * printed by the pass or fail tst_res() calls. If omitted the expression + * is converted to a string and used instead. + */ +#define TST_EXP_EXPR(EXPR, ...) \ + tst_res_(__FILE__, __LINE__, (EXPR) ? TPASS : TFAIL, "Expect: " \ + TST_FMT_(TST_2_(dummy, ##__VA_ARGS__, #EXPR), __VA_ARGS__)); + +#define TST_EXP_EQ_SILENT_(VAL_A, SVAL_A, VAL_B, SVAL_B, TYPE, PFS) do { \ + TYPE tst_tmp_a__ = VAL_A; \ + TYPE tst_tmp_b__ = VAL_B; \ + \ + TST_PASS = 0; \ + \ + if (tst_tmp_a__ != tst_tmp_b__) { \ + tst_res_(__FILE__, __LINE__, TFAIL, \ + SVAL_A " (" PFS ") != " SVAL_B " (" PFS ")", \ + tst_tmp_a__, tst_tmp_b__); \ + } else { \ + TST_PASS = 1; \ + } \ +} while (0) + +/** + * TST_EXP_EQ_LI() - Compare two long long values. + * + * @VAL_A: long long value A. + * @VAL_B: long long value B. + * + * Reports a pass if values are equal and a fail otherwise. + */ +#define TST_EXP_EQ_LI(VAL_A, VAL_B) do { \ + TST_EXP_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, long long, "%lli"); \ + \ + if (TST_PASS) { \ + tst_res_(__FILE__, __LINE__, TPASS, \ + #VAL_A " == " #VAL_B " (%lli)", \ + (long long)VAL_A); \ + } \ +} while (0) + +/** + * TST_EXP_EQ_LI_SILENT() - Compare two long long values, silent variant. + * + * @VAL_A: long long value A. + * @VAL_B: long long value B. + * + * Unlike TST_EXP_EQ_LI() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_EQ_LI_SILENT(VAL_A, VAL_B) \ + TST_EXP_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, long long, "%lli") + +/** + * TST_EXP_EQ_LU() - Compare two unsigned long long values. + * + * @VAL_A: unsigned long long value A. + * @VAL_B: unsigned long long value B. + * + * Reports a pass if values are equal and a fail otherwise. + */ +#define TST_EXP_EQ_LU(VAL_A, VAL_B) do { \ + TST_EXP_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, unsigned long long, "%llu"); \ + \ + if (TST_PASS) { \ + tst_res_(__FILE__, __LINE__, TPASS, \ + #VAL_A " == " #VAL_B " (%llu)", \ + (unsigned long long)VAL_A); \ + } \ +} while (0) + +/** + * TST_EXP_EQ_LU_SILENT() - Compare two unsigned long long values, silent variant. + * + * @VAL_A: unsigned long long value A. + * @VAL_B: unsigned long long value B. + * + * Unlike TST_EXP_EQ_LU() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_EQ_LU_SILENT(VAL_A, VAL_B) \ + TST_EXP_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, unsigned long long, "%llu") + +/** + * TST_EXP_EQ_SZ() - Compare two unsigned size_t values. + * + * @VAL_A: unsigned long long value A. + * @VAL_B: unsigned long long value B. + * + * Reports a pass if values are equal and a fail otherwise. + */ +#define TST_EXP_EQ_SZ(VAL_A, VAL_B) do { \ + TST_EXP_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, size_t, "%zu"); \ + \ + if (TST_PASS) { \ + tst_res_(__FILE__, __LINE__, TPASS, \ + #VAL_A " == " #VAL_B " (%zu)", \ + (size_t)VAL_A); \ + } \ +} while (0) + +/** + * TST_EXP_EQ_SZ_SILENT() - Compare two unsigned size_t values, silent variant. + * + * @VAL_A: unsigned long long value A. + * @VAL_B: unsigned long long value B. + * + * Unlike TST_EXP_EQ_SZ() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_EQ_SZ_SILENT(VAL_A, VAL_B) \ + TST_EXP_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, size_t, "%zu") + +/** + * TST_EXP_EQ_SSZ() - Compare two unsigned ssize_t values. + * + * @VAL_A: unsigned long long value A. + * @VAL_B: unsigned long long value B. + * + * Reports a pass if values are equal and a fail otherwise. + */ +#define TST_EXP_EQ_SSZ(VAL_A, VAL_B) do { \ + TST_EXP_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, size_t, "%zi"); \ + \ + if (TST_PASS) { \ + tst_res_(__FILE__, __LINE__, TPASS, \ + #VAL_A " == " #VAL_B " (%zi)", \ + (ssize_t)VAL_A); \ + } \ +} while (0) + +/** + * TST_EXP_EQ_SSZ_SILENT() - Compare two unsigned ssize_t values, silent variant. + * + * @VAL_A: unsigned long long value A. + * @VAL_B: unsigned long long value B. + * + * Unlike TST_EXP_EQ_SSZ() does not print :c:enum:`TPASS ` on + * success, only prints :c:enum:`TFAIL ` on failure. + */ +#define TST_EXP_EQ_SSZ_SILENT(VAL_A, VAL_B) \ + TST_EXP_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, ssize_t, "%zi") + +/** + * TST_EXP_EQ_STR() - Compare two strings. + * + * @STR_A: string to compare. + * @STR_B: string to compare. + * + * Reports a pass if strings are equal and a fail otherwise. + */ +#define TST_EXP_EQ_STR(STR_A, STR_B) do { \ + TST_PASS = strcmp(STR_A, STR_B) == 0; \ + \ + if (TST_PASS) { \ + tst_res_(__FILE__, __LINE__, TPASS, \ + "%s == %s (%s)", \ + #STR_A, #STR_B, STR_B); \ + } else { \ + tst_res_(__FILE__, __LINE__, TFAIL, \ + "%s (%s) != %s (%s)", \ + #STR_A, STR_A, #STR_B, STR_B); \ + } \ +} while (0) + +/** + * TST_EXP_EQ_STRN() - Compare two strings, providing length as well. + * + * @STR_A: string to compare. + * @STR_B: string to compare. + * @LEN: length of the string. + * + * Reports a pass if first LEN bytes of strings are equal and a fail otherwise. + */ +#define TST_EXP_EQ_STRN(STR_A, STR_B, LEN) do { \ + char str_a_cpy[LEN+1]; \ + \ + strncpy(str_a_cpy, STR_A, LEN); \ + str_a_cpy[LEN] = 0; \ + \ + TST_PASS = strncmp(STR_A, STR_B, LEN) == 0; \ + \ + if (TST_PASS) { \ + tst_res_(__FILE__, __LINE__, TPASS, \ + "%s == %s (%s)", \ + #STR_A, #STR_B, str_a_cpy); \ + } else { \ + char str_b_cpy[LEN+1]; \ + \ + strncpy(str_b_cpy, STR_B, LEN); \ + str_b_cpy[LEN] = 0; \ + \ + tst_res_(__FILE__, __LINE__, TFAIL, \ + "%s (%s) != %s (%s)", \ + #STR_A, str_a_cpy, #STR_B, str_b_cpy); \ + } \ +} while (0) + +#endif /* TST_TEST_MACROS_H__ */ diff --git a/ltp/include/tst_timer.h b/ltp/include/tst_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..6fb9400206b8a338a26da2f53900d88f1be34005 --- /dev/null +++ b/ltp/include/tst_timer.h @@ -0,0 +1,1077 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2015-2020 Cyril Hrubis + */ + + /* + + Timer - struct timespec conversion runtimes and easy to use functions to + measure elapsed time. + + */ + +#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" + +/* + * Converts timeval to microseconds. + */ +static inline long long tst_timeval_to_us(struct timeval t) +{ + return ((long long)t.tv_sec) * 1000000 + t.tv_usec; +} + +/* + * Converts timeval to milliseconds. + */ +static inline long long tst_timeval_to_ms(struct timeval t) +{ + return ((long long)t.tv_sec) * 1000 + (t.tv_usec + 500) / 1000; +} + +/* + * Converts milliseconds to struct timeval + */ +static inline struct timeval tst_ms_to_timeval(long long ms) +{ + struct timeval ret; + + ret.tv_sec = ms / 1000; + ret.tv_usec = (ms % 1000) * 1000; + + return ret; +} + +/* + * Converts microseconds to struct timeval + */ +static inline struct timeval tst_us_to_timeval(long long us) +{ + struct timeval ret; + + ret.tv_sec = us / 1000000; + ret.tv_usec = us % 1000000; + + return ret; +} + +/* + * Returns difference between two timeval structures. + */ +static inline struct timeval tst_timeval_diff(struct timeval t1, + struct timeval t2) +{ + struct timeval res; + + res.tv_sec = t1.tv_sec - t2.tv_sec; + + if (t1.tv_usec < t2.tv_usec) { + res.tv_sec--; + res.tv_usec = 1000000 - (t2.tv_usec - t1.tv_usec); + } else { + res.tv_usec = t1.tv_usec - t2.tv_usec; + } + + return res; +} + +static inline long long tst_timeval_diff_us(struct timeval t1, + struct timeval t2) +{ + return tst_timeval_to_us(tst_timeval_diff(t1, t2)); +} + +static inline long long tst_timeval_diff_ms(struct timeval t1, + struct timeval t2) +{ + return tst_timeval_to_ms(tst_timeval_diff(t1, t2)); +} + +#ifndef __kernel_timespec + +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 + +#ifndef HAVE_STRUCT___KERNEL_OLD_ITIMERVAL +struct __kernel_old_itimerval { + struct __kernel_old_timeval it_interval; /* timer interval */ + struct __kernel_old_timeval it_value; /* current value */ +}; +#endif +#endif + +enum tst_ts_type { + TST_LIBC_TIMESPEC, + TST_KERN_OLD_TIMESPEC, + TST_KERN_TIMESPEC +}; + +struct tst_ts { + enum tst_ts_type type; + union ts { + struct timespec libc_ts; + struct __kernel_old_timespec kern_old_ts; + struct __kernel_timespec kern_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) + return NULL; + + switch (t->type) { + case TST_LIBC_TIMESPEC: + return &t->ts.libc_ts; + case TST_KERN_OLD_TIMESPEC: + return &t->ts.kern_old_ts; + case TST_KERN_TIMESPEC: + return &t->ts.kern_ts; + default: + tst_brk(TBROK, "Invalid type: %d", t->type); + return NULL; + } +} + +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); +} + +static inline int sys_clock_getres(clockid_t clk_id, void *ts) +{ + return tst_syscall(__NR_clock_getres, clk_id, ts); +} + +static inline int sys_clock_getres64(clockid_t clk_id, void *ts) +{ + return tst_syscall(__NR_clock_getres_time64, clk_id, ts); +} + +static inline int libc_clock_gettime(clockid_t clk_id, void *ts) +{ + return clock_gettime(clk_id, ts); +} + +static inline int sys_clock_gettime(clockid_t clk_id, void *ts) +{ + return tst_syscall(__NR_clock_gettime, clk_id, ts); +} + +static inline int sys_clock_gettime64(clockid_t clk_id, void *ts) +{ + return tst_syscall(__NR_clock_gettime64, clk_id, ts); +} + +static inline int libc_clock_settime(clockid_t clk_id, void *ts) +{ + return clock_settime(clk_id, ts); +} + +static inline int sys_clock_settime(clockid_t clk_id, void *ts) +{ + return tst_syscall(__NR_clock_settime, clk_id, ts); +} + +static inline int sys_clock_settime64(clockid_t clk_id, void *ts) +{ + return tst_syscall(__NR_clock_settime64, clk_id, ts); +} + +static inline int libc_clock_nanosleep(clockid_t clk_id, int flags, + void *request, void *remain) +{ + return clock_nanosleep(clk_id, flags, request, remain); +} + +static inline int sys_clock_nanosleep(clockid_t clk_id, int flags, + void *request, void *remain) +{ + return tst_syscall(__NR_clock_nanosleep, clk_id, flags, + request, remain); +} + +static inline int sys_clock_nanosleep64(clockid_t clk_id, int flags, + void *request, void *remain) +{ + return tst_syscall(__NR_clock_nanosleep_time64, clk_id, 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); +} + +static inline int sys_setitimer(int which, void *new_value, void *old_value) +{ + return tst_syscall(__NR_setitimer, which, new_value, old_value); +} + +/* + * Returns tst_ts seconds. + */ +static inline long long tst_ts_get_sec(struct tst_ts ts) +{ + switch (ts.type) { + case TST_LIBC_TIMESPEC: + return ts.ts.libc_ts.tv_sec; + case TST_KERN_OLD_TIMESPEC: + return ts.ts.kern_old_ts.tv_sec; + case TST_KERN_TIMESPEC: + return ts.ts.kern_ts.tv_sec; + default: + tst_brk(TBROK, "Invalid type: %d", ts.type); + return -1; + } +} + +/* + * Returns tst_ts nanoseconds. + */ +static inline long long tst_ts_get_nsec(struct tst_ts ts) +{ + switch (ts.type) { + case TST_LIBC_TIMESPEC: + return ts.ts.libc_ts.tv_nsec; + case TST_KERN_OLD_TIMESPEC: + return ts.ts.kern_old_ts.tv_nsec; + case TST_KERN_TIMESPEC: + return ts.ts.kern_ts.tv_nsec; + default: + tst_brk(TBROK, "Invalid type: %d", ts.type); + return -1; + } +} + +/* + * Sets tst_ts seconds. + */ +static inline void tst_ts_set_sec(struct tst_ts *ts, long long sec) +{ + switch (ts->type) { + case TST_LIBC_TIMESPEC: + ts->ts.libc_ts.tv_sec = sec; + break; + case TST_KERN_OLD_TIMESPEC: + ts->ts.kern_old_ts.tv_sec = sec; + break; + case TST_KERN_TIMESPEC: + ts->ts.kern_ts.tv_sec = sec; + break; + default: + tst_brk(TBROK, "Invalid type: %d", ts->type); + } +} + +/* + * Sets tst_ts nanoseconds. + */ +static inline void tst_ts_set_nsec(struct tst_ts *ts, long long nsec) +{ + switch (ts->type) { + case TST_LIBC_TIMESPEC: + ts->ts.libc_ts.tv_nsec = nsec; + break; + case TST_KERN_OLD_TIMESPEC: + ts->ts.kern_old_ts.tv_nsec = nsec; + break; + case TST_KERN_TIMESPEC: + ts->ts.kern_ts.tv_nsec = nsec; + break; + default: + tst_brk(TBROK, "Invalid type: %d", ts->type); + } +} + +/* + * 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. + */ +static inline struct tst_ts tst_ts_from_timespec(struct timespec ts) +{ + struct tst_ts t = { + .type = TST_LIBC_TIMESPEC, + .ts.libc_ts.tv_sec = ts.tv_sec, + .ts.libc_ts.tv_nsec = ts.tv_nsec, + }; + + return t; +} + +/* + * Converst tst_ts into timespec. + */ +static inline struct timespec tst_ts_to_timespec(struct tst_ts t) +{ + return t.ts.libc_ts; +} + +/* + * Converts tst_ts to nanoseconds. + */ +static inline long long tst_ts_to_ns(struct tst_ts t) +{ + return tst_ts_get_sec(t) * 1000000000 + tst_ts_get_nsec(t); +} + +/* + * Converts tst_ts to microseconds and rounds the value. + */ +static inline long long tst_ts_to_us(struct tst_ts t) +{ + return tst_ts_get_sec(t) * 1000000 + + (tst_ts_get_nsec(t) + 500) / 1000; +} + +/* + * Converts timespec to microseconds and rounds the value. + */ +static inline long long tst_timespec_to_us(struct timespec ts) +{ + return tst_ts_to_us(tst_ts_from_timespec(ts)); +} + +/* + * Converts tst_ts to milliseconds and rounds the value. + */ +static inline long long tst_ts_to_ms(struct tst_ts t) +{ + return tst_ts_get_sec(t) * 1000 + + (tst_ts_get_nsec(t) + 500000) / 1000000; +} + +/* + * Converts timespec to milliseconds and rounds the value. + */ +static inline long long tst_timespec_to_ms(struct timespec ts) +{ + return tst_ts_to_ms(tst_ts_from_timespec(ts)); +} + +/* + * Converts nanoseconds to tst_ts + */ +static inline struct tst_ts +tst_ts_from_ns(enum tst_ts_type type, long long ns) +{ + struct tst_ts ret = {.type = type}; + + tst_ts_set_sec(&ret, ns / 1000000000); + tst_ts_set_nsec(&ret, ns % 1000000000); + + return ret; +} + +/* + * Converts microseconds to tst_ts + */ +static inline struct tst_ts +tst_ts_from_us(enum tst_ts_type type, long long us) +{ + struct tst_ts ret = {.type = type}; + + tst_ts_set_sec(&ret, us / 1000000); + tst_ts_set_nsec(&ret, (us % 1000000) * 1000); + + return ret; +} + +/* + * Converts microseconds to timespec + */ +static inline struct timespec +tst_timespec_from_us(long long us) +{ + return tst_ts_to_timespec(tst_ts_from_us(TST_LIBC_TIMESPEC, us)); +} + +/* + * Converts miliseconds to tst_ts + */ +static inline struct tst_ts +tst_ts_from_ms(enum tst_ts_type type, long long ms) +{ + struct tst_ts ret = {.type = type}; + + tst_ts_set_sec(&ret, ms / 1000); + tst_ts_set_nsec(&ret, (ms % 1000) * 1000000); + + return ret; +} + +/* + * Converts miliseconds to timespec + */ +static inline struct timespec +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. + */ +static inline int tst_ts_lt(struct tst_ts t1, struct tst_ts t2) +{ + if (tst_ts_get_sec(t1) == tst_ts_get_sec(t2)) + return tst_ts_get_nsec(t1) < tst_ts_get_nsec(t2); + + return tst_ts_get_sec(t1) < tst_ts_get_sec(t2); +} + +/* + * Returns if ts1 less than ts2. Both ts1 and ts2 must be normalized. + */ +static inline int tst_timespec_lt(struct timespec ts1, struct timespec ts2) +{ + return tst_ts_lt(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2)); +} + +/* + * Returns normalized tst_ts, i.e. 0 <= nsec < 1000000000. + */ +static inline struct tst_ts tst_ts_normalize(struct tst_ts t) +{ + long long sec = tst_ts_get_sec(t); + long long nsec = tst_ts_get_nsec(t); + + if (nsec >= 1000000000) { + tst_ts_set_sec(&t, sec + 1); + tst_ts_set_nsec(&t, nsec - 1000000000); + } + + if (nsec < 0) { + tst_ts_set_sec(&t, sec - 1); + tst_ts_set_nsec(&t, nsec + 1000000000); + } + + return t; +} + +/* + * Adds us microseconds to tst_ts. + */ +static inline struct tst_ts +tst_ts_add_us(struct tst_ts t, long long us) +{ + struct tst_ts res = {.type = t.type}; + + tst_ts_set_sec(&res, tst_ts_get_sec(t) + us / 1000000); + tst_ts_set_nsec(&res, tst_ts_get_nsec(t) + (us % 1000000) * 1000); + + return tst_ts_normalize(res); +} + +/* + * Adds us microseconds to struct timespec. + */ +static inline struct timespec +tst_timespec_add_us(struct timespec ts, long long us) +{ + struct tst_ts res; + + res = tst_ts_add_us(tst_ts_from_timespec(ts), us); + + return tst_ts_to_timespec(res); +} + +/* + * Substracts us microseconds from tst_ts. + */ +static inline struct tst_ts +tst_ts_sub_us(struct tst_ts t, long long us) +{ + struct tst_ts res = {.type = t.type}; + + tst_ts_set_sec(&res, tst_ts_get_sec(t) - us / 1000000); + tst_ts_set_nsec(&res, tst_ts_get_nsec(t) - (us % 1000000) * 1000); + + return tst_ts_normalize(res); +} + +/* + * Substracts us microseconds from timespec. + */ +static inline struct timespec +tst_timespec_sub_us(struct timespec ts, long long us) +{ + struct tst_ts res; + + res = tst_ts_sub_us(tst_ts_from_timespec(ts), us); + + return tst_ts_to_timespec(res); +} + +/* + * Adds two tst_ts structures. + */ +static inline struct tst_ts +tst_ts_add(struct tst_ts t1, struct tst_ts t2) +{ + struct tst_ts res = {.type = t1.type}; + + tst_ts_set_sec(&res, tst_ts_get_sec(t1) + tst_ts_get_sec(t2)); + tst_ts_set_nsec(&res, tst_ts_get_nsec(t1) + tst_ts_get_nsec(t2)); + + return tst_ts_normalize(res); +} + +/* + * Adds two timespec structures. + */ +static inline struct timespec +tst_timespec_add(struct timespec ts1, struct timespec ts2) +{ + struct tst_ts res; + + res = tst_ts_add(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2)); + + return tst_ts_to_timespec(res); +} + +/* + * Substract two tst_ts structures. + */ +static inline struct tst_ts +tst_ts_diff(struct tst_ts t1, struct tst_ts t2) +{ + struct tst_ts res = {.type = t1.type}; + + tst_ts_set_sec(&res, tst_ts_get_sec(t1) - tst_ts_get_sec(t2)); + tst_ts_set_nsec(&res, tst_ts_get_nsec(t1) - tst_ts_get_nsec(t2)); + + return tst_ts_normalize(res); +} + +/* + * Substract two timespec structures. + */ +static inline struct timespec +tst_timespec_diff(struct timespec ts1, struct timespec ts2) +{ + struct tst_ts res; + + res = tst_ts_diff(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2)); + + return tst_ts_to_timespec(res); +} + +/* + * Substract two tst_ts structures returns number of nanoseconds. + */ +static inline long long +tst_ts_diff_ns(struct tst_ts t1, struct tst_ts t2) +{ + return tst_ts_to_ns(tst_ts_diff(t1, t2)); +} + +/* + * Substract two timespec structures returns number of nanoseconds. + */ +static inline long long +tst_timespec_diff_ns(struct timespec ts1, struct timespec ts2) +{ + return tst_ts_diff_ns(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2)); +} + +/* + * Substract two tst_ts structures returns number of microseconds. + */ +static inline long long +tst_ts_diff_us(struct tst_ts t1, struct tst_ts t2) +{ + return tst_ts_to_us(tst_ts_diff(t1, t2)); +} + +/* + * Substract two timespec structures returns number of microseconds. + */ +static inline long long +tst_timespec_diff_us(struct timespec ts1, struct timespec ts2) +{ + return tst_ts_diff_us(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2)); +} + +/* + * Substract two tst_ts structures returns number of milliseconds. + */ +static inline long long +tst_ts_diff_ms(struct tst_ts t1, struct tst_ts t2) +{ + return tst_ts_to_ms(tst_ts_diff(t1, t2)); +} + +/* + * Substract two timespec structures returns number of milliseconds. + */ +static inline long long +tst_timespec_diff_ms(struct timespec ts1, struct timespec ts2) +{ + return tst_ts_diff_ms(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2)); +} + +/* + * Returns absolute value of difference between two timespec structures. + */ +static inline struct tst_ts +tst_ts_abs_diff(struct tst_ts t1, struct tst_ts t2) +{ + if (tst_ts_lt(t1, t2)) + return tst_ts_diff(t2, t1); + else + return tst_ts_diff(t1, t2); +} + +/* + * Returns absolute value of difference between two tst_ts structures in + * microseconds. + */ +static inline long long +tst_ts_abs_diff_us(struct tst_ts t1, struct tst_ts t2) +{ + return tst_ts_to_us(tst_ts_abs_diff(t1, t2)); +} + +/* + * Returns absolute value of difference between two timespec structures in + * microseconds. + */ +static inline long long +tst_timespec_abs_diff_us(struct timespec ts1, struct timespec ts2) +{ + return tst_ts_abs_diff_us(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2)); +} + +/* + * Returns absolute value of difference between two timespec structures in + * milliseconds. + */ +static inline long long +tst_ts_abs_diff_ms(struct tst_ts t1, struct tst_ts t2) +{ + return tst_ts_to_ms(tst_ts_abs_diff(t1, t2)); +} + +/* + * Exits the test with TCONF if particular timer is not supported. This is + * intended to be used in test setup. There is no cleanup callback parameter as + * you are expected to call it before initializing any resources that has to be + * cleaned up later. + * + * @clk_id: Posix clock to use. + */ +void tst_timer_check(clockid_t clk_id); + +/* + * Marks a start time for given clock type. + * + * @clk_id: Posix clock to use. + */ +void tst_timer_start(clockid_t clk_id); + +/* + * Returns true if timer started by tst_timer_start() has been running for + * longer than ms seconds. + * + * @ms: Time interval in milliseconds. + */ +int tst_timer_expired_ms(long long ms); + +/* + * Marks timer end time. + */ +void tst_timer_stop(void); + +/* + * Retuns elapsed time in struct timespec. + */ +struct timespec tst_timer_elapsed(void); + +/* + * Returns elapsed time in milliseconds. + */ +static inline long long tst_timer_elapsed_ms(void) +{ + return tst_timespec_to_ms(tst_timer_elapsed()); +} + +/* + * Returns elapsed time in microseconds. + */ +static inline long long tst_timer_elapsed_us(void) +{ + return tst_timespec_to_us(tst_timer_elapsed()); +} + +#endif /* TST_TIMER */ diff --git a/ltp/include/tst_timer_test.h b/ltp/include/tst_timer_test.h new file mode 100644 index 0000000000000000000000000000000000000000..b825a4d1aa4e125e8066419f6f0d46e763d1602d --- /dev/null +++ b/ltp/include/tst_timer_test.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + */ + + /* + + Timer measuring library. + + The test is supposed to define sampling function and set it in the tst_test + structure the rest of the work is then done by the library. + + int sample(int clk_id, long long usec) + { + // Any setup done here + + tst_timer_start(clk_id); + // Call that is being measured sleeps for usec + tst_timer_stop(); + tst_timer_sample(); + + // Any cleanup done here + + // Non-zero return exits the test + } + + struct tst_test test = { + .scall = "syscall_name()", + .sample = sample, + }; + + */ + +#ifndef TST_TIMER_TEST__ +#define TST_TIMER_TEST__ + +#include "tst_test.h" +#include "tst_timer.h" + +void tst_timer_sample(void); + +# ifdef TST_NO_DEFAULT_MAIN +struct tst_test *tst_timer_test_setup(struct tst_test *test); +# endif /* TST_NO_DEFAULT_MAIN */ +#endif /* TST_TIMER_TEST__ */ diff --git a/ltp/include/tst_tmpdir.h b/ltp/include/tst_tmpdir.h new file mode 100644 index 0000000000000000000000000000000000000000..85d70823318884f60490719de88dee17cbe55851 --- /dev/null +++ b/ltp/include/tst_tmpdir.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2024 Cyril Hrubis + * Copyright (c) 2020 Martin Doucha + */ + +#ifndef TST_TMPDIR_H__ +#define TST_TMPDIR_H__ + +/** + * tst_purge_dir - Wipe the content of given directory. + * + * Wipe the content of given directory but keep the directory itself. + * + * @path: Path of the directory to be wiped. + */ +void tst_purge_dir(const char *path); + +/** + * tst_tmpdir_path - Returns a pointer to a tmpdir path. + * + * The returned path is allocated and initialized the first time this function is + * called, each subsequent call will return the same pointer. + * + * return: A newly allocated path. The memory is freed automatically at the end + * of the test. If allocation fails the function calls tst_brk() and + * exits the test. + */ +char *tst_tmpdir_path(void); + +/** + * tst_tmpdir_genpath - Construct an absolute path pointing to a file inside tmpdir. + * + * Constructs a path inside tmpdir i.e. adds a prefix pointing to the current + * test tmpdir to the string build by the printf-like format. + * + * @fmt: A printf-like format string. + * @...: A printf-like parameter list. + * + * return: A newly allocated path. The memory is freed automatically at the end + * of the test. If allocation fails the function calls tst_brk() and exits the + * test. + */ +char *tst_tmpdir_genpath(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); + +/* + * Make sure nobody uses old API functions in new code. + */ +#ifndef LTPLIB +# define tst_get_tmpdir #error Use tst_tmpdir_path()! +#endif + +#endif /* TST_TMPDIR_H__ */ diff --git a/ltp/include/tst_tsc.h b/ltp/include/tst_tsc.h new file mode 100644 index 0000000000000000000000000000000000000000..3f49a6ca7e4d8fd06e8766162d9b79877e6a789a --- /dev/null +++ b/ltp/include/tst_tsc.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright © International Business Machines Corp., 2006-2008 + * + * AUTHOR + * Darren Hart + * Giuseppe Cavallaro + * + * HISTORY + * It directly comes from the librttest.h (see its HISTORY). + */ + +#ifndef TST_TSC_H +#define TST_TSC_H + +#undef TSC_UNSUPPORTED + +/* TSC macros */ +#if defined(__i386__) +#define rdtscll(val) __asm__ __volatile__("rdtsc" : "=A" (val)) +#elif defined(__x86_64__) +#define rdtscll(val) \ + do { \ + uint32_t low, high; \ + __asm__ __volatile__ ("rdtsc" : "=a" (low), "=d" (high)); \ + val = (uint64_t)high << 32 | low; \ + } while (0) +#elif defined(__powerpc__) +#if defined(__powerpc64__) /* 64bit version */ +#define rdtscll(val) \ + do { \ + __asm__ __volatile__ ("mfspr %0, 268" : "=r" (val)); \ + } while (0) +#else /*__powerpc__ 32bit version */ +#define rdtscll(val) \ + do { \ + uint32_t tbhi, tblo ; \ + __asm__ __volatile__ ("mftbu %0" : "=r" (tbhi)); \ + __asm__ __volatile__ ("mftbl %0" : "=r" (tblo)); \ + val = 1000 * ((uint64_t) tbhi << 32) | tblo; \ + } while (0) +#endif +#else +#warning TSC UNSUPPORTED +/* All tests will be compiled also for the + * architecture without TSC support (e.g. SH). + * At run-time these will fail with ENOTSUP. + */ +#define rdtscll(val) do { } while (0) +#define TSC_UNSUPPORTED +#endif + +#endif diff --git a/ltp/include/tst_uid.h b/ltp/include/tst_uid.h new file mode 100644 index 0000000000000000000000000000000000000000..e604effce9b281997e7f5cc7121ab3cd460d700c --- /dev/null +++ b/ltp/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/ltp/include/tst_uinput.h b/ltp/include/tst_uinput.h new file mode 100644 index 0000000000000000000000000000000000000000..cf351cdfbdb20f4837aab337b190ee5beeaa23af --- /dev/null +++ b/ltp/include/tst_uinput.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Cyril Hrubis + */ + +#ifndef TST_UINPUT_H__ +#define TST_UINPUT_H__ + +/** + * Tries to open the uinput device. + * + * Returns file descriptor on success, -1 on failure. + */ +int open_uinput(void); + +/** + * Creates virtual input device. + * + * @fd File descriptor returned by open_uinput(). + */ +void create_input_device(int fd); + +/** + * Parses /proc/bus/input/devices and returns the strings for our virtual device. + * If passing 'H' to it, it returns HANDLERS string. If passing 'S' to it, it + * returns SYSFS string. + * + * Returns newly allocated string, or NULL in a case of failure. + */ +char *get_input_field_value(char field); + +/** + * Sets up the virtual device to appear as a mouse, this must be called before + * the call to create_input_device(). + * + * @fd File descriptor as returned by open_uinput(). + */ +void setup_mouse_events(int fd); + +/** + * Destroys virtual input device. + * + * @fd File descriptor returned by open_uinput(). + */ +void destroy_input_device(int fd); + +#endif /* TST_UINPUT_H__ */ diff --git a/ltp/include/tst_wallclock.h b/ltp/include/tst_wallclock.h new file mode 100644 index 0000000000000000000000000000000000000000..1d142c5ca85547bc37068e7e78cd70fdbf3cfca4 --- /dev/null +++ b/ltp/include/tst_wallclock.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Linaro Limited. All rights reserved. + * Author: Rafael David Tinoco + */ + + +#ifndef TST_WALLCLK_H__ +#define TST_WALLCLK_H__ + +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/ltp/include/ujson.h b/ltp/include/ujson.h new file mode 100644 index 0000000000000000000000000000000000000000..8faeb18f0f3b5b33d6cbe430cc8cb1c3aa971ccc --- /dev/null +++ b/ltp/include/ujson.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2021-2024 Cyril Hrubis + */ + +#ifndef UJSON_H +#define UJSON_H + +#include +#include +#include + +#endif /* UJSON_H */ diff --git a/ltp/include/ujson_common.h b/ltp/include/ujson_common.h new file mode 100644 index 0000000000000000000000000000000000000000..ed31c090db61acd1e8631b22074760a5ffc1ff6f --- /dev/null +++ b/ltp/include/ujson_common.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2021-2024 Cyril Hrubis + */ + +/** + * @file ujson_common.h + * @brief Common JSON reader/writer definitions. + */ + +#ifndef UJSON_COMMON_H +#define UJSON_COMMON_H + +/** @brief Maximal error message length. */ +#define UJSON_ERR_MAX 128 +/** @brief Maximal id string lenght including terminating null element. */ +#define UJSON_ID_MAX 64 +/** @brief Maximal recursion depth allowed. */ +#define UJSON_RECURSION_MAX 128 + +#define UJSON_ERR_PRINT ujson_err_handler +#define UJSON_ERR_PRINT_PRIV stderr + +/** + * @brief A JSON data type. + */ +enum ujson_type { + /** @brief No type. Returned when parser finishes. */ + UJSON_VOID = 0, + /** @brief An integer. */ + UJSON_INT, + /** @brief A floating point. */ + UJSON_FLOAT, + /** @brief A boolean. */ + UJSON_BOOL, + /** @brief NULL */ + UJSON_NULL, + /** @brief A string. */ + UJSON_STR, + /** @brief A JSON object. */ + UJSON_OBJ, + /** @brief A JSON array. */ + UJSON_ARR, +}; + +/** + * @brief Returns type name. + * + * @param type A json type. + * @return A type name. + */ +const char *ujson_type_name(enum ujson_type type); + +/** + * @brief Default error print handler. + * + * @param print_priv A json buffer print_priv pointer. + * @param line A line of text to be printed. + */ +void ujson_err_handler(void *print_priv, const char *line); + +typedef struct ujson_reader ujson_reader; +typedef struct ujson_writer ujson_writer; +typedef struct ujson_val ujson_val; + +/** @brief An array size macro. */ +#define UJSON_ARRAY_SIZE(array) (sizeof(array) / sizeof(*array)) + +#endif /* UJSON_COMMON_H */ diff --git a/ltp/include/ujson_reader.h b/ltp/include/ujson_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..273fe624ab3a60989a4138c3803b2989a22ee2d5 --- /dev/null +++ b/ltp/include/ujson_reader.h @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2021-2024 Cyril Hrubis + */ + +/** + * @file ujson_reader.h + * @brief A recursive descend JSON parser. + * + * All the function that parse JSON return zero on success and non-zero on a + * failure. Once an error has happened all subsequent attempts to parse more + * return with non-zero exit status immediatelly. This is designed so that we + * can parse several values without checking each return value and only check + * if error has happened at the end of the sequence. + */ + +#ifndef UJSON_READER_H +#define UJSON_READER_H + +#include +#include + +/** + * @brief An ujson_reader initializer with default values. + * + * @param buf A pointer to a buffer with JSON data. + * @param buf_len A JSON data buffer lenght. + * @param rflags enum ujson_reader_flags. + * + * @return An ujson_reader initialized with default values. + */ +#define UJSON_READER_INIT(buf, buf_len, rflags) { \ + .max_depth = UJSON_RECURSION_MAX, \ + .err_print = UJSON_ERR_PRINT, \ + .err_print_priv = UJSON_ERR_PRINT_PRIV, \ + .json = buf, \ + .len = buf_len, \ + .flags = rflags \ +} + +/** @brief Reader flags. */ +enum ujson_reader_flags { + /** @brief If set warnings are treated as errors. */ + UJSON_READER_STRICT = 0x01, +}; + +/** + * @brief A JSON parser internal state. + */ +struct ujson_reader { + /** Pointer to a null terminated JSON string */ + const char *json; + /** A length of the JSON string */ + size_t len; + /** A current offset into the JSON string */ + size_t off; + /** An offset to the start of the last array or object */ + size_t sub_off; + /** Recursion depth increased when array/object is entered decreased on leave */ + unsigned int depth; + /** Maximal recursion depth */ + unsigned int max_depth; + + /** Reader flags. */ + enum ujson_reader_flags flags; + + /** Handler to print errors and warnings */ + void (*err_print)(void *err_print_priv, const char *line); + void *err_print_priv; + + char err[UJSON_ERR_MAX]; + char buf[]; +}; + +/** + * @brief An ujson_val initializer. + * + * @param sbuf A pointer to a buffer used for string values. + * @param sbuf_size A length of the buffer used for string values. + * + * @return An ujson_val initialized with default values. + */ +#define UJSON_VAL_INIT(sbuf, sbuf_size) { \ + .buf = sbuf, \ + .buf_size = sbuf_size, \ +} + +/** + * @brief A parsed JSON key value pair. + */ +struct ujson_val { + /** + * @brief A value type + * + * UJSON_VALUE_VOID means that no value was parsed. + */ + enum ujson_type type; + + /** An user supplied buffer and size to store a string values to. */ + char *buf; + size_t buf_size; + + /** + * @brief An index to attribute list. + * + * This is set by the ujson_obj_first_filter() and + * ujson_obj_next_filter() functions. + */ + size_t idx; + + /** An union to store the parsed value into. */ + union { + /** @brief A boolean value. */ + int val_bool; + /** @brief An integer value. */ + long long val_int; + /** @brief A string value. */ + const char *val_str; + }; + + /** + * @brief A floating point value. + * + * Since integer values are subset of floating point values val_float + * is always set when val_int was set. + */ + double val_float; + + /** @brief An ID for object values */ + char id[UJSON_ID_MAX]; + + char buf__[]; +}; + +/** + * @brief Allocates a JSON value. + * + * @param buf_size A maximal buffer size for a string value, pass 0 for default. + * @return A newly allocated JSON value. + */ +ujson_val *ujson_val_alloc(size_t buf_size); + +/** + * @brief Frees a JSON value. + * + * @param self A JSON value previously allocated by ujson_val_alloc(). + */ +void ujson_val_free(ujson_val *self); + +/** + * @brief Checks is result has valid type. + * + * @param res An ujson value. + * @return Zero if result is not valid, non-zero otherwise. + */ +static inline int ujson_val_valid(struct ujson_val *res) +{ + return !!res->type; +} + +/** + * @brief Fills the reader error. + * + * Once buffer error is set all parsing functions return immediatelly with type + * set to UJSON_VOID. + * + * @param self An ujson_reader + * @param fmt A printf like format string + * @param ... A printf like parameters + */ +void ujson_err(ujson_reader *self, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); + +/** + * @brief Prints error stored in the buffer. + * + * The error takes into consideration the current offset in the buffer and + * prints a few preceding lines along with the exact position of the error. + * + * The error is passed to the err_print() handler. + * + * @param self A ujson_reader + */ +void ujson_err_print(ujson_reader *self); + +/** + * @brief Prints a warning. + * + * Uses the print handler in the buffer to print a warning along with a few + * lines of context from the JSON at the current position. + * + * @param self A ujson_reader + * @param fmt A printf-like error string. + * @param ... A printf-like parameters. + */ +void ujson_warn(ujson_reader *self, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); + +/** + * @brief Returns true if error was encountered. + * + * @param self A ujson_reader + * @return True if error was encountered false otherwise. + */ +static inline int ujson_reader_err(ujson_reader *self) +{ + return !!self->err[0]; +} + +/** + * @brief Returns the type of next element in buffer. + * + * @param self An ujson_reader + * @return A type of next element in the buffer. + */ +enum ujson_type ujson_next_type(ujson_reader *self); + +/** + * @brief Returns if first element in JSON is object or array. + * + * @param self A ujson_reader + * @return On success returns UJSON_OBJ or UJSON_ARR. On failure UJSON_VOID. + */ +enum ujson_type ujson_reader_start(ujson_reader *self); + +/** + * @brief Starts parsing of a JSON object. + * + * @param self An ujson_reader + * @param res An ujson_val to store the parsed value to. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_obj_first(ujson_reader *self, struct ujson_val *res); + +/** + * @brief Parses next value from a JSON object. + * + * If the res->type is UJSON_OBJ or UJSON_ARR it has to be parsed or skipped + * before next call to this function. + * + * @param self An ujson_reader. + * @param res A ujson_val to store the parsed value to. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_obj_next(ujson_reader *self, struct ujson_val *res); + +/** + * @brief A loop over a JSON object. + * + * @code + * UJSON_OBJ_FOREACH(reader, val) { + * printf("Got value id '%s' type '%s'", val->id, ujson_type_name(val->type)); + * ... + * } + * @endcode + * + * @param self An ujson_reader. + * @param res An ujson_val to store the next parsed value to. + */ +#define UJSON_OBJ_FOREACH(self, res) \ + for (ujson_obj_first(self, res); ujson_val_valid(res); ujson_obj_next(self, res)) + +/** + * @brief Utility function for log(n) lookup in a sorted array. + * + * @param list Analphabetically sorted array. + * @param list_len Array length. + * + * @return An array index or (size_t)-1 if key wasn't found. + */ +size_t ujson_lookup(const void *arr, size_t memb_size, size_t list_len, + const char *key); + +/** + * @brief A JSON object attribute description i.e. key and type. + */ +typedef struct ujson_obj_attr { + /** @brief A JSON object key name. */ + const char *key; + /** + * @brief A JSON object value type. + * + * Note that because integer numbers are subset of floating point + * numbers if requested type was UJSON_FLOAT it will match if parsed + * type was UJSON_INT and the val_float will be set in addition to + * val_int. + */ + enum ujson_type type; +} ujson_obj_attr; + +/** @brief A JSON object description */ +typedef struct ujson_obj { + /** + * @brief A list of attributes. + * + * Attributes we are looking for, the parser sets the val->idx for these. + */ + const ujson_obj_attr *attrs; + /** @brief A size of attrs array. */ + size_t attr_cnt; +} ujson_obj; + +static inline size_t ujson_obj_lookup(const ujson_obj *obj, const char *key) +{ + return ujson_lookup(obj->attrs, sizeof(*obj->attrs), obj->attr_cnt, key); +} + +/** @brief An ujson_obj_attr initializer. */ +#define UJSON_OBJ_ATTR(keyv, typev) \ + {.key = keyv, .type = typev} + +/** @brief An ujson_obj_attr intializer with an array index. */ +#define UJSON_OBJ_ATTR_IDX(key_idx, keyv, typev) \ + [key_idx] = {.key = keyv, .type = typev} + +/** + * @brief Starts parsing of a JSON object with attribute lists. + * + * @param self An ujson_reader. + * @param res An ujson_val to store the parsed value to. + * @param obj An ujson_obj object description. + * @param ign A list of keys to ignore. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_obj_first_filter(ujson_reader *self, struct ujson_val *res, + const struct ujson_obj *obj, const struct ujson_obj *ign); + +/** + * @brief An empty object attribute list. + * + * To be passed to UJSON_OBJ_FOREACH_FITLER() as ignore list. + */ +extern const struct ujson_obj *ujson_empty_obj; + +/** + * @brief Parses next value from a JSON object with attribute lists. + * + * If the res->type is UJSON_OBJ or UJSON_ARR it has to be parsed or skipped + * before next call to this function. + * + * @param self An ujson_reader. + * @param res An ujson_val to store the parsed value to. + * @param obj An ujson_obj object description. + * @param ign A list of keys to ignore. If set to NULL all unknown keys are + * ignored, if set to ujson_empty_obj all unknown keys produce warnings. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_obj_next_filter(ujson_reader *self, struct ujson_val *res, + const struct ujson_obj *obj, const struct ujson_obj *ign); + +/** + * @brief A loop over a JSON object with a pre-defined list of expected attributes. + * + * @code + * static struct ujson_obj_attr attrs[] = { + * UJSON_OBJ_ATTR("bool", UJSON_BOOL), + * UJSON_OBJ_ATTR("number", UJSON_INT), + * }; + * + * static struct ujson_obj obj = { + * .attrs = filter_attrs, + * .attr_cnt = UJSON_ARRAY_SIZE(filter_attrs) + * }; + * + * UJSON_OBJ_FOREACH_FILTER(reader, val, &obj, NULL) { + * printf("Got value id '%s' type '%s'", + * attrs[val->idx].id, ujson_type_name(val->type)); + * ... + * } + * @endcode + * + * @param self An ujson_reader. + * @param res An ujson_val to store the next parsed value to. + * @param obj An ujson_obj with a description of attributes to parse. + * @param ign An ujson_obj with a description of attributes to ignore. + */ +#define UJSON_OBJ_FOREACH_FILTER(self, res, obj, ign) \ + for (ujson_obj_first_filter(self, res, obj, ign); \ + ujson_val_valid(res); \ + ujson_obj_next_filter(self, res, obj, ign)) + +/** + * @brief Skips parsing of a JSON object. + * + * @param self An ujson_reader. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_obj_skip(ujson_reader *self); + +/** + * @brief Starts parsing of a JSON array. + * + * @param self An ujson_reader. + * @param res An ujson_val to store the parsed value to. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_arr_first(ujson_reader *self, struct ujson_val *res); + +/** + * @brief Parses next value from a JSON array. + * + * If the res->type is UJSON_OBJ or UJSON_ARR it has to be parsed or skipped + * before next call to this function. + * + * @param self An ujson_reader. + * @param res An ujson_val to store the parsed value to. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_arr_next(ujson_reader *self, struct ujson_val *res); + +/** + * @brief A loop over a JSON array. + * + * @code + * UJSON_ARR_FOREACH(reader, val) { + * printf("Got value type '%s'", ujson_type_name(val->type)); + * ... + * } + * @endcode + * + * @param self An ujson_reader. + * @param res An ujson_val to store the next parsed value to. + */ +#define UJSON_ARR_FOREACH(self, res) \ + for (ujson_arr_first(self, res); ujson_val_valid(res); ujson_arr_next(self, res)) + +/** + * @brief Skips parsing of a JSON array. + * + * @param self A ujson_reader. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_arr_skip(ujson_reader *self); + +/** + * @brief A JSON reader state. + */ +typedef struct ujson_reader_state { + size_t off; + unsigned int depth; +} ujson_reader_state; + +/** + * @brief Returns a parser state at the start of current object/array. + * + * This function could be used for the parser to return to the start of the + * currently parsed object or array. + * + * @param self A ujson_reader + * @return A state that points to a start of the last object or array. + */ +static inline ujson_reader_state ujson_reader_state_save(ujson_reader *self) +{ + struct ujson_reader_state ret = { + .off = self->sub_off, + .depth = self->depth, + }; + + return ret; +} + +/** + * @brief Returns the parser to a saved state. + * + * This function could be used for the parser to return to the start of + * object or array saved by t the ujson_reader_state_get() function. + * + * @param self A ujson_reader + * @param state An parser state as returned by the ujson_reader_state_get(). + */ +static inline void ujson_reader_state_load(ujson_reader *self, ujson_reader_state state) +{ + if (ujson_reader_err(self)) + return; + + self->off = state.off; + self->sub_off = state.off; + self->depth = state.depth; +} + +/** + * @brief Resets the parser to a start. + * + * @param self A ujson_reader + */ +static inline void ujson_reader_reset(ujson_reader *self) +{ + self->off = 0; + self->sub_off = 0; + self->depth = 0; + self->err[0] = 0; +} + +/** + * @brief Loads a file into an ujson_reader buffer. + * + * The reader has to be later freed by ujson_reader_free(). + * + * @param path A path to a file. + * @return A ujson_reader or NULL in a case of a failure. + */ +ujson_reader *ujson_reader_load(const char *path); + +/** + * @brief Frees an ujson_reader buffer. + * + * @param self A ujson_reader allocated by ujson_reader_load() function. + */ +void ujson_reader_free(ujson_reader *self); + +/** + * @brief Prints errors and warnings at the end of parsing. + * + * Checks if self->err is set and prints the error with ujson_reader_err() + * + * Checks if there is any text left after the parser has finished with + * ujson_reader_consumed() and prints a warning if there were any non-whitespace + * characters left. + * + * @param self A ujson_reader + */ +void ujson_reader_finish(ujson_reader *self); + +/** + * @brief Returns non-zero if whole buffer has been consumed. + * + * @param self A ujson_reader. + * @return Non-zero if whole buffer was consumed. + */ +static inline int ujson_reader_consumed(ujson_reader *self) +{ + return self->off >= self->len; +} + +#endif /* UJSON_H */ diff --git a/ltp/include/ujson_utf.h b/ltp/include/ujson_utf.h new file mode 100644 index 0000000000000000000000000000000000000000..f939fbe8c276c954ab53170ed2beb63c718e213e --- /dev/null +++ b/ltp/include/ujson_utf.h @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2022-2024 Cyril Hrubis + */ + +/** + * @file ujson_utf.h + * @brief Unicode helper macros and functions. + */ + +#ifndef UJSON_UTF_H +#define UJSON_UTF_H + +#include +#include + +/** Returns true if unicode byte is ASCII */ +#define UJSON_UTF8_IS_ASCII(ch) (!((ch) & 0x80)) +/** Returns true if we have first unicode byte of single byte sequence */ +#define UJSON_UTF8_IS_NBYTE(ch) (((ch) & 0xc0) == 0x80) +/** Returns true if we have first unicode byte of two byte sequence */ +#define UJSON_UTF8_IS_2BYTE(ch) (((ch) & 0xe0) == 0xc0) +/** Returns true if we have first unicode byte of three byte sequence */ +#define UJSON_UTF8_IS_3BYTE(ch) (((ch) & 0xf0) == 0xe0) +/** Returns true if we have first unicode byte of four byte sequence */ +#define UJSON_UTF8_IS_4BYTE(ch) (((ch) & 0xf8) == 0xf0) + +#define UJSON_UTF8_NBYTE_MASK 0x3f + +/** + * @brief Parses next unicode character in UTF-8 string. + * @param str A pointer to the C string. + * @return A unicode character or 0 on error or end of the string. + */ +static inline uint32_t ujson_utf8_next(const char **str) +{ + uint32_t s0 = *str[0]; + + (*str)++; + + if (UJSON_UTF8_IS_ASCII(s0)) + return s0; + + uint32_t s1 = *str[0]; + + if (!UJSON_UTF8_IS_NBYTE(s1)) + return 0; + + s1 &= UJSON_UTF8_NBYTE_MASK; + + (*str)++; + + if (UJSON_UTF8_IS_2BYTE(s0)) + return (s0 & 0x1f)<<6 | s1; + + uint32_t s2 = *str[0]; + + if (!UJSON_UTF8_IS_NBYTE(s2)) + return 0; + + s2 &= UJSON_UTF8_NBYTE_MASK; + + (*str)++; + + if (UJSON_UTF8_IS_3BYTE(s0)) + return (s0 & 0x0f)<<12 | s1<<6 | s2; + + (*str)++; + + uint32_t s3 = *str[0]; + + if (!UJSON_UTF8_IS_NBYTE(s2)) + return 0; + + s3 &= UJSON_UTF8_NBYTE_MASK; + + if (UJSON_UTF8_IS_4BYTE(s0)) + return (s0 & 0x07)<<18 | s1<<12 | s2<<6 | s3; + + return 0; +} + +/** + * @brief Returns number of bytes next character is occupying in an UTF-8 string. + * + * @param str A pointer to a string. + * @param off An offset into the string, must point to a valid multibyte boundary. + * @return Number of bytes next character occupies, zero on string end and -1 on failure. + */ +int8_t ujson_utf8_next_chsz(const char *str, size_t off); + +/** + * @brief Returns number of bytes previous character is occupying in an UTF-8 string. + * + * @param str A pointer to a string. + * @param off An offset into the string, must point to a valid multibyte boundary. + * @return Number of bytes previous character occupies, and -1 on failure. + */ +int8_t ujson_utf8_prev_chsz(const char *str, size_t off); + +/** + * @brief Returns a number of characters in UTF-8 string. + * + * Returns number of characters in an UTF-8 string, which may be less or equal + * to what strlen() reports. + * + * @param str An UTF-8 string. + * @return Number of characters in the string. + */ +size_t ujson_utf8_strlen(const char *str); + +/** + * @brief Returns a number of bytes needed to store unicode character into UTF-8. + * + * @param unicode A unicode character. + * @return Number of utf8 bytes required to store a unicode character. + */ +static inline unsigned int ujson_utf8_bytes(uint32_t unicode) +{ + if (unicode < 0x0080) + return 1; + + if (unicode < 0x0800) + return 2; + + if (unicode < 0x10000) + return 3; + + return 4; +} + +/** + * @brief Writes an unicode character into a UTF-8 buffer. + * + * The buffer _must_ be large enough! + * + * @param unicode A unicode character. + * @param buf A byte buffer. + * @return A number of bytes written. + */ +static inline int ujson_to_utf8(uint32_t unicode, char *buf) +{ + if (unicode < 0x0080) { + buf[0] = unicode & 0x007f; + return 1; + } + + if (unicode < 0x0800) { + buf[0] = 0xc0 | (0x1f & (unicode>>6)); + buf[1] = 0x80 | (0x3f & unicode); + return 2; + } + + if (unicode < 0x10000) { + buf[0] = 0xe0 | (0x0f & (unicode>>12)); + buf[1] = 0x80 | (0x3f & (unicode>>6)); + buf[2] = 0x80 | (0x3f & unicode); + return 3; + } + + buf[0] = 0xf0 | (0x07 & (unicode>>18)); + buf[1] = 0x80 | (0x3f & (unicode>>12)); + buf[2] = 0x80 | (0x3f & (unicode>>6)); + buf[3] = 0x80 | (0x3f & unicode); + return 4; +} + +#endif /* UJSON_UTF_H */ diff --git a/ltp/include/ujson_writer.h b/ltp/include/ujson_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..dfcc95053ff7bf4632de2468fc8016fae00b9c28 --- /dev/null +++ b/ltp/include/ujson_writer.h @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2021-2024 Cyril Hrubis + */ + +/** + * @file ujson_writer.h + * @brief A JSON writer. + * + * All the function that add values return zero on success and non-zero on a + * failure. Once an error has happened all subsequent attempts to add more + * values return with non-zero exit status immediatelly. This is designed + * so that we can add several values without checking each return value + * and only check if error has happened at the end of the sequence. + * + * Failures may occur: + * - if we call the functions out of order, e.g. attempt to finish array when + * we are not writing out an array. + * - if we run out of recursion stack + * - may be propagated from the writer function, e.g. allocation failure, no + * space on disk, etc. + */ + +#ifndef UJSON_WRITER_H +#define UJSON_WRITER_H + +#include + +/** @brief A JSON writer */ +struct ujson_writer { + unsigned int depth; + char depth_type[UJSON_RECURSION_MAX/8]; + char depth_first[UJSON_RECURSION_MAX/8]; + + /** Handler to print errors and warnings */ + void (*err_print)(void *err_print_priv, const char *line); + void *err_print_priv; + char err[UJSON_ERR_MAX]; + + /** Handler to produce JSON output */ + int (*out)(struct ujson_writer *self, const char *buf, size_t buf_size); + void *out_priv; +}; + +/** + * @brief An ujson_writer initializer with default values. + * + * @param vout A pointer to function to write out the data. + * @param vout_priv An user pointer passed to the out function. + * + * @return An ujson_writer initialized with default values. + */ +#define UJSON_WRITER_INIT(vout, vout_priv) { \ + .err_print = UJSON_ERR_PRINT, \ + .err_print_priv = UJSON_ERR_PRINT_PRIV, \ + .out = vout, \ + .out_priv = vout_priv \ +} + +/** + * @brief Allocates a JSON file writer. + * + * The call may fail either when file cannot be opened for writing or if + * allocation has failed. In all cases errno should be set correctly. + * + * @param path A path to the file, file is opened for writing and created if it + * does not exist. + * + * @return A ujson_writer pointer or NULL in a case of failure. + */ +ujson_writer *ujson_writer_file_open(const char *path); + +/** + * @brief Closes and frees a JSON file writer. + * + * @param self A ujson_writer file writer. + * + * @return Zero on success, non-zero on a failure and errno is set. + */ +int ujson_writer_file_close(ujson_writer *self); + +/** + * @brief Returns true if writer error happened. + * + * @param self A JSON writer. + * + * @return True if error has happened. + */ +static inline int ujson_writer_err(ujson_writer *self) +{ + return !!self->err[0]; +} + +/** + * @brief Starts a JSON object. + * + * For a top level object the id must be NULL, every other object has to have + * non-NULL id. The call will also fail if maximal recursion depth + * UJSON_RECURSION_MAX has been reached. + * + * @param self A JSON writer. + * @param id An object name. + * + * @return Zero on a success, non-zero otherwise. + */ +int ujson_obj_start(ujson_writer *self, const char *id); + +/** + * @brief Finishes a JSON object. + * + * The call will fail if we are currenlty not writing out an object. + * + * @param self A JSON writer. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_obj_finish(ujson_writer *self); + +/** + * @brief Starts a JSON array. + * + * For a top level array the id must be NULL, every other array has to have + * non-NULL id. The call will also fail if maximal recursion depth + * UJSON_RECURSION_MAX has been reached. + * + * @param self A JSON writer. + * @param id An array name. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_arr_start(ujson_writer *self, const char *id); + +/** + * @brief Finishes a JSON array. + * + * The call will fail if we are currenlty not writing out an array. + * + * @param self A JSON writer. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_arr_finish(ujson_writer *self); + +/** + * @brief Adds a null value. + * + * The id must be NULL inside of an array, and must be non-NULL inside of an + * object. + * + * @param self A JSON writer. + * @param id A null value name. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_null_add(ujson_writer *self, const char *id); + +/** + * @brief Adds an integer value. + * + * The id must be NULL inside of an array, and must be non-NULL inside of an + * object. + * + * @param self A JSON writer. + * @param id An integer value name. + * @param val An integer value. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_int_add(ujson_writer *self, const char *id, long val); + +/** + * @brief Adds a bool value. + * + * The id must be NULL inside of an array, and must be non-NULL inside of an + * object. + * + * @param self A JSON writer. + * @param id An boolean value name. + * @param val A boolean value. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_bool_add(ujson_writer *self, const char *id, int val); + +/** + * @brief Adds a float value. + * + * The id must be NULL inside of an array, and must be non-NULL inside of an + * object. + * + * @param self A JSON writer. + * @param id A floating point value name. + * @param val A floating point value. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_float_add(ujson_writer *self, const char *id, double val); + +/** + * @brief Adds a string value. + * + * The id must be NULL inside of an array, and must be non-NULL inside of an + * object. + * + * @param self A JSON writer. + * @param id A string value name. + * @param str An UTF8 string value. + * + * @return Zero on success, non-zero otherwise. + */ +int ujson_str_add(ujson_writer *self, const char *id, const char *str); + +/** + * @brief Finalizes json writer. + * + * Finalizes the json writer, throws possible errors through the error printing + * function. + * + * @param self A JSON writer. + * @return Overall error value. + */ +int ujson_writer_finish(ujson_writer *self); + +#endif /* UJSON_WRITER_H */ diff --git a/ltp/lib/.gitignore b/ltp/lib/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..eb9901169dd5251d748a86ec652e326914fb919c --- /dev/null +++ b/ltp/lib/.gitignore @@ -0,0 +1,3 @@ +/ltp-version.h +/cached-version +/ltp.pc diff --git a/ltp/lib/Makefile b/ltp/lib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..67169f1493314c7b842c4a3f1e26d4b1add92492 --- /dev/null +++ b/ltp/lib/Makefile @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk + +CFLAGS += -I. -DLTPLIB + +ifneq ($(ANDROID),1) +FILTER_OUT_DIRS += android_libpthread android_librt +else +FILTER_OUT_LIBSRCS += tlibio.c tst_safe_sysv_ipc.c +endif + +INTERNAL_LIB := libltp.a + +pc_file := $(DESTDIR)/$(datarootdir)/pkgconfig/ltp.pc + +INSTALL_TARGETS := $(pc_file) + +tst_test.o: ltp-version.h + +ltp-version.h: gen_version + +MAKE_TARGETS += gen_version + +.PHONY: gen_version +gen_version: + @echo GEN ltp-version.h + @$(top_srcdir)/lib/gen_version.sh + +CLEAN_TARGETS += ltp-version.h cached-version + +$(pc_file): + test -d "$(@D)" || mkdir -p "$(@D)" + install -m $(INSTALL_MODE) "$(builddir)/$(@F)" "$@" + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_trunk_target.mk diff --git a/ltp/lib/README.md b/ltp/lib/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8340de0dd41b46e45cefc54405d7a66b673f5e69 --- /dev/null +++ b/ltp/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 '.needs\_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 continues 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 initializes shared 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 +a heartbeat signal handler and it 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 the reverse 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 +exited 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 of reaping these +processes 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 is not preserved over +exec(2), hence to use the test library from a binary started by an exec() it +has to be remapped. In this case, the process must 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/ltp/lib/android_libpthread/Makefile b/ltp/lib/android_libpthread/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..441cadcb95fa4aebfc4e16ac98b69bf3c4e14456 --- /dev/null +++ b/ltp/lib/android_libpthread/Makefile @@ -0,0 +1,7 @@ +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := libpthread.a + +include $(top_srcdir)/include/mk/lib.mk diff --git a/ltp/lib/android_libpthread/stub.c b/ltp/lib/android_libpthread/stub.c new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ltp/lib/android_librt/Makefile b/ltp/lib/android_librt/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..70d520c0ae261e207c0f1eec0d2f0f68b2307ca6 --- /dev/null +++ b/ltp/lib/android_librt/Makefile @@ -0,0 +1,7 @@ +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := librt.a + +include $(top_srcdir)/include/mk/lib.mk diff --git a/ltp/lib/android_librt/stub.c b/ltp/lib/android_librt/stub.c new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ltp/lib/cloner.c b/ltp/lib/cloner.c new file mode 100644 index 0000000000000000000000000000000000000000..00cbb89879816ea4835d4274f22e41be85cfcc64 --- /dev/null +++ b/ltp/lib/cloner.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) International Business Machines Corp., 2009 + * Some wrappers for clone functionality. Thrown together by Serge Hallyn + * based on existing clone usage in ltp. + * + * 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 + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "tst_clone.h" + +#undef clone /* we want to use clone() */ + +/* + * The ia64 port has never included a prototype for __clone2(). It was updated + * to take eight parameters in glibc commit: + * + * commit 625f22fc7f8e0d61e3e6cff2c65468b91dbad426 + * Author: Ulrich Drepper + * Date: Mon Mar 3 19:53:27 2003 +0000 + * + * The first release that contained this commit was glibc-2.3.3 which is old + * enough to assume that __clone2() takes eight parameters. + */ +#if defined(__ia64__) +extern int __clone2(int (*fn) (void *arg), void *child_stack_base, + size_t child_stack_size, int flags, void *arg, + pid_t *parent_tid, void *tls, pid_t *child_tid); +#endif + +/* + * ltp_clone: wrapper for clone to hide the architecture dependencies. + * 1. hppa takes bottom of stack and no stacksize (stack grows up) + * 2. __ia64__ takes bottom of stack and uses clone2 + * 3. all others take top of stack (stack grows down) + */ +static int +ltp_clone_(unsigned long flags, int (*fn)(void *arg), void *arg, + size_t stack_size, void *stack, pid_t *ptid, void *tls, pid_t *ctid) +{ + int ret; + +#if defined(__ia64__) + ret = __clone2(fn, stack, stack_size, flags, arg, ptid, tls, ctid); +#else +# if defined(__hppa__) || defined(__metag__) + /* + * These arches grow their stack up, so don't need to adjust the base. + * XXX: This should be made into a runtime test. + */ +# else + /* + * For archs where stack grows downwards, stack points to the topmost + * address of the memory space set up for the child stack. + */ + if (stack) + stack += stack_size; +# endif + + ret = clone(fn, stack, flags, arg, ptid, tls, ctid); +#endif + + return ret; +} + +int ltp_clone(unsigned long flags, int (*fn)(void *arg), void *arg, + size_t stack_size, void *stack) +{ + return ltp_clone_(flags, fn, arg, stack_size, stack, NULL, NULL, NULL); +} + +int ltp_clone7(unsigned long flags, int (*fn)(void *arg), void *arg, + size_t stack_size, void *stack, ...) +{ + pid_t *ptid, *ctid; + void *tls; + va_list arg_clone; + + va_start(arg_clone, stack); + ptid = va_arg(arg_clone, pid_t *); + tls = va_arg(arg_clone, void *); + ctid = va_arg(arg_clone, pid_t *); + va_end(arg_clone); + + return ltp_clone_(flags, fn, arg, stack_size, stack, ptid, tls, ctid); +} + +/* + * ltp_alloc_stack: allocate stack of size 'size', that is sufficiently + * aligned for all arches. User is responsible for freeing allocated + * memory. + * Returns pointer to new stack. On error, returns NULL with errno set. + */ +void *ltp_alloc_stack(size_t size) +{ + void *ret = NULL; + int err; + + err = posix_memalign(&ret, 64, size); + if (err) + errno = err; + + return ret; +} diff --git a/ltp/lib/errnos.h b/ltp/lib/errnos.h new file mode 100644 index 0000000000000000000000000000000000000000..df8fea889a1c82f8896bab17e569f4a85caf2b35 --- /dev/null +++ b/ltp/lib/errnos.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2009-2013 Cyril Hrubis + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + */ + +const char *tst_strerrno(int err) +{ + static const struct pair errno_pairs[] = { + STRPAIR(0, "SUCCESS") + /* asm-generic/errno-base.h */ + PAIR(EPERM) + PAIR(ENOENT) + PAIR(ESRCH) + PAIR(EINTR) + PAIR(EIO) + PAIR(ENXIO) + PAIR(E2BIG) + PAIR(ENOEXEC) + PAIR(EBADF) + PAIR(ECHILD) + STRPAIR(EAGAIN, "EAGAIN/EWOULDBLOCK") + PAIR(ENOMEM) + PAIR(EACCES) + PAIR(EFAULT) + PAIR(ENOTBLK) + PAIR(EBUSY) + PAIR(EEXIST) + PAIR(EXDEV) + PAIR(ENODEV) + PAIR(ENOTDIR) + PAIR(EISDIR) + PAIR(EINVAL) + PAIR(ENFILE) + PAIR(EMFILE) + PAIR(ENOTTY) + PAIR(ETXTBSY) + PAIR(EFBIG) + PAIR(ENOSPC) + PAIR(ESPIPE) + PAIR(EROFS) + PAIR(EMLINK) + PAIR(EPIPE) + PAIR(EDOM) + PAIR(ERANGE) + /* asm-generic/errno.h */ + PAIR(EDEADLK) + PAIR(ENAMETOOLONG) + PAIR(ENOLCK) + PAIR(ENOSYS) + PAIR(ENOTEMPTY) + PAIR(ELOOP) + /* EWOULDBLOCK == EAGAIN skipped */ + PAIR(ENOMSG) + PAIR(EIDRM) + PAIR(ECHRNG) + PAIR(EL2NSYNC) + PAIR(EL3HLT) + PAIR(EL3RST) + PAIR(ELNRNG) + PAIR(EUNATCH) + PAIR(ENOCSI) + PAIR(EL2HLT) + PAIR(EBADE) + PAIR(EBADR) + PAIR(EXFULL) + PAIR(ENOANO) + PAIR(EBADRQC) + PAIR(EBADSLT) + /* EDEADLOCK == EDEADLK skipped */ + PAIR(EBFONT) + PAIR(ENOSTR) + PAIR(ENODATA) + PAIR(ETIME) + PAIR(ENOSR) + PAIR(ENONET) + PAIR(ENOPKG) + PAIR(EREMOTE) + PAIR(ENOLINK) + PAIR(EADV) + PAIR(ESRMNT) + PAIR(ECOMM) + PAIR(EPROTO) + PAIR(EMULTIHOP) + PAIR(EDOTDOT) + PAIR(EBADMSG) + PAIR(EOVERFLOW) + PAIR(ENOTUNIQ) + PAIR(EBADFD) + PAIR(EREMCHG) + PAIR(ELIBACC) + PAIR(ELIBBAD) + PAIR(ELIBSCN) + PAIR(ELIBMAX) + PAIR(ELIBEXEC) + PAIR(EILSEQ) + PAIR(ERESTART) + PAIR(ESTRPIPE) + PAIR(EUSERS) + PAIR(ENOTSOCK) + PAIR(EDESTADDRREQ) + PAIR(EMSGSIZE) + PAIR(EPROTOTYPE) + PAIR(ENOPROTOOPT) + PAIR(EPROTONOSUPPORT) + PAIR(ESOCKTNOSUPPORT) + PAIR(EOPNOTSUPP) + PAIR(EPFNOSUPPORT) + PAIR(EAFNOSUPPORT) + PAIR(EADDRINUSE) + PAIR(EADDRNOTAVAIL) + PAIR(ENETDOWN) + PAIR(ENETUNREACH) + PAIR(ENETRESET) + PAIR(ECONNABORTED) + PAIR(ECONNRESET) + PAIR(ENOBUFS) + PAIR(EISCONN) + PAIR(ENOTCONN) + PAIR(ESHUTDOWN) + PAIR(ETOOMANYREFS) + PAIR(ETIMEDOUT) + PAIR(ECONNREFUSED) + PAIR(EHOSTDOWN) + PAIR(EHOSTUNREACH) + PAIR(EALREADY) + PAIR(EINPROGRESS) + PAIR(ESTALE) + PAIR(EUCLEAN) + PAIR(ENOTNAM) + PAIR(ENAVAIL) + PAIR(EISNAM) + PAIR(EREMOTEIO) + PAIR(EDQUOT) + PAIR(ENOMEDIUM) + PAIR(EMEDIUMTYPE) + PAIR(ECANCELED) +#ifdef ENOKEY + PAIR(ENOKEY) +#endif +#ifdef EKEYEXPIRED + PAIR(EKEYEXPIRED) +#endif +#ifdef EKEYREVOKED + PAIR(EKEYREVOKED) +#endif +#ifdef EKEYREJECTED + PAIR(EKEYREJECTED) +#endif +#ifdef EOWNERDEAD + PAIR(EOWNERDEAD) +#endif +#ifdef ENOTRECOVERABLE + PAIR(ENOTRECOVERABLE) +#endif +#ifdef ERFKILL + PAIR(ERFKILL) +#endif +#ifdef EHWPOISON + PAIR(EHWPOISON) +#endif + }; + + PAIR_LOOKUP(errno_pairs, err); +} diff --git a/ltp/lib/gen_version.sh b/ltp/lib/gen_version.sh new file mode 100755 index 0000000000000000000000000000000000000000..5d4250755bdb712a914f2b924404e16c2e3b73e4 --- /dev/null +++ b/ltp/lib/gen_version.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +touch cached-version + +if git describe >/dev/null 2>&1; then + VERSION=`git describe` +else + VERSION=`cat $(dirname $0)/../VERSION` +fi + +CACHED_VERSION=`cat cached-version` + +if [ "$CACHED_VERSION" != "$VERSION" ]; then + echo "$VERSION" > cached-version + echo "#define LTP_VERSION \"$VERSION\"" > ltp-version.h +fi diff --git a/ltp/lib/get_path.c b/ltp/lib/get_path.c new file mode 100644 index 0000000000000000000000000000000000000000..aafbc2ca6637b2a4e10847c4a20e651b3f1a1d87 --- /dev/null +++ b/ltp/lib/get_path.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010 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. + */ + + /* + * Looks for binary prog_name in $PATH. + * + * If such file exists and if you are able at least to read it, zero is + * returned and absolute path to the file is filled into buf. In case buf is + * too short to hold the absolute path + prog_name for the file we are looking + * for -1 is returned as well as when there is no such file in all paths in + * $PATH. + */ + +#include +#include +#include +#include +#include +#include + +#include "test.h" + +static int file_exist(const char *path) +{ + struct stat st; + + if (!access(path, R_OK) && !stat(path, &st) && S_ISREG(st.st_mode)) + return 1; + + return 0; +} + +int tst_get_path(const char *prog_name, char *buf, size_t buf_len) +{ + const char *path = (const char *)getenv("PATH"); + const char *start = path; + const char *end; + size_t size, ret; + + if (path == NULL) + return -1; + + do { + end = strchr(start, ':'); + + if (end != NULL) + snprintf(buf, MIN(buf_len, (size_t) (end - start + 1)), + "%s", start); + else + snprintf(buf, buf_len, "%s", start); + + size = strlen(buf); + + /* + * "::" inside $PATH, $PATH ending with ':' or $PATH starting + * with ':' should be expanded into current working directory. + */ + if (size == 0) { + snprintf(buf, buf_len, "."); + size = strlen(buf); + } + + /* + * If there is no '/' ad the end of path from $PATH add it. + */ + if (buf[size - 1] != '/') + ret = + snprintf(buf + size, buf_len - size, "/%s", + prog_name); + else + ret = + snprintf(buf + size, buf_len - size, "%s", + prog_name); + + if (buf_len - size > ret && file_exist(buf)) + return 0; + + start = end + 1; + + } while (end != NULL); + + return -1; +} diff --git a/ltp/lib/ltp.pc.in b/ltp/lib/ltp.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..96201292aef3f404387a899cfe1cc6349da06707 --- /dev/null +++ b/ltp/lib/ltp.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libdir@ + +Name: LTP +Description: Linux Test Project +Version: @VERSION@ +Libs: -L${libdir} -lltp +Cflags: -I${includedir} diff --git a/ltp/lib/newlib_tests/.gitignore b/ltp/lib/newlib_tests/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a4984d2ec718e73d68b1fd519c9a93a14b0490ec --- /dev/null +++ b/ltp/lib/newlib_tests/.gitignore @@ -0,0 +1,72 @@ +test01 +test02 +test03 +test04 +test05 +test06 +test07 +test08 +test09 +test11 +test13 +test14 +test15 +tst_capability01 +tst_capability02 +tst_cgroup01 +tst_cgroup02 +tst_checkpoint +tst_checkpoint_parent +tst_checkpoint_child +tst_checkpoint_wait_timeout +tst_checkpoint_wake_timeout +tst_device +tst_safe_fileops +tst_res_hexd +tst_strstatus +tst_print_result +test19 +test20 +test22 +tst_expiration_timer +test_assert +test_timer +test_exec +test_exec_child +test_kconfig +test_kconfig01 +test_kconfig02 +test_kconfig03 +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 +test_runtime01 +test_runtime02 +test_children_cleanup +tst_res_flags +tst_safe_sscanf +test_brk_child +test_brk_fail +test_brk_parent +test_brk_pass +test_brk_variant +test_fail_variant diff --git a/ltp/lib/newlib_tests/Makefile b/ltp/lib/newlib_tests/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a915a7f12e11679aa395c90f7f63c59b85e90ce6 --- /dev/null +++ b/ltp/lib/newlib_tests/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +CFLAGS += -W -Wall +LDLIBS += -lltp + +test08 test09 test15 tst_fuzzy_sync01 tst_fuzzy_sync02 tst_fuzzy_sync03: CFLAGS += -pthread +tst_expiration_timer tst_fuzzy_sync01 tst_fuzzy_sync02 tst_fuzzy_sync03: LDLIBS += -lrt + +ifeq ($(ANDROID),1) +FILTER_OUT_MAKE_TARGETS += test08 +endif + + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/lib/newlib_tests/config01 b/ltp/lib/newlib_tests/config01 new file mode 100644 index 0000000000000000000000000000000000000000..1d94d810a6cd51e3066ae87ab827c8460250c068 --- /dev/null +++ b/ltp/lib/newlib_tests/config01 @@ -0,0 +1,5 @@ +# Test should PASS in this case +CONFIG_MMU=y +CONFIG_EXT4_FS=m +CONFIG_PGTABLE_LEVELS=4 +CONFIG_DEFAULT_HOSTNAME="(none)" diff --git a/ltp/lib/newlib_tests/config02 b/ltp/lib/newlib_tests/config02 new file mode 100644 index 0000000000000000000000000000000000000000..e1b0e8086b6f35b6107969fa666a4550a9e41882 --- /dev/null +++ b/ltp/lib/newlib_tests/config02 @@ -0,0 +1,5 @@ +# Unset CONFIG_MMU +# CONFIG_MMU is not set +CONFIG_EXT4_FS=m +CONFIG_PGTABLE_LEVELS=4 +CONFIG_DEFAULT_HOSTNAME="(none)" diff --git a/ltp/lib/newlib_tests/config03 b/ltp/lib/newlib_tests/config03 new file mode 100644 index 0000000000000000000000000000000000000000..05c8e194a1918eaed531932ea39dfb6b87d44fe5 --- /dev/null +++ b/ltp/lib/newlib_tests/config03 @@ -0,0 +1,5 @@ +# Wrong number of page table levels +CONFIG_MMU=y +CONFIG_EXT4_FS=m +CONFIG_PGTABLE_LEVELS=44 +CONFIG_DEFAULT_HOSTNAME="(none)" diff --git a/ltp/lib/newlib_tests/config04 b/ltp/lib/newlib_tests/config04 new file mode 100644 index 0000000000000000000000000000000000000000..da01579b638fe665c53621628a7d8803770812ba --- /dev/null +++ b/ltp/lib/newlib_tests/config04 @@ -0,0 +1,5 @@ +# Unexpected CONFIG_EXT4_FS compiled in +CONFIG_MMU=y +CONFIG_EXT4_FS=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_DEFAULT_HOSTNAME="(none)" diff --git a/ltp/lib/newlib_tests/config05 b/ltp/lib/newlib_tests/config05 new file mode 100644 index 0000000000000000000000000000000000000000..490f94fa612f1a8ed7bbc7c05811d17d2fdbb966 --- /dev/null +++ b/ltp/lib/newlib_tests/config05 @@ -0,0 +1,4 @@ +# Everything is wrong +CONFIG_EXT4_FS=y +CONFIG_PGTABLE_LEVELS=44 +CONFIG_DEFAULT_HOSTNAME="" diff --git a/ltp/lib/newlib_tests/config06 b/ltp/lib/newlib_tests/config06 new file mode 100644 index 0000000000000000000000000000000000000000..b7db25411d06ab75b08bbd4a12922545f89ad22a --- /dev/null +++ b/ltp/lib/newlib_tests/config06 @@ -0,0 +1 @@ +# Empty diff --git a/ltp/lib/newlib_tests/config07 b/ltp/lib/newlib_tests/config07 new file mode 100644 index 0000000000000000000000000000000000000000..3310d575ea9e936b8f2de1cba11c63fde97ec446 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/runtest.sh b/ltp/lib/newlib_tests/runtest.sh new file mode 100755 index 0000000000000000000000000000000000000000..d87751c2f4a29d70665895d69757d91266caf36c --- /dev/null +++ b/ltp/lib/newlib_tests/runtest.sh @@ -0,0 +1,228 @@ +#!/bin/sh +# Copyright (c) 2021-2024 Petr Vorel + +# TODO "unknown failure, exit code": test_assert test08 tst_cgroup01 tst_cgroup02 tst_res_flags variant +# TODO TFAIL: test_macros0[1-6] test23 test26 +# TODO TBROK: test_exec_child test_kconfig01 test_kconfig02 tst_needs_cmds04 tst_needs_cmds05 test_runtime02 test01 test02 test03 test04 test06 test11 test13 test22 test25 tst_safe_fileops +# TODO TWARN: test_guarded_buf test14 tst_capability01 tst_print_result +LTP_C_API_TESTS="${LTP_C_API_TESTS:- +test_children_cleanup.sh +test_kconfig.sh +test_kconfig03 +test_parse_filesize +test_runtime01 +test_timer +test_zero_hugepage.sh +test0[579] +test1[59] +test2[04] +tst_bool_expr +tst_capability02 +tst_checkpoint +tst_checkpoint_parent +tst_checkpoint_wait_timeout +tst_checkpoint_wake_timeout +tst_device +tst_expiration_timer +tst_fuzzy_sync0[1-3] +tst_needs_cmds0[1-36-8] +tst_res_hexd +tst_safe_sscanf +tst_strstatus}" + +# TODO "unknown failure, exit code": shell/tst_res_flags.sh shell/timeout03.sh +# TODO TBROK: shell/test_timeout.sh (sometimes) shell/timeout04.sh +LTP_SHELL_API_TESTS="${LTP_SHELL_API_TESTS:- +shell/timeout0[1-2].sh +shell/tst_all_filesystems.sh +shell/tst_all_filesystems_skip.sh +shell/tst_device_size.sh +shell/tst_errexit.sh +shell/tst_format_device.sh +shell/tst_check_driver.sh +shell/tst_check_kconfig0[1-5].sh +shell/tst_mount_device.sh +shell/tst_mount_device_tmpfs.sh +shell/tst_skip_filesystems.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 + + 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/ltp/lib/newlib_tests/shell/net/tst_ipaddr_un.sh b/ltp/lib/newlib_tests/shell/net/tst_ipaddr_un.sh new file mode 100755 index 0000000000000000000000000000000000000000..76875e2b538582d27cd7a7da21cfe813b9f4c414 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/net/tst_ipaddr_un.sh @@ -0,0 +1,171 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019 Petr Vorel + +TST_TESTFUNC=do_test +TST_CNT=2 + +PATH="$(dirname $0)/../../../../testcases/lib/:$PATH" + +TST_NET_SKIP_VARIABLE_INIT=1 + +# from tst_net_vars.c +IPV4_NET16_UNUSED="10.23" +IPV6_NET32_UNUSED="fd00:23" + + +IPV4_DATA=" +0 0|10.23.0.0 +0 1|10.23.0.1 +1 0|10.23.1.0 +1 1|10.23.1.1 +1 2|10.23.1.2 +2 2|10.23.2.2 +1 3|10.23.1.3 +3 3|10.23.3.3 +1 128|10.23.1.128 +128 128|10.23.128.128 +1 254|10.23.1.254 +254 254|10.23.254.254 +1 255|10.23.1.255 +255 255|10.23.255.255 +1 256|10.23.1.0 +256 256|10.23.0.0 +1 257|10.23.1.1 +257 257|10.23.1.1 + +-c 0|10.23.0.2 +-c 0 lhost|10.23.0.2 +-c 0 rhost|10.23.0.1 + +-c 1|10.23.0.2 +-c 1 rhost|10.23.0.1 +-c 2|10.23.0.4 +-c 2 rhost|10.23.0.3 +-c 127|10.23.0.254 +-c 127 rhost|10.23.0.253 +-c 128|10.23.1.2 +-c 128 rhost|10.23.1.1 +-c 254|10.23.1.254 +-c 254 rhost|10.23.1.253 +-c 255|10.23.2.2 +-c 255 rhost|10.23.2.1 + +-c 0 -h1,255|10.23.0.2 +-c 0 -h1,255 rhost|10.23.0.1 +-c 1 -h1,255|10.23.0.2 +-c 1 -h1,255 rhost|10.23.0.1 +-c 127 -h1,255|10.23.0.254 +-c 127 -h1,255 rhost|10.23.0.253 +-c 128 -h1,255|10.23.1.1 +-c 128 -h1,255 rhost|10.23.0.255 +-c 255 -h1,255|10.23.1.255 +-c 255 -h1,255 rhost|10.23.1.254 +-c 256 -h1,255|10.23.2.2 +-c 256 -h1,255 rhost|10.23.2.1 + +-c1 -h 2,8 -n 2,8|10.23.2.3 +-c1 -h 2,8 -n 2,8 rhost|10.23.2.2 +-c2 -h 2,8 -n 2,8|10.23.2.5 +-c2 -h 2,8 -n 2,8 rhost|10.23.2.4 + +-c1 -n 22,44|10.23.22.2 +-c1 -n 22,44 rhost|10.23.22.1 +-c2 -n 22,44|10.23.22.4 +-c2 -n 22,44 rhost|10.23.22.3 +" + +IPV6_DATA=" +0 0|fd00:23:: +0 1|fd00:23::1 +1 0|fd00:23:1:: +1 1|fd00:23:1::1 +1 2|fd00:23:1::2 +2 2|fd00:23:2::2 +1 3|fd00:23:1::3 +3 3|fd00:23:3::3 +1 32767|fd00:23:1::7fff +32767 32767|fd00:23:7fff::7fff +1 65534|fd00:23:1::fffe +65534 65534|fd00:23:fffe::fffe +1 65535|fd00:23:1::ffff +65535 65535|fd00:23:ffff::ffff +1 65536|fd00:23:1:: +65536 65536|fd00:23:: +1 65537|fd00:23:1::1 +65537 65537|fd00:23:1::1 + +-c 0|fd00:23::2 +-c 0 lhost|fd00:23::2 +-c 0 rhost|fd00:23::1 + +-c 1|fd00:23::2 +-c 1 rhost|fd00:23::1 +-c 2|fd00:23::4 +-c 2 rhost|fd00:23::3 +-c 32767|fd00:23::fffe +-c 32767 rhost|fd00:23::fffd +-c 32768|fd00:23:1::2 +-c 32768 rhost|fd00:23:1::1 +-c 65534|fd00:23:1::fffe +-c 65534 rhost|fd00:23:1::fffd +-c 65535|fd00:23:2::2 +-c 65535 rhost|fd00:23:2::1 + +-c 0 -h1,65535|fd00:23::2 +-c 0 -h1,65535 rhost|fd00:23::1 +-c 1 -h1,65535|fd00:23::2 +-c 1 -h1,65535 rhost|fd00:23::1 +-c 32767 -h1,65535|fd00:23::fffe +-c 32767 -h1,65535 rhost|fd00:23::fffd +-c 32768 -h1,65535|fd00:23:1::1 +-c 32768 -h1,65535 rhost|fd00:23::ffff +-c 65535 -h1,65535|fd00:23:1::ffff +-c 65535 -h1,65535 rhost|fd00:23:1::fffe +-c 65536 -h1,65535|fd00:23:2::2 +-c 65536 -h1,65535 rhost|fd00:23:2::1 + +-c1 -h 2,8 -n 2,8|fd00:23:2::3 +-c1 -h 2,8 -n 2,8 rhost|fd00:23:2::2 +-c2 -h 2,8 -n 2,8|fd00:23:2::5 +-c2 -h 2,8 -n 2,8 rhost|fd00:23:2::4 + +-c1 -n 22,44|fd00:23:16::2 +-c1 -n 22,44 rhost|fd00:23:16::1 +-c2 -n 22,44|fd00:23:16::4 +-c2 -n 22,44 rhost|fd00:23:16::3 +" + +test_tst_ipaddr_un() +{ + local data cmd i result + local var="$1" + + tst_res TINFO "Testing for IPv${TST_IPVER}, data: \$$var" + + eval data="\$$var" + IFS=" +" + for i in $data; do + cmd="tst_ipaddr_un $(echo $i | cut -d'|' -f 1)" + result="$(echo $i | cut -d'|' -f 2)" + tst_res TINFO "testing $cmd" + EXPECT_PASS "[ '$(eval $cmd)' = '$result' ]" + done +} + +do_test2() +{ + test_tst_ipaddr_un "IPV${TST_IPVER}_DATA" +} + +do_test() +{ + case $1 in + 1) TST_IPV6= TST_IPVER=4 do_test2;; + 2) TST_IPV6=6 TST_IPVER=6 do_test2;; + esac +} + +. tst_net.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/net/tst_rhost_run.sh b/ltp/lib/newlib_tests/shell/net/tst_rhost_run.sh new file mode 100755 index 0000000000000000000000000000000000000000..773b8dd3325def309be575ea8036dc2d86d61427 --- /dev/null +++ b/ltp/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" + +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_net.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/test_timeout.sh b/ltp/lib/newlib_tests/shell/test_timeout.sh new file mode 100755 index 0000000000000000000000000000000000000000..c70e22f27aa7e23f83fa0bd3bac2912d96ba88b4 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/test_timeout.sh @@ -0,0 +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| |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 +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/ltp/lib/newlib_tests/shell/timeout01.sh b/ltp/lib/newlib_tests/shell/timeout01.sh new file mode 100755 index 0000000000000000000000000000000000000000..6945f612eb88c602dbb5bad7eaded374c7f0c185 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/timeout01.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019 Petr Vorel + +TST_TESTFUNC=do_test + +TST_TIMEOUT=-1 + +do_test() +{ + tst_res TPASS "timeout $TST_TIMEOUT set" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/timeout02.sh b/ltp/lib/newlib_tests/shell/timeout02.sh new file mode 100755 index 0000000000000000000000000000000000000000..cc8cce5d98df5ac6c8c1e7be4c44ae39d3579856 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/timeout02.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019 Petr Vorel + +TST_TESTFUNC=do_test + +TST_TIMEOUT=2 + +do_test() +{ + tst_res TPASS "timeout $TST_TIMEOUT set (LTP_TIMEOUT_MUL='$LTP_TIMEOUT_MUL')" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/timeout03.sh b/ltp/lib/newlib_tests/shell/timeout03.sh new file mode 100755 index 0000000000000000000000000000000000000000..811ce7565b73e24d81a643104b2f5120967e9875 --- /dev/null +++ b/ltp/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 + +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_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/timeout04.sh b/ltp/lib/newlib_tests/shell/timeout04.sh new file mode 100755 index 0000000000000000000000000000000000000000..eb41c2c4fb7bcb884474485f8762da333e8e739f --- /dev/null +++ b/ltp/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 + +do_test() +{ + tst_res TINFO "Start" + sleep 5 + tst_res TFAIL "End" +} + +do_cleanup() +{ + tst_res TINFO "cleanup" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_all_filesystems.sh b/ltp/lib/newlib_tests/shell/tst_all_filesystems.sh new file mode 100755 index 0000000000000000000000000000000000000000..7561579ff41727a75d8d39a5ad56acd58a634f64 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_all_filesystems.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_ALL_FILESYSTEMS=1 +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_TESTFUNC=test +TST_CNT=2 + +test1() +{ + tst_res TPASS "device using filesystem" +} + +test2() +{ + EXPECT_PASS "grep -E '$TST_MNTPOINT ($TST_FS_TYPE|fuseblk)' /proc/mounts" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_all_filesystems_skip.sh b/ltp/lib/newlib_tests/shell/tst_all_filesystems_skip.sh new file mode 100755 index 0000000000000000000000000000000000000000..9516f38d958658b18138b4c766a1127f93563f2b --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_all_filesystems_skip.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_ALL_FILESYSTEMS=1 +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_TESTFUNC=test +TST_SKIP_FILESYSTEMS="btrfs,exfat,ext2,ext3,ext4,fuse,ntfs,vfat,tmpfs,xfs" + +test1() +{ + tst_res TFAIL "test should be skipped with TCONF" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_check_driver.sh b/ltp/lib/newlib_tests/shell/tst_check_driver.sh new file mode 100755 index 0000000000000000000000000000000000000000..784c5d248420359a141d3acb6fac08ab242a6e00 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_check_driver.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2021 Petr Vorel + +TST_TESTFUNC=test +TST_SETUP=setup +TST_CNT=4 +TST_NEEDS_CMDS="tst_check_drivers find grep head sed" + +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) +} + +test4() +{ + local f="$MODULES_DIR/modules.builtin" + + tst_res TINFO "check for x68_64 arch module detection" + + [ -f "$f" ] || tst_brk TCONF "missing '$f'" + test_drivers $(grep -E '[^/]+[-_]x86[-_]64.*\.ko' $f | head -3) +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_check_kconfig01.sh b/ltp/lib/newlib_tests/shell/tst_check_kconfig01.sh new file mode 100755 index 0000000000000000000000000000000000000000..c80b8923a05f39dbaa6106ec6d0846b2ac5eddc5 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_check_kconfig01.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" + +do_test() +{ + tst_res TFAIL "kernel .config doesn't have CONFIG_EXT4" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_check_kconfig02.sh b/ltp/lib/newlib_tests/shell/tst_check_kconfig02.sh new file mode 100755 index 0000000000000000000000000000000000000000..5bdb98413d005dc2f48da0b2542a45d557f6924c --- /dev/null +++ b/ltp/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" + +do_test() +{ + tst_res TFAIL "invalid kconfig delimter" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_check_kconfig03.sh b/ltp/lib/newlib_tests/shell/tst_check_kconfig03.sh new file mode 100755 index 0000000000000000000000000000000000000000..1dcc14a81a6748f822a2881fa2415b2cbd06f9c4 --- /dev/null +++ b/ltp/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=":" + +do_test() +{ + tst_res TPASS "valid kconfig delimter" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_check_kconfig04.sh b/ltp/lib/newlib_tests/shell/tst_check_kconfig04.sh new file mode 100755 index 0000000000000000000000000000000000000000..522b3a8dc5a30e8ec78cad7e35134132acd3607f --- /dev/null +++ b/ltp/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 + +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_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_check_kconfig05.sh b/ltp/lib/newlib_tests/shell/tst_check_kconfig05.sh new file mode 100755 index 0000000000000000000000000000000000000000..045995c84deffad4715d6f7287adeb6aee8b200d --- /dev/null +++ b/ltp/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 + +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_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_device_size.sh b/ltp/lib/newlib_tests/shell/tst_device_size.sh new file mode 100755 index 0000000000000000000000000000000000000000..7514379729163bff1915214ec6159748642a1ee6 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_device_size.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2024 Petr Vorel + +TST_NEEDS_DEVICE=1 +TST_DEVICE_SIZE=10 +TST_TESTFUNC=test + +test() +{ + tst_res TPASS "TST_DEVICE_SIZE=$TST_DEVICE_SIZE" + # overlayfs adds 1 MB + EXPECT_PASS "du -ms . | grep -qw -e $TST_DEVICE_SIZE -e $(($TST_DEVICE_SIZE + 1))" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_errexit.sh b/ltp/lib/newlib_tests/shell/tst_errexit.sh new file mode 100755 index 0000000000000000000000000000000000000000..1c981af9495fa686f4c38fe284f8de401c03ccc0 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_errexit.sh @@ -0,0 +1,66 @@ +#!/bin/sh -e +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_TESTFUNC=test +TST_CNT=6 + +# not needed, just cover more code +TST_SETUP=setup +TST_CLEANUP=cleanup +TST_NEEDS_TMPDIR=1 + +setup() +{ + tst_res TINFO "in setup" +} + +cleanup() +{ + tst_res TINFO "in cleanup" +} + +run() +{ + tst_res TINFO "LTP_COLORIZE_OUTPUT: '$LTP_COLORIZE_OUTPUT'" + tst_res TPASS "shell library works with set -e" +} + +test1() +{ + export LTP_COLORIZE_OUTPUT=y + run +} + +test2() +{ + export LTP_COLORIZE_OUTPUT=n + run +} + +test3() +{ + export LTP_COLORIZE_OUTPUT=0 + run +} + +test4() +{ + export LTP_COLORIZE_OUTPUT=1 + run +} + +test5() +{ + export LTP_COLORIZE_OUTPUT= + run +} + +test6() +{ + unset LTP_COLORIZE_OUTPUT + run +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_format_device.sh b/ltp/lib/newlib_tests/shell/tst_format_device.sh new file mode 100755 index 0000000000000000000000000000000000000000..dbe4ea9e7d0cbb2c90545f8499182bc1c2e11b86 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_format_device.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_FORMAT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_TESTFUNC=test +TST_CNT=2 +TST_DEV_FS_OPTS="-b 1024" +TST_DEV_EXTRA_OPTS="5m" + +test1() +{ + tst_res TPASS "device formatted" +} + +test2() +{ + tst_check_cmds df || return + EXPECT_PASS "df $TST_DEVICE | grep -q /dev" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_mount_device.sh b/ltp/lib/newlib_tests/shell/tst_mount_device.sh new file mode 100755 index 0000000000000000000000000000000000000000..70f80f84a0a0141f0d80f8f296c8f7b40fce6591 --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_mount_device.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_FS_TYPE=ext4 +TST_TESTFUNC=test +TST_CNT=3 + +test1() +{ + EXPECT_PASS "cd $TST_MNTPOINT" +} + +test2() +{ + EXPECT_PASS "grep '$TST_MNTPOINT $TST_FS_TYPE' /proc/mounts" +} + +test3() +{ + tst_brk TCONF "quit early to test early tst_umount" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_mount_device_tmpfs.sh b/ltp/lib/newlib_tests/shell/tst_mount_device_tmpfs.sh new file mode 100755 index 0000000000000000000000000000000000000000..ed2ba8c50af78452920013fd75b46aafb75599ca --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_mount_device_tmpfs.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_FS_TYPE=tmpfs +TST_TESTFUNC=test + +test() +{ + EXPECT_PASS "cd $TST_MNTPOINT" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_res_flags.sh b/ltp/lib/newlib_tests/shell/tst_res_flags.sh new file mode 100755 index 0000000000000000000000000000000000000000..bca3d26c035cc8a11566b036135f757d3eb31b2d --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_res_flags.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 Petr Vorel + +TST_TESTFUNC=test +TST_CLEANUP=cleanup + +test() +{ + tst_res TPASS "TPASS message" + tst_res TFAIL "TFAIL message" + tst_res TBROK "TBROK message" + tst_res TCONF "TCONF message" + tst_res TWARN "TWARN message" + tst_res TINFO "TINFO message" +} + +cleanup() +{ + tst_brk TBROK "TBROK message should be TWARN in cleanup" +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/shell/tst_skip_filesystems.sh b/ltp/lib/newlib_tests/shell/tst_skip_filesystems.sh new file mode 100755 index 0000000000000000000000000000000000000000..675d0ee5ff79b9582ea40d96f9004b7fc9750bcc --- /dev/null +++ b/ltp/lib/newlib_tests/shell/tst_skip_filesystems.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_FS_TYPE=ext4 +TST_TESTFUNC=test +TST_SKIP_FILESYSTEMS="btrfs,exfat,ext2,ext3,fuse,ntfs,vfat,tmpfs,xfs" +TST_CNT=3 + +test1() +{ + EXPECT_PASS "cd $TST_MNTPOINT" +} + +test2() +{ + EXPECT_PASS "grep '$TST_MNTPOINT $TST_FS_TYPE' /proc/mounts" +} + +test3() +{ + local fs fs_skip + + fs=$(grep "$TST_MNTPOINT $TST_FS_TYPE" /proc/mounts | cut -d ' ' -f3) + EXPECT_PASS "[ '$fs' = '$TST_FS_TYPE' ]" + + for fs_skip in $TST_SKIP_FILESYSTEMS; do + EXPECT_FAIL "[ $fs = $fs_skip ]" + done +} + +. tst_test.sh +tst_run diff --git a/ltp/lib/newlib_tests/test01.c b/ltp/lib/newlib_tests/test01.c new file mode 100644 index 0000000000000000000000000000000000000000..304c205149e0afaf4fb60a8426b5fd3f08fd7087 --- /dev/null +++ b/ltp/lib/newlib_tests/test01.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * The test should abort when oldlib function is called from newlib. + */ + +#include "tst_test.h" + +void tst_exit(void); + +static void do_test(void) +{ + tst_exit(); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test02.c b/ltp/lib/newlib_tests/test02.c new file mode 100644 index 0000000000000000000000000000000000000000..ec2a1d13dc385ef12eba4a995732796b694259b6 --- /dev/null +++ b/ltp/lib/newlib_tests/test02.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * The tst_resm() and tst_brkm() should be rerouted to the new lib. + */ + +#include "tst_test.h" + +void tst_resm_(char *, int, int, char *); +void tst_brkm__(char *, int, int, void (*)(void), char *); + +static void cleanup(void) +{ +} + +static void do_test(unsigned int i) +{ + switch (i) { + case 0: + tst_resm_(__FILE__, __LINE__, TINFO, "info message"); + tst_resm_(__FILE__, __LINE__, TPASS, "passed message"); + break; + case 1: + tst_brkm__(__FILE__, __LINE__, TCONF, cleanup, "Non-NULL cleanup"); + break; + } +} + +static struct tst_test test = { + .tcnt = 2, + .test = do_test, +}; diff --git a/ltp/lib/newlib_tests/test03.c b/ltp/lib/newlib_tests/test03.c new file mode 100644 index 0000000000000000000000000000000000000000..3b451241ebce4882fdb916fe47a0095c92c761f2 --- /dev/null +++ b/ltp/lib/newlib_tests/test03.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * tst_brkm() from SAFE_MACROS() is redirected to newlib + */ + +#include "tst_test.h" + +static void do_test(void) +{ + SAFE_CHDIR("nonexistent"); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test04.c b/ltp/lib/newlib_tests/test04.c new file mode 100644 index 0000000000000000000000000000000000000000..7ecf2caed846a720001be54c647209ed41c10ada --- /dev/null +++ b/ltp/lib/newlib_tests/test04.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * Tests tst_run_as_child() + */ + +#include "tst_test.h" + +static void child_fn(unsigned int i) +{ + switch (i) { + case 0: + tst_res(TPASS, "PASSED message"); + break; + case 1: + tst_brk(TBROK, "BROKEN message"); + break; + } +} + +static void setup(void) +{ + tst_res(TINFO, "setup() executed by pid %i", getpid()); +} + +static void cleanup(void) +{ + tst_res(TINFO, "cleanup() executed by pid %i", getpid()); +} + +static void do_test(unsigned int i) +{ + if (SAFE_FORK() == 0) + child_fn(i); +} + +static struct tst_test test = { + .tcnt = 2, + .test = do_test, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test05.c b/ltp/lib/newlib_tests/test05.c new file mode 100644 index 0000000000000000000000000000000000000000..9f5d898e4b99ab3d22f221c2702ce6a5e72f6e43 --- /dev/null +++ b/ltp/lib/newlib_tests/test05.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * Test that child process that returns to test library code is reported. + */ + +#include "tst_test.h" + +static void setup(void) +{ + tst_res(TINFO, "setup() executed by pid %i", getpid()); +} + +static void cleanup(void) +{ + tst_res(TINFO, "cleanup() executed by pid %i", getpid()); +} + +static void do_test(void) +{ + pid_t pid = SAFE_FORK(); + + switch (pid) { + case 0: + tst_res(TPASS, "Child (%i) reports", getpid()); + break; + default: + tst_res(TPASS, "Parent (%i) reports", getpid()); + break; + } +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test06.c b/ltp/lib/newlib_tests/test06.c new file mode 100644 index 0000000000000000000000000000000000000000..5499f447727fa39fc75ee939f678efae57f6e67b --- /dev/null +++ b/ltp/lib/newlib_tests/test06.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * Test that child process does not trigger cleanup. + */ + +#include "tst_test.h" + +static void setup(void) +{ + tst_res(TINFO, "setup() executed by pid %i", getpid()); +} + +static void cleanup(void) +{ + tst_res(TINFO, "cleanup() executed by pid %i", getpid()); +} + +static void do_test(void) +{ + pid_t pid = SAFE_FORK(); + + switch (pid) { + case 0: + tst_brk(TBROK, "Child pid %i", getpid()); + break; + default: + tst_res(TPASS, "Parent pid %i", getpid()); + break; + } +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test07.c b/ltp/lib/newlib_tests/test07.c new file mode 100644 index 0000000000000000000000000000000000000000..de9c832b9b365ed1de999ce6ea663504e4a451bd --- /dev/null +++ b/ltp/lib/newlib_tests/test07.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * Test for result propagation. + */ + +#include "tst_test.h" + +static void setup(void) +{ + tst_res(TINFO, "setup() executed by pid %i", getpid()); +} + +static void cleanup(void) +{ + tst_res(TINFO, "cleanup() executed by pid %i", getpid()); +} + +static void do_test(void) +{ + unsigned int i; + + for (i = 0; i < 100; i++) { + if (SAFE_FORK() == 0) { + tst_res(TPASS, "Child (%i)", getpid()); + return; + } + } +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test08.c b/ltp/lib/newlib_tests/test08.c new file mode 100644 index 0000000000000000000000000000000000000000..d48bf29ee1d4e93ffb013474566263c9d43e240d --- /dev/null +++ b/ltp/lib/newlib_tests/test08.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * Test for callback thread safety. + */ +#include +#include "tst_test.h" + +#define THREADS 10 + +static pthread_barrier_t barrier; + +static void setup(void) +{ + pthread_barrier_init(&barrier, NULL, THREADS); + + tst_res(TINFO, "setup() executed"); +} + +static void cleanup(void) +{ + static tst_atomic_t flag; + + /* Avoid subsequent threads to enter the cleanup */ + if (tst_atomic_inc(&flag) != 1) + pthread_exit(NULL); + + tst_res(TINFO, "cleanup() started"); + usleep(10000); + tst_res(TINFO, "cleanup() finished"); +} + +static void *worker(void *id) +{ + tst_res(TINFO, "Thread %ld waiting...", (long)id); + pthread_barrier_wait(&barrier); + tst_brk(TBROK, "Failure %ld", (long)id); + + return NULL; +} + +static void do_test(void) +{ + long i; + pthread_t threads[THREADS]; + + for (i = 0; i < THREADS; i++) + pthread_create(threads+i, NULL, worker, (void*)i); + + for (i = 0; i < THREADS; i++) { + tst_res(TINFO, "Joining thread %li", i); + pthread_join(threads[i], NULL); + } +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/ltp/lib/newlib_tests/test09.c b/ltp/lib/newlib_tests/test09.c new file mode 100644 index 0000000000000000000000000000000000000000..eae258e2d63e0a3feb3e63914719797f5480d77b --- /dev/null +++ b/ltp/lib/newlib_tests/test09.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Linux Test Project + */ + +/* + * Test that tst_atomic_inc works as expected. + */ + +#include +#include "tst_test.h" + +#define THREADS 64 +#define ITERATIONS 100000 + +static tst_atomic_t atomic; + +static void *worker(void *id) +{ + int i; + + (void) id; + for (i = 0; i < ITERATIONS; i++) + tst_atomic_inc(&atomic); + + return NULL; +} + +static void do_test(void) +{ + long i; + pthread_t threads[THREADS]; + + for (i = 0; i < THREADS; i++) + pthread_create(threads+i, NULL, worker, (void *)i); + + for (i = 0; i < THREADS; i++) { + tst_res(TINFO, "Joining thread %li", i); + pthread_join(threads[i], NULL); + } + + if (atomic == THREADS * ITERATIONS) + tst_res(TPASS, "Atomic working as expected"); + else + tst_res(TFAIL, "Atomic does not have expected value"); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test11.c b/ltp/lib/newlib_tests/test11.c new file mode 100644 index 0000000000000000000000000000000000000000..fd9dbc6f312eb6ec2d271f62b6ae5562d7f02091 --- /dev/null +++ b/ltp/lib/newlib_tests/test11.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Linux Test Project + */ + +/* + * Test for segfault. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + volatile char *ptr = NULL; + + *ptr = 0; + + tst_res(TPASS, "Not reached"); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test13.c b/ltp/lib/newlib_tests/test13.c new file mode 100644 index 0000000000000000000000000000000000000000..83c48f734db9ef8f8d1a751d129980f863a93983 --- /dev/null +++ b/ltp/lib/newlib_tests/test13.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Linux Test Project + */ + +/* + * Test for timeout & children. + */ + +#include "tst_test.h" + +static void do_test(void) +{ + SAFE_FORK(); + SAFE_FORK(); + SAFE_FORK(); + + tst_res(TINFO, "Pausing process pid %i", getpid()); + pause(); +} + +static struct tst_test test = { + .forks_child = 1, + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test14.c b/ltp/lib/newlib_tests/test14.c new file mode 100644 index 0000000000000000000000000000000000000000..171149d99cfa1517f8840628b9731a7ed3ec0807 --- /dev/null +++ b/ltp/lib/newlib_tests/test14.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +#include "tst_test.h" +#include "tst_safe_stdio.h" +#include "tst_safe_net.h" + +static void cleanup(void) +{ + int i; + + tst_brk(TBROK, "TBROK in cleanup"); + SAFE_OPEN("foo", O_RDWR); + SAFE_FILE_SCANF("foo", "%i", &i); + SAFE_TOUCH("doo/foo", 0777, NULL); + SAFE_FOPEN("foo", "r"); + SAFE_SOCKET(AF_UNIX, SOCK_STREAM, -1); + tst_res(TINFO, "Test still here"); +} + +static void do_test(void) +{ + tst_res(TPASS, "Passed"); +} + +static struct tst_test test = { + .test_all = do_test, + .cleanup = cleanup, +}; diff --git a/ltp/lib/newlib_tests/test15.c b/ltp/lib/newlib_tests/test15.c new file mode 100644 index 0000000000000000000000000000000000000000..c63da18fc31372c1761d3f247bf7e2628fc63f4f --- /dev/null +++ b/ltp/lib/newlib_tests/test15.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Richard Palethorpe + */ + +/* + * A basic regression test for tst_atomic_{load,store}. Also provides a + * limited check that atomic stores and loads order non-atomic memory + * accesses. That is, we are checking that they implement memory fences or + * barriers. + * + * Many architectures/machines will still pass the test even if you remove the + * atomic functions. X86 in particular has strong memory ordering by default + * so that should always pass (if you use volatile). However Aarch64 + * (Raspberry Pi 3 Model B) has been observed to fail without the atomic + * functions. + * + * A failure can occur if an update to seq_n is not made globally visible by + * the time the next thread needs to use it. + */ + +#include +#include +#include "tst_test.h" +#include "tst_atomic.h" + +#define THREADS 64 +#define FILLER (1 << 20) + +/* Uncomment these to see what happens without atomics. To prevent the compiler + * from removing/reording atomic and seq_n, mark them as volatile. + */ +/* #define tst_atomic_load(v) (*(v)) */ +/* #define tst_atomic_store(i, v) *(v) = (i) */ + +struct block { + int seq_n; + intptr_t id; + intptr_t filler[FILLER]; +}; + +static tst_atomic_t atomic; +/* Instead of storing seq_n on the stack (probably next to the atomic variable + * above), we store it in the middle of some anonymous mapped memory and keep + * a pointer to it. This should decrease the probability that the value of + * seq_n will be synchronised between processors as a byproduct of the atomic + * variable being updated. + */ +static int *seq_n; +static struct block *m; + +static void *worker_load_store(void *aid) +{ + int id = (intptr_t)aid, i; + + for (i = tst_atomic_load(&atomic); + i != id; + i = tst_atomic_load(&atomic)) + ; + + (m + (*seq_n))->id = id; + *seq_n += 1; + tst_atomic_store(i + 1, &atomic); + + return NULL; +} + +/* Attempt to stress the memory transport so that memory operations are + * contended and less predictable. This should increase the likelyhood of a + * failure if a memory fence is missing. + */ +static void *mem_spam(void *vp LTP_ATTRIBUTE_UNUSED) +{ + intptr_t i = 0, j; + struct block *cur = m; + + tst_res(TINFO, "Memory spammer started"); + while (tst_atomic_load(&atomic) > 0) { + for (j = 0; j < FILLER; j++) + cur->filler[j] = j; + + if (i < THREADS - 1) { + cur = m + (++i); + } else { + i = 0; + cur = m; + } + } + + return NULL; +} + +static void do_test(void) +{ + intptr_t i, id; + pthread_t threads[THREADS + 1]; + + atomic = 0; + m = SAFE_MMAP(NULL, sizeof(*m) * THREADS, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + seq_n = &((m + THREADS / 2)->seq_n); + + pthread_create(&threads[THREADS], NULL, mem_spam, NULL); + for (i = THREADS - 1; i >= 0; i--) + pthread_create(&threads[i], NULL, worker_load_store, (void *)i); + + for (i = 0; i < THREADS; i++) { + tst_res(TINFO, "Joining thread %li", i); + pthread_join(threads[i], NULL); + } + tst_atomic_store(-1, &atomic); + pthread_join(threads[THREADS], NULL); + + tst_res(TINFO, "Expected\tFound"); + for (i = 0; i < THREADS; i++) { + id = (m + i)->id; + if (id != i) + tst_res(TFAIL, "%d\t\t%d", (int)i, (int)id); + else + tst_res(TPASS, "%d\t\t%d", (int)i, (int)id); + } + + SAFE_MUNMAP(m, sizeof(*m) * THREADS); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test19.c b/ltp/lib/newlib_tests/test19.c new file mode 100644 index 0000000000000000000000000000000000000000..a5683eaa49a0fb3518d30c209bd4574de0090132 --- /dev/null +++ b/ltp/lib/newlib_tests/test19.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018, Linux Test Project + */ + +#include +#include +#include "tst_test.h" +#include "tst_sys_conf.h" + +static void setup(void) +{ + SAFE_FILE_PRINTF("/proc/sys/kernel/core_pattern", "changed"); + tst_sys_conf_dump(); +} + +static void run(void) +{ + tst_res(TPASS, "OK"); +} + +static struct tst_test test = { + .needs_root = 1, + .test_all = run, + .setup = setup, + .save_restore = (const struct tst_path_val[]) { + {"/proc/nonexistent", NULL, TST_SR_SKIP}, + {"/proc/sys/kernel/numa_balancing", NULL, TST_SR_TBROK}, + {"/proc/sys/kernel/core_pattern", NULL, TST_SR_TCONF}, + {} + }, +}; diff --git a/ltp/lib/newlib_tests/test20.c b/ltp/lib/newlib_tests/test20.c new file mode 100644 index 0000000000000000000000000000000000000000..3726cea0e94a4cd432b9694436cd89e14b0eb62f --- /dev/null +++ b/ltp/lib/newlib_tests/test20.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Li Wang + */ + +/* + * Tests .hugepages + .save_restore + */ + +#include "tst_test.h" +#include "tst_hugepage.h" +#include "tst_sys_conf.h" + +static void do_test(void) { + + unsigned long val, hpages; + + tst_res(TINFO, "tst_hugepages = %lu", tst_hugepages); + SAFE_FILE_PRINTF("/proc/sys/kernel/numa_balancing", "1"); + + hpages = test.hugepages.number; + 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, "test .hugepges"); + + struct tst_hugepage hp = { 1000000000000, TST_REQUEST }; + hpages = tst_reserve_hugepages(&hp); + + 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_reserve_hugepages"); +} + +static struct tst_test test = { + .test_all = do_test, + .hugepages = {2, TST_NEEDS}, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/numa_balancing", "0", TST_SR_TBROK}, + {} + }, +}; diff --git a/ltp/lib/newlib_tests/test22.c b/ltp/lib/newlib_tests/test22.c new file mode 100644 index 0000000000000000000000000000000000000000..520b8dad8894eaedac63aed301f30ce321d1ffb3 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_assert.c b/ltp/lib/newlib_tests/test_assert.c new file mode 100644 index 0000000000000000000000000000000000000000..09230389346bc4c68f59d9891570fe6024db9cab --- /dev/null +++ b/ltp/lib/newlib_tests/test_assert.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Yang Xu + */ + +#include +#include "tst_test.h" + +static void do_test(void) +{ + TST_ASSERT_INT("/proc/self/oom_score", 0); + TST_ASSERT_STR("/proc/self/comm", "test_assert"); + TST_ASSERT_FILE_INT("/proc/self/io", "read_bytes:", 0); + TST_ASSERT_FILE_STR("/proc/self/status1", "State", "unexpected"); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test_brk_child.c b/ltp/lib/newlib_tests/test_brk_child.c new file mode 100644 index 0000000000000000000000000000000000000000..68c50ed1ec0f8f1f74e17aca3e90fbb896f92434 --- /dev/null +++ b/ltp/lib/newlib_tests/test_brk_child.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Cyril Hrubis + */ + +/* + * Test that tst_brk(TFAIL, ...) exits only single test variant. + */ +#include "tst_test.h" + +static void do_test(void) +{ + int i; + + for (i = 0; i < 10; i++) { + if (!SAFE_FORK()) { + tst_res(TINFO, "Suspending child %i", i); + pause(); + } + } + + if (!SAFE_FORK()) + tst_brk(TBROK, "Child triggers TBROK"); + + pause(); +} + +static struct tst_test test = { + .test_all = do_test, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test_brk_fail.c b/ltp/lib/newlib_tests/test_brk_fail.c new file mode 100644 index 0000000000000000000000000000000000000000..ee1e554a60e588d3caa024f84717cdd504344247 --- /dev/null +++ b/ltp/lib/newlib_tests/test_brk_fail.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Cyril Hrubis + */ + +/* + * Test that tst_brk(TFAIL, ...) works properly. + */ +#include "tst_test.h" + +static void do_test(void) +{ + int pid = SAFE_FORK(); + + if (pid) + return; + + tst_brk(TFAIL, "Test child exiting..."); + tst_res(TWARN, "Test child stil alive!"); +} + +static struct tst_test test = { + .test_all = do_test, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test_brk_parent.c b/ltp/lib/newlib_tests/test_brk_parent.c new file mode 100644 index 0000000000000000000000000000000000000000..974e778291197917f7923d1379165ab2bc39c6cd --- /dev/null +++ b/ltp/lib/newlib_tests/test_brk_parent.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Cyril Hrubis + */ + +/* + * Test that tst_brk(TFAIL, ...) exits only single test variant. + */ +#include "tst_test.h" + +static void do_test(void) +{ + int i; + + for (i = 0; i < 10; i++) { + if (!SAFE_FORK()) { + tst_res(TINFO, "Suspending child %i", i); + pause(); + } + } + + tst_brk(TBROK, "Parent triggers TBROK"); +} + +static struct tst_test test = { + .test_all = do_test, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test_brk_pass.c b/ltp/lib/newlib_tests/test_brk_pass.c new file mode 100644 index 0000000000000000000000000000000000000000..135270780bab65964d3daee32095858de8cd6d5e --- /dev/null +++ b/ltp/lib/newlib_tests/test_brk_pass.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Cyril Hrubis + */ + +/* + * Test that tst_brk(TPASS, ...) works properly. + */ +#include "tst_test.h" + +static void do_test(void) +{ + int pid = SAFE_FORK(); + + if (pid) + return; + + tst_brk(TPASS, "Test child exiting..."); + tst_res(TWARN, "Test child stil alive!"); +} + +static struct tst_test test = { + .test_all = do_test, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test_brk_variant.c b/ltp/lib/newlib_tests/test_brk_variant.c new file mode 100644 index 0000000000000000000000000000000000000000..6f91a72aa0c35d6c61b55fdb301ccd7762d5440b --- /dev/null +++ b/ltp/lib/newlib_tests/test_brk_variant.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Cyril Hrubis + */ + +/* + * Test that tst_brk(TBROK, ...) exits the test immediately. + */ +#include "tst_test.h" + +static void do_test(void) +{ + tst_brk(TBROK, "Exitting the test during the first variant"); +} + +static struct tst_test test = { + .test_all = do_test, + .test_variants = 10, +}; diff --git a/ltp/lib/newlib_tests/test_children_cleanup.c b/ltp/lib/newlib_tests/test_children_cleanup.c new file mode 100644 index 0000000000000000000000000000000000000000..4a1313f6d6f3955f980e53cf0ffc7b8e549da1d7 --- /dev/null +++ b/ltp/lib/newlib_tests/test_children_cleanup.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 SUSE LLC + */ + +/*\ + * Test whether the LTP library properly reaps any children left over when + * the main test process dies. Run using test_children_cleanup.sh. + */ + +#include +#include + +#include "tst_test.h" + +static void run(void) +{ + pid_t child_pid, main_pid = getpid(); + + tst_res(TINFO, "Main process %d starting", main_pid); + + /* Check that normal child reaping does not disrupt the test */ + if (!SAFE_FORK()) + return; + + SAFE_WAIT(NULL); + child_pid = SAFE_FORK(); + + /* Start child that will outlive the main test process */ + if (!child_pid) { + sleep(30); + return; + } + + tst_res(TINFO, "Forked child %d", child_pid); + kill(main_pid, SIGKILL); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/test_children_cleanup.sh b/ltp/lib/newlib_tests/test_children_cleanup.sh new file mode 100755 index 0000000000000000000000000000000000000000..5f090f8b077168f0fe2f1688050700888a907378 --- /dev/null +++ b/ltp/lib/newlib_tests/test_children_cleanup.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 SUSE LLC + +TMPFILE="/tmp/ltp_children_cleanup_$$.log" +./test_children_cleanup 1>$TMPFILE 2>&1 +CHILD_PID=`sed -n 's/^.*Forked child \([0-9]*\)$/\1/p' "$TMPFILE"` +rm "$TMPFILE" + +if [ "x$CHILD_PID" = "x" ]; then + echo "TFAIL: Child process was not created" + exit 1 +fi + +# The child process can stay alive for a short while even after receiving +# SIGKILL, especially if the system is under heavy load. Wait up to 5 seconds +# for it to fully exit. +for i in `seq 6`; do + CHILD_STATE=`sed -ne 's/^State:\s*\([A-Z]\).*$/\1/p' "/proc/$CHILD_PID/status" 2>/dev/null` + + if [ ! -e "/proc/$CHILD_PID" ] || [ "$CHILD_STATE" = "Z" ]; then + echo "TPASS: Child process was cleaned up" + exit 0 + fi + + sleep 1 +done + +echo "TFAIL: Child process was left behind" +exit 1 diff --git a/ltp/lib/newlib_tests/test_exec.c b/ltp/lib/newlib_tests/test_exec.c new file mode 100644 index 0000000000000000000000000000000000000000..370a0b948ec7de50356e1c1b7d0e96a2bebc0a20 --- /dev/null +++ b/ltp/lib/newlib_tests/test_exec.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Cyril Hrubis + */ + +/* + * Assert that tst_res() from child started by exec() is propagated to the main + * test process. + * + * This test should be executed as: + * $ PATH=$PATH:$PWD ./test_exec + */ + +#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, +}; diff --git a/ltp/lib/newlib_tests/test_exec_child.c b/ltp/lib/newlib_tests/test_exec_child.c new file mode 100644 index 0000000000000000000000000000000000000000..c572150d99d3b511c319789754b9ef4b53a51be3 --- /dev/null +++ b/ltp/lib/newlib_tests/test_exec_child.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Cyril Hrubis + */ + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int main(void) +{ + tst_reinit(); + tst_res(TPASS, "Child passed!"); + return 0; +} diff --git a/ltp/lib/newlib_tests/test_fail_variant.c b/ltp/lib/newlib_tests/test_fail_variant.c new file mode 100644 index 0000000000000000000000000000000000000000..27829c703fb0c43e6b864490122a6fce99a12d09 --- /dev/null +++ b/ltp/lib/newlib_tests/test_fail_variant.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Cyril Hrubis + */ + +/* + * Test that tst_brk(TFAIL, ...) exits only single test variant. + */ +#include "tst_test.h" + +static void do_test(void) +{ + tst_brk(TFAIL, "Failing a test variant"); + tst_res(TWARN, "Shouldn't be reached"); +} + +static struct tst_test test = { + .test_all = do_test, + .test_variants = 10, +}; diff --git a/ltp/lib/newlib_tests/test_guarded_buf.c b/ltp/lib/newlib_tests/test_guarded_buf.c new file mode 100644 index 0000000000000000000000000000000000000000..b6035fdfee3c2728b2c7a24d0f305a071c3cc727 --- /dev/null +++ b/ltp/lib/newlib_tests/test_guarded_buf.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Cyril Hrubis + */ + +/* + * Test that acces after guarded buffer causes segfault. + */ + +#include +#include +#include "tst_test.h" + +#define BUF1_LEN 10 +#define BUF2_LEN 4096 +#define BUF3_LEN 12004 + +static char *buf1; +static char *buf2; +static char *buf3; + +static void do_test(unsigned int n) +{ + int pid; + int status; + + if (n == 6) { + buf1[-1] = 0; + buf3[-1] = 0; + tst_res(TPASS, "Buffers dirtied!"); + } + + pid = SAFE_FORK(); + if (!pid) { + switch (n) { + case 0: + buf1[BUF1_LEN - 1] = 0; + break; + case 1: + buf2[BUF2_LEN - 1] = 0; + break; + case 2: + buf3[BUF3_LEN - 1] = 0; + break; + case 3: + buf1[BUF1_LEN] = 0; + break; + case 4: + buf2[BUF2_LEN] = 0; + break; + case 5: + buf3[BUF3_LEN] = 0; + break; + case 6: + buf1[-2] = 0; + buf3[-2] = 0; + break; + } + + exit(0); + } + + SAFE_WAITPID(pid, &status, 0); + + if (n == 6) + return; + + if (n < 3) { + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + tst_res(TPASS, "exited normally"); + return; + } + } else { + if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) { + tst_res(TPASS, "Killed by SIGSEGV"); + return; + } + } + + tst_res(TFAIL, "Child %s", tst_strstatus(status)); +} + +static struct tst_test test = { + .forks_child = 1, + .test = do_test, + .tcnt = 7, + .bufs = (struct tst_buffers []) { + {&buf1, .size = BUF1_LEN}, + {&buf2, .size = BUF2_LEN}, + {&buf3, .size = BUF3_LEN}, + {} + } +}; diff --git a/ltp/lib/newlib_tests/test_kconfig.c b/ltp/lib/newlib_tests/test_kconfig.c new file mode 100644 index 0000000000000000000000000000000000000000..cea36b5ee8cad4d3ca782e6bf8c5063b8b8877f4 --- /dev/null +++ b/ltp/lib/newlib_tests/test_kconfig.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Cyril Hrubis + */ + +#include "tst_test.h" +#include "tst_kconfig.h" + +static void do_test(void) +{ + tst_res(TPASS, "Test passed!"); +} + +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 +}; + +static struct tst_test test = { + .test_all = do_test, + .needs_kconfigs = kconfigs, +}; diff --git a/ltp/lib/newlib_tests/test_kconfig.sh b/ltp/lib/newlib_tests/test_kconfig.sh new file mode 100755 index 0000000000000000000000000000000000000000..4b83c354215bb18e817e3af2425a36394e27162f --- /dev/null +++ b/ltp/lib/newlib_tests/test_kconfig.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +echo "Attempting to parse currently running kernel config" +./test_kconfig +echo + +for i in config0*; do + head -n 1 "$i" + KCONFIG_PATH="$i" ./test_kconfig + echo +done diff --git a/ltp/lib/newlib_tests/test_kconfig01.c b/ltp/lib/newlib_tests/test_kconfig01.c new file mode 100644 index 0000000000000000000000000000000000000000..ee919dcacb8dae39c82edd78bd0393ec41b360ce --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_kconfig02.c b/ltp/lib/newlib_tests/test_kconfig02.c new file mode 100644 index 0000000000000000000000000000000000000000..176929222a0f01ba8b6ef45fde9b3a621c9b9c37 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_kconfig03.c b/ltp/lib/newlib_tests/test_kconfig03.c new file mode 100644 index 0000000000000000000000000000000000000000..52c0c1b4b9b5f703e4bc5561c48f01710f80c5af --- /dev/null +++ b/ltp/lib/newlib_tests/test_kconfig03.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Li Wang + */ + +#include "tst_test.h" +#include "tst_kconfig.h" + +static struct tst_kcmdline_var params[] = { + TST_KCMDLINE_INIT("BOOT_IMAGE"), + TST_KCMDLINE_INIT("root"), + TST_KCMDLINE_INIT("foo") +}; + +static void do_test(void) +{ + int i, N; + + N = (int) ARRAY_SIZE(params); + + tst_kcmdline_parse(params, N); + + for (i = 0; i < N; i++) { + if (params[i].found) { + tst_res(TPASS, "params[%d] = {%s, %s}", i, params[i].key, params[i].value); + } else { + if (!strcmp(params[i].key, "foo")) + tst_res(TPASS, "%s is not found in /proc/cmdline", params[i].key); + else + tst_res(TFAIL, "%s is not found in /proc/cmdline", params[i].key); + } + } +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test_macros01.c b/ltp/lib/newlib_tests/test_macros01.c new file mode 100644 index 0000000000000000000000000000000000000000..c04c9436372d8447a6252822373e1d8e5f8c9ccb --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_macros02.c b/ltp/lib/newlib_tests/test_macros02.c new file mode 100644 index 0000000000000000000000000000000000000000..1b12fab73737be08f781b74184e2a94951cbb3b0 --- /dev/null +++ b/ltp/lib/newlib_tests/test_macros02.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + * Copyright (c) Linux Test Project, 2021-2024 + */ + +/* + * Test macros: + * + * - TST_EXP_FAIL + * - TST_EXP_FAIL_ARR + * - TST_EXP_FAIL2 + * - TST_EXP_FAIL2_ARR + * - TST_EXP_FAIL_PTR_NULL + * - TST_EXP_FAIL_PTR_NULL_ARR + * - TST_EXP_FAIL_PTR_VOID + * - TST_EXP_FAIL_PTR_VOID_ARR + */ + +#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 char *fail_fn_null(void) +{ + errno = EINVAL; + return NULL; +} + +static char *fail_fn_void(void) +{ + errno = EINVAL; + return (void *)-1; +} + +static char *inval_ret_fn_char(void) +{ + return (void *)-1; +} + +static char *pass_fn_char(void) +{ + return "pass"; +} + +#define TEST_MACRO(macro, macro_arr, fail_fn, pass_fn, inval_fn) \ + do { \ + tst_res(TINFO, "Testing " #macro " macro"); \ + macro(fail_fn(), EINVAL, #fail_fn"()"); \ + tst_res(TINFO, "TST_PASS = %i", TST_PASS); \ + macro(fail_fn(), ENOTTY); /* skip msg parameter */ \ + tst_res(TINFO, "TST_PASS = %i", TST_PASS); \ + macro(pass_fn(), ENOTTY, #pass_fn"()"); \ + tst_res(TINFO, "TST_PASS = %i", TST_PASS); \ + macro(inval_fn(), ENOTTY, #inval_fn"()"); \ + tst_res(TINFO, "TST_PASS = %i", TST_PASS); \ + macro_arr(fail_fn(), exp_errs_pass, ARRAY_SIZE(exp_errs_pass), #fail_fn"()"); \ + tst_res(TINFO, "TST_PASS = %i", TST_PASS); \ + macro_arr(fail_fn(), exp_errs_fail, ARRAY_SIZE(exp_errs_fail)); /* skip msg parameter */ \ + tst_res(TINFO, "TST_PASS = %i", TST_PASS); \ + } while (0) + +static void do_test(void) +{ + const int exp_errs_pass[] = {ENOTTY, EINVAL}; + const int exp_errs_fail[] = {ENOTTY, EISDIR}; + + TEST_MACRO(TST_EXP_FAIL, TST_EXP_FAIL_ARR, fail_fn, pass_fn, inval_ret_fn); + TEST_MACRO(TST_EXP_FAIL2, TST_EXP_FAIL2_ARR, fail_fn, pass_fn, inval_ret_fn); + TEST_MACRO(TST_EXP_FAIL_PTR_NULL, TST_EXP_FAIL_PTR_NULL_ARR, fail_fn_null, + pass_fn_char, inval_ret_fn_char); + TEST_MACRO(TST_EXP_FAIL_PTR_VOID, TST_EXP_FAIL_PTR_VOID_ARR, fail_fn_void, + pass_fn_char, inval_ret_fn_char); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/test_macros03.c b/ltp/lib/newlib_tests/test_macros03.c new file mode 100644 index 0000000000000000000000000000000000000000..19a0ad6fd3dff3ceaa1f593c919548d166bbdd70 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_macros04.c b/ltp/lib/newlib_tests/test_macros04.c new file mode 100644 index 0000000000000000000000000000000000000000..e0111807fe3ee8f79b04968b7a9b6fd38ea4fc7e --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_macros05.c b/ltp/lib/newlib_tests/test_macros05.c new file mode 100644 index 0000000000000000000000000000000000000000..fda1410a237499c2a0deeda57f4d79d9716b734b --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_macros06.c b/ltp/lib/newlib_tests/test_macros06.c new file mode 100644 index 0000000000000000000000000000000000000000..4d300d7977c34956f16e7c2af12c4ff853eea97a --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_parse_filesize.c b/ltp/lib/newlib_tests/test_parse_filesize.c new file mode 100644 index 0000000000000000000000000000000000000000..d60d7dc6a42f702f970cd2c388fe5d0b7ec7033b --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/test_runtime01.c b/ltp/lib/newlib_tests/test_runtime01.c new file mode 100644 index 0000000000000000000000000000000000000000..169033850d251c6d2153fc763984a8ce72f6bbc7 --- /dev/null +++ b/ltp/lib/newlib_tests/test_runtime01.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018, Linux Test Project + * + * Runs for 4 seconds for each test iteration. + */ +#include +#include +#include "tst_test.h" + +static void run(void) +{ + int runtime; + + tst_res(TINFO, "Running variant %i", tst_variant); + + do { + runtime = tst_remaining_runtime(); + tst_res(TINFO, "Remaining runtime %d", runtime); + sleep(1); + } while (runtime); + + tst_res(TPASS, "Finished loop!"); +} + +static struct tst_test test = { + .test_all = run, + .runtime = 4, + .test_variants = 2, +}; diff --git a/ltp/lib/newlib_tests/test_runtime02.c b/ltp/lib/newlib_tests/test_runtime02.c new file mode 100644 index 0000000000000000000000000000000000000000..dd8eaa4d3ced0f98028ecd7dc49a8fd75a0bcd1a --- /dev/null +++ b/ltp/lib/newlib_tests/test_runtime02.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021, Linux Test Project + */ +/* + * This test is set up so that the timeout is not long enough to guarantee + * enough runtime for two iterations, i.e. the timeout without offset and after + * scaling is too small and the tests ends up with TBROK. + * + * The default timeout in the test library is set to 30 seconds. The test + * runtime is set to 5 so the test should timeout after 35 seconds. + */ + +#include +#include +#include "tst_test.h" + +static void run(void) +{ + tst_res(TINFO, "Sleeping for 40 seconds"); + sleep(40); + tst_res(TFAIL, "Still alive"); +} + +static struct tst_test test = { + .test_all = run, + .runtime = 5, +}; diff --git a/ltp/lib/newlib_tests/test_timer.c b/ltp/lib/newlib_tests/test_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..6b670d8105953fc74daaea4317c38d6eeadde97b --- /dev/null +++ b/ltp/lib/newlib_tests/test_timer.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Cyril Hrubis + */ + +/* + * Tests for include/tst_timer.h + */ + +#include "tst_test.h" +#include "tst_timer.h" + +#define VAL_MS 1001 +#define VAL_US 1001000 + +static void test_diff(enum tst_ts_type type) +{ + struct tst_ts ts1, ts2; + long long diff; + + ts1 = tst_ts_from_ms(type, VAL_MS); + ts2 = tst_ts_from_us(type, VAL_US); + + diff = tst_ts_diff_ns(ts1, ts2); + + if (diff == 0) + tst_res(TPASS, "ns_diff = 0"); + else + tst_res(TFAIL, "ns_diff = %lli", diff); + + diff = tst_ts_diff_ns(ts1, ts2); + + if (diff == 0) + tst_res(TPASS, "us_diff = 0"); + else + tst_res(TFAIL, "us_diff = %lli", diff); + + diff = tst_ts_diff_ms(ts1, ts2); + + if (diff == 0) + tst_res(TPASS, "ms_diff = 0"); + else + tst_res(TFAIL, "ms_diff = %lli", diff); +} + +static void test_lt(enum tst_ts_type type) +{ + struct tst_ts ts1, ts2; + + ts1 = tst_ts_from_ms(type, VAL_MS); + ts2 = tst_ts_from_us(type, VAL_US + 1); + + if (tst_ts_lt(ts1, ts2)) + tst_res(TPASS, "ts1 < ts2"); + else + tst_res(TFAIL, "ts1 >= ts2"); + + ts1 = tst_ts_add_us(ts1, 1); + + if (tst_ts_lt(ts1, ts2)) + tst_res(TFAIL, "ts1 < ts2"); + else + tst_res(TPASS, "ts1 >= ts2"); + + ts1 = tst_ts_add_us(ts1, 1); + + if (tst_ts_lt(ts1, ts2)) + tst_res(TFAIL, "ts1 < ts2"); + else + tst_res(TPASS, "ts1 >= ts2"); +} + +static void test_add_sub(enum tst_ts_type type) +{ + struct tst_ts ts; + + ts = tst_ts_from_ns(type, 999999000); + ts = tst_ts_add_us(ts, 1); + + long long sec = tst_ts_get_sec(ts); + long long nsec = tst_ts_get_nsec(ts); + + /* Check that result was normalized */ + if (sec != 1 || nsec != 0) + tst_res(TFAIL, "sec = %lli, nsec = %lli", sec, nsec); + else + tst_res(TPASS, "sec = %lli, nsec = %lli", sec, nsec); + + ts = tst_ts_from_ms(type, 1000); + ts = tst_ts_sub_us(ts, 1); + + sec = tst_ts_get_sec(ts); + nsec = tst_ts_get_nsec(ts); + + /* Check that result was normalized */ + if (sec != 0 || nsec != 999999000) + tst_res(TFAIL, "sec = %lli, nsec = %lli", sec, nsec); + else + tst_res(TPASS, "sec = %lli, nsec = %lli", sec, nsec); +} + +static void do_test(unsigned int n) +{ + tst_res(TINFO, "Testing with type = %i", n); + test_diff(n); + test_lt(n); + test_add_sub(n); +} + +static struct tst_test test = { + .test = do_test, + .tcnt = 3, +}; diff --git a/ltp/lib/newlib_tests/test_zero_hugepage.c b/ltp/lib/newlib_tests/test_zero_hugepage.c new file mode 100644 index 0000000000000000000000000000000000000000..eec48ffb487f86a9cce9423accbcb990182e3857 --- /dev/null +++ b/ltp/lib/newlib_tests/test_zero_hugepage.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu + */ + +/* + * Tests .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 .hugepages = {TST_NO_HUGEPAGES}"); + + struct tst_hugepage hp = { 3, TST_REQUEST }; + hpages = tst_reserve_hugepages(&hp); + 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_reserve_hugepages"); +} + +static struct tst_test test = { + .test_all = do_test, + .hugepages = {TST_NO_HUGEPAGES}, +}; diff --git a/ltp/lib/newlib_tests/test_zero_hugepage.sh b/ltp/lib/newlib_tests/test_zero_hugepage.sh new file mode 100755 index 0000000000000000000000000000000000000000..92bd7e33147f34c206ac3c6ad4be68453318c9bc --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_bool_expr.c b/ltp/lib/newlib_tests/tst_bool_expr.c new file mode 100644 index 0000000000000000000000000000000000000000..8f0929d35f84d7ce35552dc7bfd4aee8e66722ee --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_capability01.c b/ltp/lib/newlib_tests/tst_capability01.c new file mode 100644 index 0000000000000000000000000000000000000000..47ac045693ff7f4131738f55d84a8fe44f9ca858 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_capability01.c @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2019 Richard Palethorpe + * + * The user or file requires CAP_NET_RAW for this test to work. + * e.g use "$ setcap cap_net_raw=pei tst_capability" + */ + +#include +#include + +#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"); + 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"); + } +} + +static void setup(void) +{ + if (geteuid() == 0) + tst_res(TWARN, "CAP_NET_RAW may be ignored when euid == 0"); + + TEST(socket(AF_INET, SOCK_RAW, 1)); + if (TST_RET < 0) + tst_brk(TFAIL | TTERRNO, "Can't create raw socket in setup"); + + 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), + {} + }, +}; diff --git a/ltp/lib/newlib_tests/tst_capability02.c b/ltp/lib/newlib_tests/tst_capability02.c new file mode 100644 index 0000000000000000000000000000000000000000..45e3f2d22e9409a6cfb52d1a1a533713da1b70b8 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_capability02.c @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2019 Richard Palethorpe + */ + +#include +#include + +#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(TPASS, "Created raw socket"); + SAFE_CLOSE(TST_RET); + } else { + tst_res(TFAIL | TTERRNO, "Didn't create raw socket"); + } +} + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_REQ, CAP_NET_RAW), + TST_CAP(TST_CAP_DROP, CAP_AUDIT_READ), /* 64bit capability */ + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), + {} + }, +}; diff --git a/ltp/lib/newlib_tests/tst_cgroup01.c b/ltp/lib/newlib_tests/tst_cgroup01.c new file mode 100644 index 0000000000000000000000000000000000000000..eda0c548db27c1a4d0e97628d1e7d597a39ea1e1 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_cgroup01.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2021 SUSE LLC */ + +#include + +#include "tst_test.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_cg_opts cgopts; + +static void do_test(void) +{ + tst_res(TPASS, "pass"); +} + +static void setup(void) +{ + cgopts.needs_ver = !!only_mount_v1 ? TST_CG_V1 : 0; + + tst_cg_scan(); + tst_cg_print_config(); + + tst_cg_require("memory", &cgopts); + tst_cg_print_config(); + tst_cg_require("cpuset", &cgopts); + tst_cg_print_config(); +} + +static void cleanup(void) +{ + if (no_cleanup) { + tst_res(TINFO, "no cleanup"); + } else { + tst_res(TINFO, "cleanup"); + tst_cg_cleanup(); + } +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .options = opts, +}; diff --git a/ltp/lib/newlib_tests/tst_cgroup02.c b/ltp/lib/newlib_tests/tst_cgroup02.c new file mode 100644 index 0000000000000000000000000000000000000000..de2ca1812851f7171752654d3a63ac1635980250 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_cgroup02.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2021 SUSE LLC */ + +#include +#include + +#include "tst_test.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_cg_opts cgopts; +static struct tst_cg_group *cg_child; + +static void do_test(void) +{ + char buf[BUFSIZ]; + size_t mem; + + if (!TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+memory"); + if (!TST_CG_VER_IS_V1(tst_cg, "cpuset")) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+cpuset"); + + cg_child = tst_cg_group_mk(tst_cg, "child"); + if (!SAFE_FORK()) { + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + + SAFE_CG_SCANF(cg_child, "memory.current", "%zu", &mem); + tst_res(TPASS, "child/memory.current = %zu", mem); + SAFE_CG_PRINTF(cg_child, "memory.max", + "%zu", (1UL << 24) - 1); + SAFE_CG_PRINTF(cg_child, "memory.swap.max", + "%zu", 1UL << 31); + + SAFE_CG_READ(cg_child, "cpuset.mems", buf, sizeof(buf)); + tst_res(TPASS, "child/cpuset.mems = %s", buf); + SAFE_CG_PRINT(cg_child, "cpuset.mems", buf); + + exit(0); + } + + SAFE_CG_PRINTF(tst_cg, "memory.max", "%zu", (1UL << 24) - 1); + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + SAFE_CG_SCANF(tst_cg, "memory.current", "%zu", &mem); + tst_res(TPASS, "memory.current = %zu", mem); + + tst_reap_children(); + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cg_group_rm(cg_child); +} + +static void setup(void) +{ + cgopts.needs_ver = !!only_mount_v1 ? TST_CG_V1 : 0; + + tst_cg_scan(); + tst_cg_print_config(); + + tst_cg_require("memory", &cgopts); + tst_cg_require("cpuset", &cgopts); + + tst_cg_init(); +} + +static void cleanup(void) +{ + if (cg_child) { + SAFE_CG_PRINTF(tst_cg_drain, + "cgroup.procs", "%d", getpid()); + cg_child = tst_cg_group_rm(cg_child); + } + if (!no_cleanup) + tst_cg_cleanup(); +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .options = opts, + .forks_child = 1, +}; diff --git a/ltp/lib/newlib_tests/tst_checkpoint.c b/ltp/lib/newlib_tests/tst_checkpoint.c new file mode 100644 index 0000000000000000000000000000000000000000..a283f03efe1c2ca51d3a3944b431a1353a8e6a6d --- /dev/null +++ b/ltp/lib/newlib_tests/tst_checkpoint.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Modernized checkpoint usage. + */ + +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_checkpoint.h" + +/* Test 1: Basic checkpoint signal from child to parent */ +static void checkpoint_test1(void) +{ + pid_t pid = SAFE_FORK(); + + if (pid == 0) { + tst_res(TINFO, "Child: signaling checkpoint"); + TST_CHECKPOINT_WAKE(0); + _exit(0); + } + + TST_CHECKPOINT_WAIT(0); + tst_res(TPASS, "Parent: checkpoint reached"); + + SAFE_WAITPID(pid, NULL, 0); + + return; +} + +/* Test 2: Checkpoint wait with timeout, wake from child */ +static void checkpoint_test2(void) +{ + pid_t pid = SAFE_FORK(); + + if (pid == 0) { + tst_res(TINFO, "Child: signaling checkpoint"); + TST_CHECKPOINT_WAKE2(0, 1); + _exit(0); + } + + TST_CHECKPOINT_WAIT2(0, 1000); + tst_res(TPASS, "Parent: checkpoint reached"); + + SAFE_WAITPID(pid, NULL, 0); + + return; +} + +/* Test 3: Wake two child waiters on the same checkpoint */ +static void checkpoint_test3(void) +{ + pid_t pid1, pid2; + + pid1 = SAFE_FORK(); + if (pid1 == 0) { + tst_res(TINFO, "Child 1: waiting on checkpoint 0 (no timeout)"); + TST_CHECKPOINT_WAIT(0); + _exit(0); + } + + pid2 = SAFE_FORK(); + if (pid2 == 0) { + tst_res(TINFO, "Child 2: waiting on checkpoint 0 (1000ms timeout)"); + TST_CHECKPOINT_WAIT2(0, 1000); + _exit(0); + } + + TST_CHECKPOINT_WAKE2(0, 2); + tst_res(TPASS, "Parent: checkpoint wake issued"); + + tst_reap_children(); + + return; +} + +/* Test 4: Two-way checkpoint handshake (child->parent->child) */ +static void checkpoint_test4(void) +{ + pid_t pid = SAFE_FORK(); + + if (pid == 0) { + tst_res(TINFO, "Child: waking and then waiting on checkpoint 0"); + TST_CHECKPOINT_WAKE_AND_WAIT(0); + _exit(0); + } + + TST_CHECKPOINT_WAIT(0); + TST_CHECKPOINT_WAKE(0); + + tst_res(TPASS, "Parent: checkpoint handshake completed"); + + SAFE_WAITPID(pid, NULL, 0); + + return; +} + +static void run(void) +{ + checkpoint_test1(); + checkpoint_test2(); + checkpoint_test3(); + checkpoint_test4(); + + return; +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/ltp/lib/newlib_tests/tst_checkpoint_child.c b/ltp/lib/newlib_tests/tst_checkpoint_child.c new file mode 100644 index 0000000000000000000000000000000000000000..c4eaccaccab5238b29eaa11de8312ef03844dde8 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_checkpoint_child.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Child process: this binary is expected to be exec'd by the parent. + * + * It reinitializes the shared memory region using tst_reinit(), + * verifies the command-line argument, and signals checkpoint 0. + */ + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_checkpoint.h" + +int main(int argc, char *argv[]) +{ + tst_reinit(); + + if (argc != 2) + tst_brk(TFAIL, "argc is %d, expected 2", argc); + + if (strcmp(argv[1], "canary")) + tst_brk(TFAIL, "argv[1] is %s, expected 'canary'", argv[1]); + + tst_res(TINFO, "Child: signaling checkpoint"); + TST_CHECKPOINT_WAKE(0); + + return 0; +} diff --git a/ltp/lib/newlib_tests/tst_checkpoint_parent.c b/ltp/lib/newlib_tests/tst_checkpoint_parent.c new file mode 100644 index 0000000000000000000000000000000000000000..9d7f1783bcb1d61326c7bed829661ad5723bc2ef --- /dev/null +++ b/ltp/lib/newlib_tests/tst_checkpoint_parent.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Parent process: spawns a child which reinitializes checkpoint region + * using tst_reinit(). Waits for a checkpoint signal from the child. + */ + +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_checkpoint.h" + +static void run(void) +{ + pid_t pid = SAFE_FORK(); + + if (pid == 0) { + TEST(execlp("tst_checkpoint_child", "tst_checkpoint_child", "canary", NULL)); + tst_brk(TFAIL | TTERRNO, "Failed to execute tst_checkpoint_child"); + } + + TST_CHECKPOINT_WAIT(0); + tst_res(TPASS, "Parent: checkpoint reached"); + + SAFE_WAITPID(pid, NULL, 0); + + return; +} + +static struct tst_test test = { + .forks_child = 1, + .needs_checkpoints = 1, + .child_needs_reinit = 1, + .test_all = run, +}; diff --git a/ltp/lib/newlib_tests/tst_checkpoint_wait_timeout.c b/ltp/lib/newlib_tests/tst_checkpoint_wait_timeout.c new file mode 100644 index 0000000000000000000000000000000000000000..2fa6f8cf9d12caf28e47bed265f1042b880d62a2 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_checkpoint_wait_timeout.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Test: checkpoint wait with timeout. + * Expected: child blocks on checkpoint wait, parent exits without signaling. + */ + +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_checkpoint.h" + +static void run(void) +{ + pid_t pid; + + pid = SAFE_FORK(); + + if (pid == 0) { + int ret = tst_checkpoint_wait(0, 1000); + + if (ret == -1 && errno == ETIMEDOUT) + tst_res(TPASS, "Child: checkpoint wait timed out as expected"); + else + tst_brk(TBROK | TERRNO, "checkpoint wait failed"); + + _exit(0); + } + + tst_res(TINFO, "Parent: exiting without signaling checkpoint"); + SAFE_WAITPID(pid, NULL, 0); + + return; +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/ltp/lib/newlib_tests/tst_checkpoint_wake_timeout.c b/ltp/lib/newlib_tests/tst_checkpoint_wake_timeout.c new file mode 100644 index 0000000000000000000000000000000000000000..c37fd69452632499f38d42fe2b817e93d7ca1468 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_checkpoint_wake_timeout.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Test: checkpoint wake without matching wait. + * Expected: wake completes with ETIMEDOUT errno as expected. + */ + +#include +#include +#include + +#include "tst_test.h" +#include "tst_checkpoint.h" + +static void run(void) +{ + int ret = tst_checkpoint_wake(0, 1, 1000); + + if (ret == -1 && errno == ETIMEDOUT) + tst_res(TPASS, "checkpoint wake timed out as expected"); + else + tst_brk(TBROK | TERRNO, "checkpoint wake failed"); + + return; +} + +static struct tst_test test = { + .test_all = run, + .needs_checkpoints = 1, +}; diff --git a/ltp/lib/newlib_tests/tst_device.c b/ltp/lib/newlib_tests/tst_device.c new file mode 100644 index 0000000000000000000000000000000000000000..a450b284d03b7347a20dfeda1462bc48b625591f --- /dev/null +++ b/ltp/lib/newlib_tests/tst_device.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Linux Test Project + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" + +#define DEVBLOCKSIZE 2048 +#define DEV_MIN_SIZE 310 + +static char *mntpoint; +static uint64_t ltp_dev_size; + +static int set_block_size(int fd) +{ + return ioctl(fd, LOOP_SET_BLOCK_SIZE, DEVBLOCKSIZE); +} + +static void setup(void) +{ + int fd; + + mntpoint = tst_tmpdir_genpath("mnt"); + + fd = SAFE_OPEN(tst_device->dev, O_RDONLY); + + SAFE_IOCTL(fd, BLKGETSIZE64, <p_dev_size); + + TST_RETRY_FN_EXP_BACKOFF(set_block_size(fd), TST_RETVAL_EQ0, 10); + + SAFE_CLOSE(fd); + + SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL); + + SAFE_MKDIR(mntpoint, 0777); + SAFE_MOUNT(tst_device->dev, mntpoint, tst_device->fs_type, 0, 0); +} + +static void cleanup(void) +{ + if (tst_is_mounted(mntpoint)) + SAFE_UMOUNT(mntpoint); +} + +static void test_dev_min_size(void) +{ + uint64_t size; + + size = ltp_dev_size / 1024 / 1024; + + if (size == DEV_MIN_SIZE) + tst_res(TPASS, "Got expected device size %lu", size); + else + tst_res(TFAIL, "Expected device size is %d but got %lu", + DEV_MIN_SIZE, size); +} + +static void test_tst_find_backing_dev(void) +{ + char block_dev[100]; + + tst_find_backing_dev(mntpoint, block_dev, sizeof(block_dev)); + + if (!strcmp(tst_device->dev, block_dev)) + tst_res(TPASS, "%s belongs to %s block dev", mntpoint, + block_dev); + else + tst_res(TFAIL, "%s should belong to %s, but %s is returned", + mntpoint, tst_device->dev, block_dev); +} + +static void test_tst_dev_block_size(void) +{ + int block_size; + + block_size = tst_dev_block_size(mntpoint); + + if (block_size == DEVBLOCKSIZE) + tst_res(TPASS, "%s has %d block size", mntpoint, block_size); + else + tst_res(TFAIL, "%s has %d block size, but expected is %i", + mntpoint, block_size, DEVBLOCKSIZE); +} + +static void do_test(void) +{ + test_dev_min_size(); + test_tst_find_backing_dev(); + test_tst_dev_block_size(); +} + +static struct tst_test test = { + .needs_root = 1, + .needs_device = 1, + .dev_min_size = DEV_MIN_SIZE, + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .min_kver = "4.14", +}; diff --git a/ltp/lib/newlib_tests/tst_expiration_timer.c b/ltp/lib/newlib_tests/tst_expiration_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..6cc73367df174ae8b42f6c552efe5465fdf97c1a --- /dev/null +++ b/ltp/lib/newlib_tests/tst_expiration_timer.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Cyril Hrubis + */ + +/* + * Test for expiration timer the test should run for roughly 5 seconds + * when executed as time ./tst_expiration_timer + */ + +#include "tst_test.h" +#include "tst_timer.h" + +static void do_test(void) +{ + tst_timer_start(CLOCK_MONOTONIC); + + while (!tst_timer_expired_ms(5000)) + usleep(1); + + tst_res(TPASS, "All done!"); +} + +static void setup(void) +{ + tst_timer_check(CLOCK_MONOTONIC); +} + +static struct tst_test test = { + .setup = setup, + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/tst_fuzzy_sync01.c b/ltp/lib/newlib_tests/tst_fuzzy_sync01.c new file mode 100644 index 0000000000000000000000000000000000000000..b1390f460cce3a4d288ba96c7bc73e350dcbf6ea --- /dev/null +++ b/ltp/lib/newlib_tests/tst_fuzzy_sync01.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Richard Palethorpe + */ +/* + * 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(H: Hit). + * - 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 + * 'H' counter variable atomically. They both also increment it when + * leaving their critical sections. We record the value of 'H' when A + * increments it. From the recorded values of 'H' 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 tst_atomic_t H; +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(&H)) + tst_brk(TBROK, "Counter should now be zero"); + + tst_fzsync_start_race_b(&pair); + delay(b.critical_s); + + tst_atomic_add_return(1, &H); + delay(b.critical_t); + tst_atomic_add_return(1, &H); + + 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; + 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, worker, &i); + + while (tst_fzsync_run_a(&pair)) { + + tst_fzsync_start_race_a(&pair); + delay(a.critical_s); + + cs = tst_atomic_add_return(1, &H); + delay(a.critical_t); + ct = tst_atomic_add_return(1, &H); + + 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, &H); + if (r) + tst_brk(TBROK, "cs = %d, ct = %d, r = %d", cs, ct, r); + + if (critical > 100) { + tst_fzsync_pair_cleanup(&pair); + tst_atomic_store(0, &pair.exit); + break; + } + } + + /* + * If `pair->exit` is true, the test may fail to meet expected + * results due to resource constraints in shared CI environments + * (e.g., GitHub Actions). Limited control over CPU allocation + * can cause delays or interruptions in CPU time slices due to + * contention with other jobs. + * + * Binding the test to a single CPU core (e.g., via `taskset -c 0`) + * can worsen this by increasing contention, leading to performance + * degradation and premature loop termination. + * + * To ensure valid and reliable results in scenarios (e.g., HW, VM, CI), + * it is best to ignore test result when loop termination occurs, + * avoiding unnecessary false positive. + */ + if (pair.exit) { + tst_res(TCONF, "Test may not be able to generate a valid result"); + return; + } + + 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, + .runtime = 150, +}; diff --git a/ltp/lib/newlib_tests/tst_fuzzy_sync02.c b/ltp/lib/newlib_tests/tst_fuzzy_sync02.c new file mode 100644 index 0000000000000000000000000000000000000000..bc079f6ffe0e9e67295753364a198c2eb344025a --- /dev/null +++ b/ltp/lib/newlib_tests/tst_fuzzy_sync02.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Richard Palethorpe + */ +/* + * 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(H: Hit, D: Avoid), 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. + * + * Empirically 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 tst_atomic_t H, D; +static struct tst_fzsync_pair pair; + +/** + * Race 1: + * Thread A: |---(1)--|[1]|---(1)---| + * Thread B: |---(1)--|[1]|---(1)---| + * ad (A): |---(0)|[1]|(0)---| + * bd (B): |---(0)|[1]|(0)---| + * + * Race 2: + * Thread A: |------------------(30)------------------|[1]|---(1)---| + * Thread B: |---(1)--|[1]|---(1)---| + * ad (A): |---(0)|[1]|--(0)---| + * bd (B): |---(0)|[20]|--(0)---| + * + * Race 3: + * Thread A: |--------------------(40)--------------------|[1]|---(0)---| + * Thread B: |---(1)--|[1]|------------------(20)------------------| + * ad (A): |---(1)--|[10]|--(0)---| + * bd (B): |---(1)--|[10]|--(0)---| + */ +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); +} + +/** + * to_abs() - Convert relative time intervals to absolute time points + * @w: The input window structure containing relative time intervals + * + * This function converts relative time intervals (represented in the + * struct window) into absolute time points, where: + * + * - The start of the critical section is `critical_s`. + * - The end of the critical section is calculated as `critical_s + critical_t`. + * - The end of execution is calculated as `critical_s + critical_t + return_t`. + * + * Return: + * A new window structure (`wc`) with absolute time points. + */ +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, &H); + 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); + int critical = 0; + int now, fin; + + tst_fzsync_pair_reset(&pair, NULL); + SAFE_PTHREAD_CREATE(&pair.thread_b, 0, worker, &i); + + while (tst_fzsync_run_a(&pair)) { + H = 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(&H) == 1) { + tst_atomic_add_return(1, &H); + 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); + tst_atomic_store(0, &pair.exit); + break; + } + } + + /* + * If `pair->exit` is true, the test may fail to meet expected + * results due to resource constraints in shared CI environments + * (e.g., GitHub Actions). Limited control over CPU allocation + * can cause delays or interruptions in CPU time slices due to + * contention with other jobs. + * + * Binding the test to a single CPU core (e.g., via `taskset -c 0`) + * can worsen this by increasing contention, leading to performance + * degradation and premature loop termination. + * + * To ensure valid and reliable results in scenarios (e.g., HW, VM, CI), + * it is best to ignore test result when loop termination occurs, + * avoiding unnecessary false positive. + */ + if (pair.exit) { + tst_res(TCONF, "Test may not be able to generate a valid result"); + return; + } + + 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, + .runtime = 150, +}; diff --git a/ltp/lib/newlib_tests/tst_fuzzy_sync03.c b/ltp/lib/newlib_tests/tst_fuzzy_sync03.c new file mode 100644 index 0000000000000000000000000000000000000000..7468e79ea73c044619497f66495b9b420567ebe0 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_fuzzy_sync03.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Richard Palethorpe + */ +/* 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. + */ + +#include +#include "tst_test.h" +#include "tst_safe_pthread.h" +#include "tst_fuzzy_sync.h" + +/* LOOPS * 2 + 1 must be less than INT_MAX */ +#define LOOPS 0xFFFFULL + +static volatile char seq[LOOPS * 2 + 1]; +static struct tst_fzsync_pair pair; +static volatile int seq_n; +static volatile char last_wins; + +static void setup(void) +{ + pair.exec_loops = LOOPS; + tst_fzsync_pair_init(&pair); +} + +static void *worker(void *v LTP_ATTRIBUTE_UNUSED) +{ + unsigned long long i; + + for (i = 0; tst_fzsync_run_b(&pair); i++) { + tst_fzsync_start_race_b(&pair); + usleep(1); + last_wins = 'B'; + tst_fzsync_end_race_b(&pair); + seq[seq_n] = 'B'; + seq_n = (i + 1) * 2 % (int)LOOPS * 2; + } + + if (i != LOOPS) { + tst_res(TFAIL, + "Worker performed wrong number of iterations: %lld != %lld", + i, LOOPS); + } + + return NULL; +} + +static void run(void) +{ + unsigned int i, j, fail = 0, lost_race = 0; + + tst_fzsync_pair_reset(&pair, worker); + for (i = 0; tst_fzsync_run_a(&pair); i++) { + tst_fzsync_start_race_a(&pair); + seq[seq_n] = 'A'; + seq_n = i * 2 + 1; + last_wins = 'A'; + tst_fzsync_end_race_a(&pair); + if (last_wins == 'B') + lost_race++; + } + + tst_res(TINFO, "Checking sequence..."); + for (i = 0; i < LOOPS; i++) { + j = i * 2; + if (seq[j] != 'A') { + tst_res(TFAIL, "Expected A, but found %c at %d", + seq[j], j); + fail = 1; + } + j = i * 2 + 1; + if (seq[j] != 'B') { + tst_res(TFAIL, "Expected A, but found %c at %d", + seq[j], j); + fail = 1; + } + } + + if (!fail) + tst_res(TPASS, "Sequence is correct"); + + if (lost_race < 100) + tst_res(TFAIL, "A only lost the race %d times", lost_race); + else + tst_res(TPASS, "A lost the race %d times", lost_race); +} + +static void cleanup(void) +{ + tst_fzsync_pair_cleanup(&pair); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .runtime = 150, +}; diff --git a/ltp/lib/newlib_tests/tst_needs_cmds01.c b/ltp/lib/newlib_tests/tst_needs_cmds01.c new file mode 100644 index 0000000000000000000000000000000000000000..777c695057893e977affbf5f9b5456436585a634 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_needs_cmds02.c b/ltp/lib/newlib_tests/tst_needs_cmds02.c new file mode 100644 index 0000000000000000000000000000000000000000..455a275ea61bb67c6e2a08920d6705186049ec35 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_needs_cmds03.c b/ltp/lib/newlib_tests/tst_needs_cmds03.c new file mode 100644 index 0000000000000000000000000000000000000000..bdc1cdf6ae76262843430acbb4272b965c9580e8 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_needs_cmds04.c b/ltp/lib/newlib_tests/tst_needs_cmds04.c new file mode 100644 index 0000000000000000000000000000000000000000..de10b8f3e05fa95e0e26f7d6e13ac4c7e6961096 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_needs_cmds05.c b/ltp/lib/newlib_tests/tst_needs_cmds05.c new file mode 100644 index 0000000000000000000000000000000000000000..c3b2b3b9acf2f1183a75f485e3402adf88221377 --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_needs_cmds06.c b/ltp/lib/newlib_tests/tst_needs_cmds06.c new file mode 100644 index 0000000000000000000000000000000000000000..40b1cf09cedcbd656356a6f8190dd931058a4a3b --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_needs_cmds07.c b/ltp/lib/newlib_tests/tst_needs_cmds07.c new file mode 100644 index 0000000000000000000000000000000000000000..d0b4ce2ff119aa2f5d6e1f04c1353e5c5642b8aa --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_needs_cmds08.c b/ltp/lib/newlib_tests/tst_needs_cmds08.c new file mode 100644 index 0000000000000000000000000000000000000000..38df2ef6d7142fd1feea412878d5052639375aff --- /dev/null +++ b/ltp/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/ltp/lib/newlib_tests/tst_print_result.c b/ltp/lib/newlib_tests/tst_print_result.c new file mode 100644 index 0000000000000000000000000000000000000000..0a2ca5af1eac25295f2f6efd930d59cb24f5f024 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_print_result.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Veronika Kabatova + */ + +/* + * Test for cecbd0cb3 ("Fix buffer overflow in print_result() function") + */ + +#include +#include "tst_test.h" + +#define TEXT "The only purpose of this text si to try to overflow the buffers "\ + "in test library, other than that it does not include any useful "\ + "information. Whoever decides to read this wall of text is just " \ + "simply wasting his time. You are not reading this are you? Hmm " \ + "you still do. Are you feeling rebelious today? Well whatever. " \ + "It's _your_ time not mine. Feel free to waste it if you want " \ + "to. Still reading? I bet you are not. And don't try to prove me "\ + "wrong just because you can. Still reading? Do you feel better "\ + "now? Now even I am bored, how come that can you still continue "\ + "reading? And now for something completely different! Let's try "\ + "some ASCII art! This is a sitting mouse from a top: <3)~~ Did "\ + "like that? No? Hmm, let me think, I think I can draw a pengiun "\ + "as well what about this one: <(^) ? You liked the mouse better? "\ + "Why I'm even trying? Anyway I'm pretty sure nobody got here, so "\ + "I will write down a secret. It will be burried here forever and "\ + "ever until brave adventurer decides to read this paragraph to "\ + "the very end. Here it comes: the text was long enough even "\ + "before I added this sentence, therefore this sentence is as "\ + "useless as it can be, yet it exists here, sometimes strange "\ + "things like this happens..." + +static void run(void) +{ + tst_res(TPASS, TEXT); + tst_res(TPASS | TERRNO, TEXT); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/ltp/lib/newlib_tests/tst_res_flags.c b/ltp/lib/newlib_tests/tst_res_flags.c new file mode 100644 index 0000000000000000000000000000000000000000..a14f0df2c94985e7849f3c4560afa133e07ae2d4 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_res_flags.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Petr Vorel + */ + +/* + * Test tst_res() flags. + */ + +#include "tst_test.h" + +#define FLAG(x) .flag = x, .str = #x +static struct tcase { + int flag; + const char *str; + const char *note; +} tcases[] = { + {FLAG(TPASS)}, + {FLAG(TFAIL)}, + {FLAG(TBROK)}, + {FLAG(TCONF)}, + {FLAG(TWARN)}, + {FLAG(TINFO)}, + {FLAG(TDEBUG), " (printed only with -D or LTP_ENABLE_DEBUG=1)"}, +}; + +static void do_cleanup(void) +{ + tst_brk(TBROK, "TBROK message should be TWARN in cleanup"); +} + +static void do_test(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(tcases); i++) + tst_res(tcases[i].flag, "%s message%s", tcases[i].str, + tcases[i].note ?: ""); +} + +static struct tst_test test = { + .test_all = do_test, + .cleanup = do_cleanup, +}; diff --git a/ltp/lib/newlib_tests/tst_res_hexd.c b/ltp/lib/newlib_tests/tst_res_hexd.c new file mode 100644 index 0000000000000000000000000000000000000000..ac461c57e3bbe4d3edf13779bfed1009246661fc --- /dev/null +++ b/ltp/lib/newlib_tests/tst_res_hexd.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Linux Test Project + */ + +#include +#include "tst_test.h" + +static void do_test(void) +{ + char tmp[] = "Hello from tst_res_hexd"; + + tst_res_hexd(TPASS, tmp, sizeof(tmp), "%s%d", "dump", 1); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/tst_safe_fileops.c b/ltp/lib/newlib_tests/tst_safe_fileops.c new file mode 100644 index 0000000000000000000000000000000000000000..e8419bd23c6466bcc5ca157ee564bfb8b89a3896 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_safe_fileops.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Linux Test Project + */ + +#include +#include "tst_test.h" + +static void do_test(void) +{ + long free; + long nproc; + long dummy; + + SAFE_FILE_LINES_SCANF("/proc/meminfo", "MemFree: %ld", &free); + if (FILE_LINES_SCANF("/proc/stat", "processes %ld", &nproc)) + tst_brk(TBROK, "Could not parse processes"); + tst_res(TPASS, "Free: %ld, nproc: %ld", free, nproc); + + if (FILE_LINES_SCANF("/proc/stat", "non-existent %ld", &dummy)) + tst_res(TPASS, "non-existent not found"); + SAFE_FILE_LINES_SCANF("/proc/stat", "non-existent %ld", &dummy); +} + +static struct tst_test test = { + .test_all = do_test, +}; diff --git a/ltp/lib/newlib_tests/tst_safe_sscanf.c b/ltp/lib/newlib_tests/tst_safe_sscanf.c new file mode 100644 index 0000000000000000000000000000000000000000..68f49a87a8e2116536b010aea72cd0a867fdf084 --- /dev/null +++ b/ltp/lib/newlib_tests/tst_safe_sscanf.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Linux Test Project + */ + +/* + * Basic unit test for the tst_safe_sscanf() function. + */ + +#include "tst_test.h" + +static void check_safe_sscanf(void) +{ + int day, month, year; + int nvalues = SAFE_SSCANF("14-07-2023", "%d-%d-%d", &day, &month, &year); + + if (nvalues == 3 && day == 14 && month == 7 && year == 2023) + tst_res(TPASS, "%d values parsed : %d,%d,%d", nvalues, day, month, year); + else + tst_res(TFAIL, "expected 3 values 14,7,2023 got: %d values %d,%d,%d", nvalues, day, month, year); +} + +static struct tst_test test = { + .test_all = check_safe_sscanf, +}; diff --git a/ltp/lib/newlib_tests/tst_strstatus.c b/ltp/lib/newlib_tests/tst_strstatus.c new file mode 100644 index 0000000000000000000000000000000000000000..f8655fe820036e8e1412ec9e26b6c8c5fa8e742b --- /dev/null +++ b/ltp/lib/newlib_tests/tst_strstatus.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) 2019-2021 Petr Vorel + */ + +/* + * Basic unit test for the tst_strstatus() function. + */ + +#include +#include "tst_test.h" + +static struct tcase { + int status; + const char *str; +} tcases[] = { + {0x0100, "exited with 1"}, + {0x0001, "killed by SIGHUP"}, + {0x137f, "is stopped"}, + {0xffff, "is resumed"}, + {0x1ff, "invalid status 0x1ff"}, +}; + +static void do_test(unsigned int n) +{ + const char *str_status = tst_strstatus(tcases[n].status); + + if (strcmp(str_status, tcases[n].str)) + tst_res(TFAIL, "%s != %s", str_status, tcases[n].str); + else + tst_res(TPASS, "%s", str_status); +} + +static struct tst_test test = { + .test = do_test, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/ltp/lib/newlib_tests/variant.c b/ltp/lib/newlib_tests/variant.c new file mode 100644 index 0000000000000000000000000000000000000000..0f5be46e3ea053c8db676f1a58608bba888a9152 --- /dev/null +++ b/ltp/lib/newlib_tests/variant.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Cyril Hrubis + */ + +#include "tst_test.h" + +static void do_test(void) +{ + switch (tst_variant) { + case 0: + /* This is skipped after first iteration */ + tst_brk(TCONF, "Test skipped"); + break; + case 1: + /* This test is correctly looped with -i opt */ + tst_res(TPASS, "Test passed"); + break; + case 2: + /* This exits the test immediately */ + tst_brk(TBROK, "Test broken"); + break; + } + + tst_res(TINFO, "test() function exiting normally"); +} + +static void setup(void) +{ + tst_res(TINFO, "Running test setup()"); + + switch (tst_variant) { + case 0: + tst_res(TINFO, "Starting tst_brk(TCONF) test"); + break; + case 1: + tst_res(TINFO, "Starting tst_res(TPASS) test"); + break; + case 2: + tst_res(TINFO, "Starting tst_brk(TBROK) test"); + break; + } +} + +static void cleanup(void) +{ + tst_res(TINFO, "Running test cleanup()"); +} + +static struct tst_test test = { + .test_all = do_test, + .test_variants = 3, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/ltp/lib/parse_opts.c b/ltp/lib/parse_opts.c new file mode 100644 index 0000000000000000000000000000000000000000..03e8333129c5e2075f6a092935e3dee96da3e1cc --- /dev/null +++ b/ltp/lib/parse_opts.c @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * AUTHOR : William Roske/Richard Logan + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "ltp_priv.h" +#include "usctest.h" +#include "tst_clocks.h" + +#ifndef UNIT_TEST +#define UNIT_TEST 0 +#endif + +/* Define flags and args for standard options */ +static int STD_INFINITE = 0; /* flag indciating to loop forever */ +int STD_LOOP_COUNT = 1; /* number of iterations */ + +static float STD_LOOP_DURATION = 0.0; /* duration value in fractional seconds */ + +static char **STD_opt_arr = NULL; /* array of option strings */ +static int STD_argind = 1; /* argv index to next argv element */ + /* (first argument) */ + /* To getopt users, it is like optind */ + +/* + * The following variables are to support system testing additions. + */ +static int STD_TP_barrier = 0; /* flag to do barrier in TEST_PAUSE */ + /* 2 - wait_barrier(), 3 - set_barrier(), * - barrier() */ +static int STD_LP_barrier = 0; /* flag to do barrier in TEST_LOOPING */ + /* 2 - wait_barrier(), 3 - set_barrier(), * - barrier() */ +static int STD_TP_shmem_sz = 0; /* shmalloc this many words per pe in TEST_PAUSE */ +static int STD_LD_shmem = 0; /* flag to do shmem_puts and shmem_gets during delay */ +static int STD_LP_shmem = 0; /* flag to do shmem_puts and gets during TEST_LOOPING */ +static int STD_LD_recfun = 0; /* do recressive function calls in loop delay */ +static int STD_LP_recfun = 0; /* do recressive function calls in TEST_LOOPING */ +static int STD_TP_sbrk = 0; /* do sbrk in TEST_PAUSE */ +static int STD_LP_sbrk = 0; /* do sbrk in TEST_LOOPING */ +static char *STD_start_break = 0; /* original sbrk size */ +static int Debug = 0; + +static struct std_option_t { + char *optstr; + char *help; + char *flag; + char **arg; +} std_options[] = { + {"h", " -h Show this help screen\n", NULL, NULL}, + {"i:", " -i n Execute test n times\n", NULL, NULL}, + {"I:", " -I x Execute test for x seconds\n", NULL, NULL}, + {NULL, NULL, NULL, NULL} +}; + +/* + * Structure for usc_recressive_func argument + */ +struct usc_bigstack_t { + char space[4096]; +}; + +static struct usc_bigstack_t *STD_bigstack = NULL; + +/* define the string length for Mesg and Mesg2 strings */ +#define STRLEN 2048 + +static char Mesg2[STRLEN]; /* holds possible return string */ +static void usc_recressive_func(); + +/* + * Define bits for options that might have env variable default + */ +#define OPT_iteration 01 +#define OPT_duration 04 +#define OPT_delay 010 + +static void print_help(void (*user_help)(void)) +{ + int i; + + for (i = 0; std_options[i].optstr; ++i) { + if (std_options[i].help) + printf("%s", std_options[i].help); + } + + if (user_help) + user_help(); +} + +/********************************************************************** + * parse_opts: + **********************************************************************/ +const char *parse_opts(int ac, char **av, const option_t * user_optarr, + void (*uhf)(void)) +{ + int found; /* flag to indicate that an option specified was */ + /* found in the user's list */ + int k; /* scratch integer for returns and short time usage */ + float ftmp; /* tmp float for parsing env variables */ + char *ptr; /* used in getting env variables */ + int options = 0; /* no options specified */ + int optstrlen, i; + char *optionstr; + int opt; + + /* + * If not the first time this function is called, release the old STD_opt_arr + * vector. + */ + if (STD_opt_arr != NULL) { + free(STD_opt_arr); + STD_opt_arr = NULL; + } + /* Calculate how much space we need for the option string */ + optstrlen = 0; + for (i = 0; std_options[i].optstr; ++i) + optstrlen += strlen(std_options[i].optstr); + if (user_optarr) + for (i = 0; user_optarr[i].option; ++i) { + if (strlen(user_optarr[i].option) > 2) + return + "parse_opts: ERROR - Only short options are allowed"; + optstrlen += strlen(user_optarr[i].option); + } + optstrlen += 1; + + /* Create the option string for getopt */ + optionstr = malloc(optstrlen); + if (!optionstr) + return + "parse_opts: ERROR - Could not allocate memory for optionstr"; + + optionstr[0] = '\0'; + + for (i = 0; std_options[i].optstr; ++i) + strcat(optionstr, std_options[i].optstr); + if (user_optarr) + for (i = 0; user_optarr[i].option; ++i) + /* only add the option if it wasn't there already */ + if (strchr(optionstr, user_optarr[i].option[0]) == NULL) + strcat(optionstr, user_optarr[i].option); + + /* + * Loop through av parsing options. + */ + while ((opt = getopt(ac, av, optionstr)) > 0) { + + STD_argind = optind; + + switch (opt) { + case '?': /* Unknown option */ + return "Unknown option"; + break; + case ':': /* Missing Arg */ + return "Missing argument"; + break; + case 'i': /* Iterations */ + options |= OPT_iteration; + STD_LOOP_COUNT = atoi(optarg); + if (STD_LOOP_COUNT == 0) + STD_INFINITE = 1; + break; + case 'I': /* Time duration */ + options |= OPT_duration; + STD_LOOP_DURATION = atof(optarg); + if (STD_LOOP_DURATION == 0.0) + STD_INFINITE = 1; + break; + case 'h': /* Help */ + print_help(uhf); + exit(0); + break; + default: + + /* Check all the user specified options */ + found = 0; + for (i = 0; user_optarr[i].option; ++i) { + + if (opt == user_optarr[i].option[0]) { + /* Yup, This is a user option, set the flag and look for argument */ + if (user_optarr[i].flag) { + *user_optarr[i].flag = 1; + } + found++; + + /* save the argument at the user's location */ + if (user_optarr[i]. + option[strlen(user_optarr[i].option) + - 1] == ':') { + *user_optarr[i].arg = optarg; + } + break; /* option found - break out of the for loop */ + } + } + /* This condition "should never happen". SO CHECK FOR IT!!!! */ + if (!found) { + sprintf(Mesg2, + "parse_opts: ERROR - option:\"%c\" NOT FOUND... INTERNAL " + "ERROR", opt); + return (Mesg2); + } + } + + } + free(optionstr); + + STD_argind = optind; + + /* + * Turn on debug + */ + if (getenv("USC_DEBUG") != NULL) { + Debug = 1; + printf("env USC_DEBUG is defined, turning on debug\n"); + } + if (getenv("USC_VERBOSE") != NULL) { + Debug = 1; + printf("env USC_VERBOSE is defined, turning on debug\n"); + } + + /* + * If the USC_ITERATION_ENV environmental variable is set to + * a number, use that number as iteration count (same as -c option). + * The -c option with arg will be used even if this env var is set. + */ + if (!(options & OPT_iteration) + && (ptr = getenv(USC_ITERATION_ENV)) != NULL) { + if (sscanf(ptr, "%i", &k) == 1) { + if (k == 0) { /* if arg is 0, set infinite loop flag */ + STD_INFINITE = 1; + if (Debug) + printf + ("Using env %s, set STD_INFINITE to 1\n", + USC_ITERATION_ENV); + } else { /* else, set the loop count to the arguement */ + STD_LOOP_COUNT = k; + if (Debug) + printf + ("Using env %s, set STD_LOOP_COUNT to %d\n", + USC_ITERATION_ENV, k); + } + } + } + + /* + * If the USC_LOOP_WALLTIME environmental variable is set, + * use that number as duration (same as -I option). + * The -I option with arg will be used even if this env var is set. + */ + + if (!(options & OPT_duration) && + (ptr = getenv(USC_LOOP_WALLTIME)) != NULL) { + if (sscanf(ptr, "%f", &ftmp) == 1 && ftmp >= 0.0) { + STD_LOOP_DURATION = ftmp; + if (Debug) + printf + ("Using env %s, set STD_LOOP_DURATION to %f\n", + USC_LOOP_WALLTIME, ftmp); + if (STD_LOOP_DURATION == 0.0) { /* if arg is 0, set infinite loop flag */ + STD_INFINITE = 1; + if (Debug) + printf + ("Using env %s, set STD_INFINITE to 1\n", + USC_LOOP_WALLTIME); + } + } + } + if (!(options & OPT_duration) && (ptr = getenv("USC_DURATION")) != NULL) { + if (sscanf(ptr, "%f", &ftmp) == 1 && ftmp >= 0.0) { + STD_LOOP_DURATION = ftmp; + if (Debug) + printf + ("Using env USC_DURATION, set STD_LOOP_DURATION to %f\n", + ftmp); + if (STD_LOOP_DURATION == 0.0) { /* if arg is 0, set infinite loop flag */ + STD_INFINITE = 1; + if (Debug) + printf + ("Using env USC_DURATION, set STD_INFINITE to 1\n"); + } + } + } + + /* + * The following are special system testing envs to turn on special + * hooks in the code. + */ + if ((ptr = getenv("USC_TP_BARRIER")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) + STD_TP_barrier = k; + else + STD_TP_barrier = 1; + if (Debug) + printf + ("using env USC_TP_BARRIER, Set STD_TP_barrier to %d\n", + STD_TP_barrier); + } + + if ((ptr = getenv("USC_LP_BARRIER")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) + STD_LP_barrier = k; + else + STD_LP_barrier = 1; + if (Debug) + printf + ("using env USC_LP_BARRIER, Set STD_LP_barrier to %d\n", + STD_LP_barrier); + } + + if ((ptr = getenv("USC_TP_SHMEM")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) { + STD_TP_shmem_sz = k; + if (Debug) + printf + ("Using env USC_TP_SHMEM, Set STD_TP_shmem_sz to %d\n", + STD_TP_shmem_sz); + } + } + + if ((ptr = getenv("USC_LP_SHMEM")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) { + STD_LP_shmem = k; + if (Debug) + printf + ("Using env USC_LP_SHMEM, Set STD_LP_shmem to %d\n", + STD_LP_shmem); + } + } + + if ((ptr = getenv("USC_LD_SHMEM")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) { + STD_LD_shmem = k; + if (Debug) + printf + ("Using env USC_LD_SHMEM, Set STD_LD_shmem to %d\n", + STD_LD_shmem); + } + } + + if ((ptr = getenv("USC_TP_SBRK")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) { + STD_TP_sbrk = k; + if (Debug) + printf + ("Using env USC_TP_SBRK, Set STD_TP_sbrk to %d\n", + STD_TP_sbrk); + } + } + + if ((ptr = getenv("USC_LP_SBRK")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) { + STD_LP_sbrk = k; + if (Debug) + printf + ("Using env USC_LP_SBRK, Set STD_LP_sbrk to %d\n", + STD_LP_sbrk); + } + } + + if ((ptr = getenv("USC_LP_RECFUN")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) { + STD_LP_recfun = k; + if (STD_bigstack != NULL) + STD_bigstack = + malloc(sizeof(struct usc_bigstack_t)); + if (Debug) + printf + ("Using env USC_LP_RECFUN, Set STD_LP_recfun to %d\n", + STD_LP_recfun); + } + } + + if ((ptr = getenv("USC_LD_RECFUN")) != NULL) { + if (sscanf(ptr, "%i", &k) == 1 && k >= 0) { + STD_LD_recfun = k; + if (STD_bigstack != NULL) + STD_bigstack = + malloc(sizeof(struct usc_bigstack_t)); + if (Debug) + printf + ("Using env USC_LD_RECFUN, Set STD_LD_recfun to %d\n", + STD_LD_recfun); + } + } +#if UNIT_TEST + printf("The following variables after option and env parsing:\n"); + printf("STD_LOOP_DURATION = %f\n", STD_LOOP_DURATION); + printf("STD_LOOP_COUNT = %d\n", STD_LOOP_COUNT); + printf("STD_INFINITE = %d\n", STD_INFINITE); +#endif + + return NULL; +} + +/*********************************************************************** + * This function will do desired end of global setup test + * hooks. + ***********************************************************************/ +int usc_global_setup_hook(void) +{ + if (STD_TP_sbrk || STD_LP_sbrk) + STD_start_break = sbrk(0); /* get original sbreak size */ + + if (STD_TP_sbrk) { + sbrk(STD_TP_sbrk); + if (Debug) + printf("after sbrk(%d)\n", STD_TP_sbrk); + } + return 0; +} + +#define USECS_PER_SEC 1000000 /* microseconds per second */ + +static uint64_t get_current_time(void) +{ + struct timespec ts; + + tst_clock_gettime(CLOCK_MONOTONIC, &ts); + + return (((uint64_t) ts.tv_sec) * USECS_PER_SEC) + ts.tv_nsec / 1000; +} + +/*********************************************************************** + * + * This function will determine if test should continue iterating + * If the STD_INFINITE flag is set, return 1. + * If the STD_LOOP_COUNT variable is set, compare it against + * the counter. + * If the STD_LOOP_DURATION variable is set, compare current time against + * calculated stop_time. + * This function will return 1 until all desired looping methods + * have been met. + * + * counter integer is supplied by the user program. + ***********************************************************************/ +int usc_test_looping(int counter) +{ + static int first_time = 1; + static uint64_t stop_time = 0; + int keepgoing = 0; + + /* + * If this is the first iteration and we are looping for + * duration of STD_LOOP_DURATION seconds (fractional) or + * doing loop delays, get the clocks per second. + */ + if (first_time) { + first_time = 0; + + /* + * If looping for duration, calculate stop time in + * clocks. + */ + if (STD_LOOP_DURATION) { + stop_time = + (uint64_t) (USECS_PER_SEC * STD_LOOP_DURATION) + + get_current_time(); + } + } + + if (STD_INFINITE) + keepgoing++; + + if (STD_LOOP_COUNT && counter < STD_LOOP_COUNT) + keepgoing++; + + if (STD_LOOP_DURATION != 0.0 && get_current_time() < stop_time) + keepgoing++; + + if (keepgoing == 0) + return 0; + + /* + * The following code allows special system testing hooks. + */ + + if (STD_LP_recfun) { + if (Debug) + printf + ("calling usc_recressive_func(0, %d, *STD_bigstack)\n", + STD_LP_recfun); + usc_recressive_func(0, STD_LP_recfun, *STD_bigstack); + } + + if (STD_LP_sbrk) { + if (Debug) + printf("about to do sbrk(%d)\n", STD_LP_sbrk); + sbrk(STD_LP_sbrk); + } + + if (keepgoing) + return 1; + else + return 0; +} + +/* + * This function recressively calls itself max times. + */ +static void usc_recressive_func(int cnt, int max, struct usc_bigstack_t bstack) +{ + if (cnt < max) + usc_recressive_func(cnt + 1, max, bstack); + +} + +#if UNIT_TEST + +/****************************************************************************** + * UNIT TEST CODE + * UNIT TEST CODE + * + * this following code is provide so that unit testing can + * be done fairly easily. + ******************************************************************************/ + +int Help = 0; +int Help2 = 0; +char *ptr; + +long TEST_RETURN; +int TEST_ERRNO; + +/* for test specific parse_opts options */ +option_t Options[] = { + {"help", &Help2, NULL}, /* -help option */ + {"h", &Help, NULL}, /* -h option */ + +#if INVALID_TEST_CASES + {"missingflag", NULL, &ptr}, /* error */ + {"missingarg:", &Help, NULL}, /* error */ +#endif /* INVALID_TEST_CASES */ + + {NULL, NULL, NULL} +}; + +int main(int argc, char **argv) +{ + int lc; + char *msg; + struct timeval t; + int cnt; + + if ((msg = parse_opts(argc, argv, Options, NULL)) != NULL) { + printf("ERROR: %s\n", msg); + exit(1); + } + + TEST_PAUSE; + + for (lc = 0; TEST_LOOPING(lc); lc++) { + + TEST(gettimeofday(&t, NULL)); + printf("iter=%d: sec:%d, usec:%6.6d %s", lc + 1, t.tv_sec, + t.tv_usec, ctime(&t.tv_sec)); + } + + TEST_CLEANUP; + + exit(0); +} + +#endif /* UNIT_TEST */ diff --git a/ltp/lib/random_range.c b/ltp/lib/random_range.c new file mode 100644 index 0000000000000000000000000000000000000000..4c96fd913e1a09cd2b43e86ce7751d87a0459667 --- /dev/null +++ b/ltp/lib/random_range.c @@ -0,0 +1,892 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +#include +#include +#include +#include +#include "random_range.h" + +/* + * Internal format of the range array set up by parse_range() + */ + +struct range { + int min; + int max; + int mult; +}; + +/* + * parse_ranges() is a function to parse a comma-separated list of range + * tokens each having the following form: + * + * num + * or + * min:max[:mult] + * + * any of the values may be blank (ie. min::mult, :max, etc.) and default + * values for missing arguments may be supplied by the caller. + * + * The special first form is short hand for 'num:num'. + * + * After parsing the string, the ranges are put into an array of integers, + * which is malloc'd by the routine. The min, max, and mult entries of each + * range can be extracted from the array using the range_min(), range_max(), + * and range_mult() functions. + * + * It is the responsibility of the caller to free the space allocated by + * parse_ranges() - a single call to free() will free the space. + * + * str The string to parse - assumed to be a comma-separated + * list of tokens having the above format. + * defmin default value to plug in for min, if it is missing + * defmax default value to plug in for max, if it is missing + * defmult default value to plug in for mult, if missing + * parse_func A user-supplied function pointer, which parse_ranges() + * can call to parse the min, max, and mult strings. This + * allows for customized number formats. The function + * MUST have the following prototype: + * parse_func(char *str, int *val) + * The function should return -1 if str cannot be parsed + * into an integer, or >= 0 if it was successfully + * parsed. The resulting integer will be stored in + * *val. If parse_func is NULL, parse_ranges will parse + * the tokens in a manner consistent with the sscanf + * %i format. + * range_ptr A user-supplied char **, which will be set to point + * at malloc'd space which holds the parsed range + * values. If range_ptr is NULL, parse_ranges() just + * parses the string. The data returned in range_ptr + * should not be processed directly - use the functions + * range_min(), range_max(), and range_mult() to access + * data for a given range. + * errptr user-supplied char ** which can be set to point to a + * static error string. If errptr is NULL, it is ignored. + * + * parse_range() returns -1 on error, or the number of ranges parsed. + */ + +static int str_to_int(); +static long long divider(long long, long long, long long, long long); + +int parse_ranges(char *str, int defmin, int defmax, int defmult, + int (*parse_func)(), char **rangeptr, char **errptr) +{ + int ncommas; + char *tmpstr, *cp, *tok, *n1str, *n2str, *multstr; + struct range *rp, *ranges; + static char errmsg[256]; + + if (errptr != NULL) { + *errptr = errmsg; + } + + for (ncommas = 0, cp = str; *cp != '\0'; cp++) { + if (*cp == ',') { + ncommas++; + } + } + + if (parse_func == NULL) { + parse_func = str_to_int; + } + + tmpstr = strdup(str); + ranges = malloc((ncommas + 1) * sizeof(struct range)); + rp = ranges; + + tok = strtok(tmpstr, ","); + while (tok != NULL) { + n1str = tok; + n2str = NULL; + multstr = NULL; + + rp->min = defmin; + rp->max = defmax; + rp->mult = defmult; + + if ((cp = strchr(n1str, ':')) != NULL) { + *cp = '\0'; + n2str = cp + 1; + + if ((cp = strchr(n2str, ':')) != NULL) { + *cp = '\0'; + multstr = cp + 1; + } + } + + /* + * Parse the 'min' field - if it is zero length (:n2[:mult] + * format), retain the default value, otherwise, pass the + * string to the parse function. + */ + + if ((int)strlen(n1str) > 0) { + if ((*parse_func) (n1str, &rp->min) < 0) { + sprintf(errmsg, + "error parsing string %s into an integer", + n1str); + free(tmpstr); + free(ranges); + return -1; + } + } + + /* + * Process the 'max' field - if one was not present (n1 format) + * set max equal to min. If the field was present, but + * zero length (n1: format), retain the default. Otherwise + * pass the string to the parse function. + */ + + if (n2str == NULL) { + rp->max = rp->min; + } else if ((int)strlen(n2str) > 0) { + if ((*parse_func) (n2str, &rp->max) < 0) { + sprintf(errmsg, + "error parsing string %s into an integer", + n2str); + free(tmpstr); + free(ranges); + return -1; + } + } + + /* + * Process the 'mult' field - if one was not present + * (n1:n2 format), or the field was zero length (n1:n2: format) + * then set the mult field to defmult - otherwise pass then + * mult field to the parse function. + */ + + if (multstr != NULL && (int)strlen(multstr) > 0) { + if ((*parse_func) (multstr, &rp->mult) < 0) { + sprintf(errmsg, + "error parsing string %s into an integer", + multstr); + free(tmpstr); + free(ranges); + return -1; + } + } + + rp++; + tok = strtok(NULL, ","); + } + + free(tmpstr); + + if (rangeptr != NULL) { + *rangeptr = (char *)ranges; + } else { + free(ranges); /* just running in parse mode */ + } + + return (rp - ranges); +} + +/* + * The default integer-parsing function + */ + +static int str_to_int(char *str, int *ip) +{ + char c; + + if (sscanf(str, "%i%c", ip, &c) != 1) { + return -1; + } else { + return 0; + } +} + +/* + * Three simple functions to return the min, max, and mult values for a given + * range. It is assumed that rbuf is a range buffer set up by parse_ranges(), + * and that r is a valid range within that buffer. + */ + +int range_min(char *rbuf, int r) +{ + return ((struct range *)rbuf)[r].min; +} + +int range_max(char *rbuf, int r) +{ + return ((struct range *)rbuf)[r].max; +} + +int range_mult(char *rbuf, int r) +{ + return ((struct range *)rbuf)[r].mult; +} + +/***************************************************************************** + * random_range(int start, int end, int mult, char **errp) + * + * Returns a psuedo-random number which is >= 'start', <= 'end', and a multiple + * of 'mult'. Start and end may be any valid integer, but mult must be an + * integer > 0. errp is a char ** which will be set to point to a static + * error message buffer if it is not NULL, and an error occurs. + * + * The errp is the only way to check if the routine fails - currently the only + * failure conditions are: + * + * mult < 1 + * no numbers in the start-end range that are a multiple of 'mult' + * + * If random_range_fails, and errp is a valid pointer, it will point to an + * internal error buffer. If errp is a vaild pointer, and random_range + * is successful, errp will be set to NULL. + * + * Note - if mult is 1 (the most common case), there are error conditions + * possible, and errp need not be used. + * + * Note: Uses lrand48(), assuming that set_random_seed() uses srand48() when + * setting the seed. + *****************************************************************************/ + +long random_range(int min, int max, int mult, char **errp) +{ + int r, nmults, orig_min, orig_max, orig_mult, tmp; + extern long lrand48(); + static char errbuf[128]; + + /* + * Sanity check + */ + + if (mult < 1) { + if (errp != NULL) { + sprintf(errbuf, "mult arg must be greater than 0"); + *errp = errbuf; + } + return -1; + } + + /* + * Save original parameter values for use in error message + */ + + orig_min = min; + orig_max = max; + orig_mult = mult; + + /* + * switch min/max if max < min + */ + + if (max < min) { + tmp = max; + max = min; + min = tmp; + } + + /* + * select the random number + */ + + if ((r = min % mult)) /* bump to the next higher 'mult' multiple */ + min += mult - r; + + if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */ + max -= r; + + if (min > max) { /* no 'mult' multiples between min & max */ + if (errp != NULL) { + sprintf(errbuf, + "no numbers in the range %d:%d that are a multiple of %d", + orig_min, orig_max, orig_mult); + *errp = errbuf; + } + return -1; + } + + if (errp != NULL) { + *errp = NULL; + } + + nmults = ((max - min) / mult) + 1; +#if CRAY + /* + * If max is less than 2gb, then the value can fit in 32 bits + * and the standard lrand48() routine can be used. + */ + if (max <= (long)2147483647) { + return (long)(min + (((long)lrand48() % nmults) * mult)); + } else { + /* + * max is greater than 2gb - meeds more than 32 bits. + * Since lrand48 only will get a number up to 32bits. + */ + long randnum; + randnum = divider(min, max, 0, -1); + return (long)(min + ((randnum % nmults) * mult)); + } + +#else + return (min + ((lrand48() % nmults) * mult)); +#endif + +} + +/* + * Just like random_range, but all values are longs. + */ +long random_rangel(long min, long max, long mult, char **errp) +{ + long r, nmults, orig_min, orig_max, orig_mult, tmp; + extern long lrand48(); + static char errbuf[128]; + + /* + * Sanity check + */ + + if (mult < 1) { + if (errp != NULL) { + sprintf(errbuf, "mult arg must be greater than 0"); + *errp = errbuf; + } + return -1; + } + + /* + * Save original parameter values for use in error message + */ + + orig_min = min; + orig_max = max; + orig_mult = mult; + + /* + * switch min/max if max < min + */ + + if (max < min) { + tmp = max; + max = min; + min = tmp; + } + + /* + * select the random number + */ + + if ((r = min % mult)) /* bump to the next higher 'mult' multiple */ + min += mult - r; + + if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */ + max -= r; + + if (min > max) { /* no 'mult' multiples between min & max */ + if (errp != NULL) { + sprintf(errbuf, + "no numbers in the range %ld:%ld that are a multiple of %ld", + orig_min, orig_max, orig_mult); + *errp = errbuf; + } + return -1; + } + + if (errp != NULL) { + *errp = NULL; + } + + nmults = ((max - min) / mult) + 1; +#if CRAY || (_MIPS_SZLONG == 64) + /* + * If max is less than 2gb, then the value can fit in 32 bits + * and the standard lrand48() routine can be used. + */ + if (max <= (long)2147483647) { + return (long)(min + (((long)lrand48() % nmults) * mult)); + } else { + /* + * max is greater than 2gb - meeds more than 32 bits. + * Since lrand48 only will get a number up to 32bits. + */ + long randnum; + randnum = divider(min, max, 0, -1); + return (long)(min + ((randnum % nmults) * mult)); + } + +#else + return (min + ((lrand48() % nmults) * mult)); +#endif +} + +/* + * Attempts to be just like random_range, but everything is long long (64 bit) + */ +long long random_rangell(long long min, long long max, + long long mult, char **errp) +{ + long long r, nmults, orig_min, orig_max, orig_mult, tmp; + long long randnum; + extern long lrand48(); + static char errbuf[128]; + + /* + * Sanity check + */ + + if (mult < 1) { + if (errp != NULL) { + sprintf(errbuf, "mult arg must be greater than 0"); + *errp = errbuf; + } + return -1; + } + + /* + * Save original parameter values for use in error message + */ + + orig_min = min; + orig_max = max; + orig_mult = mult; + + /* + * switch min/max if max < min + */ + + if (max < min) { + tmp = max; + max = min; + min = tmp; + } + + /* + * select the random number + */ + + if ((r = min % mult)) /* bump to the next higher 'mult' multiple */ + min += mult - r; + + if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */ + max -= r; + + if (min > max) { /* no 'mult' multiples between min & max */ + if (errp != NULL) { + sprintf(errbuf, + "no numbers in the range %lld:%lld that are a multiple of %lld", + orig_min, orig_max, orig_mult); + *errp = errbuf; + } + return -1; + } + + if (errp != NULL) { + *errp = NULL; + } + + nmults = ((max - min) / mult) + 1; + /* + * If max is less than 2gb, then the value can fit in 32 bits + * and the standard lrand48() routine can be used. + */ + if (max <= (long)2147483647) { + return (long long)(min + + (((long long)lrand48() % nmults) * mult)); + } else { + /* + * max is greater than 2gb - meeds more than 32 bits. + * Since lrand48 only will get a number up to 32bits. + */ + randnum = divider(min, max, 0, -1); + return (long long)(min + ((randnum % nmults) * mult)); + } + +} + +/* + * This functional will recusively call itself to return a random + * number min and max. It was designed to work the 64bit numbers + * even when compiled as 32 bit process. + * algorithm: to use the official lrand48() routine - limited to 32 bits. + * find the difference between min and max (max-min). + * if the difference is 2g or less, use the random number gotton from lrand48(). + * Determine the midway point between min and max. + * if the midway point is less than 2g from min or max, + * randomly add the random number gotton from lrand48() to + * either min or the midpoint. + * Otherwise, call outself with min and max being min and midway value or + * midway value and max. This will reduce the range in half. + */ +static long long +divider(long long min, long long max, long long cnt, long long rand) +{ + long long med, half, diff; + + /* + * prevent run away code. We are dividing by two each count. + * if we get to a count of more than 32, we should have gotten + * to 2gb. + */ + if (cnt > 32) + return -1; + + /* + * Only get a random number the first time. + */ + if (cnt == 0 || rand < -1) { + rand = (long long)lrand48(); /* 32 bit random number */ + } + + diff = max - min; + + if (diff <= 2147483647) + return min + rand; + + half = diff / (long long)2; /* half the distance between min and max */ + med = min + half; /* med way point between min and max */ + +#if DEBUG + printf("divider: min=%lld, max=%lld, cnt=%lld, rand=%lld\n", min, max, + cnt, rand); + printf(" diff = %lld, half = %lld, med = %lld\n", diff, half, med); +#endif + + if (half <= 2147483647) { + /* + * If half is smaller than 2gb, we can use the random number + * to pick the number within the min to med or med to max + * if the cnt bit of rand is zero or one, respectively. + */ + if (rand & (1 << cnt)) + return med + rand; + else + return min + rand; + } else { + /* + * recursively call ourself to reduce the value to the bottom half + * or top half (bit cnt is set). + */ + if (rand & (1 << cnt)) { + return divider(med, max, cnt + 1, rand); + } else { + return divider(min, med, cnt + 1, rand); + } + + } + +} + +/***************************************************************************** + * random_range_seed(s) + * + * Sets the random seed to s. Uses srand48(), assuming that lrand48() will + * be used in random_range(). + *****************************************************************************/ + +void random_range_seed(long s) +{ + extern void srand48(); + + srand48(s); +} + +/**************************************************************************** + * random_bit(mask) + * + * This function randomly returns a single bit from the bits + * set in mask. If mask is zero, zero is returned. + * + ****************************************************************************/ +long random_bit(long mask) +{ + int nbits = 0; /* number of set bits in mask */ + long bit; /* used to count bits and num of set bits choosen */ + int nshift; /* used to count bit shifts */ + + if (mask == 0) + return 0; + + /* + * get the number of bits set in mask + */ +#ifndef CRAY + + bit = 1L; + for (nshift = 0; (unsigned int)nshift < sizeof(long) * 8; nshift++) { + if (mask & bit) + nbits++; + bit = bit << 1; + } + +#else + nbits = _popcnt(mask); +#endif /* if CRAY */ + + /* + * randomly choose a bit. + */ + bit = random_range(1, nbits, 1, NULL); + + /* + * shift bits until you determine which bit was randomly choosen. + * nshift will hold the number of shifts to make. + */ + + nshift = 0; + while (bit) { + /* check if the current one's bit is set */ + if (mask & 1L) { + bit--; + } + mask = mask >> 1; + nshift++; + } + + return 01L << (nshift - 1); + +} + +#if RANDOM_BIT_UNITTEST +/* + * The following is a unit test main function for random_bit(). + */ +main(argc, argv) +int argc; +char **argv; +{ + int ind; + int cnt, iter; + long mask, ret; + + printf("test for first and last bit set\n"); + mask = 1L; + ret = random_bit(mask); + printf("random_bit(%#o) returned %#o\n", mask, ret); + + mask = 1L << (sizeof(long) * 8 - 1); + ret = random_bit(mask); + printf("random_bit(%#o) returned %#o\n", mask, ret); + + if (argc >= 3) { + iter = atoi(argv[1]); + for (ind = 2; ind < argc; ind++) { + printf("Calling random_bit %d times for mask %#o\n", + iter, mask); + sscanf(argv[ind], "%i", &mask); + for (cnt = 0; cnt < iter; cnt++) { + ret = random_bit(mask); + printf("random_bit(%#o) returned %#o\n", mask, + ret); + } + } + } + exit(0); +} + +#endif /* end if RANDOM_BIT_UNITTEST */ + +#if UNIT_TEST +/* + * The following is a unit test main function for random_range*(). + */ + +#define PARTNUM 10 /* used to determine even distribution of random numbers */ +#define MEG 1024*1024*1024 +#define GIG 1073741824 +int main(argc, argv) +int argc; +char **argv; +{ + int ind; + int cnt, iter = 10; + int imin = 0, imult = 1, itmin, itmax = 0; +#if CRAY + int imax = 6 * GIG; /* higher than 32 bits */ +#else + int imax = 1048576; +#endif + + long lret, lmin = 0, lmult = 1, ltmin, ltmax = 0; +#if CRAY || (_MIPS_SZLONG == 64) + long lmax = 6 * (long)GIG; /* higher than 32 bits */ +#else + long lmax = 1048576; +#endif + long long llret, llmin = 0, llmult = 1, lltmin, lltmax = 0; + long long llmax = (long long)80 * (long long)GIG; + + long part; + long long lpart; + long cntarr[PARTNUM]; + long valbound[PARTNUM]; + long long lvalbound[PARTNUM]; + + for (ind = 0; ind < PARTNUM; ind++) + cntarr[ind] = 0; + + if (argc < 2) { + printf("Usage: %s func [iterations] \n", argv[0]); + printf + ("func can be random_range, random_rangel, random_rangell\n"); + exit(1); + } + + if (argc >= 3) { + if (sscanf(argv[2], "%i", &iter) != 1) { + printf("Usage: %s [func iterations] \n", argv[0]); + printf("argv[2] is not a number\n"); + exit(1); + } + } + + /* + * random_rangel () + */ + if (strcmp(argv[1], "random_rangel") == 0) { + ltmin = lmax; + part = lmax / PARTNUM; + for (ind = 0; ind < PARTNUM; ind++) { + valbound[ind] = part * ind; + } + + for (cnt = 0; cnt < iter; cnt++) { + lret = random_rangel(lmin, lmax, lmult, NULL); + if (iter < 100) + printf("%ld\n", lret); + if (lret < ltmin) + ltmin = lret; + if (lret > ltmax) + ltmax = lret; + for (ind = 0; ind < PARTNUM - 1; ind++) { + if (valbound[ind] < lret + && lret <= valbound[ind + 1]) { + cntarr[ind]++; + break; + } + } + if (lret > valbound[PARTNUM - 1]) { + cntarr[PARTNUM - 1]++; + } + } + for (ind = 0; ind < PARTNUM - 1; ind++) { + printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind + 1, + valbound[ind], valbound[ind + 1], cntarr[ind], + (float)(cntarr[ind] / (float)iter)); + } + printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM, + valbound[PARTNUM - 1], lmax, cntarr[PARTNUM - 1], + (float)(cntarr[PARTNUM - 1] / (float)iter)); + printf(" min=%ld, max=%ld\n", ltmin, ltmax); + + } else if (strcmp(argv[1], "random_rangell") == 0) { + /* + * random_rangell() unit test + */ + lltmin = llmax; + lpart = llmax / PARTNUM; + for (ind = 0; ind < PARTNUM; ind++) { + lvalbound[ind] = (long long)(lpart * ind); + } + + for (cnt = 0; cnt < iter; cnt++) { + llret = random_rangell(llmin, llmax, llmult, NULL); + if (iter < 100) + printf("random_rangell returned %lld\n", llret); + if (llret < lltmin) + lltmin = llret; + if (llret > lltmax) + lltmax = llret; + + for (ind = 0; ind < PARTNUM - 1; ind++) { + if (lvalbound[ind] < llret + && llret <= lvalbound[ind + 1]) { + cntarr[ind]++; + break; + } + } + if (llret > lvalbound[PARTNUM - 1]) { + cntarr[PARTNUM - 1]++; + } + } + for (ind = 0; ind < PARTNUM - 1; ind++) { + printf("%2d %-13lld to %-13lld %5ld %4.4f\n", + ind + 1, lvalbound[ind], lvalbound[ind + 1], + cntarr[ind], (float)(cntarr[ind] / (float)iter)); + } + printf("%2d %-13lld to %-13lld %5ld %4.4f\n", PARTNUM, + lvalbound[PARTNUM - 1], llmax, cntarr[PARTNUM - 1], + (float)(cntarr[PARTNUM - 1] / (float)iter)); + printf(" min=%lld, max=%lld\n", lltmin, lltmax); + + } else { + /* + * random_range() unit test + */ + itmin = imax; + part = imax / PARTNUM; + for (ind = 0; ind < PARTNUM; ind++) { + valbound[ind] = part * ind; + } + + for (cnt = 0; cnt < iter; cnt++) { + lret = random_range(imin, imax, imult, NULL); + if (iter < 100) + printf("%ld\n", lret); + if (lret < itmin) + itmin = lret; + if (lret > itmax) + itmax = lret; + + for (ind = 0; ind < PARTNUM - 1; ind++) { + if (valbound[ind] < lret + && lret <= valbound[ind + 1]) { + cntarr[ind]++; + break; + } + } + if (lret > valbound[PARTNUM - 1]) { + cntarr[PARTNUM - 1]++; + } + } + for (ind = 0; ind < PARTNUM - 1; ind++) { + printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind + 1, + valbound[ind], valbound[ind + 1], cntarr[ind], + (float)(cntarr[ind] / (float)iter)); + } + printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM, + valbound[PARTNUM - 1], (long)imax, cntarr[PARTNUM - 1], + (float)(cntarr[PARTNUM - 1] / (float)iter)); + printf(" min=%d, max=%d\n", itmin, itmax); + + } + + exit(0); +} + +#endif diff --git a/ltp/lib/safe_file_ops.c b/ltp/lib/safe_file_ops.c new file mode 100644 index 0000000000000000000000000000000000000000..8314c4b1bb3d3d82b1949302fc48052a895b2074 --- /dev/null +++ b/ltp/lib/safe_file_ops.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2012 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. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "safe_file_ops_fn.h" + +int tst_count_scanf_conversions(const char *fmt) +{ + unsigned int cnt = 0; + int flag = 0; + + while (*fmt) { + switch (*fmt) { + case '%': + if (flag) { + cnt--; + flag = 0; + } else { + flag = 1; + cnt++; + } + break; + case '*': + if (flag) { + cnt--; + flag = 0; + } + break; + default: + flag = 0; + } + + fmt++; + } + + return cnt; +} + +int file_scanf(const char *file, const int lineno, + const char *path, const char *fmt, ...) +{ + va_list va; + FILE *f; + int exp_convs, ret; + + f = fopen(path, "r"); + + if (f == NULL) { + tst_resm_(file, lineno, TINFO, "Failed to open FILE '%s'", + path); + return 1; + } + + exp_convs = tst_count_scanf_conversions(fmt); + + va_start(va, fmt); + ret = vfscanf(f, fmt, va); + va_end(va); + + if (ret == EOF) { + tst_resm_(file, lineno, TINFO, + "The FILE '%s' ended prematurely", path); + goto err; + } + + if (ret != exp_convs) { + tst_resm_(file, lineno, TINFO, + "Expected %i conversions got %i FILE '%s'", + exp_convs, ret, path); + goto err; + } + + if (fclose(f)) { + tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'", + path); + return 1; + } + + return 0; + +err: + if (fclose(f)) { + tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'", + path); + } + + return 1; +} + +void safe_file_scanf(const char *file, const int lineno, + void (*cleanup_fn) (void), + const char *path, const char *fmt, ...) +{ + va_list va; + FILE *f; + int exp_convs, ret; + + f = fopen(path, "r"); + + if (f == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to open FILE '%s' for reading", path); + return; + } + + exp_convs = tst_count_scanf_conversions(fmt); + + va_start(va, fmt); + ret = vfscanf(f, fmt, va); + va_end(va); + + if (ret == EOF) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "The FILE '%s' ended prematurely", path); + return; + } + + if (ret != exp_convs) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Expected %i conversions got %i FILE '%s'", + exp_convs, ret, path); + return; + } + + if (fclose(f)) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to close FILE '%s'", path); + return; + } +} + + +/* + * Try to parse each line from file specified by 'path' according + * to scanf format 'fmt'. If all fields could be parsed, stop and + * return 0, otherwise continue or return 1 if EOF is reached. + */ +int file_lines_scanf(const char *file, const int lineno, + void (*cleanup_fn)(void), int strict, + const char *path, const char *fmt, ...) +{ + FILE *fp; + int ret = 0; + int arg_count = 0; + char line[BUFSIZ]; + va_list ap; + + if (!fmt) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, "pattern is NULL"); + return 1; + } + + fp = fopen(path, "r"); + if (fp == NULL) { + if (strict == 0 && errno == ENOENT) + return 1; + + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to open FILE '%s' for reading", path); + return 1; + } + + arg_count = tst_count_scanf_conversions(fmt); + + while (fgets(line, BUFSIZ, fp) != NULL) { + va_start(ap, fmt); + ret = vsscanf(line, fmt, ap); + va_end(ap); + + if (ret == arg_count) + break; + } + fclose(fp); + + if (strict && ret != arg_count) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Expected %i conversions got %i FILE '%s'", + arg_count, ret, path); + return 1; + } + + return !(ret == arg_count); +} + +int file_printf(const char *file, const int lineno, + const char *path, const char *fmt, ...) +{ + va_list va; + FILE *f; + + f = fopen(path, "w"); + + if (f == NULL) { + tst_resm_(file, lineno, TINFO, "Failed to open FILE '%s'", + path); + return 1; + } + + va_start(va, fmt); + + if (vfprintf(f, fmt, va) < 0) { + tst_resm_(file, lineno, TINFO, "Failed to print to FILE '%s'", + path); + goto err; + } + + va_end(va); + + if (fclose(f)) { + tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'", + path); + return 1; + } + + return 0; + +err: + if (fclose(f)) { + tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'", + path); + } + + return 1; +} + +static void safe_file_vprintf(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *path, const char *fmt, + va_list va) +{ + FILE *f; + + f = fopen(path, "w"); + + if (f == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Failed to open FILE '%s' for writing", path); + return; + } + + if (vfprintf(f, fmt, va) < 0) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Failed to print to FILE '%s'", path); + return; + } + + if (fclose(f)) { + 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? +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; + char buf[len]; + int ret; + + snprintf(buf, sizeof(buf), "cp \"%s\" \"%s\"", src, dst); + + ret = system(buf); + + if (ret) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Failed to copy '%s' to '%s'", src, dst); + return ret; + } + + return 0; +} + +#ifndef HAVE_UTIMENSAT + +static void set_time(struct timeval *res, const struct timespec *src, + long cur_tv_sec, long cur_tv_usec) +{ + switch (src->tv_nsec) { + case UTIME_NOW: + break; + case UTIME_OMIT: + res->tv_sec = cur_tv_sec; + res->tv_usec = cur_tv_usec; + break; + default: + res->tv_sec = src->tv_sec; + res->tv_usec = src->tv_nsec / 1000; + } +} + +#endif + +int safe_touch(const char *file, const int lineno, + void (*cleanup_fn)(void), + const char *pathname, + mode_t mode, const struct timespec times[2]) +{ + int ret; + mode_t defmode; + + 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_(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_(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_(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; + } + } + + +#ifdef HAVE_UTIMENSAT + ret = utimensat(AT_FDCWD, pathname, times, 0); +#else + if (times == NULL) { + ret = utimes(pathname, NULL); + } else { + struct stat sb; + struct timeval cotimes[2]; + + ret = stat(pathname, &sb); + + if (ret == -1) { + 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_(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]; + + set_time(cotimes, times, + sb.st_atime, sb.st_atim.tv_nsec / 1000); + set_time(cotimes + 1, times + 1, + sb.st_mtime, sb.st_mtim.tv_nsec / 1000); + + ret = utimes(pathname, cotimes); + } +#endif + if (ret == -1) { + 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/ltp/lib/safe_macros.c b/ltp/lib/safe_macros.c new file mode 100644 index 0000000000000000000000000000000000000000..6946cc5bcb94202a67fcb986a504e77ab0a27738 --- /dev/null +++ b/ltp/lib/safe_macros.c @@ -0,0 +1,1369 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2010-2020 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lapi/fcntl.h" +#include "test.h" +#include "safe_macros.h" + +char *safe_basename(const char *file, const int lineno, + void (*cleanup_fn) (void), char *path) +{ + char *rval; + + rval = basename(path); + + if (rval == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "basename(%s) failed", path); + } + + return rval; +} + +int +safe_chdir(const char *file, const int lineno, void (*cleanup_fn) (void), + const char *path) +{ + int rval; + + rval = chdir(path); + + if (rval == -1) { + 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; +} + +int +safe_close(const char *file, const int lineno, void (*cleanup_fn) (void), + int fildes) +{ + int rval; + + rval = close(fildes); + + if (rval == -1) { + 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; +} + +int +safe_creat(const char *file, const int lineno, void (*cleanup_fn) (void), + const char *pathname, mode_t mode) +{ + int rval; + + rval = creat(pathname, mode); + + if (rval == -1) { + 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; +} + +char *safe_dirname(const char *file, const int lineno, + void (*cleanup_fn) (void), char *path) +{ + char *rval; + + rval = dirname(path); + + if (rval == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "dirname(%s) failed", path); + } + + return rval; +} + +char *safe_getcwd(const char *file, const int lineno, void (*cleanup_fn) (void), + char *buf, size_t size) +{ + char *rval; + + rval = getcwd(buf, size); + + if (rval == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "getcwd(%p,%zu) failed", buf, size); + } + + return rval; +} + +struct passwd *safe_getpwnam(const char *file, const int lineno, + void (*cleanup_fn) (void), const char *name) +{ + struct passwd *rval; + + rval = getpwnam(name); + + if (rval == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "getpwnam(%s) failed", name); + } + + return rval; +} + +int +safe_getrusage(const char *file, const int lineno, void (*cleanup_fn) (void), + int who, struct rusage *usage) +{ + int rval; + + rval = getrusage(who, usage); + + if (rval == -1) { + 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; +} + +void *safe_malloc(const char *file, const int lineno, void (*cleanup_fn) (void), + size_t size) +{ + void *rval; + + rval = malloc(size); + + if (rval == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "malloc(%zu) failed", size); + } + + return rval; +} + +int safe_mkdir(const char *file, const int lineno, void (*cleanup_fn) (void), + const char *pathname, mode_t mode) +{ + int rval; + + rval = mkdir(pathname, mode); + + if (rval == -1) { + 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); +} + +int safe_rmdir(const char *file, const int lineno, void (*cleanup_fn) (void), + const char *pathname) +{ + int rval; + + rval = rmdir(pathname); + + if (rval == -1) { + 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); +} + +int safe_munmap(const char *file, const int lineno, void (*cleanup_fn) (void), + void *addr, size_t length) +{ + int rval; + + rval = munmap(addr, length); + + if (rval == -1) { + 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; +} + +int safe_open(const char *file, const int lineno, void (*cleanup_fn) (void), + const char *pathname, int oflags, ...) +{ + int rval; + mode_t mode = 0; + + if (TST_OPEN_NEEDS_MODE(oflags)) { + va_list ap; + + va_start(ap, oflags); + + /* Android's NDK's mode_t is smaller than an int, which results in + * SIGILL here when passing the mode_t type. + */ + mode = va_arg(ap, int); + + va_end(ap); + } + + rval = open(pathname, oflags, mode); + + if (rval == -1) { + 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; +} + +int safe_pipe(const char *file, const int lineno, void (*cleanup_fn) (void), + int fildes[2]) +{ + int rval; + + rval = pipe(fildes); + + if (rval == -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; +} + +ssize_t safe_read(const char *file, const int lineno, void (*cleanup_fn) (void), + char len_strict, int fildes, void *buf, size_t nbyte) +{ + ssize_t rval; + + rval = read(fildes, buf, nbyte); + + if (rval == -1) { + 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); + } else if (len_strict && (size_t)rval != nbyte) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Short read(%d,%p,%zu) returned only %zd", + fildes, buf, nbyte, rval); + } + + return rval; +} + +int safe_setegid(const char *file, const int lineno, void (*cleanup_fn) (void), + gid_t egid) +{ + int rval; + + rval = setegid(egid); + + if (rval == -1) { + 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; +} + +int safe_seteuid(const char *file, const int lineno, void (*cleanup_fn) (void), + uid_t euid) +{ + int rval; + + rval = seteuid(euid); + + if (rval == -1) { + 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; +} + +int safe_setgid(const char *file, const int lineno, void (*cleanup_fn) (void), + gid_t gid) +{ + int rval; + + rval = setgid(gid); + + if (rval == -1) { + 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; +} + +int safe_setuid(const char *file, const int lineno, void (*cleanup_fn) (void), + uid_t uid) +{ + int rval; + + rval = setuid(uid); + + if (rval == -1) { + 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; +} + +int safe_getresuid(const char *file, const int lineno, void (*cleanup_fn)(void), + uid_t *ruid, uid_t *euid, uid_t *suid) +{ + int rval; + + rval = getresuid(ruid, euid, suid); + + if (rval == -1) { + 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; +} + +int safe_getresgid(const char *file, const int lineno, void (*cleanup_fn)(void), + gid_t *rgid, gid_t *egid, gid_t *sgid) +{ + int rval; + + rval = getresgid(rgid, egid, sgid); + + if (rval == -1) { + 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; +} + +int safe_unlink(const char *file, const int lineno, void (*cleanup_fn) (void), + const char *pathname) +{ + int rval; + + rval = unlink(pathname); + + if (rval == -1) { + 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; +} + + +int safe_link(const char *file, const int lineno, + void (cleanup_fn)(void), const char *oldpath, + const char *newpath) +{ + int rval; + + rval = link(oldpath, newpath); + + if (rval == -1) { + 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; +} + +int safe_linkat(const char *file, const int lineno, + void (cleanup_fn)(void), int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, int flags) +{ + int rval; + + rval = linkat(olddirfd, oldpath, newdirfd, newpath, flags); + + if (rval == -1) { + 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; +} + +ssize_t safe_readlink(const char *file, const int lineno, + void (cleanup_fn)(void), const char *path, + char *buf, size_t bufsize) +{ + ssize_t rval; + + rval = readlink(path, buf, bufsize); + + if (rval == -1) { + 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. */ + if ((size_t) rval < bufsize) + buf[rval] = '\0'; + else + buf[bufsize-1] = '\0'; + } + + return rval; +} + +int safe_symlink(const char *file, const int lineno, + void (cleanup_fn)(void), const char *oldpath, + const char *newpath) +{ + int rval; + + rval = symlink(oldpath, newpath); + + if (rval == -1) { + 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; +} + +ssize_t safe_write(const char *file, const int lineno, void (cleanup_fn) (void), + enum safe_write_opts len_strict, int fildes, const void *buf, + size_t nbyte) +{ + ssize_t rval; + const void *wbuf = buf; + size_t len = nbyte; + int iter = 0; + + do { + iter++; + rval = write(fildes, wbuf, len); + if (rval == -1) { + if (len_strict == SAFE_WRITE_RETRY) + tst_resm_(file, lineno, TINFO, + "write() wrote %zu bytes in %d calls", + nbyte-len, iter); + tst_brkm_(file, lineno, TBROK | TERRNO, + cleanup_fn, "write(%d,%p,%zu) failed", + fildes, buf, nbyte); + return rval; + } + + if (rval < 0) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "invalid write() return value %zi", + rval); + return rval; + } + + if (len_strict == SAFE_WRITE_ANY) + return rval; + + if (len_strict == SAFE_WRITE_ALL) { + if ((size_t)rval != nbyte) + tst_brkm_(file, lineno, TBROK, + cleanup_fn, "short write(%d,%p,%zu) " + "return value %zd", + fildes, buf, nbyte, rval); + return rval; + } + + wbuf += rval; + len -= rval; + } while (len > 0); + + return rval; +} + +long safe_strtol(const char *file, const int lineno, + void (cleanup_fn) (void), char *str, long min, long max) +{ + long rval; + char *endptr; + + errno = 0; + rval = strtol(str, &endptr, 10); + + if ((errno == ERANGE && (rval == LONG_MAX || rval == LONG_MIN)) + || (errno != 0 && rval == 0)) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "strtol(%s) failed", str); + return rval; + } + + if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "strtol(%s): Invalid value", str); + return 0; + } + + if (rval > max || rval < min) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "strtol(%s): %ld is out of range %ld - %ld", + str, rval, min, max); + return 0; + } + + return rval; +} + +unsigned long safe_strtoul(const char *file, const int lineno, + void (cleanup_fn) (void), char *str, + unsigned long min, unsigned long max) +{ + unsigned long rval; + char *endptr; + + errno = 0; + rval = strtoul(str, &endptr, 10); + + if ((errno == ERANGE && rval == ULONG_MAX) + || (errno != 0 && rval == 0)) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "strtoul(%s) failed", str); + return rval; + } + + if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Invalid value: '%s'", str); + return 0; + } + + if (rval > max || rval < min) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "strtoul(%s): %lu is out of range %lu - %lu", + str, rval, min, max); + return 0; + } + + return rval; +} + +float safe_strtof(const char *file, const int lineno, + void (cleanup_fn) (void), char *str, + float min, float max) +{ + float rval; + char *endptr; + + errno = 0; + rval = strtof(str, &endptr); + + if (errno) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "strtof(%s) failed", str); + return rval; + } + + if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Invalid value: '%s'", str); + return 0; + } + + if (rval > max || rval < min) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "strtof(%s): %f is out of range %f - %f", + str, rval, min, max); + return 0; + } + + return rval; +} + +long safe_sysconf(const char *file, const int lineno, + void (cleanup_fn) (void), int name) +{ + long rval; + + errno = 0; + rval = sysconf(name); + + if (rval == -1) { + if (errno) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "sysconf(%d) failed", name); + } else { + tst_resm_(file, lineno, TINFO, + "sysconf(%d): queried option is not available or there is no definite limit", + name); + } + } + + return rval; +} + +int safe_chmod(const char *file, const int lineno, + void (cleanup_fn)(void), const char *path, mode_t mode) +{ + int rval; + + rval = chmod(path, mode); + + if (rval == -1) { + 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; +} + +int safe_fchmod(const char *file, const int lineno, + void (cleanup_fn)(void), int fd, mode_t mode) +{ + int rval; + + rval = fchmod(fd, mode); + + if (rval == -1) { + 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; +} + +int safe_chown(const char *file, const int lineno, void (cleanup_fn)(void), + const char *path, uid_t owner, gid_t group) +{ + int rval; + + rval = chown(path, owner, group); + + if (rval == -1) { + 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; +} + +int safe_fchown(const char *file, const int lineno, void (cleanup_fn)(void), + int fd, uid_t owner, gid_t group) +{ + int rval; + + rval = fchown(fd, owner, group); + + if (rval == -1) { + 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; +} + +pid_t safe_wait(const char *file, const int lineno, void (cleanup_fn)(void), + int *status) +{ + pid_t rval; + + rval = wait(status); + + if (rval == -1) { + 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; +} + +pid_t safe_waitpid(const char *file, const int lineno, void (cleanup_fn)(void), + pid_t pid, int *status, int opts) +{ + pid_t rval; + + rval = waitpid(pid, status, opts); + + if (rval == -1) { + 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; +} + +void *safe_memalign(const char *file, const int lineno, + void (*cleanup_fn) (void), size_t alignment, size_t size) +{ + void *rval; + + rval = memalign(alignment, size); + + if (rval == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "memalign() failed"); + } + + return rval; +} + +int safe_kill(const char *file, const int lineno, void (cleanup_fn)(void), + pid_t pid, int sig) +{ + int rval; + + rval = kill(pid, sig); + + if (rval == -1) { + 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; +} + +int safe_mkfifo(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *pathname, mode_t mode) +{ + int rval; + + rval = mkfifo(pathname, mode); + + if (rval == -1) { + 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; +} + +int safe_rename(const char *file, const int lineno, void (*cleanup_fn)(void), + const char *oldpath, const char *newpath) +{ + int rval; + + rval = rename(oldpath, newpath); + + if (rval == -1) { + 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; +} + +static const char *const fuse_fs_types[] = { + "exfat", + "ntfs", +}; + +static int possibly_fuse(const char *fs_type) +{ + unsigned int i; + + if (!fs_type) + return 0; + + for (i = 0; i < ARRAY_SIZE(fuse_fs_types); i++) { + if (!strcmp(fuse_fs_types[i], fs_type)) + return 1; + } + + return 0; +} + +int safe_mount(const char *file, const int lineno, void (*cleanup_fn)(void), + const char *source, const char *target, + const char *filesystemtype, unsigned long mountflags, + const void *data) +{ + int rval = -1; + char mpath[PATH_MAX]; + + if (realpath(target, mpath)) { + tst_resm_(file, lineno, TINFO, + "Mounting %s to %s fstyp=%s flags=%lx", + source, mpath, filesystemtype, mountflags); + } else { + tst_resm_(file, lineno, TINFO | TERRNO, + "Cannot resolve the absolute path of %s", target); + } + /* + * Don't try using the kernel's NTFS driver when mounting NTFS, since + * the kernel's NTFS driver doesn't have proper write support. + */ + if (!filesystemtype || strcmp(filesystemtype, "ntfs")) { + mode_t old_umask = umask(0); + + rval = mount(source, target, filesystemtype, mountflags, data); + umask(old_umask); + if (!rval) + return 0; + } + + /* + * The FUSE filesystem executes mount.fuse helper, which tries to + * execute corresponding binary name which is encoded at the start of + * the source string and separated by # from the device name. + * + * The mount helpers are called mount.$fs_type. + */ + if (possibly_fuse(filesystemtype)) { + char buf[1024]; + + tst_resm_(file, lineno, TINFO, "Trying FUSE..."); + snprintf(buf, sizeof(buf), "mount.%s '%s' '%s'", + filesystemtype, source, target); + + rval = tst_system(buf); + if (WIFEXITED(rval) && WEXITSTATUS(rval) == 0) + return 0; + + 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_(file, lineno, TBROK | TERRNO, cleanup_fn, + "Invalid mount(%s, %s, %s, %lu, %p) return value %d", + source, target, filesystemtype, mountflags, data, + rval); + } + + return rval; +} + +int safe_umount(const char *file, const int lineno, void (*cleanup_fn)(void), + const char *target) +{ + int rval; + char mpath[PATH_MAX]; + + if (realpath(target, mpath)) { + tst_resm_(file, lineno, TINFO, "Umounting %s", mpath); + } else { + tst_resm_(file, lineno, TINFO | TERRNO, + "Cannot resolve the absolute path of %s", target); + } + + rval = tst_umount(target); + + if (rval == -1) { + 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; +} + +DIR* safe_opendir(const char *file, const int lineno, void (cleanup_fn)(void), + const char *name) +{ + DIR *rval; + + rval = opendir(name); + + if (!rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "opendir(%s) failed", name); + } + + return rval; +} + +int safe_closedir(const char *file, const int lineno, void (cleanup_fn)(void), + DIR *dirp) +{ + int rval; + + rval = closedir(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; +} + +struct dirent *safe_readdir(const char *file, const int lineno, void (cleanup_fn)(void), + DIR *dirp) +{ + struct dirent *rval; + int err = errno; + + errno = 0; + rval = readdir(dirp); + + if (!rval && errno) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "readdir(%p) failed", dirp); + } + + errno = err; + return rval; +} + +int safe_getpriority(const char *file, const int lineno, int which, id_t who) +{ + int rval, err = errno; + + errno = 0; + rval = getpriority(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; + return rval; +} + +ssize_t safe_getxattr(const char *file, const int lineno, const char *path, + const char *name, void *value, size_t size) +{ + ssize_t rval; + + rval = getxattr(path, name, value, size); + + if (rval == -1) { + if (errno == ENOTSUP) { + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; + } + + 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; +} + +int safe_setxattr(const char *file, const int lineno, const char *path, + const char *name, const void *value, size_t size, int flags) +{ + int rval; + + rval = setxattr(path, name, value, size, flags); + + if (rval == -1) { + if (errno == ENOTSUP) { + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs, mounted without user_xattr option " + "or invalid namespace/name format"); + return rval; + } + + 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; +} + +int safe_lsetxattr(const char *file, const int lineno, const char *path, + const char *name, const void *value, size_t size, int flags) +{ + int rval; + + rval = lsetxattr(path, name, value, size, flags); + + if (rval == -1) { + if (errno == ENOTSUP) { + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs, mounted without user_xattr option " + "or invalid namespace/name format"); + return rval; + } + + 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; +} + +int safe_fsetxattr(const char *file, const int lineno, int fd, const char *name, + const void *value, size_t size, int flags) +{ + int rval; + + rval = fsetxattr(fd, name, value, size, flags); + + if (rval == -1) { + if (errno == ENOTSUP) { + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs, mounted without user_xattr option " + "or invalid namespace/name format"); + return rval; + } + + 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; +} + +int safe_removexattr(const char *file, const int lineno, const char *path, + const char *name) +{ + int rval; + + rval = removexattr(path, name); + + if (rval == -1) { + if (errno == ENOTSUP) { + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; + } + + 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; +} + +int safe_lremovexattr(const char *file, const int lineno, const char *path, + const char *name) +{ + int rval; + + rval = lremovexattr(path, name); + + if (rval == -1) { + if (errno == ENOTSUP) { + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; + } + + 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; +} + +int safe_fremovexattr(const char *file, const int lineno, int fd, + const char *name) +{ + int rval; + + rval = fremovexattr(fd, name); + + if (rval == -1) { + if (errno == ENOTSUP) { + tst_brkm_(file, lineno, TCONF, NULL, + "no xattr support in fs or mounted without user_xattr option"); + return rval; + } + + 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; +} + +int safe_fsync(const char *file, const int lineno, int fd) +{ + int rval; + + rval = fsync(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; +} + +pid_t safe_setsid(const char *file, const int lineno) +{ + pid_t rval; + + rval = setsid(); + + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "setsid() failed"); + } + + return rval; +} + +int safe_mknod(const char *file, const int lineno, const char *pathname, + mode_t mode, dev_t dev) +{ + int rval; + + rval = mknod(pathname, mode, dev); + + if (rval == -1) { + 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; +} + +int safe_mlock(const char *file, const int lineno, const void *addr, + size_t len) +{ + int rval; + + rval = mlock(addr, len); + + if (rval == -1) { + 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; +} + +int safe_munlock(const char *file, const int lineno, const void *addr, + size_t len) +{ + int rval; + + rval = munlock(addr, len); + + if (rval == -1) { + 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; +} + +int safe_mincore(const char *file, const int lineno, void *start, + size_t length, unsigned char *vec) +{ + int rval; + + rval = mincore(start, length, vec); + + if (rval == -1) { + 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/ltp/lib/safe_net.c b/ltp/lib/safe_net.c new file mode 100644 index 0000000000000000000000000000000000000000..5dec0de113b37bce892c153235194f8d36644996 --- /dev/null +++ b/ltp/lib/safe_net.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2015 Fujitsu Ltd. + * + * 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 3 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 . + * + */ + +#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, + size_t len) +{ + char portstr[8]; + + switch (sa->sa_family) { + + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + if (!inet_ntop(AF_INET, &sin->sin_addr, res, len)) + return NULL; + + if (ntohs(sin->sin_port) != 0) { + snprintf(portstr, sizeof(portstr), ":%d", + ntohs(sin->sin_port)); + strcat(res, portstr); + } + + return res; + } + + case AF_INET6: { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + res[0] = '['; + if (!inet_ntop(AF_INET6, &sin6->sin6_addr, res + 1, len - 1)) + return NULL; + + if (ntohs(sin6->sin6_port) != 0) { + snprintf(portstr, sizeof(portstr), "]:%d", + ntohs(sin6->sin6_port)); + strcat(res, portstr); + return res; + } + + return res + 1; + } + + case AF_UNIX: { + struct sockaddr_un *unp = (struct sockaddr_un *)sa; + + if (unp->sun_path[0] == '\0') + strcpy(res, "(no pathname bound)"); + else + snprintf(res, len, "%s", unp->sun_path); + + return res; + } + + default: { + snprintf(res, len, + "sock_ntop: unknown AF_xxx: %d, len: %d", + sa->sa_family, salen); + + return res; + } + + } +} + +int tst_getsockport(const char *file, const int lineno, int sockfd) +{ + struct sockaddr_storage ss; + socklen_t addrlen = sizeof(ss); + struct sockaddr *sa = (struct sockaddr *)&ss; + + safe_getsockname(file, lineno, NULL, sockfd, sa, &addrlen); + + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + return ntohs(sin->sin_port); + } + case AF_INET6: { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + return ntohs(sin6->sin6_port); + } } + + return -1; +} + +int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void), + int domain, int type, int protocol) +{ + int rval, ttype; + + rval = socket(domain, type, protocol); + + if (rval == -1) { + switch (errno) { + case EPROTONOSUPPORT: + case ESOCKTNOSUPPORT: + case EOPNOTSUPP: + case EPFNOSUPPORT: + case EAFNOSUPPORT: + ttype = TCONF; + break; + default: + ttype = TBROK; + } + + 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; +} + +int safe_socketpair(const char *file, const int lineno, int domain, int type, + int protocol, int sv[]) +{ + int rval, ttype; + + rval = socketpair(domain, type, protocol, sv); + + if (rval == -1) { + switch (errno) { + case EPROTONOSUPPORT: + case EOPNOTSUPP: + case EAFNOSUPPORT: + ttype = TCONF; + break; + default: + ttype = TBROK; + } + + 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; +} + +int safe_getsockopt(const char *file, const int lineno, int sockfd, int level, + int optname, void *optval, socklen_t *optlen) +{ + int rval = getsockopt(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; +} + +int safe_setsockopt(const char *file, const int lineno, int sockfd, int level, + int optname, const void *optval, socklen_t optlen) +{ + int rval; + + rval = setsockopt(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; +} + +ssize_t safe_send(const char *file, const int lineno, char len_strict, + int sockfd, const void *buf, size_t len, int flags) +{ + ssize_t rval; + + rval = send(sockfd, buf, len, flags); + + if (rval == -1 || (len_strict && (size_t)rval != len)) { + 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; +} + +ssize_t safe_sendto(const char *file, const int lineno, char len_strict, + int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + ssize_t rval; + char res[128]; + + rval = sendto(sockfd, buf, len, flags, dest_addr, addrlen); + + if (rval == -1 || (len_strict && (size_t)rval != len)) { + 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; +} + +ssize_t safe_sendmsg(const char *file, const int lineno, size_t len, + int sockfd, const struct msghdr *msg, int flags) +{ + ssize_t rval; + + rval = sendmsg(sockfd, msg, flags); + + if (rval == -1) { + 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); + } + + 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, + int sockfd, struct msghdr *msg, int flags) +{ + ssize_t rval; + + rval = recvmsg(sockfd, msg, flags); + + if (rval == -1) { + 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; + +} + +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, ret; + char buf[128]; + + for (i = 0; i < 120; i++) { + ret = bind(socket, address, address_len); + + if (!ret) + return 0; + + 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_(file, lineno, TINFO, + "address is in use, waited %3i sec", i + 1); + } + + sleep(1); + } + + 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; +} + +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 == -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; +} + +int safe_accept(const char *file, const int lineno, void (cleanup_fn)(void), + int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + int rval; + + rval = accept(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; +} + +int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void), + int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + int rval; + char buf[128]; + + rval = connect(sockfd, addr, 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; +} + +int safe_getsockname(const char *file, const int lineno, + void (cleanup_fn)(void), int sockfd, struct sockaddr *addr, + socklen_t *addrlen) +{ + int rval; + char buf[128]; + + rval = getsockname(sockfd, addr, 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; +} + +int safe_gethostname(const char *file, const int lineno, + char *name, size_t size) +{ + int rval = gethostname(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; +} + +int safe_sethostname(const char *file, const int lineno, + const char *name, size_t size) +{ + int rval = sethostname(name, size); + + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "sethostname(%p, %zu) failed", name, size); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid sethostname(%p, %zu) return value %d", name, + size, rval); + } + + return rval; +} + +/* + * @return port in network byte order. + */ +unsigned short tst_get_unused_port(const char *file, const int lineno, + void (cleanup_fn)(void), unsigned short family, int type) +{ + int sock, ret; + socklen_t slen; + struct sockaddr_storage _addr; + struct sockaddr *addr = (struct sockaddr *)&_addr; + struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; + + switch (family) { + case AF_INET: + addr4->sin_family = AF_INET; + addr4->sin_port = 0; + addr4->sin_addr.s_addr = INADDR_ANY; + slen = sizeof(*addr4); + break; + + case AF_INET6: + addr6->sin6_family = AF_INET6; + addr6->sin6_port = 0; + addr6->sin6_addr = in6addr_any; + slen = sizeof(*addr6); + break; + + default: + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "%s(): Unsupported socket family %d", __func__, + family); + return -1; + } + + sock = safe_socket(file, lineno, cleanup_fn, addr->sa_family, type, 0); + + if (sock < 0) + return sock; + + ret = safe_bind(file, lineno, cleanup_fn, sock, addr, slen); + + 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: + return addr4->sin_port; + case AF_INET6: + return addr6->sin6_port; + default: + return -1; + } +} diff --git a/ltp/lib/safe_pthread.c b/ltp/lib/safe_pthread.c new file mode 100644 index 0000000000000000000000000000000000000000..aeafe014cc4648b9a27f84e672a90129924d3fcc --- /dev/null +++ b/ltp/lib/safe_pthread.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved. + */ + +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int safe_pthread_create(const char *file, const int lineno, + pthread_t *thread_id, const pthread_attr_t *attr, + void *(*thread_fn)(void *), void *arg) +{ + int rval; + + rval = pthread_create(thread_id, attr, thread_fn, arg); + + if (rval) { + tst_brk_(file, lineno, TBROK, + "pthread_create(%p,%p,%p,%p) failed: %s", thread_id, + attr, thread_fn, arg, tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_join(const char *file, const int lineno, + pthread_t thread_id, void **retval) +{ + int rval; + + rval = pthread_join(thread_id, retval); + + if (rval) { + tst_brk_(file, lineno, TBROK, + "pthread_join(..., %p) failed: %s", + retval, tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_barrier_wait(const char *file, const int lineno, + pthread_barrier_t *barrier) +{ + int rval; + + rval = pthread_barrier_wait(barrier); + + if (rval && rval != PTHREAD_BARRIER_SERIAL_THREAD) { + tst_brk_(file, lineno, TBROK, + "pthread_barrier_wait(%p) failed: %s", + barrier, tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_barrier_destroy(const char *file, const int lineno, + pthread_barrier_t *barrier) +{ + int rval; + + rval = pthread_barrier_destroy(barrier); + + if (rval) { + tst_brk_(file, lineno, TBROK, + "pthread_barrier_destroy(%p) failed: %s", + barrier, tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_cancel(const char *file, const int lineno, + pthread_t thread_id) +{ + int rval; + + rval = pthread_cancel(thread_id); + + if (rval) { + tst_brk_(file, lineno, TBROK, + "pthread_cancel(...) failed: %s", tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_barrier_init(const char *file, const int lineno, + pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned count) +{ + int rval; + + rval = pthread_barrier_init(barrier, attr, count); + + if (rval) { + tst_brk_(file, lineno, TBROK, + "pthread_barrier_init(%p, %p, %u)failed: %s", + barrier, attr, count, tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_mutexattr_init(const char *file, const int lineno, + pthread_mutexattr_t *attr) +{ + int ret; + + ret = pthread_mutexattr_init(attr); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutexattr_init(%p) failed: %s", + attr, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutexattr_destroy(const char *file, const int lineno, + pthread_mutexattr_t *attr) +{ + int ret; + + ret = pthread_mutexattr_destroy(attr); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutexattr_destroy(%p) failed: %s", + attr, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutexattr_settype(const char *file, const int lineno, + pthread_mutexattr_t *attr, int type) +{ + int ret; + + ret = pthread_mutexattr_settype(attr, type); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutexattr_settype(%p, %d) failed: %s", + attr, type, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_init(const char *file, const int lineno, + pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + int ret; + + ret = pthread_mutex_init(mutex, attr); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_init(%p, %p) failed: %s", + mutex, attr, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_destroy(const char *file, const int lineno, + pthread_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_destroy(mutex); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_destroy(%p) failed: %s", + mutex, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_lock(const char *file, const int lineno, + pthread_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_lock(mutex); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_lock(%p) failed: %s", + mutex, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_trylock(const char *file, const int lineno, + pthread_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_trylock(mutex); + + if (ret && ret != EBUSY) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_trylock(%p) failed: %s", + mutex, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_timedlock(const char *file, const int lineno, + pthread_mutex_t *mutex, const struct timespec *abstime) +{ + int ret; + + ret = pthread_mutex_timedlock(mutex, abstime); + + if (ret && ret != ETIMEDOUT) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_timedlock(%p, {%lld, %ld}) failed: %s", + mutex, (long long)abstime->tv_sec, abstime->tv_nsec, + tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_unlock(const char *file, const int lineno, + pthread_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_unlock(mutex); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_unlock(%p) failed: %s", + mutex, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_kill(const char *file, const int lineno, + pthread_t thread, int sig) +{ + int ret; + + ret = pthread_kill(thread, sig); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_kill(..., %d) failed: %s", + sig, tst_strerrno(ret)); + } + + return ret; +} diff --git a/ltp/lib/safe_stdio.c b/ltp/lib/safe_stdio.c new file mode 100644 index 0000000000000000000000000000000000000000..ab23e43bb0835cdca5eaa015bc873fd23f9a8408 --- /dev/null +++ b/ltp/lib/safe_stdio.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013 Cyril Hrubis + * + * 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 would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "test.h" +#include "safe_stdio_fn.h" + +FILE *safe_fopen(const char *file, const int lineno, void (cleanup_fn)(void), + const char *path, const char *mode) +{ + FILE *f = fopen(path, mode); + + if (f == NULL) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "fopen(%s,%s) failed", path, mode); + } + + return f; +} + +int safe_fclose(const char *file, const int lineno, void (cleanup_fn)(void), + FILE *f) +{ + int ret; + + ret = fclose(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; +} + +int safe_asprintf(const char *file, const int lineno, void (cleanup_fn)(void), + char **strp, const char *fmt, ...) +{ + int ret; + va_list va; + + va_start(va, fmt); + ret = vasprintf(strp, fmt, va); + va_end(va); + + 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; +} + +FILE *safe_popen(const char *file, const int lineno, void (cleanup_fn)(void), + const char *command, const char *type) +{ + FILE *stream; + const int saved_errno = errno; + + errno = 0; + stream = popen(command, type); + + if (stream == NULL) { + if (errno != 0) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "popen(%s,%s) failed", command, type); + } else { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "popen(%s,%s) failed: Out of memory", + command, type); + } + } + + errno = saved_errno; + + return stream; +} diff --git a/ltp/lib/signame.h b/ltp/lib/signame.h new file mode 100644 index 0000000000000000000000000000000000000000..d420458bbb9cc50ab657e4e6ee77aa6d85840de2 --- /dev/null +++ b/ltp/lib/signame.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014 Fujitsu Ltd. + * Author: Xiaoguang Wang + * + * 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. + * + * 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. + */ + +const char *tst_strsig(int sig) +{ + static const struct pair signal_pairs[] = { + PAIR(SIGHUP) + PAIR(SIGINT) + PAIR(SIGQUIT) + PAIR(SIGILL) + #ifdef SIGTRAP + PAIR(SIGTRAP) + #endif + + #ifdef SIGIOT + /* SIGIOT same as SIGABRT */ + STRPAIR(SIGABRT, "SIGIOT/SIGABRT") + #else + PAIR(SIGABRT) + #endif + + #ifdef SIGEMT + PAIR(SIGEMT) + #endif + #ifdef SIGBUS + PAIR(SIGBUS) + #endif + PAIR(SIGFPE) + PAIR(SIGKILL) + PAIR(SIGUSR1) + PAIR(SIGSEGV) + PAIR(SIGUSR2) + PAIR(SIGPIPE) + PAIR(SIGALRM) + PAIR(SIGTERM) + #ifdef SIGSTKFLT + PAIR(SIGSTKFLT) + #endif + PAIR(SIGCHLD) + PAIR(SIGCONT) + PAIR(SIGSTOP) + PAIR(SIGTSTP) + PAIR(SIGTTIN) + PAIR(SIGTTOU) + #ifdef SIGURG + PAIR(SIGURG) + #endif + #ifdef SIGXCPU + PAIR(SIGXCPU) + #endif + #ifdef SIGXFSZ + PAIR(SIGXFSZ) + #endif + #ifdef SIGVTALRM + PAIR(SIGVTALRM) + #endif + #ifdef SIGPROF + PAIR(SIGPROF) + #endif + #ifdef SIGWINCH + PAIR(SIGWINCH) + #endif + + #if defined(SIGIO) && defined(SIGPOLL) + /* SIGPOLL same as SIGIO */ + STRPAIR(SIGIO, "SIGIO/SIGPOLL") + #elif defined(SIGIO) + PAIR(SIGIO) + #elif defined(SIGPOLL) + PAIR(SIGPOLL) + #endif + + #ifdef SIGINFO + PAIR(SIGINFO) + #endif + #ifdef SIGLOST + PAIR(SIGLOST) + #endif + #ifdef SIGPWR + PAIR(SIGPWR) + #endif + #if defined(SIGSYS) + /* + * According to signal(7)'s manpage, SIGUNUSED is synonymous + * with SIGSYS on most architectures. + */ + STRPAIR(SIGSYS, "SIGSYS/SIGUNUSED") + #endif + }; + + PAIR_LOOKUP(signal_pairs, sig); +}; diff --git a/ltp/lib/tests/.gitignore b/ltp/lib/tests/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..00237f53261e54a69e73e57dbf4ed55a5efe6129 --- /dev/null +++ b/ltp/lib/tests/.gitignore @@ -0,0 +1,14 @@ +/tst_tmpdir_test +/tst_process_state +/tst_cleanup_once +/tst_safe_macros +/tst_strsig +/tst_strerrno +/tst_fs_fill_subdirs +/tst_fs_fill_hardlinks +/tst_device +/tst_record_childstatus +/trerrno +/tst_dataroot01 +/tst_dataroot02 +/tst_dataroot03 diff --git a/ltp/lib/tests/Makefile b/ltp/lib/tests/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..73a0f1655a3ca3938b8d0125b490a6dd5dec94ba --- /dev/null +++ b/ltp/lib/tests/Makefile @@ -0,0 +1,10 @@ +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +CFLAGS += -W +LDLIBS += -lltp + +tst_cleanup_once: CFLAGS += -pthread + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/lib/tests/trerrno.c b/ltp/lib/tests/trerrno.c new file mode 100644 index 0000000000000000000000000000000000000000..a160874de92faf0dbbcd7afbe21971c6595b7a83 --- /dev/null +++ b/ltp/lib/tests/trerrno.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Linux Test Project, Inc. + * + * 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. + */ + +#include +#include +#include +#include "test.h" +#include "safe_macros.h" + +#define OUTPUT_FNAME "output" + +char *TCID = "trerrno"; +int TST_TOTAL = 1; + +static void setup(void) +{ + tst_tmpdir(); +} + +static void cleanup(void) +{ + tst_rmdir(); +} + +int main(void) +{ + int fd, stdout_fd; + char msg[4096], *pos; + FILE *f; + + setup(); + + /* redirect stdout to file */ + stdout_fd = dup(fileno(stdout)); + fd = SAFE_OPEN(NULL, OUTPUT_FNAME, O_RDWR | O_CREAT, 0666); + TEST(dup2(fd, fileno(stdout))); + if (TEST_RETURN == -1) + tst_brkm(TBROK | TTERRNO, cleanup, "dup2"); + + errno = EPERM; + TEST_ERRNO = EPERM; + TEST_RETURN = EINVAL; + tst_resm(TINFO | TRERRNO, "test"); + tst_old_flush(); + + /* restore stdout */ + TEST(dup2(stdout_fd, fileno(stdout))); + if (TEST_RETURN == -1) + tst_brkm(TBROK | TTERRNO, cleanup, "dup2"); + + /* read file and verify that output is as expected */ + SAFE_LSEEK(cleanup, fd, 0, SEEK_SET); + f = fdopen(fd, "r"); + if (!f) + tst_brkm(TBROK | TERRNO, cleanup, "fdopen"); + if (!fgets(msg, sizeof(msg), f)) + tst_brkm(TBROK, cleanup, "fgets"); + fclose(f); + + pos = strchr(msg, '\n'); + if (pos != NULL) + *pos = '\0'; + + tst_resm(TINFO, "%s", msg); + if (strstr(msg, "EPERM")) + tst_resm(TFAIL, "EPERM shouldn't be in TRERRNO output"); + if (strstr(msg, "EINVAL")) + tst_resm(TPASS, "EINVAL should be in TRERRNO output"); + else + tst_resm(TFAIL, "EINVAL not found in TRERRNO output"); + + cleanup(); + tst_exit(); +} diff --git a/ltp/lib/tests/tst_cleanup_once.c b/ltp/lib/tests/tst_cleanup_once.c new file mode 100644 index 0000000000000000000000000000000000000000..328ed74924d3289196b9e6ca76f3b36f89883049 --- /dev/null +++ b/ltp/lib/tests/tst_cleanup_once.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Linux Test Project + * + * 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. + */ + +#include + +#include "test.h" + +char *TCID = "tst_cleanup_once"; +int TST_TOTAL = 1; + +/* + * This is called exactly once + */ +static void do_cleanup(void) +{ + printf("Cleanup\n"); +} + +TST_DECLARE_ONCE_FN(cleanup, do_cleanup); + +int main(void) +{ + cleanup(); + cleanup(); + + return 0; +} diff --git a/ltp/lib/tests/tst_dataroot01.c b/ltp/lib/tests/tst_dataroot01.c new file mode 100644 index 0000000000000000000000000000000000000000..fab8bfea247227ae3c11e5e86c97b5494e4cdfd0 --- /dev/null +++ b/ltp/lib/tests/tst_dataroot01.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014 Linux Test Project, Inc. + * + * 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. + */ + +#include +#include +#include +#include "test.h" +#include "safe_macros.h" + +#define OUTPUT_FNAME "output" +#define LTPROOT "/opt/ltp" + +char *TCID = "dataroot"; +int TST_TOTAL = 1; + +static void cmp_paths(const char *p1, const char *p2, const char *s) +{ + if (strncmp(p1, p2, PATH_MAX) == 0) + tst_resm(TPASS, "%s", s); + else + tst_resm(TFAIL, "%s, %s != %s", s, p1, p2); +} + +int main(void) +{ + const char *dataroot; + char tmp[PATH_MAX]; + + /* LTPROOT */ + setenv("LTPROOT", LTPROOT, 1); + dataroot = tst_dataroot(); + snprintf(tmp, PATH_MAX, "%s/testcases/data/%s", LTPROOT, TCID); + cmp_paths(dataroot, tmp, "LTPROOT, no tmpdir, " + "dataroot == $LTPROOT/testcases/data/$TCID"); + + tst_exit(); +} + diff --git a/ltp/lib/tests/tst_dataroot02.c b/ltp/lib/tests/tst_dataroot02.c new file mode 100644 index 0000000000000000000000000000000000000000..b936b57f49470039515477b624c8ab0d1bf2f395 --- /dev/null +++ b/ltp/lib/tests/tst_dataroot02.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 Linux Test Project, Inc. + * + * 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. + */ + +#include +#include +#include +#include "test.h" +#include "safe_macros.h" + +#define OUTPUT_FNAME "output" +#define LTPROOT "/opt/ltp" + +char *TCID = "dataroot"; +int TST_TOTAL = 1; + +static void cmp_paths(const char *p1, const char *p2, const char *s) +{ + if (strncmp(p1, p2, PATH_MAX) == 0) + tst_resm(TPASS, "%s", s); + else + tst_resm(TFAIL, "%s, %s != %s", s, p1, p2); +} + +int main(void) +{ + const char *dataroot; + char curdir[PATH_MAX], tmp[PATH_MAX]; + + if (getcwd(curdir, PATH_MAX) == NULL) + tst_brkm(TBROK, NULL, "getcwd"); + + /* no LTPROOT, no tmpdir */ + unsetenv("LTPROOT"); + dataroot = tst_dataroot(); + snprintf(tmp, PATH_MAX, "%s/datafiles", curdir); + cmp_paths(dataroot, tmp, "no LTPROOT, no tmpdir, " + "dataroot == $CWD/datafiles"); + + tst_exit(); +} + diff --git a/ltp/lib/tests/tst_dataroot03.c b/ltp/lib/tests/tst_dataroot03.c new file mode 100644 index 0000000000000000000000000000000000000000..cf5a04ec6f597ad08097083382534fd6539698cb --- /dev/null +++ b/ltp/lib/tests/tst_dataroot03.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Linux Test Project, Inc. + * + * 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. + */ + +#include +#include +#include +#include "test.h" +#include "safe_macros.h" + +#define OUTPUT_FNAME "output" +#define LTPROOT "/opt/ltp" + +char *TCID = "dataroot"; +int TST_TOTAL = 1; + +static void cmp_paths(const char *p1, const char *p2, const char *s) +{ + if (strncmp(p1, p2, PATH_MAX) == 0) + tst_resm(TPASS, "%s", s); + else + tst_resm(TFAIL, "%s, %s != %s", s, p1, p2); +} + +int main(void) +{ + const char *dataroot; + char curdir[PATH_MAX], tmp[PATH_MAX]; + + if (getcwd(curdir, PATH_MAX) == NULL) + tst_brkm(TBROK, NULL, "getcwd"); + + /* no LTPROOT, tmpdir */ + tst_tmpdir(); + dataroot = tst_dataroot(); + snprintf(tmp, PATH_MAX, "%s/datafiles", curdir); + cmp_paths(dataroot, tmp, "no LTPROOT, tmpdir, " + "dataroot == $STARTWD/datafiles"); + tst_rmdir(); + + tst_exit(); +} + diff --git a/ltp/lib/tests/tst_device.c b/ltp/lib/tests/tst_device.c new file mode 100644 index 0000000000000000000000000000000000000000..c010475a2d565f3934c7551adb2eeef839bb410c --- /dev/null +++ b/ltp/lib/tests/tst_device.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 Cyril Hrubis + * + * 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. + */ + +#include "test.h" + +char *TCID = "tst_device"; +int TST_TOTAL = 1; + +static const char *dev; + +static void cleanup(void) +{ + if (dev) + tst_release_device(dev); + + tst_rmdir(); +} + +int main(void) +{ + tst_tmpdir(); + + dev = tst_acquire_device(cleanup); + if (!dev) + tst_brkm(TCONF, cleanup, "Failed to acquire test device"); + + printf("Test device='%s'\n", dev); + + tst_mkfs(cleanup, dev, "ext2", NULL, NULL); + + cleanup(); + tst_exit(); +} diff --git a/ltp/lib/tests/tst_fs_fill_hardlinks.c b/ltp/lib/tests/tst_fs_fill_hardlinks.c new file mode 100644 index 0000000000000000000000000000000000000000..271776dcf4cd8b1d3c11ab202edc310e9f273dae --- /dev/null +++ b/ltp/lib/tests/tst_fs_fill_hardlinks.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 Cyril Hrubis + * + * 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. + */ + +#include "test.h" + +char *TCID = "tst_fs_fill_hardlinks"; +int TST_TOTAL = 1; + +static void cleanup(void) +{ + tst_rmdir(); +} + +int main(void) +{ + tst_tmpdir(); + + fprintf(stderr, "Max hardlinks = %i\n", + tst_fs_fill_hardlinks(NULL, "subdirs")); + + cleanup(); + tst_exit(); +} diff --git a/ltp/lib/tests/tst_fs_fill_subdirs.c b/ltp/lib/tests/tst_fs_fill_subdirs.c new file mode 100644 index 0000000000000000000000000000000000000000..496db5972aed2ace5cace991b188358712e53e56 --- /dev/null +++ b/ltp/lib/tests/tst_fs_fill_subdirs.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 Cyril Hrubis + * + * 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. + */ + +#include "test.h" + +char *TCID = "tst_fs_fill_subdirs"; +int TST_TOTAL = 1; + +static void cleanup(void) +{ + tst_rmdir(); +} + +int main(void) +{ + tst_tmpdir(); + + fprintf(stderr, "Max dir elements = %i\n", + tst_fs_fill_subdirs(NULL, "dir")); + + cleanup(); + tst_exit(); +} diff --git a/ltp/lib/tests/tst_process_state.c b/ltp/lib/tests/tst_process_state.c new file mode 100644 index 0000000000000000000000000000000000000000..dd4f0535de71ea8f0bc9bc6bd6ce24535749ffc2 --- /dev/null +++ b/ltp/lib/tests/tst_process_state.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 Cyril Hrubis + * + * 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. + */ + +#include + +#include "test.h" + +char *TCID = "tst_checkpoint_child"; +int TST_TOTAL = 1; + +void handler(int sig LTP_ATTRIBUTE_UNUSED) +{ + if (write(2, "Child in sighandler\n", 20)) { + /* silence build time warnings */ + } +} + +int main(void) +{ + int pid; + volatile int i; + + pid = fork(); + + switch (pid) { + case -1: + tst_brkm(TBROK | TERRNO, NULL, "Fork failed"); + break; + case 0: + fprintf(stderr, "Child starts\n"); + + signal(SIGALRM, handler); + + for (i = 0; i < 100000000; i++); + + fprintf(stderr, "Child about to sleep\n"); + + pause(); + + fprintf(stderr, "Child woken up\n"); + + return 0; + break; + default: + /* Wait for child to sleep */ + fprintf(stderr, "Parent waits for child to fall asleep\n"); + TST_PROCESS_STATE_WAIT(NULL, pid, 'S'); + fprintf(stderr, "Child sleeping, wake it\n"); + kill(pid, SIGALRM); + break; + } + + wait(NULL); + return 0; +} diff --git a/ltp/lib/tests/tst_record_childstatus.c b/ltp/lib/tests/tst_record_childstatus.c new file mode 100644 index 0000000000000000000000000000000000000000..74544e5ce4d6ef0150afc16a2eeedaee07d9e058 --- /dev/null +++ b/ltp/lib/tests/tst_record_childstatus.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 Cyril Hrubis + * + * 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. + */ + +#include "test.h" + +char *TCID = "tst_record_childstatus"; +int TST_TOTAL = 1; + +int main(void) +{ + int pid; + + pid = tst_fork(); + + switch (pid) { + case 0: + tst_resm(TFAIL, "Child reports failure"); + /* Uncomment to get child killed by signal */ + //alarm(1); + //pause(); + tst_exit(); + case -1: + tst_brkm(TBROK, NULL, "fork failed"); + default: + tst_record_childstatus(NULL, pid); + } + + /* Should return failure from child, i.e. exit status is 1 */ + tst_exit(); +} diff --git a/ltp/lib/tests/tst_safe_macros.c b/ltp/lib/tests/tst_safe_macros.c new file mode 100644 index 0000000000000000000000000000000000000000..5c427ee16832261b8617ad15b69195648d0d8d96 --- /dev/null +++ b/ltp/lib/tests/tst_safe_macros.c @@ -0,0 +1,40 @@ +#include "test.h" +#include "safe_macros.h" + +char *TCID = "test_safe_macros"; +int TST_TOTAL = 1; + +int fd = -1; + +void cleanup(void) +{ + SAFE_CLOSE(NULL, fd); + SAFE_UNLINK(NULL, __FILE__ "~"); + tst_resm(TINFO, "got here"); +} + +int main(int argc LTP_ATTRIBUTE_UNUSED, char **argv) +{ + char buf[10]; + int fds[2]; + + buf[9] = '\0'; + + if (system("cp " __FILE__ " " __FILE__ "~")) { + fprintf(stderr, "error: could not cp file\n"); + return 1; + } + printf("%s\n", SAFE_BASENAME(NULL, *argv)); + printf("%s\n", SAFE_DIRNAME(NULL, *argv)); + fd = SAFE_OPEN(cleanup, __FILE__ "~", O_RDWR); + SAFE_READ(cleanup, 0, fd, buf, 9); + printf("buf: %s\n", buf); + SAFE_READ(cleanup, 1, fd, buf, 9); + printf("buf: %s\n", buf); + SAFE_WRITE(cleanup, SAFE_WRITE_ANY, -1, buf, 9); + SAFE_WRITE(NULL, SAFE_WRITE_ANY, fd, buf, 9); + SAFE_WRITE(NULL, SAFE_WRITE_ALL, fd, buf, 9); + SAFE_PIPE(NULL, fds); + + return 0; +} diff --git a/ltp/lib/tests/tst_strerrno.c b/ltp/lib/tests/tst_strerrno.c new file mode 100644 index 0000000000000000000000000000000000000000..dbee7642fe3fdc4bdae45786fb7287d017b539b3 --- /dev/null +++ b/ltp/lib/tests/tst_strerrno.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 Cyril Hrubis + * + * 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. + */ + +#include +#include "test.h" + +char *TCID = "tst_strerrno"; +int TST_TOTAL = 1; + +int main(void) +{ + fprintf(stderr, "0 = %s\n", tst_strerrno(0)); + fprintf(stderr, "EINVAL = %s\n", tst_strerrno(EINVAL)); + return 0; +} diff --git a/ltp/lib/tests/tst_strsig.c b/ltp/lib/tests/tst_strsig.c new file mode 100644 index 0000000000000000000000000000000000000000..ed5be3f003e22daba3a2d15b6c242976aa323e76 --- /dev/null +++ b/ltp/lib/tests/tst_strsig.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Cyril Hrubis + * + * 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. + */ + +#include +#include "test.h" + +char *TCID = "tst_strsig"; +int TST_TOTAL = 1; + +int main(void) +{ + fprintf(stderr, "0 = %s\n", tst_strsig(0)); + fprintf(stderr, "SIGKILL = %s\n", tst_strsig(SIGKILL)); + fprintf(stderr, "SIGALRM = %s\n", tst_strsig(SIGALRM)); + return 0; +} diff --git a/ltp/lib/tests/tst_tmpdir_test.c b/ltp/lib/tests/tst_tmpdir_test.c new file mode 100644 index 0000000000000000000000000000000000000000..774537587ee69ab2f5a4f9b1844d803aefae0a86 --- /dev/null +++ b/ltp/lib/tests/tst_tmpdir_test.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2012 Marios Makris + * + * 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. + */ + +/* + * Test program for the tst_tmpdir program in /lib + * + * This program creates and deletes a temporary file in order to test + * the functionality of the tst_tmpdir functionality. + * On successful completion it prints the message: + * "Test completed successfully!" + */ + +#include +#include + +#include "test.h" + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +char *TCID = "tst_tmpdir_test"; +int TST_TOTAL = 1; + +int main(void) +{ + char *tmp_dir; + char *start_dir = getcwd(NULL, PATH_MAX); + char *changed_dir; + int fail_counter = 0; + + tst_tmpdir(); + + tmp_dir = tst_get_tmpdir(); + changed_dir = getcwd(NULL, PATH_MAX); + + if (strcmp(tmp_dir, changed_dir) == 0 && + strcmp(tmp_dir, start_dir) != 0) { + printf("Temp directory successfully created and switched to\n"); + } else { + printf("Temp directory is wrong!\n"); + fail_counter++; + } + + tst_rmdir(); + + if (chdir(tmp_dir) == -1 && errno == ENOENT) { + printf("The temp directory was removed successfully\n"); + } else { + printf("Failed to remove the temp directory!\n"); + fail_counter++; + } + + if (fail_counter > 0) + printf("Something failed please review!!\n"); + else + printf("Test completed successfully!\n"); + + return 0; +} diff --git a/ltp/lib/tlibio.c b/ltp/lib/tlibio.c new file mode 100644 index 0000000000000000000000000000000000000000..b877393df2786c44d0e2ec00f0e4a244796d5bfb --- /dev/null +++ b/ltp/lib/tlibio.c @@ -0,0 +1,1689 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +/* + * + * Lib i/o + * + * This file contains several functions to doing reads and writes. + * It was written so that a single function could be called in a test + * program and only a io type field value would have to change to + * do different types of io. There is even a couple of functions that + * will allow you to parse a string to determine the iotype. + * + * This file contains functions for writing/reading to/from open files + * Prototypes: + * + * Functions declared in this module - see individual function code for + * usage comments: + * + * int stride_bounds(int offset, int stride, int nstrides, + * int bytes_per_stride, int *min, int *max); + + * int lio_write_buffer(int fd, int method, char *buffer, int size, + * char **errmsg, long wrd); + * int lio_read_buffer(int fd, int method, char *buffer, int size, + * char **errmsg, long wrd); + * + * int lio_parse_io_arg1(char *string) + * void lio_help1(char *prefix); + * + * int lio_parse_io_arg2(char *string, char **badtoken) + * void lio_help2(char *prefix); + * + * int lio_set_debug(int level); + * + * char Lio_SysCall[]; + * struct lio_info_type Lio_info1[]; + * struct lio_info_type Lio_info2[]; + * + * Author : Richard Logan + * + */ + +#define _GNU_SOURCE +#define _LARGEFILE64_SOURCE + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* readv(2)/writev(2) */ +#include +#include +#include /* atoi, abs */ + +#include "tlibio.h" /* defines LIO* macros */ +#include "random_range.h" + +#ifndef PATH_MAX +#define PATH_MAX MAXPATHLEN +#endif + +/* + * Define the structure as used in lio_parse_arg1 and lio_help1 + */ +struct lio_info_type Lio_info1[] = { + {"s", LIO_IO_SYNC, "sync i/o"}, + {"p", LIO_IO_ASYNC | LIO_WAIT_SIGACTIVE, + "async i/o using a loop to wait for a signal"}, + {"b", LIO_IO_ASYNC | LIO_WAIT_SIGPAUSE, "async i/o using pause"}, + {"a", LIO_IO_ASYNC | LIO_WAIT_RECALL, + "async i/o using recall/aio_suspend"}, +#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) + {"r", + LIO_RANDOM | LIO_IO_TYPES | LIO_WAIT_TYPES, + "random sync i/o types and wait methods"}, + {"R", + LIO_RANDOM | LIO_IO_ATYPES | LIO_WAIT_ATYPES, + "random i/o types and wait methods"}, +#else + {"r", + LIO_RANDOM | LIO_IO_TYPES | LIO_WAIT_TYPES, + "random i/o types and wait methods"}, + {"R", + LIO_RANDOM | LIO_IO_TYPES | LIO_WAIT_TYPES, + "random i/o types and wait methods"}, +#endif + {"l", LIO_IO_SLISTIO | LIO_WAIT_RECALL, "single stride sync listio"}, + {"L", LIO_IO_ALISTIO | LIO_WAIT_RECALL, + "single stride async listio using recall"}, + {"X", LIO_IO_ALISTIO | LIO_WAIT_SIGPAUSE, + "single stride async listio using pause"}, + {"v", LIO_IO_SYNCV, "single buffer sync readv/writev"}, + {"P", LIO_IO_SYNCP, "sync pread/pwrite"}, +}; + +/* + * Define the structure used by lio_parse_arg2 and lio_help2 + */ +struct lio_info_type Lio_info2[] = { + {"sync", LIO_IO_SYNC, "sync i/o (read/write)"}, + {"async", LIO_IO_ASYNC, "async i/o (reada/writea/aio_read/aio_write)"}, + {"slistio", LIO_IO_SLISTIO, "single stride sync listio"}, + {"alistio", LIO_IO_ALISTIO, "single stride async listio"}, + {"syncv", LIO_IO_SYNCV, "single buffer sync readv/writev"}, + {"syncp", LIO_IO_SYNCP, "pread/pwrite"}, + {"active", LIO_WAIT_ACTIVE, "spin on status/control values"}, + {"recall", LIO_WAIT_RECALL, + "use recall(2)/aio_suspend(3) to wait for i/o to complete"}, + {"sigactive", LIO_WAIT_SIGACTIVE, "spin waiting for signal"}, + {"sigpause", LIO_WAIT_SIGPAUSE, "call pause(2) to wait for signal"}, +/* nowait is a touchy thing, it's an accident that this implementation worked at all. 6/27/97 roehrich */ +/* { "nowait", LIO_WAIT_NONE, "do not wait for async io to complete" },*/ + {"random", LIO_RANDOM, "set random bit"}, + {"randomall", + LIO_RANDOM | LIO_IO_TYPES | LIO_WAIT_TYPES, + "all random i/o types and wait methods (except nowait)"}, +}; + +char Lio_SysCall[PATH_MAX]; /* string containing last i/o system call */ + +static volatile int Received_signal = 0; /* number of signals received */ +static volatile int Rec_signal; +#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) +static volatile int Received_callback = 0; /* number of callbacks received */ +static volatile int Rec_callback; +#endif +static char Errormsg[PATH_MAX*2]; +static int Debug_level = 0; + +/*********************************************************************** + * stride_bounds() + * + * Determine the bounds of a strided request, normalized to offset. Returns + * the number of bytes needed to satisfy the request, and optionally sets + * *min and *max to the mininum and maximum bytes referenced, normalized + * around offset. + * + * Returns -1 on error - the only possible error conditions are illegal values + * for nstrides and/or bytes_per_stride - both parameters must be >= 0. + * + * (maule, 11/16/95) + ***********************************************************************/ + +int stride_bounds(int offset, int stride, int nstrides, int bytes_per_stride, + int *min, int *max) +{ + int nbytes, min_byte, max_byte; + + /* + * sanity checks ... + */ + + if (nstrides < 0 || bytes_per_stride < 0) { + return -1; + } + + if (stride == 0) { + stride = bytes_per_stride; + } + + /* + * Determine the # of bytes needed to satisfy the request. This + * value, along with the offset argument, determines the min and max + * bytes referenced. + */ + + nbytes = abs(stride) * (nstrides - 1) + bytes_per_stride; + + if (stride < 0) { + max_byte = offset + bytes_per_stride - 1; + min_byte = max_byte - nbytes + 1; + } else { + min_byte = offset; + max_byte = min_byte + nbytes - 1; + } + + if (min != NULL) { + *min = min_byte; + } + + if (max != NULL) { + *max = max_byte; + } + + return nbytes; +} + +/*********************************************************************** + * This function will allow someone to set the debug level. + ***********************************************************************/ +int lio_set_debug(int level) +{ + int old; + + old = Debug_level; + Debug_level = level; + return old; +} + +/*********************************************************************** + * This function will parse a string and return desired io-method. + * Only the first character of the string is used. + * + * This function does not provide for meaningful option arguments, + * but it supports current growfiles/btlk interface. + * + * (rrl 04/96) + ***********************************************************************/ +int lio_parse_io_arg1(char *string) +{ + unsigned int ind; + int found = 0; + int mask = 0; + + /* + * Determine if token is a valid string. + */ + for (ind = 0; ind < sizeof(Lio_info1) / sizeof(struct lio_info_type); + ind++) { + if (strcmp(string, Lio_info1[ind].token) == 0) { + mask |= Lio_info1[ind].bits; + found = 1; + break; + } + } + + if (found == 0) { + return -1; + } + + return mask; + +} + +/*********************************************************************** + * This function will print a help message describing the characters + * that can be parsed by lio_parse_io_arg1(). + * They will be printed one per line. + * (rrl 04/96) + ***********************************************************************/ +void lio_help1(char *prefix) +{ + unsigned int ind; + + for (ind = 0; ind < sizeof(Lio_info1) / sizeof(struct lio_info_type); + ind++) { + printf("%s %s : %s\n", prefix, Lio_info1[ind].token, + Lio_info1[ind].desc); + } + + return; +} + +/*********************************************************************** + * This function will parse a string and return the desired io-method. + * This function will take a comma separated list of io type and wait + * method tokens as defined in Lio_info2[]. If a token does not match + * any of the tokens in Lio_info2[], it will be coverted to a number. + * If it was a number, those bits are also set. + * + * (rrl 04/96) + ***********************************************************************/ +int lio_parse_io_arg2(char *string, char **badtoken) +{ + char *token = string; + char *cc = token; + char savecc; + int found; + int mask = 0; + + int tmp; + unsigned int ind; + char chr; + + if (token == NULL) + return -1; + + for (;;) { + for (; ((*cc != ',') && (*cc != '\0')); cc++) ; + savecc = *cc; + *cc = '\0'; + + found = 0; + + /* + * Determine if token is a valid string or number and if + * so, add the bits to the mask. + */ + for (ind = 0; + ind < sizeof(Lio_info2) / sizeof(struct lio_info_type); + ind++) { + if (strcmp(token, Lio_info2[ind].token) == 0) { + mask |= Lio_info2[ind].bits; + found = 1; + break; + } + } + + /* + * If token does not match one of the defined tokens, determine + * if it is a number, if so, add the bits. + */ + if (!found) { + if (sscanf(token, "%i%c", &tmp, &chr) == 1) { + mask |= tmp; + found = 1; + } + } + + *cc = savecc; + + if (!found) { /* token is not valid */ + if (badtoken != NULL) + *badtoken = token; + return (-1); + } + + if (savecc == '\0') + break; + + token = ++cc; + } + + return mask; +} + +/*********************************************************************** + * This function will print a help message describing the tokens + * that can be parsed by lio_parse_io_arg2(). + * It will print them one per line. + * + * (rrl 04/96) + ***********************************************************************/ +void lio_help2(char *prefix) +{ + unsigned int ind; + + for (ind = 0; ind < sizeof(Lio_info2) / sizeof(struct lio_info_type); + ind++) { + printf("%s %s : %s\n", prefix, Lio_info2[ind].token, + Lio_info2[ind].desc); + } + return; +} + +/*********************************************************************** + * This is an internal signal handler. + * If the handler is called, it will increment the Received_signal + * global variable. + ***********************************************************************/ +static void lio_async_signal_handler(int sig) +{ + if (Debug_level) + printf + ("DEBUG %s/%d: received signal %d, a signal caught %d times\n", + __FILE__, __LINE__, sig, Received_signal + 1); + + Received_signal++; + + return; +} + +#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) +/*********************************************************************** + * This is an internal callback handler. + * If the handler is called, it will increment the Received_callback + * global variable. + ***********************************************************************/ +static void lio_async_callback_handler(union sigval sigval) +{ + if (Debug_level) + printf + ("DEBUG %s/%d: received callback, nbytes=%ld, a callback called %d times\n", + __FILE__, __LINE__, (long)sigval.sival_int, + Received_callback + 1); + + Received_callback++; + + return; +} +#endif /* sgi */ + +/*********************************************************************** + * lio_random_methods + * This function will randomly choose an io type and wait method + * from set of io types and wait methods. Since this information + * is stored in a bitmask, it randomly chooses an io type from + * the io type bits specified and does the same for wait methods. + * + * Return Value + * This function will return a value with all non choosen io type + * and wait method bits cleared. The LIO_RANDOM bit is also + * cleared. All other bits are left unchanged. + * + * (rrl 04/96) + ***********************************************************************/ +int lio_random_methods(long curr_mask) +{ + int mask = 0; + + /* remove random select, io type, and wait method bits from curr_mask */ + mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM)); + + /* randomly select io type from specified io types */ + mask = mask | random_bit(curr_mask & LIO_IO_TYPES); + + /* randomly select wait methods from specified wait methods */ + mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES); + + return mask; +} + +static void wait4sync_io(int fd, int read) +{ + fd_set s; + FD_ZERO(&s); + FD_SET(fd, &s); + + select(fd + 1, read ? &s : NULL, read ? NULL : &s, NULL, NULL); +} + +/*********************************************************************** + * Generic write function + * This function can be used to do a write using write(2), writea(2), + * aio_write(3), writev(2), pwrite(2), + * or single stride listio(2)/lio_listio(3). + * By setting the desired bits in the method + * bitmask, the caller can control the type of write and the wait method + * that will be used. If no io type bits are set, write will be used. + * + * If async io was attempted and no wait method bits are set then the + * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for + * aio_write(3) and lio_listio(3). + * + * If multiple wait methods are specified, + * only one wait method will be used. The order is predetermined. + * + * If the call specifies a signal and one of the two signal wait methods, + * a signal handler for the signal is set. This will reset an already + * set handler for this signal. + * + * If the LIO_RANDOM method bit is set, this function will randomly + * choose a io type and wait method from bits in the method argument. + * + * If an error is encountered, an error message will be generated + * in a internal static buffer. If errmsg is not NULL, it will + * be updated to point to the static buffer, allowing the caller + * to print the error message. + * + * Return Value + * If a system call fails, -errno is returned. + * If LIO_WAIT_NONE bit is set, the return value is the return value + * of the system call. + * If the io did not fail, the amount of data written is returned. + * If the size the system call say was written is different + * then what was asked to be written, errmsg is updated for + * this error condition. The return value is still the amount + * the system call says was written. + * + * (rrl 04/96) + ***********************************************************************/ +int lio_write_buffer(int fd, /* open file descriptor */ + int method, /* contains io type and wait method bitmask */ + char *buffer, /* pointer to buffer */ + int size, /* the size of the io */ + int sig, /* signal to use if async io */ + char **errmsg, /* char pointer that will be updated to point to err message */ + long wrd) /* to allow future features, use zero for now */ +{ + int ret = 0; /* syscall return or used to get random method */ + /* as we cycle writes in case of partial writes, we have to report up + * total bytes written + */ + int totally_written = 0; + char *io_type; /* Holds string of type of io */ + int omethod = method; + int listio_cmd; /* Holds the listio/lio_listio cmd */ + struct iovec iov; /* iovec for writev(2) */ + struct aiocb aiocbp; /* POSIX aio control block */ + struct aiocb *aiolist[1]; /* list of aio control blocks for lio_listio */ + off64_t poffset; /* pwrite(2) offset */ + + /* + * If LIO_RANDOM bit specified, get new method randomly. + */ + if (method & LIO_RANDOM) { + if (Debug_level > 3) + printf("DEBUG %s/%d: method mask to choose from: %#o\n", + __FILE__, __LINE__, method); + method = lio_random_methods(method); + if (Debug_level > 2) + printf("DEBUG %s/%d: random chosen method %#o\n", + __FILE__, __LINE__, method); + } + + if (errmsg != NULL) + *errmsg = Errormsg; + + Rec_signal = Received_signal; /* get the current number of signals received */ + Rec_callback = Received_callback; /* get the current number of callbacks received */ + + memset(&iov, 0x00, sizeof(struct iovec)); + iov.iov_base = buffer; + iov.iov_len = size; + + memset(&aiocbp, 0x00, sizeof(struct aiocb)); + + aiocbp.aio_fildes = fd; + aiocbp.aio_nbytes = size; + aiocbp.aio_buf = buffer; +/* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */ + aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE; + aiocbp.aio_sigevent.sigev_signo = 0; + aiocbp.aio_sigevent.sigev_notify_function = NULL; + aiocbp.aio_sigevent.sigev_notify_attributes = 0; + + aiolist[0] = &aiocbp; + + if ((ret = lseek(fd, 0, SEEK_CUR)) == -1) { + ret = 0; + /* If there is an error and it is not ESPIPE then kick out the error. + * If the fd is a fifo then we have to make sure that + * lio_random_methods() didn't select pwrite/pread; if it did then + * switch to write/read. + */ + if (errno == ESPIPE) { + if (method & LIO_IO_SYNCP) { + if (omethod & LIO_RANDOM) { + method &= ~LIO_IO_SYNCP; + method |= LIO_IO_SYNC; + if (Debug_level > 2) + printf + ("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", + __FILE__, __LINE__, + method); + } else if (Debug_level) { + printf + ("DEBUG %s/%d: pwrite will fail when it writes to a fifo\n", + __FILE__, __LINE__); + } + } + /* else: let it ride */ + } else { + sprintf(Errormsg, + "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s", + __FILE__, __LINE__, fd, errno, strerror(errno)); + return -errno; + } + } + + poffset = (off64_t) ret; + aiocbp.aio_offset = ret; + + /* + * If the LIO_USE_SIGNAL bit is not set, only use the signal + * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit. + * Otherwise there is not necessary a signal handler to trap + * the signal. + */ + if (sig && !(method & LIO_USE_SIGNAL) && !(method & LIO_WAIT_SIGTYPES)) { + + sig = 0; /* ignore signal parameter */ + } + if (sig && (method & LIO_WAIT_CBTYPES)) + sig = 0; /* ignore signal parameter */ + + /* + * only setup signal hander if sig was specified and + * a sig wait method was specified. + * Doing this will change the handler for this signal. The + * old signal handler will not be restored. + *** restoring the signal handler could be added *** + */ + + if (sig && (method & LIO_WAIT_SIGTYPES)) { + aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocbp.aio_sigevent.sigev_signo = sig; + sigset(sig, lio_async_signal_handler); + } + else if (method & LIO_WAIT_CBTYPES) { + /* sival_int just has to be something that I can use + * to identify the callback, and "size" happens to be handy... + */ + aiocbp.aio_sigevent.sigev_notify = SIGEV_THREAD; + aiocbp.aio_sigevent.sigev_notify_function = + lio_async_callback_handler; + aiocbp.aio_sigevent.sigev_notify_attributes = + (void *)(uintptr_t) size; + } + + /* + * Determine the system call that will be called and produce + * the string of the system call and place it in Lio_SysCall. + * Also update the io_type char pointer to give brief description + * of system call. Execute the system call and check for + * system call failure. If sync i/o, return the number of + * bytes written/read. + */ + + if ((method & LIO_IO_SYNC) + || (method & (LIO_IO_TYPES | LIO_IO_ATYPES)) == 0) { + /* + * write(2) is used if LIO_IO_SYNC bit is set or not none + * of the LIO_IO_TYPES bits are set (default). + */ + + sprintf(Lio_SysCall, "write(%d, buf, %d)", fd, size); + io_type = "write"; + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + while (1) { + if (((ret = write(fd, buffer, size)) == -1) + && errno != EAGAIN && errno != EINTR) { + sprintf(Errormsg, + "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s", + __FILE__, __LINE__, fd, size, errno, + strerror(errno)); + return -errno; + } + + if (ret != -1) { + if (ret != size) { + sprintf(Errormsg, + "%s/%d write(%d, buf, %d) returned=%d", + __FILE__, __LINE__, + fd, size, ret); + size -= ret; + buffer += ret; + totally_written += ret; + } else { + if (Debug_level > 1) + printf + ("DEBUG %s/%d: write completed without error (ret %d)\n", + __FILE__, __LINE__, ret); + + return totally_written + ret; + } + } + wait4sync_io(fd, 0); + } + + } + + else if (method & LIO_IO_ASYNC) { + sprintf(Lio_SysCall, + "aio_write(fildes=%d, buf, nbytes=%d, signo=%d)", fd, + size, sig); + io_type = "aio_write"; + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + + if (sig) + sighold(sig); + if ((ret = aio_write(&aiocbp)) == -1) { + sprintf(Errormsg, + "%s/%d aio_write(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s", + __FILE__, __LINE__, + fd, size, sig, errno, strerror(errno)); + if (sig) + sigrelse(sig); + return -errno; + } + } + /* LIO_IO_ASYNC */ + else if (method & LIO_IO_SLISTIO) { + aiocbp.aio_lio_opcode = LIO_WRITE; + listio_cmd = LIO_WAIT; + io_type = "lio_listio(3) sync write"; + + sprintf(Lio_SysCall, + "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d, sig:%d", + fd, size, sig); + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + + if (sig) + sighold(sig); + if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) { + sprintf(Errormsg, + "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", + __FILE__, __LINE__, Lio_SysCall, fd, size, + errno, strerror(errno)); + if (sig) + sigrelse(sig); + return -errno; + } + + if (Debug_level > 1) + printf("DEBUG %s/%d: %s did not return -1\n", + __FILE__, __LINE__, Lio_SysCall); + + ret = lio_check_asyncio(io_type, size, &aiocbp, method); + return ret; + } + /* LIO_IO_SLISTIO */ + else if (method & LIO_IO_ALISTIO) { + aiocbp.aio_lio_opcode = LIO_WRITE; + listio_cmd = LIO_NOWAIT; + io_type = "lio_listio(3) async write"; + + sprintf(Lio_SysCall, + "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d", + fd, size); + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + + if (sig) + sighold(sig); + if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) { + sprintf(Errormsg, + "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", + __FILE__, __LINE__, Lio_SysCall, fd, size, + errno, strerror(errno)); + if (sig) + sigrelse(sig); + return -errno; + } + } + /* LIO_IO_ALISTIO */ + else if (method & LIO_IO_SYNCV) { + io_type = "writev(2)"; + + sprintf(Lio_SysCall, "writev(%d, &iov, 1) nbyte:%d", fd, size); + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + if ((ret = writev(fd, &iov, 1)) == -1) { + sprintf(Errormsg, + "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s", + __FILE__, __LINE__, fd, size, errno, + strerror(errno)); + return -errno; + } + + if (ret != size) { + sprintf(Errormsg, + "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d", + __FILE__, __LINE__, fd, size, ret); + } else if (Debug_level > 1) + printf + ("DEBUG %s/%d: writev completed without error (ret %d)\n", + __FILE__, __LINE__, ret); + + return ret; + } /* LIO_IO_SYNCV */ + else if (method & LIO_IO_SYNCP) { + io_type = "pwrite(2)"; + + sprintf(Lio_SysCall, + "pwrite(%d, buf, %d, %lld)", fd, size, + (long long)poffset); + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + if ((ret = pwrite(fd, buffer, size, poffset)) == -1) { + sprintf(Errormsg, + "%s/%d pwrite(%d, buf, %d, %lld) ret:-1, errno=%d %s", + __FILE__, __LINE__, fd, size, + (long long)poffset, errno, strerror(errno)); + return -errno; + } + + if (ret != size) { + sprintf(Errormsg, + "%s/%d pwrite(%d, buf, %d, %lld) returned=%d", + __FILE__, __LINE__, + fd, size, (long long)poffset, ret); + } else if (Debug_level > 1) + printf + ("DEBUG %s/%d: pwrite completed without error (ret %d)\n", + __FILE__, __LINE__, ret); + + return ret; + } /* LIO_IO_SYNCP */ + else { + printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, + __LINE__); + return -1; + } + + /* + * wait for async io to complete. + */ + ret = lio_wait4asyncio(method, fd, &aiocbp); + + /* + * If there was an error waiting for async i/o to complete, + * return the error value (errno) to the caller. + * Note: Errormsg should already have been updated. + */ + if (ret < 0) { + return ret; + } + + /* + * If i/o was not waited for (may not have been completed at this time), + * return the size that was requested. + */ + if (ret == 1) + return size; + + /* + * check that async io was successful. + * Note: if the there was an system call failure, -errno + * was returned and Errormsg should already have been updated. + * If amount i/o was different than size, Errormsg should already + * have been updated but the actual i/o size if returned. + */ + + ret = lio_check_asyncio(io_type, size, &aiocbp, method); + + return ret; +} /* end of lio_write_buffer */ + +/*********************************************************************** + * Generic read function + * This function can be used to do a read using read(2), reada(2), + * aio_read(3), readv(2), pread(2), + * or single stride listio(2)/lio_listio(3). + * By setting the desired bits in the method + * bitmask, the caller can control the type of read and the wait method + * that will be used. If no io type bits are set, read will be used. + * + * If async io was attempted and no wait method bits are set then the + * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for + * aio_read(3) and lio_listio(3). + * + * If multiple wait methods are specified, + * only one wait method will be used. The order is predetermined. + * + * If the call specifies a signal and one of the two signal wait methods, + * a signal handler for the signal is set. This will reset an already + * set handler for this signal. + * + * If the LIO_RANDOM method bit is set, this function will randomly + * choose a io type and wait method from bits in the method argument. + * + * If an error is encountered, an error message will be generated + * in a internal static buffer. If errmsg is not NULL, it will + * be updated to point to the static buffer, allowing the caller + * to print the error message. + * + * Return Value + * If a system call fails, -errno is returned. + * If LIO_WAIT_NONE bit is set, the return value is the return value + * of the system call. + * If the io did not fail, the amount of data written is returned. + * If the size the system call say was written is different + * then what was asked to be written, errmsg is updated for + * this error condition. The return value is still the amount + * the system call says was written. + * + * (rrl 04/96) + ***********************************************************************/ +int lio_read_buffer(int fd, /* open file descriptor */ + int method, /* contains io type and wait method bitmask*/ + char *buffer, /* pointer to buffer */ + int size, /* the size of the io */ + int sig, /* signal to use if async io */ + char **errmsg, /* char pointer that will be updated to point to err message */ + long wrd) /* to allow future features, use zero for now */ +{ + int ret = 0; /* syscall return or used to get random method */ + /* as we cycle reads in case of partial reads, we have to report up + * total bytes read + */ + int totally_read = 0; + char *io_type; /* Holds string of type of io */ + int listio_cmd; /* Holds the listio/lio_listio cmd */ + int omethod = method; + struct iovec iov; /* iovec for readv(2) */ + struct aiocb aiocbp; /* POSIX aio control block */ + struct aiocb *aiolist[1]; /* list of aio control blocks for lio_listio */ + off64_t poffset; /* pread(2) offset */ + + /* + * If LIO_RANDOM bit specified, get new method randomly. + */ + if (method & LIO_RANDOM) { + if (Debug_level > 3) + printf("DEBUG %s/%d: method mask to choose from: %#o\n", + __FILE__, __LINE__, method); + method = lio_random_methods(method); + if (Debug_level > 2) + printf("DEBUG %s/%d: random chosen method %#o\n", + __FILE__, __LINE__, method); + } + + if (errmsg != NULL) + *errmsg = Errormsg; + + Rec_signal = Received_signal; /* get the current number of signals received */ + Rec_callback = Received_callback; /* get the current number of callbacks received */ + + memset(&iov, 0x00, sizeof(struct iovec)); + iov.iov_base = buffer; + iov.iov_len = size; + + memset(&aiocbp, 0x00, sizeof(struct aiocb)); + + aiocbp.aio_fildes = fd; + aiocbp.aio_nbytes = size; + aiocbp.aio_buf = buffer; +/* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */ + aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE; + aiocbp.aio_sigevent.sigev_signo = 0; + + aiocbp.aio_sigevent.sigev_notify_function = NULL; + aiocbp.aio_sigevent.sigev_notify_attributes = 0; + + aiolist[0] = &aiocbp; + + if ((ret = lseek(fd, 0, SEEK_CUR)) == -1) { + ret = 0; + /* If there is an error and it is not ESPIPE then kick out the error. + * If the fd is a fifo then we have to make sure that + * lio_random_methods() didn't select pwrite/pread; if it did then + * switch to write/read. + */ + if (errno == ESPIPE) { + if (method & LIO_IO_SYNCP) { + if (omethod & LIO_RANDOM) { + method &= ~LIO_IO_SYNCP; + method |= LIO_IO_SYNC; + if (Debug_level > 2) + printf + ("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", + __FILE__, __LINE__, + method); + } else if (Debug_level) { + printf + ("DEBUG %s/%d: pread will fail when it reads from a fifo\n", + __FILE__, __LINE__); + } + } + /* else: let it ride */ + } else { + sprintf(Errormsg, + "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s", + __FILE__, __LINE__, fd, errno, strerror(errno)); + return -errno; + } + } + poffset = (off64_t) ret; + aiocbp.aio_offset = ret; + + /* + * If the LIO_USE_SIGNAL bit is not set, only use the signal + * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set. + * Otherwise there is not necessarily a signal handler to trap + * the signal. + */ + if (sig && !(method & LIO_USE_SIGNAL) && !(method & LIO_WAIT_SIGTYPES)) { + + sig = 0; /* ignore signal parameter */ + } + + if (sig && (method & LIO_WAIT_CBTYPES)) + sig = 0; /* ignore signal parameter */ + + /* + * only setup signal hander if sig was specified and + * a sig wait method was specified. + * Doing this will change the handler for this signal. The + * old signal handler will not be restored. + *** restoring the signal handler could be added *** + */ + + if (sig && (method & LIO_WAIT_SIGTYPES)) { + aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocbp.aio_sigevent.sigev_signo = sig; + sigset(sig, lio_async_signal_handler); + } else if (method & LIO_WAIT_CBTYPES) { + aiocbp.aio_sigevent.sigev_notify = SIGEV_THREAD; + aiocbp.aio_sigevent.sigev_notify_function = + lio_async_callback_handler; + /* sival_int just has to be something that I can use + * to identify the callback, and "size" happens to be handy... + */ + aiocbp.aio_sigevent.sigev_notify_attributes = + (void *)(uintptr_t) size; + } + + /* + * Determine the system call that will be called and produce + * the string of the system call and place it in Lio_SysCall. + * Also update the io_type char pointer to give brief description + * of system call. Execute the system call and check for + * system call failure. If sync i/o, return the number of + * bytes written/read. + */ + + if ((method & LIO_IO_SYNC) + || (method & (LIO_IO_TYPES | LIO_IO_ATYPES)) == 0) { + /* + * read(2) is used if LIO_IO_SYNC bit is set or not none + * of the LIO_IO_TYPES bits are set (default). + */ + + sprintf(Lio_SysCall, "read(%d, buf, %d)", fd, size); + io_type = "read"; + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + + while (1) { + if (((ret = read(fd, buffer, size)) == -1) + && errno != EINTR && errno != EAGAIN) { + sprintf(Errormsg, + "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s", + __FILE__, __LINE__, fd, size, errno, + strerror(errno)); + return -errno; + } + + if (ret == 0) + return 0; + if (ret != -1) { + if (ret != size) { + sprintf(Errormsg, + "%s/%d read(%d, buf, %d) returned=%d", + __FILE__, __LINE__, + fd, size, ret); + size -= ret; + buffer += ret; + totally_read += ret; + } else { + if (Debug_level > 1) + printf + ("DEBUG %s/%d: read completed without error (ret %d)\n", + __FILE__, __LINE__, ret); + + return totally_read + ret; + } + } + wait4sync_io(fd, 1); + } + + } else if (method & LIO_IO_ASYNC) { + sprintf(Lio_SysCall, + "aio_read(fildes=%d, buf, nbytes=%d, signo=%d)", fd, + size, sig); + io_type = "aio_read"; + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + + if (sig) + sighold(sig); + if ((ret = aio_read(&aiocbp)) == -1) { + sprintf(Errormsg, + "%s/%d aio_read(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s", + __FILE__, __LINE__, + fd, size, sig, errno, strerror(errno)); + if (sig) + sigrelse(sig); + return -errno; + } + } + /* LIO_IO_ASYNC */ + else if (method & LIO_IO_SLISTIO) { + aiocbp.aio_lio_opcode = LIO_READ; + listio_cmd = LIO_WAIT; + io_type = "lio_listio(3) sync read"; + + sprintf(Lio_SysCall, + "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d", + fd, size); + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + + if (sig) + sighold(sig); + if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) { + sprintf(Errormsg, + "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", + __FILE__, __LINE__, Lio_SysCall, fd, size, + errno, strerror(errno)); + if (sig) + sigrelse(sig); + return -errno; + } + + if (Debug_level > 1) + printf("DEBUG %s/%d: %s did not return -1\n", + __FILE__, __LINE__, Lio_SysCall); + + ret = lio_check_asyncio(io_type, size, &aiocbp, method); + return ret; + } + /* LIO_IO_SLISTIO */ + else if (method & LIO_IO_ALISTIO) { + aiocbp.aio_lio_opcode = LIO_READ; + listio_cmd = LIO_NOWAIT; + io_type = "lio_listio(3) async read"; + + sprintf(Lio_SysCall, + "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d", + fd, size); + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + + if (sig) + sighold(sig); + if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) { + sprintf(Errormsg, + "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", + __FILE__, __LINE__, Lio_SysCall, fd, size, + errno, strerror(errno)); + if (sig) + sigrelse(sig); + return -errno; + } + } + /* LIO_IO_ALISTIO */ + else if (method & LIO_IO_SYNCV) { + io_type = "readv(2)"; + + sprintf(Lio_SysCall, "readv(%d, &iov, 1) nbyte:%d", fd, size); + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + if ((ret = readv(fd, &iov, 1)) == -1) { + sprintf(Errormsg, + "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s", + __FILE__, __LINE__, fd, size, errno, + strerror(errno)); + return -errno; + } + + if (ret != size) { + sprintf(Errormsg, + "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d", + __FILE__, __LINE__, fd, size, ret); + } else if (Debug_level > 1) + printf + ("DEBUG %s/%d: readv completed without error (ret %d)\n", + __FILE__, __LINE__, ret); + + return ret; + } /* LIO_IO_SYNCV */ + else if (method & LIO_IO_SYNCP) { + io_type = "pread(2)"; + + sprintf(Lio_SysCall, + "pread(%d, buf, %d, %lld)", fd, size, + (long long)poffset); + + if (Debug_level) { + printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, + Lio_SysCall); + } + if ((ret = pread(fd, buffer, size, poffset)) == -1) { + sprintf(Errormsg, + "%s/%d pread(%d, buf, %d, %lld) ret:-1, errno=%d %s", + __FILE__, __LINE__, fd, size, + (long long)poffset, errno, strerror(errno)); + return -errno; + } + + if (ret != size) { + sprintf(Errormsg, + "%s/%d pread(%d, buf, %d, %lld) returned=%d", + __FILE__, __LINE__, + fd, size, (long long)poffset, ret); + } else if (Debug_level > 1) + printf + ("DEBUG %s/%d: pread completed without error (ret %d)\n", + __FILE__, __LINE__, ret); + + return ret; + } /* LIO_IO_SYNCP */ + + else { + printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, + __LINE__); + return -1; + } + + /* + * wait for async io to complete. + * Note: Sync io should have returned prior to getting here. + */ + ret = lio_wait4asyncio(method, fd, &aiocbp); + + /* + * If there was an error waiting for async i/o to complete, + * return the error value (errno) to the caller. + * Note: Errormsg should already have been updated. + */ + if (ret < 0) { + return ret; + } + + /* + * If i/o was not waited for (may not have been completed at this time), + * return the size that was requested. + */ + if (ret == 1) + return size; + + /* + * check that async io was successful. + * Note: if the there was an system call failure, -errno + * was returned and Errormsg should already have been updated. + * If amount i/o was different than size, Errormsg should already + * have been updated but the actual i/o size if returned. + */ + + ret = lio_check_asyncio(io_type, size, &aiocbp, method); + + return ret; +} /* end of lio_read_buffer */ + +#if !defined(__sun) && !defined(__hpux) && !defined(_AIX) +/*********************************************************************** + * This function will check that async io was successful. + * It can also be used to check sync listio since it uses the + * same method. + * + * Return Values + * If status.sw_error is set, -status.sw_error is returned. + * Otherwise sw_count's field value is returned. + * + * (rrl 04/96) + ***********************************************************************/ +int lio_check_asyncio(char *io_type, int size, struct aiocb *aiocbp, int method) +{ + int ret; + int cnt = 1; + + /* The I/O may have been synchronous with signal completion. It doesn't + * make sense, but the combination could be generated. Release the + * completion signal here otherwise it'll hang around and bite us + * later. + */ + if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) + sigrelse(aiocbp->aio_sigevent.sigev_signo); + + ret = aio_error(aiocbp); + + while (ret == EINPROGRESS) { + ret = aio_error(aiocbp); + ++cnt; + } + if (cnt > 1) { + sprintf(Errormsg, + "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s", + __FILE__, __LINE__, io_type, cnt, method, + (aiocbp->aio_sigevent.sigev_notify == + SIGEV_SIGNAL ? "signal" : aiocbp->aio_sigevent. + sigev_notify == SIGEV_NONE ? "none" : + aiocbp->aio_sigevent.sigev_notify == + SIGEV_THREAD ? "thread" : "unknown")); + return -ret; + } + + if (ret != 0) { + sprintf(Errormsg, + "%s/%d %s, aio_error = %d %s; random method %#o", + __FILE__, __LINE__, io_type, + ret, strerror(ret), method); + return -ret; + } + ret = aio_return(aiocbp); + if (ret != size) { + sprintf(Errormsg, + "%s/%d %s, aio_return not as expected(%d), but actual:%d", + __FILE__, __LINE__, io_type, size, ret); + } else if (Debug_level > 1) { + printf + ("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n", + __FILE__, __LINE__, io_type, ret); + } + + return ret; + +} /* end of lio_check_asyncio */ + +/*********************************************************************** + * + * This function will wait for async io to complete. + * If multiple wait methods are specified, the order is predetermined + * to LIO_WAIT_RECALL, + * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE, + * then LIO_WAIT_NONE. + * + * If no wait method was specified the default wait method is: recall(2) + * or aio_suspend(3), as appropriate. + * + * Return Values + * <0: errno of failed recall + * 0 : async io was completed + * 1 : async was not waited for, io may not have completed. + * + * (rrl 04/96) + ***********************************************************************/ +int lio_wait4asyncio(int method, int fd, struct aiocb *aiocbp) +{ + int cnt; + int ret; + const struct aiocb *aioary[1]; + + if ((method & LIO_WAIT_RECALL) + || (method & LIO_WAIT_CBSUSPEND) + || (method & LIO_WAIT_SIGSUSPEND) + || ((method & LIO_WAIT_TYPES) == 0)) { + /* + * If method has LIO_WAIT_RECALL bit set or method does + * not have any wait method bits set (default), use recall/aio_suspend. + */ + if (Debug_level > 2) + printf + ("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", + __FILE__, __LINE__, + (aiocbp->aio_sigevent.sigev_notify == + SIGEV_SIGNAL ? "signal" : aiocbp->aio_sigevent. + sigev_notify == SIGEV_NONE ? "none" : + aiocbp->aio_sigevent.sigev_notify == + SIGEV_THREAD ? "thread" : "unknown")); + + aioary[0] = aiocbp; + ret = aio_suspend(aioary, 1, NULL); + if ((ret == -1) && (errno == EINTR)) { + if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) { + if (Debug_level > 2) { + printf + ("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n", + __FILE__, __LINE__); + } + } else { + sprintf(Errormsg, + "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n", + __FILE__, __LINE__, + (aiocbp->aio_sigevent.sigev_notify == + SIGEV_SIGNAL ? "signal" : aiocbp-> + aio_sigevent.sigev_notify == + SIGEV_NONE ? "none" : + aiocbp->aio_sigevent.sigev_notify == + SIGEV_THREAD ? "thread" : "unknown")); + return -errno; + } + } else if (ret) { + sprintf(Errormsg, + "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s", + __FILE__, __LINE__, fd, errno, strerror(errno)); + return -errno; + } + } else if (method & LIO_WAIT_ACTIVE) { + if (Debug_level > 2) + printf("DEBUG %s/%d: wait method : active\n", __FILE__, + __LINE__); + /* loop while aio_error() returns EINPROGRESS */ + cnt = 0; + while (1) { + ret = aio_error(aiocbp); + if (ret != EINPROGRESS) { + break; + } + ++cnt; + } + + if (Debug_level > 5 && cnt && (cnt % 50) == 0) + printf("DEBUG %s/%d: wait active cnt = %d\n", + __FILE__, __LINE__, cnt); + + } else if (method & LIO_WAIT_SIGPAUSE) { + if (Debug_level > 2) + printf("DEBUG %s/%d: wait method : sigpause\n", + __FILE__, __LINE__); + pause(); + + } else if (method & LIO_WAIT_SIGACTIVE) { + if (Debug_level > 2) + printf("DEBUG %s/%d: wait method : sigactive\n", + __FILE__, __LINE__); + if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) + sigrelse(aiocbp->aio_sigevent.sigev_signo); + else { + printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", + __FILE__, __LINE__); + return -1; + } + /* loop waiting for signal */ + while (Received_signal == Rec_signal) { + sigrelse(aiocbp->aio_sigevent.sigev_signo); + } + + } else if (method & LIO_WAIT_NONE) { + if (Debug_level > 2) + printf("DEBUG %s/%d: wait method : none\n", __FILE__, + __LINE__); + /* It's broken because the aiocb/iosw is an automatic variable in + * lio_{read,write}_buffer, so when the function returns and the + * I/O completes there will be nowhere to write the I/O status. + * It doesn't cause a problem on unicos--probably because of some + * compiler quirk, or an accident. It causes POSIX async I/O + * to core dump some threads. spr/pv 705909. 6/27/97 roehrich + */ + sprintf(Errormsg, + "%s/%d LIO_WAIT_NONE was selected (this is broken)\n", + __FILE__, __LINE__); + return -1; + } else { + if (Debug_level > 2) + printf("DEBUG %s/%d: no wait method was chosen\n", + __FILE__, __LINE__); + return -1; + } + + return 0; + +} /* end of lio_wait4asyncio */ + +#endif + +#if UNIT_TEST +/*********************************************************************** + * The following code is provided as unit test. + * Just define add "-DUNIT_TEST=1" to the cc line. + * + * (rrl 04/96) + ***********************************************************************/ +struct unit_info_t { + int method; + int sig; + char *str; +} Unit_info[] = { + { + LIO_IO_SYNC, 0, "sync io"}, { + LIO_IO_SYNCV, 0, "sync readv/writev"}, { + LIO_IO_SYNCP, 0, "sync pread/pwrite"}, { + LIO_IO_ASYNC, 0, "async io, def wait"}, { + LIO_IO_SLISTIO, 0, "sync listio"}, { + LIO_IO_ALISTIO, 0, "async listio, def wait"}, { + LIO_IO_ASYNC | LIO_WAIT_ACTIVE, 0, "async active"}, { + LIO_IO_ASYNC | LIO_WAIT_RECALL, 0, "async recall/suspend"}, { + LIO_IO_ASYNC | LIO_WAIT_SIGPAUSE, SIGUSR1, "async sigpause"}, { + LIO_IO_ASYNC | LIO_WAIT_SIGACTIVE, SIGUSR1, "async sigactive"}, { + LIO_IO_ALISTIO | LIO_WAIT_ACTIVE, 0, "async listio active"}, { + LIO_IO_ALISTIO | LIO_WAIT_RECALL, 0, "async listio recall"}, { + LIO_IO_ALISTIO | LIO_WAIT_SIGACTIVE, SIGUSR1, "async listio sigactive"}, + { + LIO_IO_ALISTIO | LIO_WAIT_SIGPAUSE, SIGUSR1, "async listio sigpause"}, + { + LIO_IO_ASYNC, SIGUSR2, "async io, def wait, sigusr2"}, { +LIO_IO_ALISTIO, SIGUSR2, "async listio, def wait, sigusr2"},}; + +int main(argc, argv) +int argc; +char **argv; +{ + extern char *optarg; + extern int optind; + + int fd; + char *err; + char buffer[4096]; + int size = 4096; + int ret; + int ind; + int iter = 3; + int method; + int exit_status = 0; + int c; + int i; + char *symbols = NULL; + int die_on_err = 0; + + while ((c = getopt(argc, argv, "s:di:")) != -1) { + switch (c) { + case 's': + symbols = optarg; + break; + case 'd': + ++die_on_err; + break; + case 'i': + iter = atoi(optarg); + break; + } + } + + if ((fd = + open("unit_test_file", O_CREAT | O_RDWR | O_TRUNC, 0777)) == -1) { + perror + ("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed"); + exit(1); + } + + Debug_level = 9; + + if (symbols != NULL) { + if ((method = lio_parse_io_arg2(symbols, &err)) == -1) { + printf + ("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n", + symbols, err); + if (die_on_err) + exit(1); + } else + printf("lio_parse_io_arg2(%s, &err) returned %#o\n", + symbols, method); + + exit_status = 0; + for (ind = 0; ind < iter; ind++) { + memset(buffer, 'A', 4096); + if (lseek(fd, 0, 0) == -1) { + printf("lseek(fd,0,0), %d, failed, errno %d\n", + __LINE__, errno); + ++exit_status; + } + if ((ret = lio_write_buffer(fd, method, buffer, + size, SIGUSR1, &err, + 0)) != size) { + printf + ("lio_write_buffer returned -1, err = %s\n", + err); + } else + printf("lio_write_buffer returned %d\n", ret); + + memset(buffer, 'B', 4096); + if (lseek(fd, 0, 0) == -1) { + printf("lseek(fd,0,0), %d, failed, errno %d\n", + __LINE__, errno); + ++exit_status; + } + if ((ret = lio_read_buffer(fd, method, buffer, + size, SIGUSR2, &err, + 0)) != size) { + printf + ("lio_read_buffer returned -1, err = %s\n", + err); + } else + printf("lio_read_buffer returned %d\n", ret); + + for (i = 0; i < 4096; ++i) { + if (buffer[i] != 'A') { + printf(" buffer[%d] = %d\n", i, + buffer[i]); + ++exit_status; + break; + } + } + + if (exit_status) + exit(exit_status); + + } + + unlink("unit_test_file"); + exit(0); + } + + for (ind = 0; ind < sizeof(Unit_info) / sizeof(struct unit_info_t); + ind++) { + + printf("\n********* write %s ***************\n", + Unit_info[ind].str); + if (lseek(fd, 0, 0) == -1) { + printf("lseek(fd,0,0), %d, failed, errno %d\n", + __LINE__, errno); + ++exit_status; + } + + memset(buffer, 'A', 4096); + if ((ret = lio_write_buffer(fd, Unit_info[ind].method, buffer, + size, Unit_info[ind].sig, &err, + 0)) != size) { + printf + (">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n", + Unit_info[ind].method, size, Unit_info[ind].sig, + err); + ++exit_status; + if (die_on_err) + exit(exit_status); + } else { + printf("lio_write_buffer returned %d\n", ret); + } + + printf("\n********* read %s ***************\n", + Unit_info[ind].str); + if (lseek(fd, 0, 0) == -1) { + printf("lseek(fd,0,0), %d, failed, errno %d\n", + __LINE__, errno); + ++exit_status; + } + memset(buffer, 'B', 4096); + if ((ret = lio_read_buffer(fd, Unit_info[ind].method, buffer, + size, Unit_info[ind].sig, &err, + 0)) != size) { + printf + (">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n", + Unit_info[ind].method, size, Unit_info[ind].sig, + err); + ++exit_status; + if (die_on_err) + exit(exit_status); + } else { + printf("lio_read_buffer returned %d\n", ret); + } + + for (i = 0; i < 4096; ++i) { + if (buffer[i] != 'A') { + printf(" buffer[%d] = %d\n", i, buffer[i]); + ++exit_status; + if (die_on_err) + exit(exit_status); + break; + } + } + + fflush(stdout); + fflush(stderr); + sleep(1); + + } + + unlink("unit_test_file"); + + exit(exit_status); +} +#endif diff --git a/ltp/lib/tst_af_alg.c b/ltp/lib/tst_af_alg.c new file mode 100644 index 0000000000000000000000000000000000000000..a14f9865c9a4efef70e82485448c8dfccdec37ed --- /dev/null +++ b/ltp/lib/tst_af_alg.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2019 Google LLC + * Copyright (c) Linux Test Project, 2019-2021 + */ + +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_af_alg.h" +#include "lapi/socket.h" + +int tst_alg_create(void) +{ + 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 | TERRNO, "unexpected error creating AF_ALG socket"); + return -1; +} + +void tst_alg_bind_addr(int algfd, const struct sockaddr_alg *addr) +{ + const long ret = bind(algfd, (const struct sockaddr *)addr, + sizeof(*addr)); + + if (ret == 0) + return; + + 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 | TERRNO, + "unexpected error binding AF_ALG socket to %s algorithm '%s'", + addr->salg_type, addr->salg_name); +} + +static void init_sockaddr_alg(struct sockaddr_alg *addr, + const char *algtype, const char *algname) +{ + memset(addr, 0, sizeof(*addr)); + + addr->salg_family = AF_ALG; + + strncpy((char *)addr->salg_type, algtype, sizeof(addr->salg_type)); + if (addr->salg_type[sizeof(addr->salg_type) - 1] != '\0') + tst_brk(TBROK, "algorithm type too long: '%s'", algtype); + + strncpy((char *)addr->salg_name, algname, sizeof(addr->salg_name)); + if (addr->salg_name[sizeof(addr->salg_name) - 1] != '\0') + tst_brk(TBROK, "algorithm name too long: '%s'", algname); +} + +void tst_alg_bind(int algfd, const char *algtype, const char *algname) +{ + struct sockaddr_alg addr; + + init_sockaddr_alg(&addr, algtype, algname); + + tst_alg_bind_addr(algfd, &addr); +} + +int tst_try_alg(const char *algtype, const char *algname) +{ + long ret; + int retval = 0; + int algfd; + struct sockaddr_alg addr; + + algfd = tst_alg_create(); + + init_sockaddr_alg(&addr, algtype, algname); + + 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: + case EINVAL: + 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; + } + /* fallthrough */ + default: + errno = ret; + tst_brk(TBROK | TERRNO, + "unexpected error binding AF_ALG socket to %s algorithm '%s'", + algtype, algname); + return false; + } +} + +void tst_require_alg(const char *algtype, const char *algname) +{ + int algfd = tst_alg_create(); + + tst_alg_bind(algfd, algtype, algname); + + close(algfd); +} + +void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen) +{ + long ret; + uint8_t *keybuf = NULL; + unsigned int i; + + if (key == NULL) { + /* generate a random key */ + keybuf = SAFE_MALLOC(keylen); + for (i = 0; i < keylen; i++) + keybuf[i] = rand(); + key = keybuf; + } + 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); +} + +int tst_alg_accept(int algfd) +{ + const long ret = accept(algfd, NULL, NULL); + + if (ret < 0) { + tst_brk(TBROK | TERRNO, + "unexpected error accept()ing AF_ALG request socket"); + } + return ret; +} + +int tst_alg_setup(const char *algtype, const char *algname, + const uint8_t *key, unsigned int keylen) +{ + int algfd = tst_alg_create(); + + tst_alg_bind(algfd, algtype, algname); + + if (keylen != 0) + tst_alg_setkey(algfd, key, keylen); + + return algfd; +} + +int tst_alg_setup_reqfd(const char *algtype, const char *algname, + const uint8_t *key, unsigned int keylen) +{ + int algfd = tst_alg_setup(algtype, algname, key, keylen); + int reqfd = tst_alg_accept(algfd); + + 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/ltp/lib/tst_ansi_color.c b/ltp/lib/tst_ansi_color.c new file mode 100644 index 0000000000000000000000000000000000000000..98041c0afa572dc34d2ef3e4af641ba0a34d1cbc --- /dev/null +++ b/ltp/lib/tst_ansi_color.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Petr Vorel + */ + +#include +#include +#include + +#include "tst_res_flags.h" +#include "tst_ansi_color.h" + +char* tst_ttype2color(int ttype) +{ + switch (TTYPE_RESULT(ttype)) { + case TPASS: + return ANSI_COLOR_GREEN; + break; + case TFAIL: + return ANSI_COLOR_RED; + break; + case TBROK: + return ANSI_COLOR_RED; + break; + case TCONF: + return ANSI_COLOR_YELLOW; + break; + case TWARN: + return ANSI_COLOR_MAGENTA; + break; + case TINFO: + return ANSI_COLOR_BLUE; + break; + case TDEBUG: + return ANSI_COLOR_WHITE; + break; + default: + return ""; + } +} + +int tst_color_enabled(int fd) +{ + static int color; + + if (color) + return color - 1; + + char *env = getenv("LTP_COLORIZE_OUTPUT"); + + if (env) { + if (!strcmp(env, "n") || !strcmp(env, "0")) + color = 1; + + if (!strcmp(env, "y") || !strcmp(env, "1")) + color = 2; + + return color - 1; + } + + if (isatty(fd) == 0) + color = 1; + else + color = 2; + + return color - 1; +} diff --git a/ltp/lib/tst_arch.c b/ltp/lib/tst_arch.c new file mode 100644 index 0000000000000000000000000000000000000000..acae1c3faccb2bbc973097122b18d632b751fb42 --- /dev/null +++ b/ltp/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/ltp/lib/tst_assert.c b/ltp/lib/tst_assert.c new file mode 100644 index 0000000000000000000000000000000000000000..b68bd5d397dee4f5968e22dd8d42d129ebdfa7ff --- /dev/null +++ b/ltp/lib/tst_assert.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + * Copyright (c) 2020 Cyril Hrubis + */ +#include +#define TST_NO_DEFAULT_MAIN +#include "tst_assert.h" +#include "tst_test.h" + +void tst_assert_int(const char *file, const int lineno, const char *path, int val) +{ + int sys_val; + + safe_file_scanf(file, lineno, NULL, path, "%d", &sys_val); + + if (val == sys_val) { + tst_res_(file, lineno, TPASS, "%s = %d", path, val); + return; + } + + 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; + char fmt[1024]; + + snprintf(fmt, sizeof(fmt), "%s%%d", prefix); + file_lines_scanf(file, lineno, NULL, 1, path, fmt, &sys_val); + + if (val == sys_val) { + tst_res_(file, lineno, TPASS, "%s %s = %d", path, prefix, sys_val); + return; + } + + tst_res_(file, lineno, TFAIL, "%s %s != %d got %d", path, prefix, val, sys_val); +} + +void tst_assert_str(const char *file, const int lineno, const char *path, const char *val) +{ + char sys_val[1024]; + + safe_file_scanf(file, lineno, NULL, path, "%1023s", sys_val); + if (!strcmp(val, sys_val)) { + tst_res_(file, lineno, TPASS, "%s = '%s'", path, val); + return; + } + + tst_res_(file, lineno, TFAIL, "%s != '%s' got '%s'", path, val, sys_val); +} + +void tst_assert_file_str(const char *file, const int lineno, const char *path, const char *prefix, const char *val) +{ + char sys_val[1024]; + char fmt[2048]; + + snprintf(fmt, sizeof(fmt), "%s: %%1023s", prefix); + file_lines_scanf(file, lineno, NULL, 1, path, fmt, sys_val); + + if (!strcmp(val, sys_val)) { + tst_res_(file, lineno, TPASS, "%s %s = '%s'", path, prefix, sys_val); + return; + } + + tst_res_(file, lineno, TFAIL, "%s %s != '%s' got '%s'", path, prefix, val, sys_val); +} diff --git a/ltp/lib/tst_bool_expr.c b/ltp/lib/tst_bool_expr.c new file mode 100644 index 0000000000000000000000000000000000000000..d7983e7b0091bdfbc6cbcb9fc82679ed7ea78419 --- /dev/null +++ b/ltp/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 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/ltp/lib/tst_buffers.c b/ltp/lib/tst_buffers.c new file mode 100644 index 0000000000000000000000000000000000000000..ac76a784bb7060ad46815310b56b2a4229bfd395 --- /dev/null +++ b/ltp/lib/tst_buffers.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Cyril Hrubis + */ + +#include +#include +#include +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +struct map { + void *addr; + size_t size; + size_t buf_shift; + struct map *next; +}; + +static struct map *maps; + +static void setup_canary(struct map *map) +{ + size_t i; + char *buf = map->addr; + + for (i = 0; i < map->buf_shift/2; i++) { + char c = random(); + + buf[map->buf_shift - i - 1] = c; + buf[i] = c; + } +} + +static void check_canary(struct map *map) +{ + size_t i; + char *buf = map->addr; + + for (i = 0; i < map->buf_shift/2; i++) { + if (buf[map->buf_shift - i - 1] != buf[i]) { + tst_res(TWARN, + "pid %i: buffer modified address %p[%zi]", + getpid(), (char *)map->addr + map->buf_shift, -i-1); + } + } +} + +void *tst_alloc(size_t size) +{ + size_t page_size = getpagesize(); + unsigned int pages = (size / page_size) + !!(size % page_size) + 1; + void *ret; + struct map *map = SAFE_MALLOC(sizeof(struct map)); + static int print_msg = 1; + + if (print_msg) { + tst_res(TINFO, "Test is using guarded buffers"); + print_msg = 0; + } + + ret = SAFE_MMAP(NULL, page_size * pages, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + + mprotect(ret + (pages-1) * page_size, page_size, PROT_NONE); + + map->addr = ret; + map->size = pages * page_size; + map->next = maps; + maps = map; + + if (size % page_size) + map->buf_shift = page_size - (size % page_size); + else + map->buf_shift = 0; + + setup_canary(map); + + return ret + map->buf_shift; +} + +char *tst_aprintf(const char *fmt, ...) +{ + va_list va; + int len; + char *ret; + + va_start(va, fmt); + len = vsnprintf(NULL, 0, fmt, va)+1; + va_end(va); + + ret = tst_alloc(len); + + va_start(va, fmt); + vsprintf(ret, fmt, va); + va_end(va); + + return ret; +} + +static int count_iovec(int *sizes) +{ + int ret = 0; + + while (sizes[ret++] != -1) + ; + + return ret - 1; +} + +struct iovec *tst_iovec_alloc(int sizes[]) +{ + int i, cnt = count_iovec(sizes); + struct iovec *iovec; + + if (cnt <= 0) + return NULL; + + iovec = tst_alloc(sizeof(struct iovec) * cnt); + + for (i = 0; i < cnt; i++) { + if (sizes[i]) { + iovec[i].iov_base = tst_alloc(sizes[i]); + iovec[i].iov_len = sizes[i]; + } else { + iovec[i].iov_base = NULL; + iovec[i].iov_base = 0; + } + } + + return iovec; +} + +void tst_buffers_alloc(struct tst_buffers bufs[]) +{ + unsigned int i; + + for (i = 0; bufs[i].ptr; i++) { + if (bufs[i].size) + *((void **)bufs[i].ptr) = tst_alloc(bufs[i].size); + else if (bufs[i].iov_sizes) + *((void **)bufs[i].ptr) = tst_iovec_alloc(bufs[i].iov_sizes); + else + *((void **)bufs[i].ptr) = tst_strdup(bufs[i].str); + } +} + +char *tst_strdup(const char *str) +{ + char *ret = tst_alloc(strlen(str) + 1); + + return strcpy(ret, str); +} + +void tst_free_all(void) +{ + struct map *i = maps; + + while (i) { + struct map *j = i; + + check_canary(i); + SAFE_MUNMAP(i->addr, i->size); + i = i->next; + free(j); + } + + maps = NULL; +} diff --git a/ltp/lib/tst_capability.c b/ltp/lib/tst_capability.c new file mode 100644 index 0000000000000000000000000000000000000000..cb0502e2ec4dcb7cfb9a643c0af0aeaaab9a9031 --- /dev/null +++ b/ltp/lib/tst_capability.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Richard Palethorpe + */ + +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_capability.h" + +#include "lapi/syscalls.h" + +int tst_capget(struct tst_cap_user_header *hdr, + struct tst_cap_user_data *data) +{ + return tst_syscall(__NR_capget, hdr, data); +} + +int tst_capset(struct tst_cap_user_header *hdr, + const struct tst_cap_user_data *data) +{ + return tst_syscall(__NR_capset, hdr, data); +} + +static void do_cap_drop(uint32_t *set, uint32_t mask, const struct tst_cap *cap) +{ + if (*set & mask) { + tst_res(TINFO, "Dropping %s(%d)", cap->name, cap->id); + *set &= ~mask; + } +} + +static void do_cap_req(uint32_t *permitted, uint32_t *effective, uint32_t mask, + const struct tst_cap *cap) +{ + if (!(*permitted & mask)) + tst_brk(TCONF, "Need %s(%d)", cap->name, cap->id); + + if (!(*effective & mask)) { + tst_res(TINFO, "Permitting %s(%d)", cap->name, cap->id); + *effective |= mask; + } +} + +void tst_cap_action(struct tst_cap *cap) +{ + struct tst_cap_user_header hdr = { + .version = 0x20080522, + .pid = tst_syscall(__NR_gettid), + }; + struct tst_cap_user_data cur[2] = { {0} }; + struct tst_cap_user_data new[2] = { {0} }; + uint32_t act = cap->action; + uint32_t *pE = &new[CAP_TO_INDEX(cap->id)].effective; + uint32_t *pP = &new[CAP_TO_INDEX(cap->id)].permitted; + uint32_t mask = CAP_TO_MASK(cap->id); + + if (tst_capget(&hdr, cur)) + tst_brk(TBROK | TERRNO, "tst_capget()"); + + memcpy(new, cur, sizeof(new)); + + switch (act) { + case TST_CAP_DROP: + do_cap_drop(pE, mask, cap); + break; + case TST_CAP_REQ: + do_cap_req(pP, pE, mask, cap); + break; + default: + tst_brk(TBROK, "Unrecognised action %d", cap->action); + } + + if (!memcmp(cur, new, sizeof(new))) + return; + + if (tst_capset(&hdr, new)) + tst_brk(TBROK | TERRNO, "tst_capset(%s)", cap->name); +} + +void tst_cap_setup(struct tst_cap *caps, unsigned int action_mask) +{ + struct tst_cap *cap; + + for (cap = caps; cap->action; cap++) { + if (cap->action & action_mask) + tst_cap_action(cap); + } +} diff --git a/ltp/lib/tst_cgroup.c b/ltp/lib/tst_cgroup.c new file mode 100644 index 0000000000000000000000000000000000000000..36602402d4ac0f683e78cc373623f072507824ed --- /dev/null +++ b/ltp/lib/tst_cgroup.c @@ -0,0 +1,1533 @@ +// 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 "tst_test.h" +#include "lapi/fcntl.h" +#include "lapi/mount.h" +#include "tst_safe_file_at.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; + + unsigned int we_created_it:1; +}; + +/* The root of a CGroup hierarchy/tree */ +struct cgroup_root { + enum tst_cg_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; + + unsigned int nsdelegate:1; + + unsigned int we_mounted_it:1; + /* cpuset is in compatability mode */ + unsigned int no_cpuset_prefix:1; + unsigned int memory_recursiveprot:1; +}; + +/* Controller sub-systems */ +enum cgroup_ctrl_indx { + CTRL_MEMORY = 1, + CTRL_CPU, + CTRL_CPUSET, + CTRL_DMEM, + CTRL_IO, + CTRL_PIDS, + CTRL_HUGETLB, + CTRL_CPUACCT, + CTRL_DEVICES, + CTRL_FREEZER, + CTRL_NETCLS, + CTRL_NETPRIO, + CTRL_BLKIO, + CTRL_MISC, + CTRL_PERFEVENT, + CTRL_DEBUG, + CTRL_RDMA, + CTRL_BASE +}; +#define CTRLS_MAX CTRL_BASE + +/* 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 */ + unsigned int we_require_it:1; +}; + +struct tst_cg_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]; +}; + +/* If controllers are required via the tst_test struct then this is + * populated with the test's CGroup. + */ +static struct tst_cg_group test_group; +static struct tst_cg_group drain_group; +const struct tst_cg_group *const tst_cg = &test_group; +const struct tst_cg_group *const tst_cg_drain = &drain_group; + +/* 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 }, + { "cgroup.kill", NULL, 0 }, + { } +}; + +static const struct cgroup_file memory_ctrl_files[] = { + { "memory.current", "memory.usage_in_bytes", CTRL_MEMORY }, + { "memory.events", NULL, CTRL_MEMORY }, + { "memory.low", NULL, CTRL_MEMORY }, + { "memory.min", NULL, 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 }, + { } +}; + +static const struct cgroup_file dmem_ctrl_files[] = { + { "dmem.capacity", NULL, CTRL_DMEM }, + { "dmem.current", NULL, CTRL_DMEM }, + { "dmem.min", NULL, CTRL_DMEM }, + { "dmem.low", NULL, CTRL_DMEM }, + { "dmem.max", NULL, CTRL_DMEM }, + { } +}; + +static const struct cgroup_file io_ctrl_files[] = { + { "io.stat", NULL, CTRL_IO }, + { } +}; + +static const struct cgroup_file pids_ctrl_files[] = { + { "pids.max", "pids.max", CTRL_PIDS }, + { "pids.current", "pids.current", CTRL_PIDS }, + { } +}; + +static const struct cgroup_file hugetlb_ctrl_files[] = { + { } +}; + +static const struct cgroup_file cpuacct_ctrl_files[] = { + { } +}; + +static const struct cgroup_file devices_ctrl_files[] = { + { } +}; + +static const struct cgroup_file freezer_ctrl_files[] = { + { } +}; + +static const struct cgroup_file net_cls_ctrl_files[] = { + { } +}; + +static const struct cgroup_file net_prio_ctrl_files[] = { + { } +}; + +static const struct cgroup_file blkio_ctrl_files[] = { + { } +}; + +static const struct cgroup_file misc_ctrl_files[] = { + { } +}; + +static const struct cgroup_file perf_event_ctrl_files[] = { + { } +}; + +static const struct cgroup_file debug_ctrl_files[] = { + { } +}; + +static const struct cgroup_file rdma_ctrl_files[] = { + { } +}; + +static const struct cgroup_file base_ctrl_files[] = { + { } +}; + +#define CTRL_NAME_MAX 31 +#define CGROUP_CTRL_MEMBER(x, y)[y] = { .ctrl_name = #x, .files = \ + x ## _ctrl_files, .ctrl_indx = y, NULL, 0 } + +/* Lookup tree for item names. */ +static struct cgroup_ctrl controllers[] = { + CGROUP_CTRL_MEMBER(cgroup, 0), + CGROUP_CTRL_MEMBER(memory, CTRL_MEMORY), + CGROUP_CTRL_MEMBER(cpu, CTRL_CPU), + CGROUP_CTRL_MEMBER(cpuset, CTRL_CPUSET), + CGROUP_CTRL_MEMBER(dmem, CTRL_DMEM), + CGROUP_CTRL_MEMBER(io, CTRL_IO), + CGROUP_CTRL_MEMBER(pids, CTRL_PIDS), + CGROUP_CTRL_MEMBER(hugetlb, CTRL_HUGETLB), + CGROUP_CTRL_MEMBER(cpuacct, CTRL_CPUACCT), + CGROUP_CTRL_MEMBER(devices, CTRL_DEVICES), + CGROUP_CTRL_MEMBER(freezer, CTRL_FREEZER), + CGROUP_CTRL_MEMBER(net_cls, CTRL_NETCLS), + CGROUP_CTRL_MEMBER(net_prio, CTRL_NETPRIO), + CGROUP_CTRL_MEMBER(blkio, CTRL_BLKIO), + CGROUP_CTRL_MEMBER(misc, CTRL_MISC), + CGROUP_CTRL_MEMBER(perf_event, CTRL_PERFEVENT), + CGROUP_CTRL_MEMBER(debug, CTRL_DEBUG), + CGROUP_CTRL_MEMBER(rdma, CTRL_RDMA), + CGROUP_CTRL_MEMBER(base, CTRL_BASE), + { } +}; + +/* 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 = "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; (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_v2_nsdelegate(void) +{ + return !!roots[0].nsdelegate; +} + +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_CG_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; + mode_t old_umask = umask(0); + + 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 if (errno == EROFS) { + tst_brk(TCONF | TERRNO, "'%s/%s' must not be read-only", + 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); + umask(old_umask); +} + +#define PATH_MAX_STRLEN 4095 +#define CONFIG_HEADER "ctrl_name ver we_require_it mnt_path we_mounted_it ltp_dir.we_created_it test_dir.dir_name" +#define CONFIG_FORMAT "%" TST_TO_STR(CTRL_NAME_MAX) "s\t%d\t%d\t%" TST_TO_STR(PATH_MAX_STRLEN) "s\t%d\t%d\t%" TST_TO_STR(NAME_MAX) "s" +/* Prints out the state associated with each controller to be consumed by + * tst_cg_load_config. + * + * The config keeps track of the minimal state needed for tst_cg_cleanup + * to cleanup mounts and directories made by tst_cg_require. + */ +void tst_cg_print_config(void) +{ + const struct cgroup_ctrl *ctrl; + + printf("%s\n", CONFIG_HEADER); + + for_each_ctrl(ctrl) { + struct cgroup_root *root = ctrl->ctrl_root; + + if (!root) + continue; + + printf("%s\t%d\t%d\t%s\t%d\t%d\t%s\n", + ctrl->ctrl_name, + root->ver, + ctrl->we_require_it, + root->mnt_path, + root->we_mounted_it, + root->ltp_dir.we_created_it, + root->test_dir.dir_name ? root->test_dir.dir_name : "NULL"); + } +} + +__attribute__ ((nonnull, warn_unused_result)) +static struct cgroup_ctrl *cgroup_find_ctrl(const char *const ctrl_name, + unsigned int strict) +{ + struct cgroup_ctrl *ctrl; + int l = 0; + char c = ctrl_name[l]; + + while (c == '_' || (c >= 'a' && c <= 'z')) + c = ctrl_name[++l]; + + if (l > 32 && strict) + tst_res(TWARN, "Subsys name len greater than max known value of MAX_CGROUP_TYPE_NAMELEN: %d > 32", l); + + if (!(c == '\n' || c == '\0')) { + if (!strict) + return NULL; + + tst_brk(TBROK, "Unexpected char in %s: %c", ctrl_name, c); + } + + for_each_ctrl(ctrl) { + if (!strncmp(ctrl_name, ctrl->ctrl_name, l)) + return ctrl; + } + + return NULL; +} + +static struct cgroup_root *cgroup_find_root(const char *const mnt_path) +{ + struct cgroup_root *root; + + for_each_root(root) { + if (!strcmp(root->mnt_path, mnt_path)) + return root; + } + + return NULL; +} + +static void cgroup_parse_config_line(const char *const config_entry) +{ + char ctrl_name[CTRL_NAME_MAX + 1], mnt_path[PATH_MAX_STRLEN + 1], test_dir_name[NAME_MAX + 1]; + int ver, we_require_it, we_mounted_it, ltp_dir_we_created_it, vars_read; + struct cgroup_root *root; + struct cgroup_ctrl *ctrl; + + vars_read = sscanf(config_entry, CONFIG_FORMAT, + ctrl_name, &ver, &we_require_it, mnt_path, &we_mounted_it, + <p_dir_we_created_it, test_dir_name); + + if (vars_read != 7) + tst_brk(TBROK, "Incorrect number of vars read from config. Config possibly malformed?"); + + ctrl = cgroup_find_ctrl(ctrl_name, 1); + if (!ctrl) + tst_brk(TBROK, "Could not find ctrl from config. Ctrls changing between calls?"); + + ctrl->we_require_it = we_require_it; + + root = cgroup_find_root(mnt_path); + if (!root) + tst_brk(TBROK, "Could not find root from config. Config possibly malformed?"); + + if (we_mounted_it) + root->we_mounted_it = 1; + + if (!root->ltp_dir.dir_name) { + cgroup_dir_mk(&root->mnt_dir, cgroup_ltp_dir, &root->ltp_dir); + cgroup_dir_mk(&root->ltp_dir, cgroup_ltp_drain_dir, &root->drain_dir); + if (ltp_dir_we_created_it) { + root->ltp_dir.we_created_it = 1; + root->drain_dir.we_created_it = 1; + } + } + + if (!root->test_dir.dir_name && strcmp(test_dir_name, "NULL")) { + strncpy(cgroup_test_dir, test_dir_name, NAME_MAX + 1); + cgroup_dir_mk(&root->ltp_dir, cgroup_test_dir, &root->test_dir); + root->test_dir.we_created_it = 1; + } +} + +/* Load the test state config provided by tst_cg_print_config + * + * This will reload some internal tst_cgroup state given by the config + * that might otherwise have been lost between calls or between different + * processes. In particular this is used by testcases/lib/tst_cgctl to + * provide access to this C api to shell scripts. + * + * The config keeps track of the minimal state needed for tst_cg_cleanup + * to cleanup mounts and directories created by tst_cg_require. + */ +void tst_cg_load_config(const char *const config) +{ + char temp_config[BUFSIZ]; + char *line; + const size_t config_len = strlen(config) + 1; + + if (config_len >= BUFSIZ) + tst_brk(TBROK, "Config has exceeded buffer size?"); + + memcpy(temp_config, config, config_len); + temp_config[config_len] = '\0'; + + line = strtok(temp_config, "\n"); + /* Make sure to consume the header. */ + for (line = strtok(NULL, "\n"); line; line = strtok(NULL, "\n")) + cgroup_parse_config_line(line); +} + +/* 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; + unsigned int nsdelegate = 0; + unsigned int memory_recursiveprot = 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, 1); + if (const_ctrl) + add_ctrl(&ctrl_field, const_ctrl); + } + for (tok = strtok(mnt_opts, ","); tok; tok = strtok(NULL, ",")) { + nsdelegate |= !strcmp("nsdelegate", tok); + memory_recursiveprot |= !strcmp("memory_recursiveprot", tok); + } + + 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_CG_V2; + + goto backref; + +v1: + for (tok = strtok(mnt_opts, ","); tok; tok = strtok(NULL, ",")) { + const_ctrl = cgroup_find_ctrl(tok, 0); + 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_CG_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; + root->nsdelegate = nsdelegate; + root->memory_recursiveprot = memory_recursiveprot; + + for_each_ctrl(ctrl) { + if (has_ctrl(root->ctrl_field, ctrl)) + ctrl->ctrl_root = root; + } + + return; + +discard: + close(mnt_dfd); +} + +void tst_cg_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) +{ + int ret; + char mnt_path[PATH_MAX]; + const char *tmpdir = tst_get_tmpdir_root(); + + sprintf(mnt_path, "%s/%s%s", + tmpdir, 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: + ret = mount("cgroup2", mnt_path, "cgroup2", + 0, "memory_recursiveprot"); + + if (ret && errno == EINVAL) + ret = mount("cgroup2", mnt_path, "cgroup2", 0, NULL); + + if (!ret) { + tst_res(TINFO, "Mounted V2 CGroups on %s", mnt_path); + tst_cg_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; + const char *tmpdir = tst_get_tmpdir_root(); + + if (ctrl->ctrl_indx == CTRL_BLKIO && controllers[CTRL_IO].ctrl_root) { + tst_res(TCONF, + "IO controller found on V2 root, skipping blkio mount that would unmount IO controller"); + return; + } + + sprintf(mnt_path, "%s/%s%s", + tmpdir, 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_cg_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_cg_require(const char *const ctrl_name, + const struct tst_cg_opts *options) +{ + const char *const cgsc = "cgroup.subtree_control"; + struct cgroup_ctrl *const ctrl = cgroup_find_ctrl(ctrl_name, 1); + struct cgroup_root *root; + int base = !strcmp(ctrl->ctrl_name, "base"); + + if (base && options->needs_ver != TST_CG_V2) + tst_brk(TCONF, "Base control only support needs_ver TST_CG_V2!"); + + if (!ctrl) { + tst_brk(TBROK, "'%s' controller is unknown to LTP", ctrl_name); + tst_brk(TBROK, "Calling %s in cleanup?", __func__); + return; + } + + 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_cg_scan(); + + if (ctrl->ctrl_root) + goto mkdirs; + + if (!cgroup_v2_mounted() && options->needs_ver != TST_CG_V1) + cgroup_mount_v2(); + + if (ctrl->ctrl_root) + goto mkdirs; + + if (options->needs_ver != TST_CG_V2) + cgroup_mount_v1(ctrl); + + if (base) + ctrl->ctrl_root = roots; + + if (!ctrl->ctrl_root) { + tst_brk(TCONF, + "'%s' controller required, but not available", + ctrl->ctrl_name); + return; + } + +mkdirs: + root = ctrl->ctrl_root; + + if (options->needs_nsdelegate && cgroup_v2_mounted() && !cgroup_v2_nsdelegate()) + tst_brk(TCONF, "Requires cgroup2 to be mounted with nsdelegate"); + + add_ctrl(&root->mnt_dir.ctrl_field, ctrl); + + if (cgroup_ctrl_on_v2(ctrl) && options->needs_ver == TST_CG_V1) { + tst_brk(TCONF, + "V1 '%s' controller required, but it's mounted on V2", + ctrl->ctrl_name); + } + if (!cgroup_ctrl_on_v2(ctrl) && options->needs_ver == TST_CG_V2) { + tst_brk(TCONF, + "V2 '%s' controller required, but it's mounted on V1", + ctrl->ctrl_name); + } + + if (cgroup_ctrl_on_v2(ctrl) && !base) { + 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 (!base) { + 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); + + if (options->test_pid) + sprintf(cgroup_test_dir, "test-%d", options->test_pid); + else + 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_cg_ver ver, + const int source_dfd, const int dest_dfd) +{ + char pid_list[BUFSIZ]; + char *tok; + const char *const file_name = + ver == TST_CG_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_cg_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 + || !strcmp(ctrl->ctrl_name, "base")) + 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(2, 3))) +static void cgroup_group_add_dir(const struct tst_cg_group *const parent, + struct tst_cg_group *const cg, + struct cgroup_dir *const dir) +{ + const struct cgroup_ctrl *ctrl; + int i; + + if (dir->dir_root->ver != TST_CG_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_CG_V1) + continue; + + if (strcmp(ctrl->ctrl_name, "base")) { + SAFE_CG_PRINTF(parent, "cgroup.subtree_control", + "+%s", ctrl->ctrl_name); + } + } + + for (i = 0; cg->dirs[i]; i++) + ; + cg->dirs[i] = dir; +} + +struct tst_cg_group * +tst_cg_group_mk(const struct tst_cg_group *const parent, + const char *const group_name_fmt, ...) +{ + struct tst_cg_group *cg; + struct cgroup_dir *const *dir; + struct cgroup_dir *new_dir; + va_list ap; + size_t name_len; + + cg = SAFE_MALLOC(sizeof(*cg)); + memset(cg, 0, sizeof(*cg)); + + va_start(ap, group_name_fmt); + name_len = vsnprintf(cg->group_name, NAME_MAX, + group_name_fmt, ap); + va_end(ap); + + if (name_len >= NAME_MAX) + tst_brk(TBROK, "CGroup name is too long"); + + for_each_dir(parent, 0, dir) { + new_dir = SAFE_MALLOC(sizeof(*new_dir)); + cgroup_dir_mk(*dir, cg->group_name, new_dir); + cgroup_group_add_dir(parent, cg, new_dir); + } + + return cg; +} + +const char *tst_cg_group_name(const struct tst_cg_group *const cg) +{ + return cg->group_name; +} + +int tst_cg_group_unified_dir_fd(const struct tst_cg_group *const cg) +{ + if(cg->dirs_by_ctrl[0]) + return cg->dirs_by_ctrl[0]->dir_fd; + + return -1; +} + +struct tst_cg_group *tst_cg_group_rm(struct tst_cg_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[CTRL_NAME_MAX + 1]; + 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, 1); + + 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_cg_ver tst_cg_ver(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const ctrl_name) +{ + const struct cgroup_ctrl *const ctrl = cgroup_find_ctrl(ctrl_name, 1); + 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_CG_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_cg_has(const char *const file, const int lineno, + const struct tst_cg_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; +} + +static void group_from_roots(struct tst_cg_group *const cg) +{ + struct cgroup_root *root; + + if (cg->group_name[0]) { + tst_brk(TBROK, + "%s CGroup already initialized", + cg == &test_group ? "Test" : "Drain"); + } + + for_each_root(root) { + struct cgroup_dir *dir = + cg == &test_group ? &root->test_dir : &root->drain_dir; + + 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; + } + + tst_brk(TBROK, + "No CGroups found; maybe you forgot to call tst_cg_require?"); +} + +void tst_cg_init(void) +{ + group_from_roots(&test_group); + group_from_roots(&drain_group); +} + +ssize_t safe_cg_read(const char *const file, const int lineno, + const struct tst_cg_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, (ssize_t)0)] = '\0'; + + return read_ret; +} + +void safe_cg_printf(const char *const file, const int lineno, + const struct tst_cg_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); + } +} + +int safe_cg_open(const char *const file, const int lineno, + const struct tst_cg_group *cg, + const char *const file_name, int flags, int *fds) +{ + const struct cgroup_file *const cfile = + cgroup_file_find(file, lineno, file_name); + struct cgroup_dir *const *dir; + const char *alias; + int i = 0; + + for_each_dir(cg, cfile->ctrl_indx, dir) { + alias = cgroup_file_alias(cfile, *dir); + if (!alias) + continue; + + fds[i++] = safe_openat(file, lineno, (*dir)->dir_fd, alias, flags); + } + + return i; +} + +void safe_cg_fchown(const char *const file, const int lineno, + const struct tst_cg_group *cg, + const char *const file_name, + uid_t owner, gid_t group) +{ + const struct cgroup_file *const cfile = + cgroup_file_find(file, lineno, file_name); + struct cgroup_dir *const *dir; + const char *alias; + + for_each_dir(cg, cfile->ctrl_indx, dir) { + alias = cgroup_file_alias(cfile, *dir); + if (!alias) + continue; + + safe_fchownat(file, lineno, (*dir)->dir_fd, alias, owner, group, 0); + } +} + + +void safe_cg_scanf(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + const char *const fmt, ...) +{ + va_list va; + char buf[BUFSIZ]; + ssize_t len = safe_cg_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_cg_lines_scanf(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + const char *const fmt, ...) +{ + va_list va; + char buf[BUFSIZ]; + ssize_t len = safe_cg_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_cg_occursin(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + const char *const needle) +{ + char buf[BUFSIZ]; + + safe_cg_read(file, lineno, cg, file_name, buf, sizeof(buf)); + + return !!strstr(buf, needle); +} + +int tst_cg_memory_recursiveprot(struct tst_cg_group *cg) +{ + if (cg && cg->dirs_by_ctrl[0]->dir_root) + return cg->dirs_by_ctrl[0]->dir_root->memory_recursiveprot; + return 0; +} diff --git a/ltp/lib/tst_checkpoint.c b/ltp/lib/tst_checkpoint.c new file mode 100644 index 0000000000000000000000000000000000000000..9f803e3eff65a4434593ed782109592f6eb32cfd --- /dev/null +++ b/ltp/lib/tst_checkpoint.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Cyril Hrubis + * Copyright (c) Linux Test Project, 2016-2025 + */ + +#include +#include +#include +#include + +#include "test.h" +#include "safe_macros.h" +#include "lapi/futex.h" + +#define DEFAULT_MSEC_TIMEOUT 10000 + +/* + * Global futex array and size for checkpoint synchronization. + * + * NOTE: These are initialized by setup_ipc()/tst_reinit() in tst_test.c + * when .needs_checkpoints is set in the tst_test struct. + */ +futex_t *tst_futexes; +unsigned int tst_max_futexes; + +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; + } + + timeout.tv_sec = msec_timeout/1000; + timeout.tv_nsec = (msec_timeout%1000) * 1000000; + + do { + ret = syscall(SYS_futex, &tst_futexes[id], FUTEX_WAIT, + tst_futexes[id], &timeout); + } while (ret == -1 && errno == EINTR); + + return ret; +} + +int tst_checkpoint_wake(unsigned int id, unsigned int nr_wake, + unsigned int msec_timeout) +{ + 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; + } + + for (;;) { + waked += syscall(SYS_futex, &tst_futexes[id], FUTEX_WAKE, + INT_MAX, NULL); + + if (waked == nr_wake) + break; + + usleep(1000); + msecs++; + + if (msecs >= msec_timeout) { + errno = ETIMEDOUT; + return -1; + } + } + + return 0; +} + +void tst_safe_checkpoint_wait(const char *file, const int lineno, + void (*cleanup_fn)(void), unsigned int id, + unsigned int msec_timeout) +{ + int ret; + + if (!msec_timeout) + msec_timeout = DEFAULT_MSEC_TIMEOUT; + + ret = tst_checkpoint_wait(id, msec_timeout); + + if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "tst_checkpoint_wait(%u, %i) failed", id, + msec_timeout); + } +} + +void tst_safe_checkpoint_wake(const char *file, const int lineno, + void (*cleanup_fn)(void), unsigned int id, + unsigned int nr_wake) +{ + int ret = tst_checkpoint_wake(id, nr_wake, DEFAULT_MSEC_TIMEOUT); + + if (ret) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "tst_checkpoint_wake(%u, %u, %i) failed", id, nr_wake, + DEFAULT_MSEC_TIMEOUT); + } +} diff --git a/ltp/lib/tst_checksum.c b/ltp/lib/tst_checksum.c new file mode 100644 index 0000000000000000000000000000000000000000..903bf3da190b8cd9be4c1b2e01e9cbef917c3245 --- /dev/null +++ b/ltp/lib/tst_checksum.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. */ + +#include "tst_checksum.h" + +static const uint32_t crc32c_table[] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351, +}; + +uint32_t tst_crc32c(uint8_t *buf, size_t buf_len) +{ + uint32_t crc = 0xffffffff; + + while (buf_len--) + crc = crc32c_table[(crc ^ (*buf++)) & 0xff] ^ (crc >> 8); + + return ~crc; +} diff --git a/ltp/lib/tst_clocks.c b/ltp/lib/tst_clocks.c new file mode 100644 index 0000000000000000000000000000000000000000..fba4a4f7ba51ff91233b7a40f99d5247950a05f2 --- /dev/null +++ b/ltp/lib/tst_clocks.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + */ + +#include + +#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; + struct __kernel_timespec foo; + + ret = syscall(sysnr, 0, &foo); + if (ret == -1 && errno == ENOSYS) + return 0; + + return 1; +} + +int tst_clock_getres(clockid_t clk_id, struct timespec *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) +{ + 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) +{ + 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) +{ + switch (clk_id) { + case CLOCK_REALTIME: + return "CLOCK_REALTIME"; + case CLOCK_MONOTONIC: + return "CLOCK_MONOTONIC"; + case CLOCK_PROCESS_CPUTIME_ID: + return "CLOCK_PROCESS_CPUTIME_ID"; + case CLOCK_THREAD_CPUTIME_ID: + return "CLOCK_THREAD_CPUTIME_ID"; + case CLOCK_MONOTONIC_RAW: + return "CLOCK_MONOTONIC_RAW"; + case CLOCK_REALTIME_COARSE: + return "CLOCK_REALTIME_COARSE"; + case CLOCK_MONOTONIC_COARSE: + return "CLOCK_MONOTONIC_COARSE"; + case CLOCK_BOOTTIME: + return "CLOCK_BOOTTIME"; + case CLOCK_REALTIME_ALARM: + return "CLOCK_REALTIME_ALARM"; + case CLOCK_BOOTTIME_ALARM: + return "CLOCK_BOOTTIME_ALARM"; + case CLOCK_TAI: + return "CLOCK_TAI"; + default: + return "INVALID/UNKNOWN CLOCK"; + } +} + +time_t tst_clock_get_timestamp(clockid_t clk_id) +{ + struct timespec ts; + int ret; + + ret = tst_clock_gettime(clk_id, &ts); + + if (ret < 0) { + tst_brk(TBROK | TERRNO, "clock_gettime(%s)", + tst_clock_name(clk_id)); + } + + return ts.tv_sec; +} + +time_t tst_fs_timestamp_start(void) +{ + return tst_clock_get_timestamp(CLOCK_REALTIME_COARSE); +} + +time_t tst_fs_timestamp_end(void) +{ + return tst_clock_get_timestamp(CLOCK_REALTIME); +} diff --git a/ltp/lib/tst_clone.c b/ltp/lib/tst_clone.c new file mode 100644 index 0000000000000000000000000000000000000000..2aa00beb1a191d8c4a68a96ba529fc48d3777e84 --- /dev/null +++ b/ltp/lib/tst_clone.c @@ -0,0 +1,47 @@ +// 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/sched.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, + .cgroup = tst_args->cgroup, + }; + 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/ltp/lib/tst_cmd.c b/ltp/lib/tst_cmd.c new file mode 100644 index 0000000000000000000000000000000000000000..82d60497a8aea65b402297267ecb8b976f7ef8fe --- /dev/null +++ b/ltp/lib/tst_cmd.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) 2020 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 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 would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Alexey Kodanev + */ + +#include +#include +#include +#include +#include +#include +#include +#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) + +int tst_cmd_fds_(void (cleanup_fn)(void), + const char *const argv[], + int stdout_fd, + int stderr_fd, + enum tst_cmd_flags flags) +{ + int rc; + + if (argv == NULL || argv[0] == NULL) { + tst_brkm(TBROK, cleanup_fn, + "argument list is empty at %s:%d", __FILE__, __LINE__); + return -1; + } + + /* + * The tst_sig() install poisoned signal handlers for all signals the + * test is not expected to get. + * + * So we temporarily disable the handler for sigchild we get after our + * child exits so that we don't have to disable it in each test that + * uses this interface. + */ + void *old_handler = signal(SIGCHLD, SIG_DFL); + + char path[PATH_MAX]; + + if (tst_get_path(argv[0], path, sizeof(path))) { + if (flags & TST_CMD_TCONF_ON_MISSING) + tst_brkm(TCONF, cleanup_fn, "Couldn't find '%s' in $PATH at %s:%d", argv[0], + __FILE__, __LINE__); + else + return 255; + } + + pid_t pid = vfork(); + if (pid == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, "vfork failed at %s:%d", + __FILE__, __LINE__); + return -1; + } + if (!pid) { + /* redirecting stdout and stderr if needed */ + if (stdout_fd != -1) { + close(STDOUT_FILENO); + dup2(stdout_fd, STDOUT_FILENO); + } + + if (stderr_fd != -1) { + close(STDERR_FILENO); + dup2(stderr_fd, STDERR_FILENO); + } + + execvp(argv[0], (char *const *)argv); + _exit(254); + } + + int ret = -1; + if (waitpid(pid, &ret, 0) != pid) { + tst_brkm(TBROK | TERRNO, cleanup_fn, "waitpid failed at %s:%d", + __FILE__, __LINE__); + return -1; + } + + signal(SIGCHLD, old_handler); + + if (!WIFEXITED(ret)) { + tst_brkm(TBROK, cleanup_fn, "failed to exec cmd '%s' at %s:%d", + argv[0], __FILE__, __LINE__); + return -1; + } + + rc = WEXITSTATUS(ret); + + if (!(flags & TST_CMD_PASS_RETVAL) && rc) { + tst_brkm(TBROK, cleanup_fn, + "'%s' exited with a non-zero code %d at %s:%d", + argv[0], rc, __FILE__, __LINE__); + return -1; + } + + return rc; +} + +int tst_cmd_(void (cleanup_fn)(void), + const char *const argv[], + const char *stdout_path, + const char *stderr_path, + enum tst_cmd_flags flags) +{ + int stdout_fd = -1; + int stderr_fd = -1; + int rc; + + if (stdout_path != NULL) { + stdout_fd = open(stdout_path, + OPEN_FLAGS, OPEN_MODE); + + if (stdout_fd == -1) + tst_resm(TWARN | TERRNO, + "open() on %s failed at %s:%d", + stdout_path, __FILE__, __LINE__); + } + + if (stderr_path != NULL) { + stderr_fd = open(stderr_path, + OPEN_FLAGS, OPEN_MODE); + + if (stderr_fd == -1) + tst_resm(TWARN | TERRNO, + "open() on %s failed at %s:%d", + stderr_path, __FILE__, __LINE__); + } + + rc = tst_cmd_fds(cleanup_fn, argv, stdout_fd, stderr_fd, flags); + + if ((stdout_fd != -1) && (close(stdout_fd) == -1)) + tst_resm(TWARN | TERRNO, + "close() on %s failed at %s:%d", + stdout_path, __FILE__, __LINE__); + + if ((stderr_fd != -1) && (close(stderr_fd) == -1)) + tst_resm(TWARN | TERRNO, + "close() on %s failed at %s:%d", + stderr_path, __FILE__, __LINE__); + + return rc; +} + +int tst_system(const char *command) +{ + int ret = 0; + + /* + *Temporarily disable SIGCHLD of user defined handler, so the + *system(3) function will not cause unexpected SIGCHLD signal + *callback function for test cases. + */ + void *old_handler = signal(SIGCHLD, SIG_DFL); + + ret = system(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_generic_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 int mkfs_xfs_version_parser(void) +{ + FILE *f; + int rc, major, minor, patch; + + f = popen("mkfs.xfs -V 2>&1", "r"); + if (!f) { + tst_resm(TWARN, "Could not run mkfs.xfs -V 2>&1 cmd"); + return -1; + } + + rc = fscanf(f, "mkfs.xfs version %d.%d.%d", &major, &minor, &patch); + pclose(f); + if (rc != 3) { + tst_resm(TWARN, "Unable to parse mkfs.xfs 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_generic_version_table_get}, + {"mkfs.xfs", mkfs_xfs_version_parser, mkfs_generic_version_table_get}, + {}, +}; + +int tst_check_cmd(const char *cmd, const int brk_nosupp) +{ + 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; + + 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 0; + + 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); + + if (!strcmp(op_token, ">=")) { + if (ver_parser < ver_get) + goto error; + } else if (!strcmp(op_token, ">")) { + if (ver_parser <= ver_get) + goto error; + } else if (!strcmp(op_token, "<=")) { + if (ver_parser > ver_get) + goto error; + } else if (!strcmp(op_token, "<")) { + if (ver_parser >= ver_get) + goto error; + } else if (!strcmp(op_token, "==")) { + if (ver_parser != ver_get) + goto error; + } else if (!strcmp(op_token, "!=")) { + if (ver_parser == ver_get) + goto error; + } else { + tst_brkm(TCONF, NULL, "Invalid op(%s)", op_token); + } + + return 0; +error: + if (brk_nosupp) { + tst_brkm(TCONF, NULL, "%s requires %s %d, but got %d", + cmd, op_token, ver_get, ver_parser); + } else { + tst_resm(TCONF, "%s requires %s %d, but got %d", + cmd, op_token, ver_get, ver_parser); + } + + return 1; +} diff --git a/ltp/lib/tst_coredump.c b/ltp/lib/tst_coredump.c new file mode 100644 index 0000000000000000000000000000000000000000..83aa2c3980d9552e59de6733e6404b1017ce87b2 --- /dev/null +++ b/ltp/lib/tst_coredump.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Red Hat, Inc. + */ + +#define TST_NO_DEFAULT_MAIN + +#include +#include + +#include "tst_test.h" +#include "tst_coredump.h" + +void tst_no_corefile(int verbose) +{ + struct rlimit new_r, old_r; + + SAFE_GETRLIMIT(RLIMIT_CORE, &old_r); + if (old_r.rlim_max >= 1 || geteuid() == 0) { + /* + * 1 is a special value, that disables core-to-pipe. + * At the same time it is small enough value for + * core-to-file, so it skips creating cores as well. + */ + new_r.rlim_cur = 1; + new_r.rlim_max = 1; + SAFE_SETRLIMIT(RLIMIT_CORE, &new_r); + + if (verbose) { + tst_res(TINFO, + "Avoid dumping corefile for process(pid=%d)", + getpid()); + } + } +} diff --git a/ltp/lib/tst_cpu.c b/ltp/lib/tst_cpu.c new file mode 100644 index 0000000000000000000000000000000000000000..b4c7c2f815ccdf43dd8f13da39e7e5915e03ed6c --- /dev/null +++ b/ltp/lib/tst_cpu.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2012 Fujitsu Ltd. + * Author: Wanlong Gao + * + * 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 + */ + +#include "lapi/cpuset.h" + +#include +#include +#include "test.h" +#include "safe_macros.h" + +long tst_ncpus(void) +{ + long ncpus = -1; +#ifdef _SC_NPROCESSORS_ONLN + ncpus = SAFE_SYSCONF(NULL, _SC_NPROCESSORS_ONLN); +#else + tst_brkm(TBROK, NULL, "could not determine number of CPUs online"); +#endif + return ncpus; +} + +long tst_ncpus_conf(void) +{ + long ncpus_conf = -1; +#ifdef _SC_NPROCESSORS_CONF + ncpus_conf = SAFE_SYSCONF(NULL, _SC_NPROCESSORS_CONF); +#else + tst_brkm(TBROK, NULL, "could not determine number of CPUs configured"); +#endif + return ncpus_conf; +} + +#define KERNEL_MAX "/sys/devices/system/cpu/kernel_max" + +long tst_ncpus_max(void) +{ + long ncpus_max = -1; + struct stat buf; + + /* sched_getaffinity() and sched_setaffinity() cares about number of + * possible CPUs the OS or hardware can support, which can be larger + * than what sysconf(_SC_NPROCESSORS_CONF) currently provides + * (by enumarating /sys/devices/system/cpu/cpu* entries). + * + * Use /sys/devices/system/cpu/kernel_max, if available. This + * represents NR_CPUS-1, a compile time option which specifies + * "maximum number of CPUs which this kernel will support". + * This should provide cpu mask size large enough for any purposes. */ + if (stat(KERNEL_MAX, &buf) == 0) { + SAFE_FILE_SCANF(NULL, KERNEL_MAX, "%ld", &ncpus_max); + /* this is maximum CPU index allowed by the kernel + * configuration, so # of cpus allowed by config is +1 */ + ncpus_max++; + } else { + /* fall back to _SC_NPROCESSORS_CONF */ + ncpus_max = tst_ncpus_conf(); + } + 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/ltp/lib/tst_crypto.c b/ltp/lib/tst_crypto.c new file mode 100644 index 0000000000000000000000000000000000000000..4495d0baa0c28826995cd2e4f429dc07657d811d --- /dev/null +++ b/ltp/lib/tst_crypto.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Richard Palethorpe + * Nicolai Stange + */ + +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_crypto.h" + +int tst_crypto_add_alg(struct tst_netlink_context *ctx, + const struct crypto_user_alg *alg) +{ + struct nlmsghdr nh = { + .nlmsg_type = CRYPTO_MSG_NEWALG, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + }; + + NETLINK_ADD_MESSAGE(ctx, &nh, alg, sizeof(struct crypto_user_alg)); + return NETLINK_SEND_VALIDATE(ctx) ? 0 : -tst_netlink_errno; +} + +int tst_crypto_del_alg(struct tst_netlink_context *ctx, + const struct crypto_user_alg *alg, unsigned int retries) +{ + int ret; + unsigned int i = 0; + struct nlmsghdr nh = { + .nlmsg_type = CRYPTO_MSG_DELALG, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + }; + + for (i = 0; i < retries; i++) { + NETLINK_ADD_MESSAGE(ctx, &nh, alg, + sizeof(struct crypto_user_alg)); + + if (NETLINK_SEND_VALIDATE(ctx)) + return 0; + + ret = -tst_netlink_errno; + + if (ret != -EBUSY) + break; + + usleep(1); + } + + return ret; +} diff --git a/ltp/lib/tst_device.c b/ltp/lib/tst_device.c new file mode 100644 index 0000000000000000000000000000000000000000..6d1abf065930026d95a0f360eaafc3a982b29766 --- /dev/null +++ b/ltp/lib/tst_device.c @@ -0,0 +1,794 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2014 Cyril Hrubis chrubis@suse.cz + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lapi/syscalls.h" +#include "test.h" +#include "safe_macros.h" +#include "tst_device.h" + +#ifndef LOOP_CTL_GET_FREE +# define LOOP_CTL_GET_FREE 0x4C82 +#endif + +#define LOOP_CONTROL_FILE "/dev/loop-control" + +#define DEV_FILE "test_dev.img" +#define DEV_SIZE_MB 300u +#define UUID_STR_SZ 37 +#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" + +static char dev_path[PATH_MAX]; +static int device_acquired; +static unsigned long prev_dev_sec_write; + +static const char * const dev_loop_variants[] = { + "/dev/loop%i", + "/dev/loop/%i", + "/dev/block/loop%i" +}; + +static const char * const dev_variants[] = { + "/dev/%s", + "/dev/block/%s" +}; + +static int set_dev_loop_path(int dev, char *path, size_t path_len) +{ + unsigned int i; + struct stat st; + + for (i = 0; i < ARRAY_SIZE(dev_loop_variants); i++) { + snprintf(path, path_len, dev_loop_variants[i], dev); + + if (stat(path, &st) == 0 && S_ISBLK(st.st_mode)) + return 0; + } + + return 1; +} + +static int set_dev_path(char *dev, char *path, size_t path_len) +{ + unsigned int i; + struct stat st; + + for (i = 0; i < ARRAY_SIZE(dev_variants); i++) { + snprintf(path, path_len, dev_variants[i], dev); + + if (stat(path, &st) == 0 && S_ISBLK(st.st_mode)) + return 0; + } + + return 1; +} + +int tst_find_free_loopdev(char *path, size_t path_len) +{ + int ctl_fd, dev_fd, rc, i; + struct loop_info loopinfo; + char buf[PATH_MAX]; + + /* since Linux 3.1 */ + ctl_fd = open(LOOP_CONTROL_FILE, O_RDWR); + + if (ctl_fd > 0) { + rc = ioctl(ctl_fd, LOOP_CTL_GET_FREE); + close(ctl_fd); + if (rc >= 0) { + if (path && set_dev_loop_path(rc, path, path_len)) + tst_brkm(TBROK, NULL, "Could not stat loop device %i", rc); + tst_resm(TINFO, "Found free device %d '%s'", + rc, path ?: ""); + return rc; + } + tst_resm(TINFO, "Couldn't find free loop device"); + return -1; + } + + switch (errno) { + case ENOENT: + break; + case EACCES: + tst_resm(TINFO | TERRNO, + "Not allowed to open " LOOP_CONTROL_FILE ". " + "Are you root?"); + break; + default: + tst_resm(TBROK | TERRNO, "Failed to open " LOOP_CONTROL_FILE); + } + + /* + * Older way is to iterate over /dev/loop%i and /dev/loop/%i and try + * LOOP_GET_STATUS ioctl() which fails for free loop devices. + */ + for (i = 0; i < 256; i++) { + + if (set_dev_loop_path(i, buf, sizeof(buf))) + continue; + + dev_fd = open(buf, O_RDONLY); + + if (dev_fd < 0) + continue; + + if (ioctl(dev_fd, LOOP_GET_STATUS, &loopinfo) == 0) { + tst_resm(TINFO, "Device '%s' in use", buf); + } else { + if (errno != ENXIO) + continue; + tst_resm(TINFO, "Found free device '%s'", buf); + close(dev_fd); + if (path != NULL) { + strncpy(path, buf, path_len); + path[path_len-1] = '\0'; + } + return i; + } + + close(dev_fd); + } + + tst_resm(TINFO, "No free devices found"); + + return -1; +} + +int tst_attach_device(const char *dev, const char *file) +{ + int dev_fd, file_fd; + struct loop_info loopinfo; + + dev_fd = open(dev, O_RDWR); + if (dev_fd < 0) { + tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", dev); + return 1; + } + + file_fd = open(file, O_RDWR); + if (file_fd < 0) { + tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", file); + close(dev_fd); + return 1; + } + + if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) { + close(dev_fd); + close(file_fd); + tst_resm(TWARN | TERRNO, "ioctl(%s, LOOP_SET_FD, %s) failed", + dev, file); + return 1; + } + + /* Old mkfs.btrfs use LOOP_GET_STATUS instead of backing_file to get + * associated filename, so we need to set up the device by calling + * LOOP_SET_FD and LOOP_SET_STATUS. + */ + memset(&loopinfo, 0, sizeof(loopinfo)); + strcpy(loopinfo.lo_name, file); + + if (ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo)) { + close(dev_fd); + close(file_fd); + tst_resm(TWARN | TERRNO, + "ioctl(%s, LOOP_SET_STATUS, %s) failed", dev, file); + return 1; + } + + close(dev_fd); + close(file_fd); + return 0; +} + +uint64_t tst_get_device_size(const char *dev_path) +{ + int fd; + uint64_t size; + struct stat st; + + 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 + * + * Since 18048c1af783 ("loop: Fix a race between loop detach and loop open") + * device is detached only after last close. + */ + for (i = 0; i < 40; i++) { + ret = ioctl(dev_fd, LOOP_CLR_FD, 0); + + if (ret && (errno == ENXIO)) { + SAFE_CLOSE(NULL, dev_fd); + return 0; + } + + if (ret && (errno != EBUSY)) { + tst_resm(TWARN, + "ioctl(%s, LOOP_CLR_FD, 0) unexpectedly failed with: %s", + dev, tst_strerrno(errno)); + SAFE_CLOSE(NULL, dev_fd); + return 1; + } + + usleep(50000); + } + + tst_resm(TWARN, + "ioctl(%s, LOOP_CLR_FD, 0) no ENXIO for too long", dev); + SAFE_CLOSE(NULL, dev_fd); + 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); + return ret; +} + +int tst_dev_sync(int fd) +{ + return syscall(__NR_syncfs, fd); +} + +const char *tst_acquire_loop_device(unsigned int size, const char *filename) +{ + unsigned int acq_dev_size = size ? size : DEV_SIZE_MB; + + if (tst_prealloc_file(filename, 1024 * 1024, acq_dev_size)) { + tst_resm(TWARN | TERRNO, "Failed to create %s", filename); + return NULL; + } + + if (tst_find_free_loopdev(dev_path, sizeof(dev_path)) == -1) + return NULL; + + if (tst_attach_device(dev_path, filename)) + return NULL; + + return dev_path; +} + +const char *tst_acquire_device__(unsigned int size) +{ + const char *dev; + unsigned int acq_dev_size; + uint64_t ltp_dev_size; + + acq_dev_size = size ? size : DEV_SIZE_MB; + + dev = getenv("LTP_DEV"); + + if (dev) { + tst_resm(TINFO, "Using test device LTP_DEV='%s'", dev); + + ltp_dev_size = tst_get_device_size(dev); + + if (acq_dev_size <= ltp_dev_size) + return dev; + + tst_resm(TINFO, "Skipping $LTP_DEV size %"PRIu64"MB, requested size %uMB", + ltp_dev_size, acq_dev_size); + } + + dev = tst_acquire_loop_device(acq_dev_size, DEV_FILE); + + if (dev) + device_acquired = 1; + + return dev; +} + +const char *tst_acquire_device_(void (cleanup_fn)(void), unsigned int size) +{ + const char *device; + + if (device_acquired) { + tst_brkm(TBROK, cleanup_fn, "Device already acquired"); + return NULL; + } + + if (!tst_tmpdir_created()) { + tst_brkm(TBROK, cleanup_fn, + "Cannot acquire device without tmpdir() created"); + return NULL; + } + + device = tst_acquire_device__(size); + + if (!device) { + tst_brkm(TBROK, cleanup_fn, "Failed to acquire device"); + return NULL; + } + + return device; +} + +int tst_release_device(const char *dev) +{ + int ret; + + if (!device_acquired) + return 0; + + /* + * Loop device was created -> we need to detach it. + * + * The file image is deleted in tst_rmdir(); + */ + ret = tst_detach_device(dev); + + device_acquired = 0; + + return ret; +} + +int tst_clear_device(const char *dev) +{ + if (tst_fill_file(dev, 0, 1024, 512)) { + tst_resm(TWARN, "Failed to clear 512k block on %s", dev); + return 1; + } + + return 0; +} + +int tst_umount(const char *path) +{ + int err, ret, i; + + for (i = 0; i < 50; i++) { + ret = umount(path); + err = errno; + + if (!ret) + return 0; + + if (err != EBUSY) { + tst_resm(TWARN, "umount('%s') failed with %s", + path, tst_strerrno(err)); + errno = err; + return ret; + } + + tst_resm(TINFO, "umount('%s') failed with %s, try %2i...", + path, tst_strerrno(err), i+1); + + if (i == 0) { + tst_resm(TINFO, "Likely gvfsd-trash is probing newly " + "mounted fs, kill it to speed up tests."); + } + + usleep(100000); + } + + tst_resm(TWARN, "Failed to umount('%s') after 50 retries", path); + errno = err; + return -1; +} + +int tst_is_mounted(const char *path) +{ + char line[PATH_MAX]; + FILE *file; + int ret = 0; + + file = SAFE_FOPEN(NULL, "/proc/mounts", "r"); + + while (fgets(line, sizeof(line), file)) { + if (strstr(line, path) != NULL) { + ret = 1; + break; + } + } + + SAFE_FCLOSE(NULL, file); + + if (!ret) + tst_resm(TINFO, "No device is mounted at %s", path); + + return ret; +} + +int tst_is_mounted_at_tmpdir(const char *path) +{ + char cdir[PATH_MAX], mpath[PATH_MAX]; + int ret; + + if (!getcwd(cdir, PATH_MAX)) { + tst_resm(TWARN | TERRNO, "Failed to find current directory"); + return 0; + } + + ret = snprintf(mpath, PATH_MAX, "%s/%s", cdir, path); + if (ret < 0 || ret >= PATH_MAX) { + tst_resm(TWARN | TERRNO, + "snprintf() should have returned %d instead of %d", + PATH_MAX, ret); + return 0; + } + + return tst_is_mounted(mpath); +} + +static int find_stat_file(const char *dev, char *path, size_t path_len) +{ + const char *devname = strrchr(dev, '/') + 1; + + snprintf(path, path_len, "/sys/block/%s/stat", devname); + + if (!access(path, F_OK)) + return 1; + + DIR *dir = SAFE_OPENDIR(NULL, "/sys/block/"); + struct dirent *ent; + + while ((ent = readdir(dir))) { + snprintf(path, path_len, "/sys/block/%s/%s/stat", ent->d_name, devname); + + if (!access(path, F_OK)) { + SAFE_CLOSEDIR(NULL, dir); + return 1; + } + } + + SAFE_CLOSEDIR(NULL, dir); + return 0; +} + +unsigned long tst_dev_bytes_written(const char *dev) +{ + unsigned long dev_sec_write = 0, dev_bytes_written, io_ticks = 0; + char dev_stat_path[PATH_MAX]; + + if (!find_stat_file(dev, dev_stat_path, sizeof(dev_stat_path))) + tst_brkm(TCONF, NULL, "Test device stat file: %s not found", + dev_stat_path); + + SAFE_FILE_SCANF(NULL, dev_stat_path, + "%*s %*s %*s %*s %*s %*s %lu %*s %*s %lu", + &dev_sec_write, &io_ticks); + + if (!io_ticks) + tst_brkm(TCONF, NULL, "Test device stat file: %s broken", + dev_stat_path); + + dev_bytes_written = (dev_sec_write - prev_dev_sec_write) * 512; + + prev_dev_sec_write = dev_sec_write; + + return dev_bytes_written; +} + +static void btrfs_get_uevent_path(char *tmp_path, char *uevent_path) +{ + int fd; + struct btrfs_ioctl_fs_info_args args = {0}; + char btrfs_uuid_str[UUID_STR_SZ]; + struct dirent *d; + char bdev_path[PATH_MAX]; + DIR *dir; + + tst_resm(TINFO, "Use BTRFS specific strategy"); + + fd = SAFE_OPEN(NULL, tmp_path, O_DIRECTORY); + if (!ioctl(fd, BTRFS_IOC_FS_INFO, &args)) { + sprintf(btrfs_uuid_str, + UUID_FMT, + args.fsid[0], args.fsid[1], + args.fsid[2], args.fsid[3], + args.fsid[4], args.fsid[5], + args.fsid[6], args.fsid[7], + args.fsid[8], args.fsid[9], + args.fsid[10], args.fsid[11], + args.fsid[12], args.fsid[13], + args.fsid[14], args.fsid[15]); + sprintf(bdev_path, + "/sys/fs/btrfs/%s/devices", btrfs_uuid_str); + } else { + tst_brkm(TBROK | TERRNO, NULL, "BTRFS ioctl on %s failed.", tmp_path); + } + SAFE_CLOSE(NULL, fd); + + dir = SAFE_OPENDIR(NULL, bdev_path); + while ((d = SAFE_READDIR(NULL, dir))) { + if (d->d_name[0] != '.') + break; + } + + uevent_path[0] = '\0'; + + if (d) + sprintf(uevent_path, "%s/%s/uevent", bdev_path, d->d_name); + else + tst_brkm(TBROK | TERRNO, NULL, "No backing device found while looking in %s", bdev_path); + + if (SAFE_READDIR(NULL, dir)) + tst_resm(TINFO, "Warning: used first of multiple backing device."); + + SAFE_CLOSEDIR(NULL, dir); +} + +static char *overlay_mount_from_dev(dev_t dev) +{ + unsigned int dev_major, dev_minor, mnt_major, mnt_minor; + FILE *fp; + char line[4096]; + char *mountpoint; + int ret; + + dev_major = major(dev); + dev_minor = minor(dev); + + fp = SAFE_FOPEN(NULL, "/proc/self/mountinfo", "r"); + while (fgets(line, sizeof(line), fp) != NULL) { + ret = sscanf(line, "%*d %*d %u:%u %*s %ms", + &mnt_major, &mnt_minor, &mountpoint); + if (ret != 3) + tst_brkm(TBROK, NULL, + "failed to parse mountinfo line: '%s'", + line); + if (mnt_major == dev_major && mnt_minor == dev_minor) + break; + free(mountpoint); + mountpoint = NULL; + } + SAFE_FCLOSE(NULL, fp); + if (!mountpoint) + tst_brkm(TBROK, NULL, + "Unable to find mount entry for device %u:%u", + dev_major, dev_minor); + + return mountpoint; +} + +static char *overlay_get_upperdir(char *mountpoint) +{ + FILE *mntf; + struct mntent *mnt; + char *optstr, *optstart, *optend; + char *upperdir = NULL; + + mntf = setmntent("/proc/self/mounts", "r"); + if (!mntf) + tst_brkm(TBROK | TERRNO, NULL, "Can't open /proc/self/mounts"); + + while ((mnt = getmntent(mntf)) != NULL) { + if (strcmp(mnt->mnt_dir, mountpoint)) + continue; + + if (strcmp(mnt->mnt_type, "overlay")) + tst_brkm(TBROK, NULL, + "expected overlayfs on mount point \"%s\", but it is of type %s.", + mountpoint, mnt->mnt_type); + + optstr = hasmntopt(mnt, "upperdir"); + + if (optstr) { + optstart = strchr(optstr, '='); + optstart++; + optend = strchrnul(optstr, ','); + upperdir = strndup(optstart, optend - optstart); + break; + } + + tst_brkm(TBROK, NULL, + "mount point %s does not contain an upperdir", + mountpoint); + } + endmntent(mntf); + + if (!upperdir) + tst_brkm(TBROK, NULL, + "Unable to find mount point \"%s\" in mount table", + mountpoint); + + return upperdir; +} + +/* + * To get from a file or directory on an overlayfs to a device + * for an underlying mountpoint requires the following steps: + * + * 1. stat() the pathname and pick out st_dev. + * 2. use the st_dev to look up the mount point of the file + * system in /proc/self/mountinfo + * + * Because 'mountinfo' is a much more complicated file format than + * 'mounts', we switch to looking up the mount point in /proc/mounts, + * and use the mntent.h helpers to parse the entries. + * + * 3. Using getmntent(), find the entry for the mount point identified + * in step 2. + * 4. Call hasmntopt() to find the upperdir option, and parse that + * option to get to the path name for the upper directory. + * 5. Call stat on the upper directory. This should now contain + * the major and minor number for the underlying device (assuming + * that there aren't nested overlay file systems). + * 6. Populate the uevent path. + * + * Example /proc/self/mountinfo line for overlayfs: + * 471 69 0:48 / /tmp rw,relatime shared:242 - overlay overlay rw,seclabel,lowerdir=/tmp,upperdir=/mnt/upper/upper,workdir=/mnt/upper/work,uuid=null + * + * See section 3.5 of the kernel's Documentation/filesystems/proc.rst file + * for a detailed explanation of the mountinfo format. + */ +static void overlay_get_uevent_path(char *tmp_path, char *uevent_path) +{ + struct stat st; + char *mountpoint, *upperdir; + + tst_resm(TINFO, "Use OVERLAYFS specific strategy"); + + SAFE_STAT(NULL, tmp_path, &st); + + mountpoint = overlay_mount_from_dev(st.st_dev); + upperdir = overlay_get_upperdir(mountpoint); + free(mountpoint); + + SAFE_STAT(NULL, upperdir, &st); + free(upperdir); + + tst_resm(TINFO, "WARNING: used first of multiple backing devices"); + sprintf(uevent_path, "/sys/dev/block/%d:%d/uevent", + major(st.st_dev), minor(st.st_dev)); +} + +__attribute__((nonnull)) +void tst_find_backing_dev(const char *path, char *dev, size_t dev_size) +{ + struct stat buf; + struct statfs fsbuf; + char uevent_path[PATH_MAX+PATH_MAX+10]; //10 is for the static uevent path + char dev_name[NAME_MAX]; + char tmp_path[PATH_MAX]; + unsigned int dev_major, dev_minor; + + if (stat(path, &buf) < 0) + tst_brkm(TWARN | TERRNO, NULL, "stat() failed"); + + strncpy(tmp_path, path, PATH_MAX-1); + tmp_path[PATH_MAX-1] = '\0'; + if (S_ISREG(buf.st_mode)) + dirname(tmp_path); + + dev_major = major(buf.st_dev); + dev_minor = minor(buf.st_dev); + *dev = '\0'; + + if (statfs(path, &fsbuf) < 0) + tst_brkm(TBROK | TERRNO, NULL, "statfs() failed"); + + if (fsbuf.f_type == TST_BTRFS_MAGIC) { + btrfs_get_uevent_path(tmp_path, uevent_path); + } else if (fsbuf.f_type == TST_OVERLAYFS_MAGIC) { + overlay_get_uevent_path(tmp_path, uevent_path); + } else if (dev_major == 0) { + tst_brkm(TBROK, NULL, "%s resides on an unsupported pseudo-file system", path); + } else { + tst_resm(TINFO, "Use uevent strategy"); + sprintf(uevent_path, + "/sys/dev/block/%d:%d/uevent", dev_major, dev_minor); + } + + if (!access(uevent_path, R_OK)) { + FILE_LINES_SCANF(NULL, uevent_path, "DEVNAME=%s", dev_name); + + if (!dev_name[0] || set_dev_path(dev_name, dev, dev_size)) + tst_brkm(TBROK, NULL, "Could not stat backing device %s", dev); + + } else { + tst_brkm(TBROK, NULL, "uevent file (%s) access failed", uevent_path); + } +} + +void tst_stat_mount_dev(const char *const mnt_path, struct stat *const st) +{ + struct mntent *mnt; + FILE *mntf = setmntent("/proc/self/mounts", "r"); + + if (!mntf) { + tst_brkm(TBROK | TERRNO, NULL, "Can't open /proc/self/mounts"); + return; + } + + mnt = getmntent(mntf); + if (!mnt) { + tst_brkm(TBROK | TERRNO, NULL, "Can't read mounts or no mounts?"); + return; + } + + do { + if (strcmp(mnt->mnt_dir, mnt_path)) { + mnt = getmntent(mntf); + continue; + } + + if (stat(mnt->mnt_fsname, st)) { + tst_brkm(TBROK | TERRNO, NULL, + "Can't stat '%s', mounted at '%s'", + mnt->mnt_fsname, mnt_path); + } + + return; + } while (mnt); + + tst_brkm(TBROK, NULL, "Could not find mount device"); +} + +int tst_dev_block_size(const char *path) +{ + int fd; + int size; + char dev_name[PATH_MAX]; + + tst_find_backing_dev(path, dev_name, sizeof(dev_name)); + + fd = SAFE_OPEN(NULL, dev_name, O_RDONLY); + SAFE_IOCTL(NULL, fd, BLKSSZGET, &size); + SAFE_CLOSE(NULL, fd); + + return size; +} diff --git a/ltp/lib/tst_dir_is_empty.c b/ltp/lib/tst_dir_is_empty.c new file mode 100644 index 0000000000000000000000000000000000000000..43764eeba5cb3b3fa6dc031b5e09c86b765459d4 --- /dev/null +++ b/ltp/lib/tst_dir_is_empty.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved. + * + * 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 would 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 . + * + * Author: Alexey Kodanev + * + */ + +#include +#include +#include + +#include "test.h" +#include "safe_macros.h" + +int tst_dir_is_empty_(void (cleanup_fn)(void), const char *name, int verbose) +{ + struct dirent *entry; + DIR *dir = SAFE_OPENDIR(cleanup_fn, name); + int ret = 1; + + while ((entry = SAFE_READDIR(cleanup_fn, dir)) != NULL) { + const char *file = entry->d_name; + + if (!strcmp(file, "..") || !strcmp(file, ".")) + continue; + + if (verbose) + tst_resm(TINFO, "found a file: %s", file); + ret = 0; + break; + } + + SAFE_CLOSEDIR(cleanup_fn, dir); + + return ret; +} diff --git a/ltp/lib/tst_epoll.c b/ltp/lib/tst_epoll.c new file mode 100644 index 0000000000000000000000000000000000000000..556b3bdab2d7ef6b3df315b372d083ea2ede0ea2 --- /dev/null +++ b/ltp/lib/tst_epoll.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 SUSE LLC + */ +#define _GNU_SOURCE +#define TST_NO_DEFAULT_MAIN + +#include "tst_test.h" +#include "tst_epoll.h" + +int safe_epoll_create1(const char *const file, const int lineno, + const int flags) +{ + const char *flags_str; + int ret = epoll_create1(flags); + + switch (flags) { + case EPOLL_CLOEXEC: + flags_str = "EPOLL_CLOEXEC"; + break; + case 0: + flags_str = ""; + break; + default: + flags_str = "???"; + } + + if (ret == -1) { + tst_brk_(file, lineno, + TBROK | TERRNO, "epoll_create1(%s)", flags_str); + } + + return ret; +} + +int safe_epoll_ctl(const char *const file, const int lineno, + int epfd, int op, int fd, struct epoll_event *ev) +{ + const char *op_str; + int ret; + + switch (op) { + case EPOLL_CTL_ADD: + op_str = "EPOLL_CTL_ADD"; + break; + case EPOLL_CTL_DEL: + op_str = "EPOLL_CTL_DEL"; + break; + case EPOLL_CTL_MOD: + op_str = "EPOLL_CTL_MOD"; + break; + default: + op_str = "???"; + } + + ret = epoll_ctl(epfd, op, fd, ev); + + if (ret == -1) { + tst_brk_(file, lineno, + TBROK | TERRNO, + "epoll_ctl(%d, %s, %d, ...", epfd, op_str, fd); + } + + return ret; +} + +int safe_epoll_wait(const char *const file, const int lineno, + int epfd, struct epoll_event *events, + int maxevents, int timeout) +{ + int ret = epoll_wait(epfd, events, maxevents, timeout); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "epoll_wait(%d, ..., %d, %d)", + epfd, maxevents, timeout); + } + + return ret; +} + diff --git a/ltp/lib/tst_fd.c b/ltp/lib/tst_fd.c new file mode 100644 index 0000000000000000000000000000000000000000..6538a098c79bffebd7085f130b0db7bb1eaa46d5 --- /dev/null +++ b/ltp/lib/tst_fd.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2023 Cyril Hrubis + */ + +#define TST_NO_DEFAULT_MAIN + +#include +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_macros.h" + +#include "lapi/pidfd.h" +#include "lapi/io_uring.h" +#include "lapi/bpf.h" +#include "lapi/fsmount.h" + +#include "tst_fd.h" + +struct tst_fd_desc { + void (*open_fd)(struct tst_fd *fd); + void (*destroy)(struct tst_fd *fd); + const char *desc; +}; + +static void open_file(struct tst_fd *fd) +{ + fd->fd = SAFE_OPEN("fd_file", O_RDWR | O_CREAT, 0666); + SAFE_UNLINK("fd_file"); +} + +static void open_path(struct tst_fd *fd) +{ + int tfd; + + tfd = SAFE_CREAT("fd_file", 0666); + SAFE_CLOSE(tfd); + + fd->fd = SAFE_OPEN("fd_file", O_PATH); + + SAFE_UNLINK("fd_file"); +} + +static void open_dir(struct tst_fd *fd) +{ + SAFE_MKDIR("fd_dir", 0700); + fd->fd = SAFE_OPEN("fd_dir", O_DIRECTORY); + SAFE_RMDIR("fd_dir"); +} + +static void open_dev_zero(struct tst_fd *fd) +{ + fd->fd = SAFE_OPEN("/dev/zero", O_RDONLY); +} + +static void open_proc_self_maps(struct tst_fd *fd) +{ + fd->fd = SAFE_OPEN("/proc/self/maps", O_RDONLY); +} + +static void open_pipe_read(struct tst_fd *fd) +{ + int pipe[2]; + + SAFE_PIPE(pipe); + fd->fd = pipe[0]; + fd->priv = pipe[1]; +} + +static void open_pipe_write(struct tst_fd *fd) +{ + int pipe[2]; + + SAFE_PIPE(pipe); + fd->fd = pipe[1]; + fd->priv = pipe[0]; +} + +static void destroy_pipe(struct tst_fd *fd) +{ + SAFE_CLOSE(fd->priv); +} + +static void open_unix_sock(struct tst_fd *fd) +{ + fd->fd = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0); +} + +static void open_inet_sock(struct tst_fd *fd) +{ + fd->fd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); +} + +static void open_epoll(struct tst_fd *fd) +{ + fd->fd = epoll_create(1); + + if (fd->fd < 0) + tst_res(TCONF | TERRNO, "epoll_create()"); +} + +static void open_eventfd(struct tst_fd *fd) +{ + fd->fd = eventfd(0, 0); + + if (fd->fd < 0) + tst_res(TCONF | TERRNO, "Skipping %s", tst_fd_desc(fd)); +} + +static void open_signalfd(struct tst_fd *fd) +{ + sigset_t sfd_mask; + + sigemptyset(&sfd_mask); + + fd->fd = signalfd(-1, &sfd_mask, 0); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_timerfd(struct tst_fd *fd) +{ + fd->fd = timerfd_create(CLOCK_REALTIME, 0); + + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_pidfd(struct tst_fd *fd) +{ + fd->fd = syscall(__NR_pidfd_open, getpid(), 0); + if (fd->fd < 0) + tst_res(TCONF | TERRNO, "pidfd_open()"); +} + +static void open_fanotify(struct tst_fd *fd) +{ + fd->fd = syscall(__NR_fanotify_init, FAN_CLASS_NOTIF, O_RDONLY); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_inotify(struct tst_fd *fd) +{ + fd->fd = inotify_init(); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_userfaultfd(struct tst_fd *fd) +{ + fd->fd = syscall(__NR_userfaultfd, 0); + + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_perf_event(struct tst_fd *fd) +{ + struct perf_event_attr pe_attr = { + .type = PERF_TYPE_SOFTWARE, + .size = sizeof(struct perf_event_attr), + .config = PERF_COUNT_SW_CPU_CLOCK, + .disabled = 1, + .exclude_kernel = 1, + .exclude_hv = 1, + }; + + fd->fd = syscall(__NR_perf_event_open, &pe_attr, 0, -1, -1, 0); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_io_uring(struct tst_fd *fd) +{ + struct io_uring_params uring_params = {}; + + fd->fd = syscall(__NR_io_uring_setup, 1, &uring_params); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_bpf_map(struct tst_fd *fd) +{ + union bpf_attr array_attr = { + .map_type = BPF_MAP_TYPE_ARRAY, + .key_size = 4, + .value_size = 8, + .max_entries = 1, + }; + + fd->fd = syscall(__NR_bpf, BPF_MAP_CREATE, &array_attr, sizeof(array_attr)); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_fsopen(struct tst_fd *fd) +{ + fd->fd = syscall(__NR_fsopen, "ext2", 0); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_fspick(struct tst_fd *fd) +{ + fd->fd = syscall(__NR_fspick, AT_FDCWD, "/", 0); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_open_tree(struct tst_fd *fd) +{ + fd->fd = syscall(__NR_open_tree, AT_FDCWD, "/", 0); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_memfd(struct tst_fd *fd) +{ + fd->fd = syscall(__NR_memfd_create, "ltp_memfd", 0); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static void open_memfd_secret(struct tst_fd *fd) +{ + fd->fd = syscall(__NR_memfd_secret, 0); + if (fd->fd < 0) { + tst_res(TCONF | TERRNO, + "Skipping %s", tst_fd_desc(fd)); + } +} + +static struct tst_fd_desc fd_desc[] = { + [TST_FD_FILE] = {.open_fd = open_file, .desc = "file"}, + [TST_FD_PATH] = {.open_fd = open_path, .desc = "O_PATH file"}, + [TST_FD_DIR] = {.open_fd = open_dir, .desc = "directory"}, + [TST_FD_DEV_ZERO] = {.open_fd = open_dev_zero, .desc = "/dev/zero"}, + [TST_FD_PROC_MAPS] = {.open_fd = open_proc_self_maps, .desc = "/proc/self/maps"}, + [TST_FD_PIPE_READ] = {.open_fd = open_pipe_read, .desc = "pipe read end", .destroy = destroy_pipe}, + [TST_FD_PIPE_WRITE] = {.open_fd = open_pipe_write, .desc = "pipe write end", .destroy = destroy_pipe}, + [TST_FD_UNIX_SOCK] = {.open_fd = open_unix_sock, .desc = "unix socket"}, + [TST_FD_INET_SOCK] = {.open_fd = open_inet_sock, .desc = "inet socket"}, + [TST_FD_EPOLL] = {.open_fd = open_epoll, .desc = "epoll"}, + [TST_FD_EVENTFD] = {.open_fd = open_eventfd, .desc = "eventfd"}, + [TST_FD_SIGNALFD] = {.open_fd = open_signalfd, .desc = "signalfd"}, + [TST_FD_TIMERFD] = {.open_fd = open_timerfd, .desc = "timerfd"}, + [TST_FD_PIDFD] = {.open_fd = open_pidfd, .desc = "pidfd"}, + [TST_FD_FANOTIFY] = {.open_fd = open_fanotify, .desc = "fanotify"}, + [TST_FD_INOTIFY] = {.open_fd = open_inotify, .desc = "inotify"}, + [TST_FD_USERFAULTFD] = {.open_fd = open_userfaultfd, .desc = "userfaultfd"}, + [TST_FD_PERF_EVENT] = {.open_fd = open_perf_event, .desc = "perf event"}, + [TST_FD_IO_URING] = {.open_fd = open_io_uring, .desc = "io uring"}, + [TST_FD_BPF_MAP] = {.open_fd = open_bpf_map, .desc = "bpf map"}, + [TST_FD_FSOPEN] = {.open_fd = open_fsopen, .desc = "fsopen"}, + [TST_FD_FSPICK] = {.open_fd = open_fspick, .desc = "fspick"}, + [TST_FD_OPEN_TREE] = {.open_fd = open_open_tree, .desc = "open_tree"}, + [TST_FD_MEMFD] = {.open_fd = open_memfd, .desc = "memfd"}, + [TST_FD_MEMFD_SECRET] = {.open_fd = open_memfd_secret, .desc = "memfd secret"}, +}; + +const char *tst_fd_desc(struct tst_fd *fd) +{ + if (fd->type >= ARRAY_SIZE(fd_desc)) + return "invalid"; + + return fd_desc[fd->type].desc; +} + +int tst_fd_next(struct tst_fd *fd) +{ + size_t len = ARRAY_SIZE(fd_desc); + + if (fd->fd >= 0) { + SAFE_CLOSE(fd->fd); + + if (fd_desc[fd->type].destroy) + fd_desc[fd->type].destroy(fd); + + fd->type++; + } + + for (;;) { + if (fd->type >= len) + return 0; + + fd_desc[fd->type].open_fd(fd); + + if (fd->fd >= 0) + return 1; + + fd->type++; + } +} diff --git a/ltp/lib/tst_fill_file.c b/ltp/lib/tst_fill_file.c new file mode 100644 index 0000000000000000000000000000000000000000..6cedde73d101d2480a75e3ab3c7f0995e2c0d33a --- /dev/null +++ b/ltp/lib/tst_fill_file.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2014-2024 + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Author: Stanislav Kholmanskikh + */ + +#define _GNU_SOURCE +#include +#include +#include "lapi/fallocate.h" +#include "tst_fs.h" + +int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount) +{ + size_t i; + char *buf; + + /* Filling a memory buffer with provided pattern */ + buf = malloc(bs); + if (buf == NULL) + return -1; + + for (i = 0; i < bs; i++) + buf[i] = pattern; + + /* Filling the file */ + for (i = 0; i < bcount; i++) { + if (write(fd, buf, bs) != (ssize_t)bs) { + free(buf); + return -1; + } + } + + free(buf); + + 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; + + fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR); + if (fd < 0) + return -1; + + if (tst_fill_fd(fd, pattern, bs, bcount)) { + close(fd); + unlink(path); + return -1; + } + + if (close(fd) < 0) { + unlink(path); + + return -1; + } + + 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/ltp/lib/tst_fill_fs.c b/ltp/lib/tst_fill_fs.c new file mode 100644 index 0000000000000000000000000000000000000000..c62d48e289965d59ef6c877870c6047bbecb33da --- /dev/null +++ b/ltp/lib/tst_fill_fs.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + */ + +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "lapi/fcntl.h" +#include "tst_fs.h" +#include "tst_rand_data.h" +#include "tst_safe_file_at.h" + +static void fill_random(const char *path, int verbose) +{ + int i = 0; + char file[PATH_MAX]; + size_t len; + ssize_t ret; + int fd; + struct statvfs fi; + + statvfs(path, &fi); + + for (;;) { + len = random() % (1024 * 102400); + + snprintf(file, sizeof(file), "%s/file%i", path, i++); + + if (verbose) + tst_res(TINFO, "Creating file %s size %zu", file, len); + + fd = open(file, O_WRONLY | O_CREAT, 0700); + if (fd == -1) { + if (errno != ENOSPC) + tst_brk(TBROK | TERRNO, "open()"); + + tst_res(TINFO | TERRNO, "open()"); + return; + } + + while (len) { + ret = write(fd, tst_rand_data, MIN(len, tst_rand_data_len)); + + if (ret < 0) { + /* retry on ENOSPC to make sure filesystem is really full */ + if (errno == ENOSPC && len >= fi.f_bsize/2) { + SAFE_FSYNC(fd); + len /= 2; + continue; + } + + SAFE_CLOSE(fd); + + if (errno != ENOSPC) + tst_brk(TBROK | TERRNO, "write()"); + + tst_res(TINFO | TERRNO, "write()"); + return; + } + + len -= ret; + } + + SAFE_CLOSE(fd); + } +} + +static void fill_flat_vec(const char *path, int verbose) +{ + int dir, fd; + struct iovec iov[512]; + int iovcnt = ARRAY_SIZE(iov); + int retries = 3; + + dir = open(path, O_PATH | O_DIRECTORY); + if (dir == -1) { + if (errno == ENOSPC) { + tst_res(TINFO | TERRNO, "open()"); + return; + } + tst_brk(TBROK | TERRNO, "open(%s, %d) failed", path, O_PATH | O_DIRECTORY); + } + + fd = openat(dir, "AOF", O_WRONLY | O_CREAT, 0600); + if (fd == -1) { + if (errno == ENOSPC) { + tst_res(TINFO | TERRNO, "openat()"); + return; + } + tst_brk(TBROK | TERRNO, "openat(%d, %d, 0600) failed for path %s", + dir, O_PATH | O_DIRECTORY, path); + } + + SAFE_CLOSE(dir); + + for (int i = 0; i < iovcnt; i++) { + iov[i] = (struct iovec) { + (void *)tst_rand_data, + tst_rand_data_len + }; + } + + while (retries) { + const int ret = writev(fd, iov, iovcnt); + + if (!ret) + tst_res(TWARN | TERRNO, "writev returned 0; not sure what this means"); + + if (ret > -1) { + if (verbose && retries < 3) + tst_res(TINFO, "writev(\"%s/AOF\", iov, %d) = %d", path, iovcnt, ret); + + retries = 3; + continue; + } + + if (errno != ENOSPC) + tst_brk(TBROK | TERRNO, "writev(\"%s/AOF\", iov, %d)", path, iovcnt); + + if (verbose) + tst_res(TINFO, "writev(\"%s/AOF\", iov, %d): ENOSPC", path, iovcnt); + + retries--; + } + + SAFE_CLOSE(fd); +} + +void tst_fill_fs(const char *path, int verbose, enum tst_fill_access_pattern pattern) +{ + + switch (pattern) { + case TST_FILL_BLOCKS: + return fill_flat_vec(path, verbose); + case TST_FILL_RANDOM: + return fill_random(path, verbose); + } +} diff --git a/ltp/lib/tst_fs_has_free.c b/ltp/lib/tst_fs_has_free.c new file mode 100644 index 0000000000000000000000000000000000000000..080d693ab3822a1cea3e89da9313ed987f5fe03e --- /dev/null +++ b/ltp/lib/tst_fs_has_free.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Fujitsu Ltd. + * Author: Xiaoguang Wang + * + * 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. + * + * 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. + */ + +/* + * DESCRIPTION + * Check if the mounted file system has enough free space, + * if it is, tst_fs_has_free() returns 1, otherwise 0. + */ + +#include +#include +#include "test.h" +#include "tst_fs.h" + +int tst_fs_has_free_(void (*cleanup)(void), const char *path, + uint64_t size, unsigned int mult) +{ + struct statfs sf; + + if (statfs(path, &sf)) { + tst_brkm(TBROK | TERRNO, cleanup, + "tst_fs_has_free: failed to statfs(%s)", path); + return 0; + } + + if ((uint64_t)sf.f_bavail * sf.f_bsize >= (uint64_t)size * mult) + return 1; + + return 0; +} diff --git a/ltp/lib/tst_fs_link_count.c b/ltp/lib/tst_fs_link_count.c new file mode 100644 index 0000000000000000000000000000000000000000..6a6bb52b299189604b25931764263f6a1d7ca422 --- /dev/null +++ b/ltp/lib/tst_fs_link_count.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2014 Fujitsu Ltd. + * Author: Xiaoguang Wang + * + * 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. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "test.h" +#include "usctest.h" +#include "safe_macros.h" + +#define MAX_SANE_HARD_LINKS 65535 + +/* + * filesystems whose subdir limit is less than MAX_SANE_HARD_LINKS + * XXX: we cannot filter ext4 out, because ext2/ext3/ext4 have the + * same magic number + */ +const long subdir_limit_whitelist[] = { + TST_EXT2_OLD_MAGIC, TST_EXT234_MAGIC, TST_MINIX_MAGIC, + TST_MINIX_MAGIC2, TST_MINIX2_MAGIC, TST_MINIX2_MAGIC2, + TST_MINIX3_MAGIC, TST_UDF_MAGIC, TST_SYSV2_MAGIC, + TST_SYSV4_MAGIC, TST_UFS_MAGIC, TST_UFS2_MAGIC, + TST_F2FS_MAGIC, TST_NILFS_MAGIC, TST_EXOFS_MAGIC +}; + +int tst_fs_fill_hardlinks_(void (*cleanup) (void), const char *dir) +{ + unsigned int i, j; + char base_filename[PATH_MAX], link_filename[PATH_MAX]; + struct stat s; + + if (stat(dir, &s) == -1 && errno == ENOENT) + SAFE_MKDIR(cleanup, dir, 0744); + + SAFE_STAT(cleanup, dir, &s); + if (!S_ISDIR(s.st_mode)) { + tst_brkm(TBROK, cleanup, "%s is not directory", dir); + return 0; + } + + sprintf(base_filename, "%s/testfile0", dir); + SAFE_TOUCH(cleanup, base_filename, 0644, NULL); + + for (i = 1; i < MAX_SANE_HARD_LINKS; i++) { + sprintf(link_filename, "%s/testfile%d", dir, i); + + if (link(base_filename, link_filename) == 0) + continue; + + switch (errno) { + case EMLINK: + SAFE_STAT(cleanup, base_filename, &s); + if (s.st_nlink != i) { + tst_brkm(TBROK, cleanup, "wrong number of " + "hard links for %s have %i, should be" + " %d", base_filename, + (int)s.st_nlink, i); + return 0; + } else { + tst_resm(TINFO, "the maximum number of hard " + "links to %s is hit: %d", + base_filename, (int)s.st_nlink); + return s.st_nlink; + } + case ENOSPC: + case EDQUOT: + tst_resm(TINFO | TERRNO, "link(%s, %s) failed", + base_filename, link_filename); + goto max_hardlinks_cleanup; + default: + tst_brkm(TBROK, cleanup, "link(%s, %s) failed " + "unexpectedly: %s", base_filename, + link_filename, strerror(errno)); + return 0; + } + } + + tst_resm(TINFO, "Failed reach the hardlinks limit"); + +max_hardlinks_cleanup: + for (j = 0; j < i; j++) { + sprintf(link_filename, "%s/testfile%d", dir, j); + SAFE_UNLINK(cleanup, link_filename); + } + + return 0; +} + +int tst_fs_fill_subdirs_(void (*cleanup) (void), const char *dir) +{ + unsigned int i, j, whitelist_size; + char dirname[PATH_MAX]; + struct stat s; + long fs_type; + + if (stat(dir, &s) == -1 && errno == ENOENT) + SAFE_MKDIR(cleanup, dir, 0744); + + SAFE_STAT(cleanup, dir, &s); + if (!S_ISDIR(s.st_mode)) { + tst_brkm(TBROK, cleanup, "%s is not directory", dir); + return 0; + } + + /* for current kernel, subdir limit is not available for all fs */ + fs_type = tst_fs_type(cleanup, dir); + + whitelist_size = ARRAY_SIZE(subdir_limit_whitelist); + for (i = 0; i < whitelist_size; i++) { + if (fs_type == subdir_limit_whitelist[i]) + break; + } + if (i == whitelist_size) { + tst_resm(TINFO, "subdir limit is not availiable for " + "%s filesystem", tst_fs_type_name(fs_type)); + return 0; + } + + for (i = 0; i < MAX_SANE_HARD_LINKS; i++) { + sprintf(dirname, "%s/testdir%d", dir, i); + + if (mkdir(dirname, 0755) == 0) + continue; + + switch (errno) { + case EMLINK: + SAFE_STAT(cleanup, dir, &s); + /* + * i+2 because there are two links to each newly + * 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); + return 0; + } else { + tst_resm(TINFO, "the maximum subdirectories in " + "%s is hit: %d", dir, (int)s.st_nlink); + return s.st_nlink; + } + case ENOSPC: + case EDQUOT: + tst_resm(TINFO | TERRNO, "mkdir(%s, 0755) failed", + dirname); + goto max_subdirs_cleanup; + default: + tst_brkm(TBROK, cleanup, "mkdir(%s, 0755) failed " + "unexpectedly: %s", dirname, + strerror(errno)); + return 0; + } + + } + + tst_resm(TINFO, "Failed reach the subdirs limit on %s filesystem", + tst_fs_type_name(fs_type)); + +max_subdirs_cleanup: + for (j = 0; j < i; j++) { + sprintf(dirname, "%s/testdir%d", dir, j); + SAFE_RMDIR(cleanup, dirname); + } + + return 0; +} diff --git a/ltp/lib/tst_fs_setup.c b/ltp/lib/tst_fs_setup.c new file mode 100644 index 0000000000000000000000000000000000000000..d3284a145d4e9b5aeaeed4a7eb69d5a88667c852 --- /dev/null +++ b/ltp/lib/tst_fs_setup.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_fs.h" + +#define TST_FS_SETUP_OVERLAYFS_MSG "overlayfs is not configured in this kernel" +#define TST_FS_SETUP_OVERLAYFS_CONFIG "lowerdir="OVL_LOWER",upperdir="OVL_UPPER",workdir="OVL_WORK + +void tst_create_overlay_dirs(void) +{ + DIR *dir = opendir(OVL_LOWER); + + if (dir == NULL) { + SAFE_MKDIR(OVL_LOWER, 0755); + SAFE_MKDIR(OVL_UPPER, 0755); + SAFE_MKDIR(OVL_WORK, 0755); + SAFE_MKDIR(OVL_MNT, 0755); + return; + } + closedir(dir); +} + +int tst_mount_overlay(const char *file, const int lineno, int strict) +{ + int ret; + + tst_create_overlay_dirs(); + ret = mount("overlay", OVL_MNT, "overlay", 0, + TST_FS_SETUP_OVERLAYFS_CONFIG); + if (ret == 0) + return 0; + + if (errno == ENODEV) { + if (strict) { + tst_brk_(file, lineno, TCONF, + TST_FS_SETUP_OVERLAYFS_MSG); + } else { + tst_res_(file, lineno, TINFO, + TST_FS_SETUP_OVERLAYFS_MSG); + } + } else if (strict) { + tst_brk_(file, lineno, TBROK | TERRNO, + "overlayfs mount failed"); + } + return ret; +} diff --git a/ltp/lib/tst_fs_type.c b/ltp/lib/tst_fs_type.c new file mode 100644 index 0000000000000000000000000000000000000000..e9efb89dcc98e9336602362a56f268001ac1c6af --- /dev/null +++ b/ltp/lib/tst_fs_type.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2005-2021 Linux Test Project + * + * Cyril Hrubis 2014 + * Michal Simek 2009 + * Kumar Gala 2007 + * Ricky Ng-Adam 2005 + */ + +#include +#include "test.h" +#include "tst_fs.h" + +long tst_fs_type_(void (*cleanup)(void), const char *path) +{ + struct statfs sbuf; + + if (statfs(path, &sbuf)) { + tst_brkm(TBROK | TERRNO, cleanup, + "tst_fs_type: Failed to statfs(%s)", path); + return 0; + } + + return sbuf.f_type; +} + +const char *tst_fs_type_name(long f_type) +{ + switch (f_type) { + case TST_TMPFS_MAGIC: + return "tmpfs"; + case TST_NFS_MAGIC: + return "nfs"; + case TST_V9FS_MAGIC: + return "9p"; + case TST_RAMFS_MAGIC: + return "ramfs"; + case TST_BCACHE_MAGIC: + return "bcachefs"; + case TST_BTRFS_MAGIC: + return "btrfs"; + case TST_XFS_MAGIC: + return "xfs"; + case TST_EXT2_OLD_MAGIC: + return "ext2"; + case TST_EXT234_MAGIC: + 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"; + case TST_UDF_MAGIC: + return "udf"; + case TST_SYSV2_MAGIC: + case TST_SYSV4_MAGIC: + return "sysv"; + case TST_UFS_MAGIC: + case TST_UFS2_MAGIC: + return "ufs"; + case TST_F2FS_MAGIC: + return "f2fs"; + case TST_NILFS_MAGIC: + return "nilfs"; + case TST_EXOFS_MAGIC: + return "exofs"; + case TST_OVERLAYFS_MAGIC: + return "overlayfs"; + case TST_FUSE_MAGIC: + return "fuse"; + case TST_VFAT_MAGIC: + return "vfat"; + case TST_EXFAT_MAGIC: + return "exfat"; + default: + return "unknown"; + } +} diff --git a/ltp/lib/tst_get_bad_addr.c b/ltp/lib/tst_get_bad_addr.c new file mode 100644 index 0000000000000000000000000000000000000000..098e72b8bfc9529c564a0eee7550132390af13a0 --- /dev/null +++ b/ltp/lib/tst_get_bad_addr.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 . + */ + +#include +#include "test.h" +#include "tst_get_bad_addr.h" + +void *tst_get_bad_addr(void (*cleanup_fn) (void)) +{ + void *bad_addr; + + bad_addr = mmap(0, 1, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (bad_addr == MAP_FAILED) + tst_brkm(TBROK, cleanup_fn, "mmap() failed to get bad address"); + + return bad_addr; +} diff --git a/ltp/lib/tst_hugepage.c b/ltp/lib/tst_hugepage.c new file mode 100644 index 0000000000000000000000000000000000000000..d2e70a955d68246b1e02ec2ddf4ca575d26ae883 --- /dev/null +++ b/ltp/lib/tst_hugepage.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Red Hat, Inc. + */ + +#define TST_NO_DEFAULT_MAIN + +#include "tst_test.h" +#include "tst_hugepage.h" + +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_reserve_hugepages(struct tst_hugepage *hp) +{ + unsigned long val, max_hpages; + struct tst_path_val pvl = { + .path = PATH_NR_HPAGES, + .val = NULL, + .flags = TST_SR_SKIP_MISSING | TST_SR_TCONF_RO + }; + + if (access(PATH_HUGEPAGES, F_OK)) { + if (hp->policy == TST_NEEDS) + tst_brk(TCONF, "hugetlbfs is not supported"); + tst_hugepages = 0; + goto out; + } + + if (nr_opt) + tst_hugepages = SAFE_STRTOL(nr_opt, 1, LONG_MAX); + else + tst_hugepages = hp->number; + + if (hp->number == TST_NO_HUGEPAGES) { + tst_hugepages = 0; + goto set_hugepages; + } + + SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3"); + SAFE_FILE_PRINTF("/proc/sys/vm/compact_memory", "1"); + if (hp->policy == TST_NEEDS) { + tst_hugepages += SAFE_READ_MEMINFO("HugePages_Total:"); + goto set_hugepages; + } + + max_hpages = SAFE_READ_MEMINFO("MemFree:") / SAFE_READ_MEMINFO("Hugepagesize:"); + if (tst_hugepages > max_hpages) { + tst_res(TINFO, "Requested number(%lu) of hugepages is too large, " + "limiting to 80%% of the max hugepage count %lu", + tst_hugepages, max_hpages); + tst_hugepages = max_hpages * 0.8; + + if (tst_hugepages < 1) + goto out; + } + +set_hugepages: + tst_sys_conf_save(&pvl); + SAFE_FILE_PRINTF(PATH_NR_HPAGES, "%lu", tst_hugepages); + SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val); + if (val != tst_hugepages) + tst_brk(TCONF, "nr_hugepages = %lu, but expect %lu. " + "Not enough hugepages for testing.", + val, tst_hugepages); + + if (hp->policy == TST_NEEDS) { + unsigned long free_hpages = SAFE_READ_MEMINFO("HugePages_Free:"); + if (hp->number > free_hpages) + tst_brk(TCONF, "free_hpages = %lu, but expect %lu. " + "Not enough hugepages for testing.", + free_hpages, hp->number); + } + + tst_res(TINFO, "%lu hugepage(s) reserved", tst_hugepages); +out: + return tst_hugepages; +} diff --git a/ltp/lib/tst_ioctl.c b/ltp/lib/tst_ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..985cd53299d0d0c5f7001247429a5ee09b4dfabe --- /dev/null +++ b/ltp/lib/tst_ioctl.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2019-2023 + */ + +#include +#include + +#define TST_NO_DEFAULT_MAIN + +#include "tst_test.h" +#include "tst_fs.h" + +int tst_fibmap(const char *filename) +{ + int fd, block = 0; + + fd = SAFE_OPEN(filename, O_RDWR | O_CREAT, 0666); + + if (ioctl(fd, FIBMAP, &block)) { + tst_res(TINFO | TERRNO, "FIBMAP ioctl is NOT supported"); + SAFE_CLOSE(fd); + return 1; + } + + tst_res(TINFO, "FIBMAP ioctl is supported"); + SAFE_CLOSE(fd); + + return 0; +} diff --git a/ltp/lib/tst_kconfig.c b/ltp/lib/tst_kconfig.c new file mode 100644 index 0000000000000000000000000000000000000000..9bcd577210e1da1c5d7ef79b6a3f2b660cb1e6ca --- /dev/null +++ b/ltp/lib/tst_kconfig.c @@ -0,0 +1,686 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Cyril Hrubis + */ + +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_private.h" +#include "tst_kconfig.h" +#include "tst_bool_expr.h" +#include "tst_safe_stdio.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) +{ + const char *path = getenv("KCONFIG_PATH"); + struct utsname un; + + if (path) { + if (!access(path, F_OK)) + return path; + + tst_res(TWARN, "KCONFIG_PATH='%s' does not exist", path); + } + + if (!access("/proc/config.gz", F_OK)) + return "/proc/config.gz"; + + 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; + + snprintf(path_buf, path_buf_len, "/lib/modules/%s/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); + + if (!access(path_buf, F_OK)) + return path_buf; + + /* Clear Linux */ + snprintf(path_buf, path_buf_len, "/lib/kernel/config-%s", un.release); + + if (!access(path_buf, F_OK)) + return path_buf; + + tst_res(TINFO, "Couldn't locate kernel config!"); + + return NULL; +} + +static char is_gzip; + +static FILE *open_kconfig(void) +{ + FILE *fp; + char buf[1064]; + char path_buf[1024]; + const char *path = kconfig_path(path_buf, sizeof(path_buf)); + + if (!path) + return NULL; + + tst_res(TINFO, "Parsing kernel config '%s'", path); + + is_gzip = !!strstr(path, ".gz"); + + if (is_gzip) { + snprintf(buf, sizeof(buf), "zcat '%s'", path); + fp = popen(buf, "r"); + } else { + fp = fopen(path, "r"); + } + + if (!fp) + tst_brk(TBROK | TERRNO, "Failed to open '%s'", path); + + return fp; +} + +static void close_kconfig(FILE *fp) +{ + if (is_gzip) + pclose(fp); + else + fclose(fp); +} + +static inline int kconfig_parse_line(const char *line, + struct tst_kconfig_var *vars, + unsigned int vars_len) +{ + unsigned int i, var_len = 0; + const char *var; + int is_not_set = 0; + + while (isspace(*line)) + line++; + + if (*line == '#') { + if (!strstr(line, "is not set")) + return 0; + + is_not_set = 1; + } + + var = strstr(line, "CONFIG_"); + + if (!var) + return 0; + + for (;;) { + switch (var[var_len]) { + case 'A' ... 'Z': + case '0' ... '9': + case '_': + var_len++; + break; + default: + goto out; + break; + } + } + +out: + + for (i = 0; i < vars_len; i++) { + const char *val; + unsigned int val_len = 0; + + if (vars[i].id_len != var_len) + continue; + + if (strncmp(vars[i].id, var, var_len)) + continue; + + if (is_not_set) { + vars[i].choice = 'n'; + return 1; + } + + val = var + var_len; + + while (isspace(*val)) + val++; + + if (*val != '=') + return 0; + + val++; + + while (isspace(*val)) + 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; + } + } + + vars[i].choice = 'v'; + vars[i].val = strndup(val, val_len); + } + + 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(line, sizeof(line), fp)) { + if (kconfig_parse_line(line, vars, vars_len)) + vars_found++; + + if (vars_found == vars_len) + goto exit; + } + +exit: + close_kconfig(fp); +} + +static size_t array_len(const char *const kconfigs[]) +{ + size_t i = 0; + + while (kconfigs[++i]); + + return i; +} + +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) +{ + 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; + } + + 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; + } + + 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; +} + +static int validate_vars(struct tst_expr *const exprs[], unsigned int expr_cnt) +{ + unsigned int i; + 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]; + } + + 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; + + 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 (var->choice == 'v') { + tst_res(TINFO, " %s=%s", var->id, var->val); + continue; + } + + 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 (kconfig_skip_check()) + return 0; + + for (i = 0; i < expr_cnt; i++) { + exprs[i] = tst_bool_expr_parse(kconfigs[i]); + + if (!exprs[i]) + tst_brk(TBROK, "Invalid kconfig expression!"); + } + + if (validate_vars(exprs, expr_cnt)) + tst_brk(TBROK, "Invalid kconfig variables!"); + + 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]); + } + + tst_bool_expr_free(exprs[i]); + } + + for (i = 0; i < var_cnt; i++) { + if (vars[i].choice == 'v') + free(vars[i].val); + } + + 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; +} + +void tst_kcmdline_parse(struct tst_kcmdline_var params[], size_t params_len) +{ + char buf[256], line[1024]; + size_t b_pos = 0,l_pos =0, i; + int var_id = -1; + + FILE *f = SAFE_FOPEN("/proc/cmdline", "r"); + + if (fgets(line, sizeof(line), f) == NULL) { + SAFE_FCLOSE(f); + tst_brk(TBROK, "Failed to read /proc/cmdline"); + } + + for (l_pos = 0; line[l_pos] != '\0'; l_pos++) { + char c = line[l_pos]; + + switch (c) { + case '=': + buf[b_pos] = '\0'; + for (i = 0; i < params_len; i++) { + if (strcmp(buf, params[i].key) == 0) { + var_id = (int)i; + params[i].found = true; + } + } + + b_pos = 0; + break; + case ' ': + case '\n': + buf[b_pos] = '\0'; + if (var_id >= 0 && var_id < (int)params_len) + strcpy(params[var_id].value, buf); + + var_id = -1; + b_pos = 0; + break; + default: + if (b_pos + 1 >= sizeof(buf)) { + tst_res(TINFO, "WARNING: Buffer overflowed while parsing /proc/cmdline"); + while (line[l_pos] != '\0' && line[l_pos] != ' ' && line[l_pos] != '\n') + l_pos++; + + var_id = -1; + b_pos = 0; + + if (line[l_pos] != '\0') + l_pos--; + } else { + buf[b_pos++] = c; + } + break; + } + } + + for (i = 0; i < params_len; i++) { + if (params[i].found) + tst_res(TINFO, "%s is found in /proc/cmdline", params[i].key); + else + tst_res(TINFO, "%s is not found in /proc/cmdline", params[i].key); + } + + SAFE_FCLOSE(f); +} + +/* + * List of kernel config options that may degrade performance when enabled. + */ +static struct tst_kconfig_var slow_kconfigs[] = { + TST_KCONFIG_INIT("CONFIG_PROVE_LOCKING"), + TST_KCONFIG_INIT("CONFIG_LOCKDEP"), + TST_KCONFIG_INIT("CONFIG_DEBUG_SPINLOCK"), + TST_KCONFIG_INIT("CONFIG_DEBUG_RT_MUTEXES"), + TST_KCONFIG_INIT("CONFIG_DEBUG_MUTEXES"), + TST_KCONFIG_INIT("CONFIG_KASAN"), + TST_KCONFIG_INIT("CONFIG_SLUB_RCU_DEBUG"), + TST_KCONFIG_INIT("CONFIG_TRACE_IRQFLAGS"), + TST_KCONFIG_INIT("CONFIG_DEBUG_NET"), + TST_KCONFIG_INIT("CONFIG_EXT4_DEBUG"), + TST_KCONFIG_INIT("CONFIG_QUOTA_DEBUG"), + TST_KCONFIG_INIT("CONFIG_FAULT_INJECTION"), + TST_KCONFIG_INIT("CONFIG_DEBUG_OBJECTS") +}; + +static bool slow_kconfig_cached; +static bool slow_kconfig_result; + +int tst_has_slow_kconfig(void) +{ + unsigned int i; + char path_buf[1024]; + + if (slow_kconfig_cached) + return slow_kconfig_result; + + slow_kconfig_cached = 1; + + if (!kconfig_path(path_buf, sizeof(path_buf))) { + slow_kconfig_result = 0; + return 0; + } + + tst_kconfig_read(slow_kconfigs, ARRAY_SIZE(slow_kconfigs)); + + for (i = 0; i < ARRAY_SIZE(slow_kconfigs); i++) { + if (slow_kconfigs[i].choice == 'y') { + tst_res(TINFO, + "%s kernel option detected which might slow the execution", + slow_kconfigs[i].id); + slow_kconfig_result = 1; + return 1; + } + } + + slow_kconfig_result = 0; + return 0; +} diff --git a/ltp/lib/tst_kernel.c b/ltp/lib/tst_kernel.c new file mode 100644 index 0000000000000000000000000000000000000000..9ab02e5d30cc3ddc0669cb77dcbfa35efb44c269 --- /dev/null +++ b/ltp/lib/tst_kernel.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) 2020-2021 Petr Vorel + * Copyright (c) Linux Test Project, 2017-2024 + * + * 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 . + */ + +#include +#include +#include +#include + +#include "test.h" +#include "tst_kernel.h" +#include "old_safe_stdio.h" +#include "lapi/abisize.h" + +static int get_kernel_bits_from_uname(struct utsname *buf) +{ + if (uname(buf)) { + tst_brkm(TBROK | TERRNO, NULL, "uname()"); + return -1; + } + + return strstr(buf->machine, "64") ? 64 : 32; +} + +int tst_kernel_bits(void) +{ + struct utsname 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; + + /* + * ARM64 (aarch64) defines 32-bit compatibility modes as + * armv8l and armv8b (little and big endian). + * s390x is 64bit but not contain 64 in the words. + */ + if (!strcmp(buf.machine, "armv8l") || !strcmp(buf.machine, "armv8b") + || !strcmp(buf.machine, "s390x")) + kernel_bits = 64; + +#ifdef __ANDROID__ + /* Android's bionic libc sets the PER_LINUX32 personality for all 32-bit + * programs. This will cause buf.machine to report as i686 even though + * the kernel itself is 64-bit. + */ + if (!strcmp(buf.machine, "i686") && + (personality(0xffffffff) & PER_MASK) == PER_LINUX32) { + /* Set the personality back to the default. */ + if (personality(PER_LINUX) == -1) { + tst_brkm(TBROK | TERRNO, NULL, "personality()"); + return -1; + } + + /* Redo the uname check without the PER_LINUX32 personality to + * determine the actual kernel bits value. + */ + kernel_bits = get_kernel_bits_from_uname(&buf); + if (kernel_bits == -1) + return -1; + + /* Set the personality back to PER_LINUX32. */ + if (personality(PER_LINUX32) == -1) { + tst_brkm(TBROK | TERRNO, NULL, "personality()"); + return -1; + } + } +#endif /* __ANDROID__ */ + + tst_resm(TINFO, "uname.machine=%s kernel is %ibit", + buf.machine, kernel_bits); + + return kernel_bits; +} + +int tst_is_compat_mode(void) +{ + return TST_ABI != tst_kernel_bits(); +} + +bool tst_abi_bits(int abi) +{ + if (abi != 32 && abi != 64) + tst_brkm(TBROK | TERRNO, NULL, "abi parameter can be only 32 or 64"); + + return abi == TST_ABI; +} + +static int tst_search_driver_(const char *driver, const char *file) +{ + 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; + } + + /* always search for x86_64 */ + char *fix = strstr(driver, "x86-64"); + + if (fix) + fix[3] = '_'; + + 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_search_driver(const char *driver, const char *file) +{ +#ifdef __ANDROID__ + /* + * Android may not have properly installed modules.* files. We could + * search modules in /system/lib/modules, but to determine built-in + * drivers we need modules.builtin. Therefore assume all drivers are + * available. + */ + return 0; +#endif + + if (!tst_search_driver_(driver, file)) + 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_search_driver_(driver2, file); + free(driver2); + } + + return ret; +} + +int tst_check_builtin_driver(const char *driver) +{ + if (!tst_search_driver(driver, "modules.builtin")) + return 0; + + return -1; +} + +int tst_check_driver(const char *driver) +{ + if (!tst_search_driver(driver, "modules.dep") || + !tst_check_builtin_driver(driver)) + return 0; + + return -1; +} + +int tst_check_preempt_rt(void) +{ + struct utsname uval; + + uname(&uval); + if (strstr(uval.version, "PREEMPT_RT")) + return 1; + return 0; +} diff --git a/ltp/lib/tst_kvercmp.c b/ltp/lib/tst_kvercmp.c new file mode 100644 index 0000000000000000000000000000000000000000..9e1a511affc61834aca9e4da3035902ed603d456 --- /dev/null +++ b/ltp/lib/tst_kvercmp.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) International Business Machines Corp., 2003 + * AUTHOR: Paul Larson + * Copyright (c) 2016 Cyril Hrubis + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include "test.h" + +#define OSRELEASE_PATH "/etc/os-release" + +static char *parse_digit(const char *str, int *d) +{ + unsigned long v; + char *end; + + v = strtoul(str, &end, 10); + if (str == end) + return NULL; + + if (v > INT_MAX) + return NULL; + + *d = v; + + return end; +} + +int tst_parse_kver(const char *str_kver, int *v1, int *v2, int *v3) +{ + const char *str = str_kver; + + *v1 = 0; + *v2 = 0; + *v3 = 0; + + if (!(str = parse_digit(str, v1))) + return 1; + + if (*(str++) != '.') + return 1; + + if (!(str = parse_digit(str, v2))) + return 1; + + /* + * Check for a short version e.g '2.4' + */ + if (*str == ' ' || *str == '\0' || *str == '-') + return 0; + + if (*(str++) != '.') + return 1; + + /* + * Ignore rest of the string in order not to break on versions as + * 4.8.1-52-default. + */ + if (!parse_digit(str, v3)) + return 1; + + return 0; +} + +int tst_kvcmp(const char *cur_kver, int r1, int r2, int r3) +{ + int a1, a2, a3; + int testver, currver; + + if (tst_parse_kver(cur_kver, &a1, &a2, &a3)) { + tst_resm(TWARN, + "Invalid kernel version %s, expected %%d.%%d.%%d", + cur_kver); + } + + testver = (r1 << 20) + (r2 << 10) + r3; + currver = (a1 << 20) + (a2 << 10) + a3; + + return currver - testver; +} + +int tst_kvercmp(int r1, int r2, int r3) +{ + struct utsname uval; + + uname(&uval); + + return tst_kvcmp(uval.release, r1, r2, r3); +} + +int tst_kvexcmp(const char *tst_exv, const char *cur_ver) +{ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0; + int t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0; + int ret; + + sscanf(cur_ver, "%d.%d.%d-%d.%d", &c1, &c2, &c3, &c4, &c5); + sscanf(tst_exv, "%d.%d.%d-%d.%d", &t1, &t2, &t3, &t4, &t5); + + if ((ret = c1 - t1)) + return ret; + if ((ret = c2 - t2)) + return ret; + if ((ret = c3 - t3)) + return ret; + if ((ret = c4 - t4)) + return ret; + + return c5 - t5; +} + +const char *tst_kvcmp_distname(const char *kver) +{ + static char distname[64]; + char *ret = distname; + char *p = distname; + + if (strstr(kver, ".el7")) + return "RHEL7"; + + if (strstr(kver, ".el8")) + return "RHEL8"; + + if (strstr(kver, ".el9")) + return "RHEL9"; + + 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; +} + +int tst_kvercmp2(int r1, int r2, int r3, struct tst_kern_exv *vers) +{ + int i; + const char *kver; + struct utsname uval; + const char *cur_dist_name; + + uname(&uval); + kver = uval.release; + cur_dist_name = tst_kvcmp_distname(kver); + + if (cur_dist_name == NULL) + return tst_kvercmp(r1, r2, r3); + + for (i = 0; vers[i].dist_name; i++) { + if (!strcmp(vers[i].dist_name, cur_dist_name)) { + tst_resm(TINFO, "Detected %s using kernel version %s", + cur_dist_name, kver); + return tst_kvexcmp(vers[i].extra_ver, kver); + } + } + + return tst_kvcmp(kver, r1, r2, r3); +} diff --git a/ltp/lib/tst_memutils.c b/ltp/lib/tst_memutils.c new file mode 100644 index 0000000000000000000000000000000000000000..e49684ba1e97fb6437fbffba2262c1bdcc261e80 --- /dev/null +++ b/ltp/lib/tst_memutils.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 SUSE LLC + * Copyright (c) Linux Test Project, 2021-2023 + */ + +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_memutils.h" +#include "tst_capability.h" +#include "tst_safe_stdio.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; + size_t min_free; + void **map_blocks; + struct sysinfo info; + + SAFE_FILE_SCANF("/proc/sys/vm/min_free_kbytes", "%zi", &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), 128L * 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((long long)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; +} + +long long tst_available_swap(void) +{ + unsigned long long swap_available = 0; + + FILE_LINES_SCANF("/proc/meminfo", "SwapFree: %llu", &swap_available); + + return swap_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) { + fclose(f); + 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); +} + +int tst_mapping_in_range(unsigned long low, unsigned long high) +{ + FILE *fp; + + fp = SAFE_FOPEN("/proc/self/maps", "r"); + + while (!feof(fp)) { + unsigned long start, end; + int ret; + + ret = fscanf(fp, "%lx-%lx %*[^\n]\n", &start, &end); + if (ret != 2) { + fclose(fp); + tst_brk(TBROK | TERRNO, "Couldn't parse /proc/self/maps line."); + } + + if ((start >= low) && (start < high)) { + fclose(fp); + return 1; + } + if ((end >= low) && (end < high)) { + fclose(fp); + return 1; + } + } + + fclose(fp); + return 0; +} diff --git a/ltp/lib/tst_mkfs.c b/ltp/lib/tst_mkfs.c new file mode 100644 index 0000000000000000000000000000000000000000..736324f042e375a8eddabebb535502a3d85186f7 --- /dev/null +++ b/ltp/lib/tst_mkfs.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2013-2016 Cyril Hrubis + * + * 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 . + */ + +#include "test.h" +#include "ltp_priv.h" +#include "tst_mkfs.h" +#include "tst_device.h" + +#define OPTS_MAX 32 + +void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), + const char *dev, const char *fs_type, + const char *const fs_opts[], const char *const extra_opts[]) +{ + int i, pos = 1, ret; + char mkfs[64]; + const char *argv[OPTS_MAX] = {mkfs}; + char fs_opts_str[1024] = ""; + char extra_opts_str[1024] = ""; + + if (!dev) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "No device specified"); + return; + } + + if (!fs_type) { + 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; + } + + snprintf(mkfs, sizeof(mkfs), "mkfs.%s", fs_type); + + if (fs_opts) { + for (i = 0; fs_opts[i]; i++) { + argv[pos++] = fs_opts[i]; + + if (pos + 2 > OPTS_MAX) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Too many mkfs options"); + return; + } + + if (i) + strcat(fs_opts_str, " "); + strcat(fs_opts_str, fs_opts[i]); + } + } + + argv[pos++] = dev; + + if (extra_opts) { + for (i = 0; extra_opts[i]; i++) { + argv[pos++] = extra_opts[i]; + + if (pos + 1 > OPTS_MAX) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Too many mkfs options"); + return; + } + + if (i) + strcat(extra_opts_str, " "); + strcat(extra_opts_str, extra_opts[i]); + } + } + + argv[pos] = NULL; + + if (tst_clear_device(dev)) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "tst_clear_device() failed"); + } + + 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); + + switch (ret) { + case 0: + break; + case 255: + tst_brkm_(file, lineno, TCONF, cleanup_fn, + "%s not found in $PATH", mkfs); + break; + default: + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "%s failed with exit code %i", mkfs, ret); + } +} + +const char *tst_dev_fs_type(void) +{ + const char *fs_type; + + fs_type = getenv("LTP_DEV_FS_TYPE"); + + if (fs_type) + return fs_type; + + return DEFAULT_FS_TYPE; +} diff --git a/ltp/lib/tst_module.c b/ltp/lib/tst_module.c new file mode 100644 index 0000000000000000000000000000000000000000..42d63ede65cb5b77570da428aa46b463c5c2d369 --- /dev/null +++ b/ltp/lib/tst_module.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) Linux Test Project, 2016-2024 + * + * 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 would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Alexey Kodanev + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "test.h" +#include "tst_kconfig.h" +#include "ltp_priv.h" +#include "old_module.h" + +void tst_module_exists_(void (cleanup_fn)(void), + const char *mod_name, char **mod_path) +{ + /* check current working directory */ + if (access(mod_name, F_OK) == 0) { + if (mod_path != NULL) + *mod_path = strdup(mod_name); + return; + } + char *buf = NULL; + int err = -1; + /* check LTP installation path */ + const char *ltproot = getenv("LTPROOT"); + if (ltproot != NULL) { + if (asprintf(&buf, "%s/testcases/bin/%s", + ltproot, mod_name) == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "asprintf failed at %s:%d", + __FILE__, __LINE__); + return; + } + err = access(buf, F_OK); + } + /* check start working directory */ + if (err == -1 && tst_tmpdir_created()) { + free(buf); + if (asprintf(&buf, "%s/%s", tst_get_startwd(), + mod_name) == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "asprintf failed at %s:%d", + __FILE__, __LINE__); + return; + } + err = access(buf, F_OK); + } + + if (err != 0) { + free(buf); + tst_brkm(TCONF, cleanup_fn, "Failed to find module '%s'", + mod_name); + return; + } + + if (mod_path != NULL) + *mod_path = buf; + else + free(buf); +} + +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); + + const int offset = 2; /* command name & module path */ + int size = 0; + while (argv && argv[size]) + ++size; + size += offset; + const char *mod_argv[size + 1]; /* + NULL in the end */ + mod_argv[size] = NULL; + mod_argv[0] = "insmod"; + mod_argv[1] = mod_path; + + int i; + for (i = offset; i < size; ++i) + mod_argv[i] = argv[i - offset]; + + tst_cmd(cleanup_fn, mod_argv, NULL, NULL, 0); + free(mod_path); +} + +void tst_module_unload_(void (cleanup_fn)(void), const char *mod_name) +{ + int i, rc; + + const char *const argv[] = { "rmmod", mod_name, NULL }; + + rc = 1; + for (i = 0; i < 50; i++) { + rc = tst_cmd(NULL, argv, "/dev/null", "/dev/null", + TST_CMD_PASS_RETVAL); + if (!rc) + break; + + usleep(20000); + } + + if (rc) { + tst_brkm(TBROK, cleanup_fn, + "could not unload %s module", mod_name); + } +} + +bool tst_module_signature_enforced_(void) +{ + struct tst_kcmdline_var params = TST_KCMDLINE_INIT("module.sig_enforce"); + struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_MODULE_SIG_FORCE"); + int rc; + + tst_kcmdline_parse(¶ms, 1); + tst_kconfig_read(&kconfig, 1); + + rc = params.found || kconfig.choice == 'y'; + tst_resm(TINFO, "module signature enforcement: %s", rc ? "on" : "off"); + + return rc; +} + +void tst_requires_module_signature_disabled_(void) +{ + if (tst_module_signature_enforced_()) + tst_brkm(TCONF, NULL, "module signature is enforced, skip test"); +} + +void tst_modprobe(const char *mod_name, char *const argv[]) +{ + const int offset = 2; /* command name & module path */ + int i, size = 0; + + while (argv && argv[size]) + ++size; + size += offset; + + const char *mod_argv[size + 1]; /* + NULL in the end */ + + mod_argv[size] = NULL; + mod_argv[0] = "modprobe"; + mod_argv[1] = mod_name; + + for (i = offset; i < size; ++i) + mod_argv[i] = argv[i - offset]; + + tst_cmd(NULL, mod_argv, NULL, NULL, 0); +} + +void tst_module_reload(const char *mod_name, char *const argv[]) +{ + tst_resm(TINFO, "Reloading kernel module %s", mod_name); + tst_module_unload_(NULL, mod_name); + tst_modprobe(mod_name, argv); +} diff --git a/ltp/lib/tst_net.c b/ltp/lib/tst_net.c new file mode 100644 index 0000000000000000000000000000000000000000..a97e25b1137af9fb09543961f7155e33bd74bc52 --- /dev/null +++ b/ltp/lib/tst_net.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2019 Petr Vorel + * Copyright (c) 2019 Martin Doucha + */ + +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_net.h" +#include "tst_private.h" +#include "lapi/sched.h" + +void tst_print_svar(const char *name, const char *val) +{ + if (name && val) + printf("export %s=\"%s\"\n", name, val); +} + +void tst_print_svar_change(const char *name, const char *val) +{ + if (name && val) + printf("export %s=\"${%s:-%s}\"\n", name, name, val); +} + +/* + * Function bit_count is from ipcalc project, ipcalc.c. + */ +static int tst_bit_count(uint32_t i) +{ + int c = 0; + unsigned int seen_one = 0; + + while (i > 0) { + if (i & 1) { + seen_one = 1; + c++; + } else { + if (seen_one) + return -1; + } + i >>= 1; + } + + return c; +} + +/* + * Function mask2prefix is from ipcalc project, ipcalc.c. + */ +static int tst_mask2prefix(struct in_addr mask) +{ + return tst_bit_count(ntohl(mask.s_addr)); +} + +/* + * Function ipv4_mask_to_int is from ipcalc project, ipcalc.c. + */ +static int tst_ipv4_mask_to_int(const char *prefix) +{ + int ret; + struct in_addr in; + + ret = inet_pton(AF_INET, prefix, &in); + if (ret == 0) + return -1; + + return tst_mask2prefix(in); +} + +/* + * Function safe_atoi is from ipcalc project, ipcalc.c. + */ +static int tst_safe_atoi(const char *s, int *ret_i) +{ + char *x = NULL; + long l; + + errno = 0; + l = strtol(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((long)(int)l != l) + return -ERANGE; + + *ret_i = (int)l; + + return 0; +} + +/* + * Function get_prefix use code from ipcalc project, str_to_prefix/ipcalc.c. + */ +int tst_get_prefix(const char *ip_str, int is_ipv6) +{ + char *prefix_str = NULL; + int prefix = -1, r; + + prefix_str = strchr(ip_str, '/'); + if (!prefix_str) + return -1; + + *(prefix_str++) = '\0'; + + if (!is_ipv6 && strchr(prefix_str, '.')) + prefix = tst_ipv4_mask_to_int(prefix_str); + else { + r = tst_safe_atoi(prefix_str, &prefix); + if (r != 0) + tst_brk_comment("conversion error: '%s' is not integer", + prefix_str); + } + + if (prefix < 0 || ((is_ipv6 && prefix > MAX_IPV6_PREFIX) || + (!is_ipv6 && prefix > MAX_IPV4_PREFIX))) + tst_brk_comment("bad %s prefix: %s", is_ipv6 ? "IPv6" : "IPv4", + prefix_str); + + return prefix; +} + +void tst_get_in_addr(const char *ip_str, struct in_addr *ip) +{ + if (inet_pton(AF_INET, ip_str, ip) <= 0) + tst_brk_comment("bad IPv4 address: '%s'", ip_str); +} + +void tst_get_in6_addr(const char *ip_str, struct in6_addr *ip6) +{ + if (inet_pton(AF_INET6, ip_str, ip6) <= 0) + tst_brk_comment("bad IPv6 address: '%s'", ip_str); +} + +socklen_t tst_get_connect_address(int sock, struct sockaddr_storage *addr) +{ + struct sockaddr_in *inet_ptr; + struct sockaddr_in6 *inet6_ptr; + size_t tmp_size; + socklen_t ret = sizeof(*addr); + + SAFE_GETSOCKNAME(sock, (struct sockaddr*)addr, &ret); + + /* Sanitize wildcard addresses */ + switch (addr->ss_family) { + case AF_INET: + inet_ptr = (struct sockaddr_in*)addr; + + switch (ntohl(inet_ptr->sin_addr.s_addr)) { + case INADDR_ANY: + case INADDR_BROADCAST: + inet_ptr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + break; + } + + break; + + case AF_INET6: + inet6_ptr = (struct sockaddr_in6*)addr; + tmp_size = sizeof(struct in6_addr); + + if (!memcmp(&inet6_ptr->sin6_addr, &in6addr_any, tmp_size)) { + memcpy(&inet6_ptr->sin6_addr, &in6addr_loopback, + tmp_size); + } + + break; + } + + return ret; +} + +void tst_init_sockaddr_inet(struct sockaddr_in *sa, const char *ip_str, uint16_t port) +{ + memset(sa, 0, sizeof(struct sockaddr_in)); + sa->sin_family = AF_INET; + sa->sin_port = htons(port); + tst_get_in_addr(ip_str, &sa->sin_addr); +} + +void tst_init_sockaddr_inet_bin(struct sockaddr_in *sa, uint32_t ip_val, uint16_t port) +{ + memset(sa, 0, sizeof(struct sockaddr_in)); + sa->sin_family = AF_INET; + sa->sin_port = htons(port); + sa->sin_addr.s_addr = htonl(ip_val); +} + +void tst_init_sockaddr_inet6(struct sockaddr_in6 *sa, const char *ip_str, uint16_t port) +{ + memset(sa, 0, sizeof(struct sockaddr_in6)); + sa->sin6_family = AF_INET6; + sa->sin6_port = htons(port); + tst_get_in6_addr(ip_str, &sa->sin6_addr); +} + +void tst_init_sockaddr_inet6_bin(struct sockaddr_in6 *sa, const struct in6_addr *ip_val, uint16_t port) +{ + memset(sa, 0, sizeof(struct sockaddr_in6)); + sa->sin6_family = AF_INET6; + sa->sin6_port = htons(port); + memcpy(&sa->sin6_addr, ip_val, sizeof(struct in6_addr)); +} + +void safe_getaddrinfo(const char *file, const int lineno, const char *src_addr, + const char *port, const struct addrinfo *hints, + struct addrinfo **addr_info) +{ + int err = getaddrinfo(src_addr, port, hints, addr_info); + + if (err) { + tst_brk_(file, lineno, TBROK, "getaddrinfo failed, %s", + gai_strerror(err)); + } + + if (!*addr_info) + tst_brk_(file, lineno, TBROK, "failed to get the address"); +} + +void tst_setup_netns(void) +{ + int real_uid = getuid(); + int real_gid = getgid(); + int nscount = 1; + + if (!access("/proc/sys/user/max_user_namespaces", F_OK)) { + SAFE_FILE_SCANF("/proc/sys/user/max_user_namespaces", "%d", + &nscount); + } + + if (!nscount) + tst_brk(TCONF, "User namespaces are disabled"); + + SAFE_UNSHARE(CLONE_NEWUSER); + SAFE_UNSHARE(CLONE_NEWNET); + SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); + SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid); + SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid); +} diff --git a/ltp/lib/tst_netdevice.c b/ltp/lib/tst_netdevice.c new file mode 100644 index 0000000000000000000000000000000000000000..1042466bf7e46d10fcb4748f35bd60220ffb8245 --- /dev/null +++ b/ltp/lib/tst_netdevice.c @@ -0,0 +1,642 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Linux Test Project + */ + +#include +#include +#include +#include +#include +#include "lapi/rtnetlink.h" + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_netlink.h" +#include "tst_netdevice.h" + +static struct tst_netlink_context *create_request(const char *file, + const int lineno, unsigned int type, unsigned int flags, + const void *payload, size_t psize) +{ + struct tst_netlink_context *ctx; + struct nlmsghdr header = { + .nlmsg_type = type, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags, + }; + + ctx = tst_netlink_create_context(file, lineno, NETLINK_ROUTE); + + if (!ctx) + return NULL; + + if (!tst_netlink_add_message(file, lineno, ctx, &header, payload, + psize)) { + tst_netlink_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, int strict, + const char *ifname1, const char *ifname2) +{ + int ret; + struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; + struct tst_netlink_context *ctx; + struct tst_netlink_attr_list peerinfo[] = { + {IFLA_IFNAME, ifname2, strlen(ifname2) + 1, NULL}, + {0, NULL, -1, NULL} + }; + struct tst_netlink_attr_list peerdata[] = { + {VETH_INFO_PEER, &info, sizeof(info), peerinfo}, + {0, NULL, -1, NULL} + }; + struct tst_netlink_attr_list attrs[] = { + {IFLA_IFNAME, ifname1, strlen(ifname1) + 1, NULL}, + {IFLA_LINKINFO, NULL, 0, (const struct tst_netlink_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_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_netlink_send_validate(file, lineno, ctx); + tst_netlink_destroy_context(file, lineno, ctx); + + if (strict && !ret) { + tst_brk_(file, lineno, TBROK, + "Failed to create veth interfaces %s+%s: %s", ifname1, + ifname2, tst_strerrno(tst_netlink_errno)); + } + + return ret; +} + +int tst_netdev_add_device(const char *file, const int lineno, int strict, + const char *ifname, const char *devtype) +{ + int ret; + struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; + struct tst_netlink_context *ctx; + struct tst_netlink_attr_list attrs[] = { + {IFLA_IFNAME, ifname, strlen(ifname) + 1, NULL}, + {IFLA_LINKINFO, NULL, 0, (const struct tst_netlink_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_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_netlink_send_validate(file, lineno, ctx); + tst_netlink_destroy_context(file, lineno, ctx); + + if (strict && !ret) { + tst_brk_(file, lineno, TBROK, + "Failed to create %s device %s: %s", devtype, ifname, + tst_strerrno(tst_netlink_errno)); + } + + return ret; +} + +int tst_netdev_remove_device(const char *file, const int lineno, int strict, + const char *ifname) +{ + struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; + struct tst_netlink_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_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_netlink_send_validate(file, lineno, ctx); + tst_netlink_destroy_context(file, lineno, ctx); + + if (strict && !ret) { + tst_brk_(file, lineno, TBROK, + "Failed to remove netdevice %s: %s", ifname, + tst_strerrno(tst_netlink_errno)); + } + + return ret; +} + +static int modify_address(const char *file, const int lineno, int strict, + 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_netlink_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_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + if (!tst_rtnl_add_attr(file, lineno, ctx, IFA_LOCAL, address, + addrlen)) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_netlink_send_validate(file, lineno, ctx); + tst_netlink_destroy_context(file, lineno, ctx); + + if (strict && !ret) { + tst_brk_(file, lineno, TBROK, + "Failed to modify %s network address: %s", ifname, + tst_strerrno(tst_netlink_errno)); + } + + return ret; +} + +int tst_netdev_add_address(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, const void *address, + unsigned int prefix, size_t addrlen, unsigned int flags) +{ + return modify_address(file, lineno, strict, 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, int strict, + const char *ifname, in_addr_t address, unsigned int prefix, + unsigned int flags) +{ + return tst_netdev_add_address(file, lineno, strict, ifname, AF_INET, + &address, prefix, sizeof(address), flags); +} + +int tst_netdev_remove_address(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, const void *address, + size_t addrlen) +{ + return modify_address(file, lineno, strict, RTM_DELADDR, 0, ifname, + family, address, 0, addrlen, 0); +} + +int tst_netdev_remove_address_inet(const char *file, const int lineno, + int strict, const char *ifname, in_addr_t address) +{ + return tst_netdev_remove_address(file, lineno, strict, ifname, AF_INET, + &address, sizeof(address)); +} + +static int change_ns(const char *file, const int lineno, int strict, + const char *ifname, unsigned short attr, uint32_t value) +{ + struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; + struct tst_netlink_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 (!ctx) + return 0; + + if (!tst_rtnl_add_attr_string(file, lineno, ctx, IFLA_IFNAME, ifname)) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + if (!tst_rtnl_add_attr(file, lineno, ctx, attr, &value, + sizeof(uint32_t))) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_netlink_send_validate(file, lineno, ctx); + tst_netlink_destroy_context(file, lineno, ctx); + + if (strict && !ret) { + tst_brk_(file, lineno, TBROK, + "Failed to move %s to another namespace: %s", ifname, + tst_strerrno(tst_netlink_errno)); + } + + return ret; +} + +int tst_netdev_change_ns_fd(const char *file, const int lineno, int strict, + const char *ifname, int nsfd) +{ + return change_ns(file, lineno, strict, ifname, IFLA_NET_NS_FD, nsfd); +} + +int tst_netdev_change_ns_pid(const char *file, const int lineno, int strict, + const char *ifname, pid_t nspid) +{ + return change_ns(file, lineno, strict, ifname, IFLA_NET_NS_PID, nspid); +} + +static int modify_route(const char *file, const int lineno, int strict, + 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_netlink_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 (!ctx) + return 0; + + if (srcaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_SRC, srcaddr, + srclen)) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + if (dstaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_DST, dstaddr, + dstlen)) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + if (gateway && !tst_rtnl_add_attr(file, lineno, ctx, RTA_GATEWAY, + gateway, gatewaylen)) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + if (ifname && !tst_rtnl_add_attr(file, lineno, ctx, RTA_OIF, &index, + sizeof(index))) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_netlink_send_validate(file, lineno, ctx); + tst_netlink_destroy_context(file, lineno, ctx); + + if (strict && !ret) { + tst_brk_(file, lineno, TBROK, + "Failed to modify network route: %s", + tst_strerrno(tst_netlink_errno)); + } + + return ret; +} + +static int modify_route_inet(const char *file, const int lineno, int strict, + 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, strict, action, flags, ifname, + AF_INET, src, srcprefix, srclen, dst, dstprefix, dstlen, gw, + gwlen); +} + +int tst_netdev_add_route(const char *file, const int lineno, int strict, + 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, strict, 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, int strict, + 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, strict, 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, int strict, + 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, strict, 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, + int strict, 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, strict, RTM_DELROUTE, 0, ifname, + srcaddr, srcprefix, dstaddr, dstprefix, gateway); +} + +static int modify_qdisc(const char *file, const int lineno, int strict, + const char *object, unsigned int action, unsigned int nl_flags, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, unsigned int info, const char *qd_kind, + const struct tst_netlink_attr_list *config) +{ + struct tst_netlink_context *ctx; + int ret; + struct tcmsg msg = { + .tcm_family = family, + .tcm_handle = handle, + .tcm_parent = parent, + .tcm_info = info + }; + + if (!qd_kind) { + tst_brk_(file, lineno, TBROK, + "Queueing discipline name required"); + return 0; + } + + if (ifname) { + msg.tcm_ifindex = tst_netdev_index_by_name(file, lineno, + ifname); + + if (msg.tcm_ifindex < 0) { + tst_brk_(file, lineno, TBROK, "Interface %s not found", + ifname); + return 0; + } + } + + ctx = create_request(file, lineno, action, nl_flags, &msg, sizeof(msg)); + + if (!ctx) + return 0; + + if (!tst_rtnl_add_attr_string(file, lineno, ctx, TCA_KIND, qd_kind)) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + if (config && !tst_rtnl_add_attr_list(file, lineno, ctx, config)) { + tst_netlink_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_netlink_send_validate(file, lineno, ctx); + tst_netlink_destroy_context(file, lineno, ctx); + + if (strict && !ret) { + tst_brk_(file, lineno, TBROK, + "Failed to modify %s: %s", object, + tst_strerrno(tst_netlink_errno)); + } + + return ret; +} + +int tst_netdev_add_qdisc(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, const char *qd_kind, + const struct tst_netlink_attr_list *config) +{ + return modify_qdisc(file, lineno, strict, "queueing discipline", + RTM_NEWQDISC, NLM_F_CREATE | NLM_F_EXCL, ifname, family, + parent, handle, 0, qd_kind, config); +} + +int tst_netdev_remove_qdisc(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, const char *qd_kind) +{ + return modify_qdisc(file, lineno, strict, "queueing discipline", + RTM_DELQDISC, 0, ifname, family, parent, handle, 0, qd_kind, + NULL); +} + +int tst_netdev_add_traffic_class(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, const char *qd_kind, + const struct tst_netlink_attr_list *config) +{ + return modify_qdisc(file, lineno, strict, "traffic class", + RTM_NEWTCLASS, NLM_F_CREATE | NLM_F_EXCL, ifname, AF_UNSPEC, + parent, handle, 0, qd_kind, config); +} + +int tst_netdev_remove_traffic_class(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, const char *qd_kind) +{ + return modify_qdisc(file, lineno, strict, "traffic class", + RTM_DELTCLASS, 0, ifname, AF_UNSPEC, parent, handle, 0, + qd_kind, NULL); +} + +int tst_netdev_add_traffic_filter(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, unsigned int protocol, unsigned int priority, + const char *f_kind, const struct tst_netlink_attr_list *config) +{ + return modify_qdisc(file, lineno, strict, "traffic filter", + RTM_NEWTFILTER, NLM_F_CREATE | NLM_F_EXCL, ifname, AF_UNSPEC, + parent, handle, TC_H_MAKE(priority << 16, htons(protocol)), + f_kind, config); +} + +int tst_netdev_remove_traffic_filter(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, unsigned int protocol, unsigned int priority, + const char *f_kind) +{ + return modify_qdisc(file, lineno, strict, "traffic filter", + RTM_DELTFILTER, 0, ifname, AF_UNSPEC, parent, handle, + TC_H_MAKE(priority << 16, htons(protocol)), f_kind, NULL); +} diff --git a/ltp/lib/tst_netlink.c b/ltp/lib/tst_netlink.c new file mode 100644 index 0000000000000000000000000000000000000000..d61cc8b886f22bbf17ec31750951da7316912526 --- /dev/null +++ b/ltp/lib/tst_netlink.c @@ -0,0 +1,499 @@ +// 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_netlink.h" + +struct tst_netlink_context { + int socket; + pid_t pid; + uint32_t seq; + size_t bufsize, datalen; + char *buffer; + struct nlmsghdr *curmsg; +}; + +int tst_netlink_errno; + +static int netlink_grow_buffer(const char *file, const int lineno, + struct tst_netlink_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_netlink_destroy_context(const char *file, const int lineno, + struct tst_netlink_context *ctx) +{ + if (!ctx) + return; + + safe_close(file, lineno, NULL, ctx->socket); + free(ctx->buffer); + free(ctx); +} + +struct tst_netlink_context *tst_netlink_create_context(const char *file, + const int lineno, int protocol) +{ + struct tst_netlink_context *ctx; + struct sockaddr_nl addr = { .nl_family = AF_NETLINK }; + + ctx = safe_malloc(file, lineno, NULL, + sizeof(struct tst_netlink_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, protocol); + + if (ctx->socket < 0) { + free(ctx); + return NULL; + } + + if (safe_bind(file, lineno, NULL, ctx->socket, (struct sockaddr *)&addr, + sizeof(addr))) { + tst_netlink_destroy_context(file, lineno, ctx); + return NULL; + } + + ctx->buffer = safe_malloc(file, lineno, NULL, ctx->bufsize); + + if (!ctx->buffer) { + tst_netlink_destroy_context(file, lineno, ctx); + return NULL; + } + + memset(ctx->buffer, 0, ctx->bufsize); + + return ctx; +} + +void tst_netlink_free_message(struct tst_netlink_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_netlink_send(const char *file, const int lineno, + struct tst_netlink_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_netlink_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_netlink_wait(struct tst_netlink_context *ctx) +{ + struct pollfd fdinfo = { + .fd = ctx->socket, + .events = POLLIN + }; + + return poll(&fdinfo, 1, 1000); +} + +struct tst_netlink_message *tst_netlink_recv(const char *file, + const int lineno, struct tst_netlink_context *ctx) +{ + char tmp, *tmpbuf, *buffer = NULL; + struct tst_netlink_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_netlink_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_netlink_add_message(const char *file, const int lineno, + struct tst_netlink_context *ctx, const struct nlmsghdr *header, + const void *payload, size_t payload_size) +{ + size_t size; + unsigned int extra_flags = 0; + + if (!netlink_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_netlink_add_attr(const char *file, const int lineno, + struct tst_netlink_context *ctx, unsigned short type, + const void *data, unsigned short len) +{ + size_t size = NLA_HDRLEN + NLA_ALIGN(len); + struct nlattr *attr; + + if (!ctx->curmsg) { + tst_brk_(file, lineno, TBROK, + "%s(): No message to add attributes to", __func__); + return 0; + } + + if (!netlink_grow_buffer(file, lineno, ctx, size)) + return 0; + + size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len); + attr = (struct nlattr *)(((char *)ctx->curmsg) + size); + attr->nla_type = type; + attr->nla_len = NLA_HDRLEN + len; + memcpy(((char *)attr) + NLA_HDRLEN, data, len); + ctx->curmsg->nlmsg_len = size + attr->nla_len; + ctx->datalen = NLMSG_ALIGN(ctx->datalen) + attr->nla_len; + + return 1; +} + +int tst_netlink_add_attr_string(const char *file, const int lineno, + struct tst_netlink_context *ctx, unsigned short type, + const char *data) +{ + return tst_netlink_add_attr(file, lineno, ctx, type, data, + strlen(data) + 1); +} + +int tst_netlink_add_attr_list(const char *file, const int lineno, + struct tst_netlink_context *ctx, + const struct tst_netlink_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_netlink_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_netlink_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_add_attr(const char *file, const int lineno, + struct tst_netlink_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 (!netlink_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_netlink_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_netlink_context *ctx, + const struct tst_netlink_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_netlink_check_acks(const char *file, const int lineno, + struct tst_netlink_context *ctx, struct tst_netlink_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->err && res->err->error) && + res->header->nlmsg_seq != msg->nlmsg_seq) + res++; + + if (res->err && res->err->error) { + tst_netlink_errno = -res->err->error; + return 0; + } + + if (!res->header || res->header->nlmsg_seq != msg->nlmsg_seq) { + tst_brk_(file, lineno, TBROK, + "No ACK found for Netlink message %u", + msg->nlmsg_seq); + return 0; + } + } + + return 1; +} + +int tst_netlink_send_validate(const char *file, const int lineno, + struct tst_netlink_context *ctx) +{ + struct tst_netlink_message *response; + int ret; + + tst_netlink_errno = 0; + + if (tst_netlink_send(file, lineno, ctx) <= 0) + return 0; + + tst_netlink_wait(ctx); + response = tst_netlink_recv(file, lineno, ctx); + + if (!response) + return 0; + + ret = tst_netlink_check_acks(file, lineno, ctx, response); + tst_netlink_free_message(response); + + return ret; +} diff --git a/ltp/lib/tst_parse_opts.c b/ltp/lib/tst_parse_opts.c new file mode 100644 index 0000000000000000000000000000000000000000..94970e1a868e996931ef662334f8441ad97222a4 --- /dev/null +++ b/ltp/lib/tst_parse_opts.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 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. + */ + +#include "test.h" +#include "ltp_priv.h" + +void tst_parse_opts(int argc, char *argv[], const option_t *user_optarg, + void (*user_help)(void)) +{ + const char *msg; + + msg = parse_opts(argc, argv, user_optarg, user_help); + + if (msg) + tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); +} diff --git a/ltp/lib/tst_path_exists.c b/ltp/lib/tst_path_exists.c new file mode 100644 index 0000000000000000000000000000000000000000..333c4b0e55cfcd620c17894fd555a1f23dc6180b --- /dev/null +++ b/ltp/lib/tst_path_exists.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2011-2021 + * Copyright (c) Cyril Hrubis 2024 + */ + +#include +#include +#include +#include +#include "tst_fs.h" + +int tst_path_exists(const char *fmt, ...) +{ + va_list ap; + char pathbuf[PATH_MAX]; + + va_start(ap, fmt); + vsnprintf(pathbuf, sizeof(pathbuf), fmt, ap); + va_end(ap); + + return access(pathbuf, F_OK) == 0; +} diff --git a/ltp/lib/tst_path_has_mnt_flags.c b/ltp/lib/tst_path_has_mnt_flags.c new file mode 100644 index 0000000000000000000000000000000000000000..154bf4126eaab9bd06c8f264689002e1ab9c411f --- /dev/null +++ b/ltp/lib/tst_path_has_mnt_flags.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014 Fujitsu Ltd. + * Author: Xing Gu + * + * 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. + * + * 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. + */ + +#include +#include +#include +#include +#include "test.h" + +/* + * Check whether a path is on a filesystem that is mounted with + * specified flags. + */ +int tst_path_has_mnt_flags_(void (cleanup_fn)(void), + const char *path, const char *flags[]) +{ + struct mntent *mnt; + size_t prefix_max = 0, prefix_len; + int flags_matched = 0; + FILE *f; + int i; + char *tmpdir = NULL; + + /* + * Default parameter is test temporary directory + */ + if (path == NULL) + path = tmpdir = tst_get_tmpdir(); + + if (access(path, F_OK) == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "tst_path_has_mnt_flags: path %s doesn't exist", path); + return -1; + } + + f = setmntent("/proc/mounts", "r"); + if (f == NULL) { + tst_brkm(TBROK | TERRNO, cleanup_fn, + "tst_path_has_mnt_flags: failed to open /proc/mounts"); + return -1; + } + + while ((mnt = getmntent(f))) { + /* ignore duplicit record for root fs */ + if (!strcmp(mnt->mnt_fsname, "rootfs")) + continue; + + prefix_len = strlen(mnt->mnt_dir); + + if (strncmp(path, mnt->mnt_dir, prefix_len) == 0 + && prefix_len > prefix_max) { + prefix_max = prefix_len; + flags_matched = 0; + i = 0; + + while (flags[i] != NULL) { + if (hasmntopt(mnt, flags[i]) != NULL) + flags_matched++; + i++; + } + } + } + + endmntent(f); + + free(tmpdir); + + return flags_matched; +} diff --git a/ltp/lib/tst_pid.c b/ltp/lib/tst_pid.c new file mode 100644 index 0000000000000000000000000000000000000000..4e9dc7a5269628745772eb2e7de9c0d244f22ddf --- /dev/null +++ b/ltp/lib/tst_pid.c @@ -0,0 +1,173 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved. + * + * 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 + */ + +#include +#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" +#include "lapi/syscalls.h" + +#define PID_MAX_PATH "/proc/sys/kernel/pid_max" +#define THREADS_MAX_PATH "/proc/sys/kernel/threads-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)) +{ + pid_t pid; + + SAFE_FILE_SCANF(cleanup_fn, PID_MAX_PATH, "%d", &pid); + + 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; +} + +static int get_used_pids(void (*cleanup_fn) (void)) +{ + DIR *dir_proc; + struct dirent *ent; + char status_path[PATH_MAX]; + int used_threads, used_pids = 0; + + dir_proc = SAFE_OPENDIR("/proc"); + + while ((ent = SAFE_READDIR(dir_proc))) { + if (isdigit(ent->d_name[0])) { + snprintf(status_path, sizeof(status_path), "/proc/%s/status", ent->d_name); + if (!FILE_LINES_SCANF(cleanup_fn, status_path, "Threads: %d", &used_threads)) + used_pids += used_threads; + } + } + + SAFE_CLOSEDIR(dir_proc); + + return used_pids; +} + +int tst_get_free_pids_(void (*cleanup_fn) (void)) +{ + int max_pids, max_session_pids, max_threads, used_pids = get_used_pids(cleanup_fn); + + SAFE_FILE_SCANF(cleanup_fn, PID_MAX_PATH, "%d", &max_pids); + SAFE_FILE_SCANF(cleanup_fn, THREADS_MAX_PATH, "%d", &max_threads); + max_pids = MIN(max_pids, max_threads); + + 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; +} + +pid_t tst_getpid(void) +{ + return syscall(SYS_getpid); +} + +pid_t tst_gettid(void) +{ + return syscall(SYS_gettid); +} diff --git a/ltp/lib/tst_process_state.c b/ltp/lib/tst_process_state.c new file mode 100644 index 0000000000000000000000000000000000000000..033af2023f3e36f209bfe734062373f03aa22b40 --- /dev/null +++ b/ltp/lib/tst_process_state.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2014 Cyril Hrubis chrubis@suse.cz + * Copyright (c) 2021 Xie Ziyao + */ + +#include +#include +#include + +#include "test.h" +#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) +{ + char proc_path[128], cur_state; + unsigned int msecs = 0; + + snprintf(proc_path, sizeof(proc_path), "/proc/%i/stat", pid); + + for (;;) { + safe_file_scanf(file, lineno, cleanup_fn, proc_path, + "%*[^)]%*c %c", &cur_state); + + if (state == cur_state) + break; + + usleep(1000); + msecs += 1; + + if (msec_timeout && msecs >= msec_timeout) { + errno = ETIMEDOUT; + return -1; + } + } + + return 0; +} + +int tst_process_state_wait2(pid_t pid, const char state) +{ + char proc_path[128], cur_state; + + snprintf(proc_path, sizeof(proc_path), "/proc/%i/stat", pid); + + for (;;) { + FILE *f = fopen(proc_path, "r"); + + if (!f) { + fprintf(stderr, "Failed to open '%s': %s\n", + proc_path, strerror(errno)); + return 1; + } + + if (fscanf(f, "%*[^)]%*c %c", &cur_state) != 1) { + fclose(f); + fprintf(stderr, "Failed to read '%s': %s\n", + proc_path, strerror(errno)); + return 1; + } + fclose(f); + + if (state == cur_state) + return 0; + + 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/ltp/lib/tst_rand_data.c b/ltp/lib/tst_rand_data.c new file mode 100644 index 0000000000000000000000000000000000000000..2543f966081498bd26c4843c9bca9eab4c13e266 --- /dev/null +++ b/ltp/lib/tst_rand_data.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "tst_rand_data.h" + +const size_t tst_rand_data_len = 4096; +const char *const tst_rand_data = +"\xa5\xf8\xde\x82\x8a\x94\x8d\xa0\x02\x67\x79\x53\xf9\x77\x34\x69\x8d\xdb\xe6\xfc" +"\xa2\xca\x15\xd0\x6d\x0c\xc2\x53\x88\xef\x2c\xd9\x9c\x03\x9c\xff\x3f\xff\x43\x87" +"\x32\x33\x72\x4a\x8b\xc1\xb9\x32\xcc\x63\x3d\xe6\x60\xfb\x3b\x42\x41\xab\xde\x0e" +"\xe5\x0a\xcd\x57\x09\xee\x53\x52\x6a\x98\x64\xae\xac\x53\x0a\x7c\x51\x12\xc4\xfe" +"\x03\x34\xf9\x00\xcc\x04\x43\xe3\x9f\x72\x4f\xbc\xa1\x4e\x30\xa4\xac\xda\xdd\x11" +"\x14\xf3\x3d\x9d\xaa\x35\x11\x66\x2c\x32\x67\xe4\xcb\xc3\xbe\x16\x61\xc3\x9d\xfe" +"\xad\x88\x12\x9b\x75\x26\xdb\x55\x5d\x3e\xfd\x0e\xd0\x05\x69\x38\x08\x9f\xf3\xa2" +"\x32\x15\x9c\xcb\x47\x30\x42\xff\x4d\x5c\x86\xda\xb7\x77\x4e\x77\x74\x28\xe1\xe6" +"\xe2\xde\x4d\x27\xe7\x88\xbc\xc7\x57\x99\x79\x60\xd3\xd9\xb3\x0b\x15\x0d\xd4\xb8" +"\xaa\x78\x7b\x17\x85\xf6\xa9\x7f\xdb\x17\x7c\x4b\xfc\x9d\xd3\xc2\x7b\xef\x1e\xb0" +"\xbd\x31\xfe\x69\x3e\xdf\x94\x55\x03\xcf\xc9\x9f\xbf\x04\xdf\x9e\xfc\x78\xb1\xa1" +"\xf6\x00\x94\xff\x1e\x71\x4e\xca\xd7\x92\xe1\xa4\x58\x42\x12\xc7\x25\x15\x2a\xd8" +"\x27\x44\xcf\x71\xce\x72\x13\x41\x5a\x6d\x71\x55\x95\x16\xab\x54\x84\x2f\xfe\xc3" +"\x0f\xc6\xef\x39\x8b\x66\xaf\x8f\x0f\x33\xd6\x1f\xe2\x47\x86\xdf\xac\x1b\x2e\x9c" +"\xeb\x9a\x4d\x0a\x86\xb3\x5b\x08\x13\xdf\x47\x41\x6b\x71\x9e\x68\xc0\xbf\xdd\x51" +"\x26\xa2\x61\x1e\xdc\x78\x32\x61\x86\xe4\xcf\x89\x41\x98\x56\xe1\x3f\xe3\x9c\x49" +"\x56\x6a\xf1\x9c\x84\x22\x02\xaf\xdd\x9a\xa2\x98\x39\x2b\xea\x88\xd9\x42\x0e\x63" +"\x80\xdb\x64\xfd\xdd\x34\xe4\x01\x48\xce\xee\xf3\x8e\xae\x81\xf0\x39\x74\x6e\xeb" +"\xc7\x60\x58\x4e\xce\x31\x69\x36\xed\x4a\x52\xae\x5d\x6f\x27\xdf\x46\xa8\xdd\x5e" +"\x0a\xdb\x4f\x06\xa4\x21\xc7\x9d\x96\x70\x7c\xfc\xcf\x55\x20\xff\x10\xac\x12\xd9" +"\x22\x58\x18\x7c\x8e\x6c\x3b\x05\x8f\x69\xd3\x15\x6e\x64\x72\xc5\x2a\xef\x97\xd1" +"\xa3\xf1\xc5\xf1\xb8\x66\x37\xc4\x4d\x69\xea\x4e\x53\xa8\x85\xc7\x5e\xf6\xf9\x55" +"\x5f\xf9\x74\xcb\x39\x1b\xd1\x56\x88\x54\xd4\x29\xfa\xfc\xcf\x74\xd3\xcc\x5d\x4a" +"\xb4\x3e\x78\xf5\xa4\x3a\x6d\x74\x6e\x46\x5f\xa3\x2e\xe1\xb9\x78\x35\xad\x67\x5b" +"\xe4\x0c\xf6\x6e\xff\x24\x2c\x9a\x3a\xff\xb9\x43\x1b\x92\xe2\x66\xc0\x80\x1c\x13" +"\x03\x97\xd1\x8e\xc0\x17\x24\x14\x71\x16\x35\x92\x5e\x27\x34\x6e\xc0\x07\xb5\xaf" +"\xc9\xc6\xc0\x50\x28\xe7\xf1\xd2\x34\x1d\x8c\x66\x9a\xb5\xc9\x5c\xf7\xd7\x72\x0b" +"\x20\x37\x5b\x22\xfa\xa2\xa0\x3c\xe4\x04\x05\x67\x76\x0b\x75\x10\xd6\x9c\xd2\x9b" +"\x96\x6d\xec\x93\xb8\x26\x8b\xf7\x71\x84\x3e\xf5\x58\x26\x0f\x62\x17\x0c\xa0\x89" +"\x56\x30\xba\xa5\x5d\xb6\x94\x85\x71\xbe\xb8\x71\x02\x5b\xe1\x4d\xf0\x25\x52\x3a" +"\xd8\x36\xb9\xe0\x2f\x6b\x3b\x3d\x96\x56\x27\x75\x17\x44\x37\x42\xba\x86\x90\x4c" +"\x1a\xf3\xcd\xc5\x81\x88\xc5\xa4\x3b\xac\x3e\xd3\x2d\xdf\xed\xab\xe3\x42\x03\xed" +"\xbf\x11\x8d\x78\xc2\x83\x1a\xed\x97\xe9\x06\x61\x46\xb4\xc2\xa7\xf2\xcb\x96\xa4" +"\xb4\xcb\x1f\x42\x93\x03\xd7\x26\x76\xba\x36\x74\x98\x59\x5a\x26\xe5\x19\xf9\xcd" +"\xc2\x36\xb2\xbb\x77\x4c\x3b\x53\x7d\x98\xb5\x02\xde\x70\xa9\x7e\x07\xa2\x56\x7b" +"\x43\x4d\xdb\x4d\xc4\x02\xfc\x5e\x82\xf8\xcc\x78\x09\x9f\x49\x52\x56\xbe\x3e\x26" +"\x7a\x97\xef\x50\x6b\xe1\x4a\x3d\xb2\xe1\xac\xae\x3a\x4b\x8f\xf0\x4d\xd7\x7b\x7e" +"\x77\x62\x36\xba\xfc\xad\xeb\x68\x2a\x92\xe1\x1c\xa6\xeb\x23\x97\x01\xa0\xc5\xb0" +"\x3c\xd8\xd4\x7e\x08\xcd\x25\x67\xe6\xa5\xf6\x82\xb7\x31\x74\xf7\x4a\x3a\x86\x91" +"\xe9\x8c\x31\x47\x2c\x77\x17\xfa\xc8\x98\xd2\xa9\xa8\x39\x12\x1a\x59\x6e\x2a\x86" +"\x72\x71\x9d\x9d\x77\xd9\x27\xac\xb1\xa5\x8b\x41\xca\x4c\x9a\x0d\xac\xfc\xd8\xb9" +"\x32\xcf\x77\xef\x8f\xf6\x49\xba\x8f\x16\x40\x5c\x51\x5d\xcd\x47\x76\x3f\x08\xdd" +"\x51\x66\x17\xa7\xa6\xba\x6a\x54\xce\x55\x80\x73\xd5\xdf\x22\x98\x4e\xb5\x64\x3d" +"\x71\xb6\xeb\x85\xe0\x93\xdc\xe9\x16\xa1\xfb\x77\xa5\xbc\x88\x62\x62\x9e\x9e\x24" +"\xb2\x3b\xa2\x6b\x18\x7b\xbc\xaa\x2e\xb4\xc1\x3a\x26\x63\x9f\x40\x33\x49\xe1\x4d" +"\x23\xae\x53\x87\xfb\xaa\x41\x52\xea\x9e\xdb\x36\xee\x35\x3d\xaa\xe5\x54\x8d\x1b" +"\x0d\x87\xfd\xc2\x13\xf6\x0d\x7f\xe1\x73\x98\x8a\x9d\xe3\x4f\xec\xa0\xf1\xa6\x49" +"\xa0\x0d\x98\xc9\xd2\x97\x0f\xb5\x84\x90\x26\xcb\x49\xc7\x44\x32\xa9\x13\xbd\x64" +"\x98\xf0\x29\xeb\x8a\x4a\x36\x00\x8c\xed\x6b\x47\x68\x01\x65\xfc\x33\x9d\xd6\xc3" +"\x57\xf2\x60\x0c\xaa\xf1\x22\x30\x94\x70\xcb\x77\xe8\xa5\x77\xf9\xa3\x7a\x49\x71" +"\x60\x8b\x4e\xa3\xd3\x21\x6d\xc4\xdb\x45\x75\x54\xb2\x65\xdf\xc6\x42\xc2\x6b\xab" +"\x4e\xc4\xef\x80\xe3\xaa\x79\x2c\x77\x5c\x6e\x7f\x1a\x52\xfc\x1c\x32\x6d\xff\x39" +"\x91\xc5\x17\x57\x00\x19\xb9\xf2\x11\x69\xcb\x34\xa1\xdb\x4f\xc9\x8a\xee\x2d\xac" +"\x4e\x99\xe2\x0f\xdc\x14\xc9\x1c\x02\x6a\xab\xf3\xa5\xdb\x65\x6e\xd6\xcd\x70\xa8" +"\x48\xfc\x41\xb9\x86\x0c\x01\xfc\x5e\x5e\x98\xa0\x66\xf3\xbf\xcc\x0c\x76\xf0\x20" +"\x6d\x97\xf0\x81\xd7\x7c\x64\x6d\xf9\x48\x62\x7c\x54\xfa\x06\x83\x63\x76\x07\x12" +"\x67\x7f\x1f\x7e\x84\x8c\x2c\xe0\x8e\xcf\xe6\xa3\x7d\x26\xc0\x1f\x2e\x3a\xd2\x04" +"\xbc\x17\x0f\x28\x79\xff\xa5\xf0\x52\x98\xa4\x3c\x02\x44\x3e\xcb\x4d\xe5\xb8\x60" +"\x2b\x63\x16\x9c\xc2\x58\x41\xd1\xff\x01\x6b\xbe\x73\xd5\x1e\x01\x2e\x89\x58\x6a" +"\x25\xf7\x33\xdc\x90\xe8\x05\x07\x54\x3e\x7c\xfe\x45\x27\x1b\xc0\x34\xbb\x1d\x3b" +"\x59\x13\xe3\xb0\x4e\xc7\xc7\x32\xe5\x54\xe8\x74\xcc\x93\x36\x98\x91\x75\x32\x36" +"\xda\x5b\x37\xe4\xa0\x91\x77\x16\xa5\xa9\x65\x72\x8b\x28\xe4\x3d\x44\xc2\x20\xa1" +"\xce\x07\x00\x78\x0d\x0d\xf0\x87\x1b\x1b\x0b\xc2\xb4\x44\xb2\x7d\x36\xef\x01\x12" +"\xd4\xdd\x02\x69\x70\x72\xe7\x9f\x0d\x63\xbc\x00\xe3\xbc\x04\xb3\xa1\xa2\xd0\x3a" +"\x88\xd5\xb3\x14\x96\x78\xa4\x29\x31\x44\x0a\xf2\xdf\xe9\x33\x3d\x77\x5d\x63\x1b" +"\x67\xc2\xa8\xc9\xe8\x27\x18\xed\xf6\xfd\x35\xf8\xff\x0f\x96\x8e\x27\x76\x4c\x4a" +"\x63\x80\x01\xe8\x6a\x90\x14\x3d\x71\xf7\xa8\xf1\xfd\x46\x53\x75\x0c\xd6\x57\xff" +"\x33\x43\x9e\xb9\xb2\x83\x1c\x8d\x91\x0e\x4c\xc2\x6d\x3c\xcc\xf9\xe9\xfd\xbe\xd4" +"\x51\xb8\xe4\xc4\x43\xc9\xd7\x92\x71\x5c\xbc\x91\x7e\x0a\xd3\x6a\x83\xf0\xa9\x1b" +"\x72\x6a\xd0\x4c\x92\xc5\x10\x86\xfe\x36\x59\x71\x28\x95\xaa\x8a\xdb\x6c\x8c\xdd" +"\x9e\x3f\xf7\xa8\xfd\x14\xd0\x81\xd6\xf0\x37\x65\x72\x4e\x27\xee\x4a\x8b\xa5\xac" +"\xe4\x4e\xd3\xe3\xd1\xf6\xfb\x45\x19\x26\xf2\x72\xd3\xe2\x5e\x8b\xe9\x1d\xcf\x47" +"\x06\xe8\x02\x6b\xdf\xbe\xe3\x01\x74\x3d\xfe\xc9\x41\x04\x6c\xe6\x3c\x96\x59\x37" +"\x82\xc7\x2a\x55\x8c\xf3\x93\x6e\xa8\x83\xed\xea\x32\x59\x26\xc8\xec\xd2\x76\x36" +"\x39\xd7\x2c\x04\x88\x75\x32\x5a\xec\x62\x6a\x01\xa9\xb8\x9d\x0a\x30\x7e\xab\xe6" +"\x7d\xfb\x54\x4c\x79\xe6\x2d\x89\xbd\x53\x48\xdb\x42\x1b\x76\x09\x40\x54\x6c\x28" +"\x9c\x45\x09\x2e\xb1\xc9\x3a\x2e\x32\x0e\xcf\xe3\xbf\xf0\xa9\xf8\x7a\xe1\x02\xc2" +"\xed\x7d\x46\xe8\xee\x22\xd9\x5b\x86\xa0\x53\x5b\x0f\xd8\x0f\x1b\x7e\x75\x07\xe6" +"\xa4\x7d\xe2\x21\x0e\x09\x47\x85\x1c\xe5\x78\xd4\xad\x2d\xee\xac\xfd\x48\x7d\xd2" +"\xab\xb0\xb7\x4e\xba\x4c\x80\x5d\xed\xd3\x5a\x9b\xde\x68\xb4\xd7\x72\xbc\xa3\x1f" +"\xbf\xa2\x15\x1b\x13\x5c\x6c\xce\x53\xf4\xc9\x50\xf8\xa0\xde\xcf\x9e\xe3\x1c\xc7" +"\x8e\x4c\xab\xe9\xfc\x3e\x23\xe9\x30\xb3\x32\x06\xd4\x28\xc7\xae\x3b\xdc\x0c\xf6" +"\xdd\xc4\x56\xb6\xfd\x70\xb4\xc7\xff\xf1\xd9\x5b\x17\x7f\x0c\xa4\x85\x7d\x52\xcf" +"\xbd\x4e\xb9\xd5\xd6\x55\xb5\x23\x1c\x20\x4a\x5b\xfc\x75\x89\x34\x5e\x13\x63\xae" +"\x66\x7a\x65\x83\x35\x4f\xf6\x94\xa9\xc4\xab\xb7\x21\x66\x9d\x88\xb3\xe4\xe3\x18" +"\xb6\xb2\x4a\x6a\x39\x53\x3b\xee\x39\x58\xe3\x28\x33\xab\xcc\x0a\x58\x2d\x12\xe3" +"\x58\x26\x50\x36\x7d\xee\xb0\xe7\x36\x0f\x18\x88\x8d\x94\xc1\xe7\x68\xea\x34\x07" +"\x90\x12\xc6\x16\x68\xd5\x93\x71\x4a\x52\xc6\x83\x8a\x36\x89\x50\x63\x93\x1f\xd5" +"\x29\xaa\x27\x60\x2c\x0b\x96\x38\x91\x4a\x72\x5c\xb0\xd0\x2a\x25\xb8\x4d\x75\xa1" +"\xfe\x6f\x01\x25\x74\x7d\xed\xd7\x55\x2f\x49\xff\x2a\x59\x50\xc2\xfc\xb9\xfd\x7e" +"\x8f\x2b\x92\x6f\x94\xc9\x69\x26\x8f\x5f\xeb\x0c\x47\x59\x6a\xbb\x44\x8f\x24\x16" +"\x94\xab\xb1\x57\x8b\x38\x37\xa1\x7c\x5c\x14\x47\x13\x39\x6e\x8d\x8f\x42\xd4\xb2" +"\xb3\xbe\x42\xbb\x79\x7a\xd4\xdf\xda\x10\x59\xb8\xbd\x50\x1e\x91\x51\x12\xf0\x38" +"\xd4\xed\xaf\xec\x83\x77\x88\xaa\xc6\xb5\xb6\x15\xa4\xf2\xcb\x30\x3a\xbe\x50\x68" +"\x82\xc3\x81\x84\xc3\xfe\x0b\xbf\x10\x2b\x30\xcd\x08\xf1\x88\x0d\xbd\x16\xe0\x07" +"\x0f\x28\x0e\xf7\x40\xd4\x6f\x5f\xcc\xfb\x6b\x60\x63\x7b\xbc\x75\xa0\xc6\xb3\x73" +"\xd2\xb2\xd8\x07\x49\xda\x3b\xd9\xd6\x68\x17\xcc\xa0\xab\xd8\x3a\x5d\x08\xeb\x3e" +"\xd6\x73\xac\x69\x78\x6e\x29\xff\x43\x72\x8c\x2c\x77\x01\x72\xd2\x70\x99\xc1\xbf" +"\x48\x05\x0c\xa9\x2d\x79\x4a\x7f\xcc\x12\x4a\xfb\x96\x41\x3b\xf0\x55\xf6\x8a\xf5" +"\xe2\x70\xf8\xf4\xcb\x1e\x80\x0a\x82\xc1\x7b\x90\x71\x78\xf6\xf0\x07\x78\xbd\x1a" +"\xf0\x7a\x4b\x2e\x13\xd6\x69\x57\x08\x2a\x6f\x89\xf7\x5a\x60\xb7\xce\xbd\xba\x2d" +"\xd6\x4f\xb9\xfb\x0a\xb2\xa4\x6d\x00\xb2\x77\x0c\xcd\xdc\xf4\x8d\x7d\xd8\x3b\xe8" +"\x34\x7b\x0d\x50\x7e\xe9\xa3\x53\x6c\xd7\x7a\xc9\xc3\xf7\xa8\x26\x59\xf5\x32\x96" +"\x31\x9d\xc8\x2a\x16\x7a\x38\x84\x3d\xf2\x2b\x27\x6a\x97\xf1\x72\x56\x39\xdd\x36" +"\x26\x12\x80\x08\x91\x69\x44\x9d\xc1\xca\x8a\x1d\x67\x15\x01\x8a\x25\xde\xe6\xde" +"\x81\x53\x3a\x3e\x69\xa0\x1c\x1a\x47\x5d\x61\x1d\x2c\x9e\x43\x97\x98\x9b\xe2\xf1" +"\xa6\x4a\x4b\x50\x19\x01\xb6\xfc\x15\x53\x88\x1e\x18\x86\x5b\xf5\x4d\x3e\x5d\x07" +"\x93\xcf\xb9\xa4\x7e\x7f\x82\xe6\xae\xb6\xb1\xb0\xe9\x07\xb1\x94\x92\x5c\x3e\x51" +"\x8d\x51\x9d\xaa\xb7\xb3\xb7\x9d\x4d\x7d\x79\x34\x3b\xea\x88\xa6\x67\x12\xf6\xfe" +"\xa2\xd3\x35\x1c\x81\xe8\x6e\xc2\xa3\x23\x95\x57\x87\x12\x4b\x3b\xc8\xd7\x2a\xfb" +"\x64\xc8\xab\x23\xdd\x64\x80\xbf\x21\xca\x32\xf8\xf3\xdb\x23\x45\x6a\x52\x00\x11" +"\xae\x84\x3c\xe0\x55\x0a\xd1\x78\xff\x16\x4f\x06\xc2\xa6\x16\x94\x45\xeb\xf7\x82" +"\x1a\x1c\x81\x82\x4e\x60\x1f\xde\x7b\x6f\xfc\x3e\x03\xb3\x59\x46\x5a\x34\x8f\x92" +"\x97\x48\x37\xcd\x64\xea\x0e\x22\x72\xf5\x2a\x38\x68\xc9\xd7\x3b\xb1\x66\xf1\xc8" +"\x80\x53\xcd\xb3\xd9\x22\x5b\x9c\x3d\x71\xae\x9e\xe6\xca\x9f\x32\xc6\x38\x28\x6a" +"\x02\xb4\x70\xf4\x01\xfa\x73\x35\x91\x9a\x7b\x88\xf3\x7f\x8f\xdc\xff\x40\x1e\xeb" +"\x91\x0b\xfe\x18\xa3\xf9\x83\x55\xd2\x2b\x7c\x32\xc5\x58\xc6\xd9\xeb\xdc\x63\xee" +"\xd5\x85\x67\x3e\x48\xc9\x77\x85\x6d\x6e\x68\xd9\x6b\xbe\x56\x8a\x2f\xa1\xfb\xac" +"\xaf\x92\xc9\x9f\xcc\x74\x57\x5c\xce\x95\x24\x6a\x69\xf7\xf6\xe2\x5c\xdf\xe8\x51" +"\x59\x7c\xeb\x5d\xdb\xee\x23\xcf\x06\xfd\x41\x61\x7c\x0c\x68\xfc\x0d\x3c\x31\xbc" +"\x21\x47\x30\x8e\x40\xc7\xd5\xf7\x38\x59\xef\x04\xfd\x48\x93\xf6\xa1\x4d\x31\x41" +"\x25\xf4\xe0\x14\xbe\xd4\xd9\xe5\x09\x0f\xd4\xd8\x14\x01\xe2\xf2\xe5\x63\x92\xea" +"\x09\xdf\x04\x73\x0f\x1b\x2f\x53\xd4\xf7\xab\xc4\xce\x5c\x69\x08\x66\x51\x96\xc4" +"\xeb\xe1\xc1\x1e\x2f\xe7\x66\xb9\x6b\x2f\x04\xe2\x91\x5d\xcf\x56\x6a\x92\x93\x82" +"\xa4\x6f\x9c\xc4\xe2\x51\x5b\xfb\xba\xd9\x07\x56\x2f\xa8\xb8\x9c\x1d\x2c\x72\x8d" +"\xd4\xcd\x81\x3a\x34\x04\x05\x4d\x1b\xdc\x4d\x06\xf8\x30\xb1\x53\x22\xd8\x5a\xc8" +"\xf2\xbc\x28\x7f\x24\x25\x46\x4f\xfa\xb2\x2f\x14\x42\x9a\x5c\xe2\x54\xec\xed\x28" +"\x68\xc1\x0c\xf5\xcc\x59\x81\x05\x33\x1d\xee\x91\xb2\x29\xf0\x6c\x36\x21\x65\xb1" +"\x62\xf6\x05\x7e\xe2\x0f\xf4\x18\x88\x9f\x6b\xa9\xb7\x51\x7c\x30\xba\xb0\x12\xba" +"\xa9\x08\xdb\x3c\x03\xaf\x64\xcf\x14\x7a\xe6\xb0\xdf\x05\x61\xf2\xd5\x66\xce\x6d" +"\x5b\xcf\x4f\x34\xd0\xe9\xa4\xbb\x8e\xff\x12\xef\xf8\x46\x20\x85\xaa\x9a\xe0\xdf" +"\x15\x58\xbb\x3f\xee\xf0\x94\x83\x34\x8f\xd6\x59\x24\xe2\xbc\x06\x36\x8b\x6b\xd1" +"\x4b\x8b\xc6\x83\x48\x7d\xed\x7d\x89\x75\x89\x04\xf6\x04\xbf\xf6\x13\xad\xae\x32" +"\x0c\x6a\xc0\xde\xe0\xfd\x82\xc8\x21\xa1\xdb\xef\x7a\x4f\x82\xfc\x2f\xe2\x52\xe7" +"\x6c\xdd\x6f\xad\x76\x5f\x0c\xf3\x58\x7d\x22\x24\x43\xfa\x52\x90\xd2\x78\x3f\xdc" +"\xc9\xf4\x1c\x3f\x1c\xab\x68\x26\x7e\x97\x72\x0f\xd1\x14\x8e\xbb\xc7\xfc\xe9\x11" +"\x6b\xe2\x6b\xfd\x9c\xf0\x48\xcd\x35\xb6\xc2\x32\x78\xf1\xbc\x2d\x14\x2f\x43\xad" +"\x15\xee\xfa\xf7\xf8\x2b\x11\xc9\x8a\x3b\x96\xcc\xd9\x2d\x33\x67\xa5\xe3\x09\xe6" +"\xfe\x68\xd9\x44\x26\x71\xc8\x64\xd3\xf6\x43\x9e\xde\x53\xe9\x8b\x9f\x95\x10\x8e" +"\x06\x16\x46\x2f\xb2\xaa\xfc\x30\x5f\xc9\xe3\x34\xaa\x42\xbe\x6b\x91\x51\x0e\x1d" +"\x53\x1f\xa6\x4b\xe2\x4e\x2c\xd4\x3f\xd1\x4f\x63\x16\xae\x3c\x11\xf8\xbe\x06\xdf" +"\x35\x3a\xe1\x17\x50\xe6\xca\xfa\x07\x6b\x0d\x93\x23\xce\xe0\xf4\x81\x82\x7d\x7b" +"\xc2\x46\xab\x79\xd7\x43\xa4\x64\x3d\x41\xac\x9b\xd4\x6e\xf2\xaa\x4e\x15\x5b\x25" +"\x48\xa5\xc5\xa2\x92\x3f\xa0\x57\xcc\xfe\xa6\x16\x22\xd0\x4a\x8e\x3f\x42\x73\x10" +"\xe2\xc8\x6e\x32\xa1\xb3\x8d\xad\x10\x54\xc1\xf9\x1b\x7a\x42\x1b\xa6\xfb\x66\xf7" +"\x61\x5d\xee\x3d\x74\xd2\x8e\xf4\xb5\x68\xd7\x67\x06\x1d\xf2\xaa\x7c\x39\x8a\xa6" +"\x96\x64\x07\xec\x95\xb9\x94\x6c\x0d\xf5\x1d\x52\x46\x43\x2b\x9f\x08\x52\xa9\x3a" +"\x1f\x84\x32\x4a\xbd\x95\xae\x8e\xd5\x49\x39\xba\xa6\x05\x01\x6b\x68\xcf\xa0\x63" +"\x75\x86\xd6\x8a\xac\x45\xeb\x4b\xb6\x1f\xec\x38\xb7\xe7\x02\x44\x43\xdc\x3e\x22" +"\x03\x46\x30\xb9\xf0\x95\xdc\xdf\x99\xf6\x32\x40\x7f\x3d\xc3\x7a\xf7\x5c\xa9\x9e" +"\xe8\x4a\xf2\xab\x8f\x4b\xda\x06\xda\xcd\x5d\x4e\xfd\x4d\x6b\x71\x76\xe1\xe1\xdf" +"\x00\xc1\x11\x87\x48\xbd\x45\x1f\x7b\x6e\xd6\xa0\x55\x2d\x39\x6a\x2d\x72\x27\xbd" +"\x20\xd6\xb4\x24\x76\x89\x78\xf3\x74\xaa\x1d\x14\x73\x5d\x36\x59\xcb\xc3\x55\x37" +"\x48\xc8\xb6\x94\xed\xbb\x37\x89\xec\x8c\x75\xb1\x1f\x08\x10\xec\x54\x88\x34\x91" +"\x49\x00\xdd\xbe\xb5\x4b\xe6\xb5\xe9\x2b\x73\x67\x49\x86\xc6\x19\xa7\xb9\x3a\xb4" +"\x33\x49\x48\xd1\xba\x97\xcb\xda\x04\x8a\x5a\x1e\xae\x4c\xe8\xfa\xfc\x9d\x57\xd9" +"\x8f\xb7\x35\xf9\x47\x8a\x48\xbc\xb3\x9b\x42\x95\xa9\x6d\x01\xd5\x16\x38\xe0\x88" +"\xc5\x17\xa1\x6c\xf5\x83\x0d\xc8\xa0\x8d\x20\xf4\xae\xb3\x42\x8b\x41\xc3\x2c\x65" +"\x60\x92\x63\xb7\xaa\xd9\x73\xcb\xa8\xb1\x9d\x09\x14\x0d\xc9\x71\x5f\x67\x5a\x76" +"\xf8\x2f\xef\x82\x40\xc4\x6a\xee\x87\x3a\x84\x3c\x09\xfe\xce\x35\x8d\x51\x8b\xfe" +"\x1a\x7f\xe4\x48\xf9\x04\x81\xb5\x77\xb5\x3f\x13\x40\xd5\x5e\xb6\x95\xe4\x78\x93" +"\x4e\xf6\xf4\x58\x48\xf7\xdb\xc6\x96\xbe\x38\x36\x05\x08\xe7\x08\x50\xbe\x48\xcc" +"\xcc\x1b\x30\x4a\xef\x5c\x17\xb9\x62\x18\x40\xf6\x47\x11\x30\x2d\x4b\x9a\xf8\x05" +"\x9d\x4b\xfe\x19\x32\xb1\x95\xe7\x29\xaf\x79\x06\x93\x19\x62\x91\x28\x1c\xe1\x10" +"\x15\xde\xc8\x55\x4d\xb5\x4e\x0f\xdc\x9d\x15\x66\x1c\x96\x53\x7a\xce\x0b\x17\xf4" +"\x9e\xa8\xd4\x93\xc4\x94\xe2\x61\xbb\xbc\x6f\x5b\x1e\x93\x53\x2d\xe9\xe6\x79\x75" +"\x84\xd8\x17\x28\x17\x5e\x31\x3e\xe4\x82\x1c\x86\x07\x1a\x86\x08\x17\x02\x77\xe6" +"\x50\xe2\x5b\xd4\xc9\x29\xe0\x80\x46\xa4\xdb\x8d\xa9\x3d\x9a\xd6\x25\x15\xa4\x1e" +"\x9a\xa0\x58\xde\x5f\x6b\x9e\xaa\x05\xb1\x2d\x8e\xcf\xa3\x6a\x3e\xf6\xef\xc1\xf6" +"\xe3\xaf\x0f\x41\x94\x0e\x87\x6c\xf1\x21\xab\x31\xaa\x67\x23\x7b\xb6\xd9\xd6\x6e" +"\x35\x9f\x12\x05\x8e\xe4\xb7\xbd\x10\xe2\x3c\x4b\xc9\xe2\x77\x30\x49\x85\xb8\xa9" +"\xf1\xba\x06\x5f\x91\x60\xfd\x1e\xf3\x69\x88\x1f\x00\x5c\x59\x0e\xf8\x32\x11\x16" +"\xd8\x9a\xd8\xce\xdf\xd1\xcf\x34\xe8\x79\x1f\xbc\xa2\x30\x58\x3d\x1c\xf5\x9c\x30" +"\x5e\xea\x36\x97\x35\xd6\x1b\x3d\x0c\x25\xbc\xe9\xc5\xfc\xec\xd4\x86\x04\x13\xb3" +"\x1a\x0a\xd3\x0e\x16\xba\x0b\x36\x48\x99\x72\xe3\xe2\x01\xe5\xc0\x64\xce\x26\x72" +"\xf3\xca\x30\x6b\x6e\xee\xb8\x2c\x76\xd0\x25\xb7\xca\x5d\x97\xfd\xc8\x99\xdf\x51" +"\x5a\xd6\xb5\x0c\x86\xbc\x06\x26\x75\xd2\xff\x6f\x5c\x39\xe7\xe6\x9f\xdc\x87\x27" +"\x07\x48\x5c\x1f\x16\x29\x5b\xe0\x02\x2e\x27\xe8\x33\xae\xc1\x68\x39\x2c\x14\x90" +"\xed\x45\xa7\x33\xce\x6e\x17\x09\x74\x03\x9a\x3f\xd9\xa0\xe4\x9d\xbd\xb4\x7c\x7c" +"\x2a\x55\xc4\xce\x03\x03\x7e\xfb\x23\x63\x31\x1c\xf6\x47\x01\x34\x9c\x91\x74\x8a" +"\xe8\x78\x9c\xe3\x4a\x9e\x6e\x53\x63\x39\x7f\xbb\xb1\x09\xf6\x28\x05\x70\x2e\x46" +"\x24\x98\xd0\xc1\x20\x64\x57\xef\xfd\xb1\x29\xc6\x31\x01\x41\x70\xc7\xf6\xa8\x72" +"\xe6\xbe\xff\xc9\x19\x8d\xb6\xd6\xe0\x69\x40\xbc\x09\x14\x60\x88\x34\x8f\xba\x6c" +"\x6d\x75\xa9\x6a\x5d\x2a\x54\x99\xfa\xe8\xa8\x2a\x1e\x96\xef\x4a\xe9\x8d\xd8\xcb" +"\x34\x0a\xbd\x97\x90\x2a\xde\x50\x05\xdb\x78\x07\x39\x68\x20\xe8\x2d\x7a\x96\xa3" +"\x5c\xec\xa9\x24\x68\xa5\xc6\xf6\xba\xd9\x14\xa0\x83\x8d\xa6\x1d\x79\x78\x39\x94" +"\x62\x72\x38\xee\xc1\x76\xc1\xe0\xdc\xf4\x3c\xc6\x26\xfc\xac\xfb\x73\xc0\x17\x82" +"\x1b\x4b\x4c\xb6\x95\x65\x05\x54\x30\xa0\xca\xb6\x70\xfb\x72\xe6\x11\x9a\x49\xa2" +"\x92\xab\xda\x86\x25\x21\xa1\xce\x72\xf2\x51\xba\x82\x33\x42\x29\x8c\x83\x86\x6a" +"\x27\x54\xfd\xe7\x65\x47\x93\x54\xb6\xe4\x6e\xd2\xe7\xe5\x76\xea\x0c\xb4\xbe\xed" +"\x7d\xbe\x96\xe3\x81\xee\x69\x27\x50\x26\xf2\x5e\xf3\x5c\xcc\xf7\xca\xfd\x07\x92" +"\x08\x04\xd9\xbd\x4b\xab\x85\x63\x4c\x55\x81\xac\x6e\xd5\x7d\x22\x61\xae\x36\x54" +"\xb0\x81\xab\xca\x45\x39\x88\xd1\x28\xae\x19\xff\x08\x45\x3b\x7c\xc0\xb3\x62\xcd" +"\x43\x17\xaf\x72\xe5\x49\x47\x79\x92\x81\x96\x75\x2f\x1a\x76\xc9\x88\x86\xd4\x2b" +"\x06\x21\x0e\x02\x6a\x9f\xcb\x69\x7d\xe6\x5c\x89\xe6\x3e\x01\x89\x6a\x7e\x8e\x8d" +"\x5a\x59\x43\x36\x9c\xe7\x6c\x26\xc1\x60\x23\xd0\x86\xfb\x42\xb2\x56\xd2\xd4\xd6" +"\xc4\x8a\xb6\xc2\x7e\x45\x6c\xe5\x76\xda\x57\xd8\x8b\x76\x2b\xee\x88\x19\xd0\xff" +"\xf3\xaa\x3f\x86\x70\x53\x28\x57\x44\xde\xce\x2f\x88\x60\xf8\xbc\xb2\xbc\xca\xd7" +"\xc1\x65\xbd\x56\x6a\xa0\x63\x69\xcd\x26\xf7\x82\xe5\x43\x59\xb7\x5f\x52\xb1\xa5" +"\x30\xd1\x0d\x07\xc9\xcc\x79\x63\x3f\x00\x97\x28\xdd\x66\xd5\x3f\xe7\x7a\xc9\xe8" +"\xde\x53\x6a\xa6\x63\xb8\xf1\x91\xde\x53\xed\xe6\xb0\x56\xc9\x47\x14\xdb\x54\x1d" +"\x3f\xea\x87\x60\x59\x2c\x6f\x9f\x91\x00\x9e\x9b\x79\x5e\x7c\x3f\x33\x83\xe8\x57" +"\x8f\x8e\xe5\xa7\xc3\x26\x50\xf2\x76\xcd\xbc\x7d\x15\x42\x1f\x7a\x4c\x22\xce\x49" +"\x5b\xb9\xc4\xe1\xb0\xfa\xfa\x9f\x4c\xd7\x99\x19\x6b\xc9\xde\x32\x05\x27\x19\x33" +"\xf9\x47\x49\x2a\xf0\x29\x7d\x98\xb1\xf7\x81\x78\x36\x9a\x9b"; diff --git a/ltp/lib/tst_res.c b/ltp/lib/tst_res.c new file mode 100644 index 0000000000000000000000000000000000000000..f50c07271f5abdb3984bf91198c56e98382a19ec --- /dev/null +++ b/ltp/lib/tst_res.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * AUTHOR : Kent Rogers (from Dave Fenner's original) + * CO-PILOT : Rich Logan + * DATE STARTED : 05/01/90 (rewritten 1/96) + * Copyright (c) 2009-2016 Cyril Hrubis + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "safe_macros.h" +#include "usctest.h" +#include "ltp_priv.h" +#include "tst_ansi_color.h" + +long TEST_RETURN; +int TEST_ERRNO; +void *TST_RET_PTR; + +#define VERBOSE 1 +#define NOPASS 3 +#define DISCARD 4 + +#define MAXMESG 80 /* max length of internal messages */ +#define USERMESG 2048 /* max length of user message */ +#define TRUE 1 +#define FALSE 0 + +/* + * EXPAND_VAR_ARGS - Expand the variable portion (arg_fmt) of a result + * message into the specified string. + * + * NOTE (garrcoop): arg_fmt _must_ be the last element in each function + * argument list that employs this. + */ +#define EXPAND_VAR_ARGS(buf, arg_fmt, buf_len) do {\ + va_list ap; \ + assert(arg_fmt != NULL); \ + va_start(ap, arg_fmt); \ + vsnprintf(buf, buf_len, arg_fmt, ap); \ + va_end(ap); \ + assert(strlen(buf) > 0); \ +} while (0) + +#if !defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(__ANDROID__) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#endif + +#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +static pthread_mutex_t tmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#else +static pthread_mutex_t tmutex; + +__attribute__((constructor)) +static void init_tmutex(void) +{ + pthread_mutexattr_t mutattr = {0}; + + pthread_mutexattr_init(&mutattr); + pthread_mutexattr_settype(&mutattr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&tmutex, &mutattr); + pthread_mutexattr_destroy(&mutattr); +} +#endif + +static void check_env(void); +static void tst_condense(int tnum, int ttype, const char *tmesg); +static void tst_print(const char *tcid, int tnum, int ttype, const char *tmesg); + +static int T_exitval = 0; /* exit value used by tst_exit() */ +static int passed_cnt; +static int T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */ + /* NOPASS, DISCARD */ + +static char Warn_mesg[MAXMESG]; /* holds warning messages */ + +/* + * These are used for condensing output when NOT in verbose mode. + */ +static int Buffered = FALSE; /* TRUE if condensed output is currently */ + /* buffered (i.e. not yet printed) */ +static char *Last_tcid; /* previous test case id */ +static int Last_num; /* previous test case number */ +static int Last_type; /* previous test result type */ +static char *Last_mesg; /* previous test result message */ + +int tst_count = 0; + +/* + * These globals must be defined in the test. + */ +extern char *TCID; /* Test case identifier from the test source */ +extern int TST_TOTAL; /* Total number of test cases from the test */ + + +struct pair { + const char *name; + int val; +}; + +#define PAIR(def) [def] = {.name = #def, .val = def}, +#define STRPAIR(key, value) [key] = {.name = value, .val = key}, + +#define PAIR_LOOKUP(pair_arr, idx) do { \ + static char pair_str_buf__[16]; \ + if (idx < 0 || (size_t)idx >= ARRAY_SIZE(pair_arr) || \ + pair_arr[idx].name == NULL) { \ + snprintf(pair_str_buf__, sizeof(pair_str_buf__), "%i", idx); \ + return pair_str_buf__; \ + } \ + return pair_arr[idx].name; \ +} while (0) + +const char *strttype(int ttype) +{ + static const struct pair ttype_pairs[] = { + PAIR(TPASS) + PAIR(TFAIL) + PAIR(TBROK) + PAIR(TCONF) + PAIR(TWARN) + PAIR(TINFO) + }; + + PAIR_LOOKUP(ttype_pairs, TTYPE_RESULT(ttype)); +} + +#include "errnos.h" +#include "signame.h" + +static void tst_res__(const char *file, const int lineno, int ttype, + const char *arg_fmt, ...) +{ + pthread_mutex_lock(&tmutex); + + char tmesg[USERMESG]; + int len = 0; + int ttype_result = TTYPE_RESULT(ttype); + + if (ttype_result == TDEBUG) { + printf("%s: %i: TDEBUG is not supported\n", __func__, __LINE__); + abort(); + } + + if (file && (ttype_result != TPASS && ttype_result != TINFO)) + len = sprintf(tmesg, "%s:%d: ", file, lineno); + EXPAND_VAR_ARGS(tmesg + len, arg_fmt, USERMESG - len); + + /* + * Save the test result type by ORing ttype into the current exit + * value (used by tst_exit()). + */ + T_exitval |= ttype_result; + + if (ttype_result == TPASS) + passed_cnt++; + + check_env(); + + /* + * Set the test case number and print the results, depending on the + * display type. + */ + if (ttype_result == TWARN || ttype_result == TINFO) { + tst_print(TCID, 0, ttype, tmesg); + } else { + if (tst_count < 0) + tst_print(TCID, 0, TWARN, + "tst_res(): tst_count < 0 is not valid"); + + /* + * Process each display type. + */ + switch (T_mode) { + case DISCARD: + break; + case NOPASS: /* filtered by tst_print() */ + tst_condense(tst_count + 1, ttype, tmesg); + break; + default: /* VERBOSE */ + tst_print(TCID, tst_count + 1, ttype, tmesg); + break; + } + + tst_count++; + } + + pthread_mutex_unlock(&tmutex); +} + +static void tst_condense(int tnum, int ttype, const char *tmesg) +{ + int ttype_result = TTYPE_RESULT(ttype); + + /* + * If this result is the same as the previous result, return. + */ + if (Buffered == TRUE) { + if (strcmp(Last_tcid, TCID) == 0 && Last_type == ttype_result && + strcmp(Last_mesg, tmesg) == 0) + return; + + /* + * This result is different from the previous result. First, + * print the previous result. + */ + tst_print(Last_tcid, Last_num, Last_type, Last_mesg); + free(Last_tcid); + free(Last_mesg); + } + + /* + * If a file was specified, print the current result since we have no + * way of retaining the file contents for comparing with future + * results. Otherwise, buffer the current result info for next time. + */ + Last_tcid = malloc(strlen(TCID) + 1); + strcpy(Last_tcid, TCID); + Last_num = tnum; + Last_type = ttype_result; + Last_mesg = malloc(strlen(tmesg) + 1); + strcpy(Last_mesg, tmesg); + Buffered = TRUE; +} + +void tst_old_flush(void) +{ + NO_NEWLIB_ASSERT("Unknown", 0); + + pthread_mutex_lock(&tmutex); + + /* + * Print out last line if in NOPASS mode. + */ + if (Buffered == TRUE && T_mode == NOPASS) { + tst_print(Last_tcid, Last_num, Last_type, Last_mesg); + Buffered = FALSE; + } + + fflush(stdout); + + pthread_mutex_unlock(&tmutex); +} + +static void tst_print(const char *tcid, int tnum, int ttype, const char *tmesg) +{ + int err = errno; + const char *type; + int ttype_result = TTYPE_RESULT(ttype); + char message[USERMESG]; + size_t size = 0; + + /* + * Save the test result type by ORing ttype into the current exit value + * (used by tst_exit()). This is already done in tst_res(), but is + * also done here to catch internal warnings. For internal warnings, + * tst_print() is called directly with a case of TWARN. + */ + T_exitval |= ttype_result; + + /* + * If output mode is DISCARD, or if the output mode is NOPASS and this + * result is not one of FAIL, BROK, or WARN, just return. This check + * is necessary even though we check for DISCARD mode inside of + * tst_res(), since occasionally we get to this point without going + * through tst_res() (e.g. internal TWARN messages). + */ + if (T_mode == DISCARD || (T_mode == NOPASS && ttype_result != TFAIL && + ttype_result != TBROK + && ttype_result != TWARN)) + return; + + /* + * Build the result line and print it. + */ + type = strttype(ttype); + + if (T_mode == VERBOSE) { + size += snprintf(message + size, sizeof(message) - size, + "%-8s %4d ", tcid, tnum); + } else { + size += snprintf(message + size, sizeof(message) - size, + "%-8s %4d ", tcid, tnum); + } + + if (size >= sizeof(message)) { + printf("%s: %i: line too long\n", __func__, __LINE__); + abort(); + } + + if (tst_color_enabled(STDOUT_FILENO)) + size += snprintf(message + size, sizeof(message) - size, + "%s%s%s : %s", tst_ttype2color(ttype), type, ANSI_COLOR_RESET, tmesg); + else + size += snprintf(message + size, sizeof(message) - size, + "%s : %s", type, tmesg); + + if (size >= sizeof(message)) { + printf("%s: %i: line too long\n", __func__, __LINE__); + abort(); + } + + if (ttype & TERRNO) { + size += snprintf(message + size, sizeof(message) - size, + ": errno=%s(%i): %s", tst_strerrno(err), + err, strerror(err)); + } + + if (size >= sizeof(message)) { + printf("%s: %i: line too long\n", __func__, __LINE__); + abort(); + } + + if (ttype & TTERRNO) { + size += snprintf(message + size, sizeof(message) - size, + ": TEST_ERRNO=%s(%i): %s", + tst_strerrno(TEST_ERRNO), (int)TEST_ERRNO, + strerror(TEST_ERRNO)); + } + + if (size >= sizeof(message)) { + printf("%s: %i: line too long\n", __func__, __LINE__); + abort(); + } + + if (ttype & TRERRNO) { + err = TEST_RETURN < 0 ? -(int)TEST_RETURN : (int)TEST_RETURN; + size += snprintf(message + size, sizeof(message) - size, + ": TEST_RETURN=%s(%i): %s", + tst_strerrno(err), err, strerror(err)); + } + + if (size + 1 >= sizeof(message)) { + printf("%s: %i: line too long\n", __func__, __LINE__); + abort(); + } + + message[size] = '\n'; + message[size + 1] = '\0'; + + fputs(message, stdout); +} + +static void check_env(void) +{ + static int first_time = 1; + char *value; + + if (!first_time) + return; + + first_time = 0; + + /* BTOUTPUT not defined, use default */ + if ((value = getenv(TOUTPUT)) == NULL) { + T_mode = VERBOSE; + return; + } + + if (strcmp(value, TOUT_NOPASS_S) == 0) { + T_mode = NOPASS; + return; + } + + if (strcmp(value, TOUT_DISCARD_S) == 0) { + T_mode = DISCARD; + return; + } + + T_mode = VERBOSE; + return; +} + +void tst_exit(void) +{ + NO_NEWLIB_ASSERT("Unknown", 0); + + pthread_mutex_lock(&tmutex); + + tst_old_flush(); + + T_exitval &= ~TINFO; + + if (T_exitval == TCONF && passed_cnt) + T_exitval &= ~TCONF; + + exit(T_exitval); +} + +pid_t tst_fork(void) +{ + pid_t child; + + NO_NEWLIB_ASSERT("Unknown", 0); + + tst_old_flush(); + + child = fork(); + if (child == 0) + T_exitval = 0; + + return child; +} + +void tst_record_childstatus(void (*cleanup)(void), pid_t child) +{ + int status, ttype_result; + + NO_NEWLIB_ASSERT("Unknown", 0); + + SAFE_WAITPID(cleanup, child, &status, 0); + + if (WIFEXITED(status)) { + ttype_result = WEXITSTATUS(status); + ttype_result = TTYPE_RESULT(ttype_result); + T_exitval |= ttype_result; + + if (ttype_result == TPASS) + tst_resm(TINFO, "Child process returned TPASS"); + + if (ttype_result & TFAIL) + tst_resm(TINFO, "Child process returned TFAIL"); + + if (ttype_result & TBROK) + tst_resm(TINFO, "Child process returned TBROK"); + + if (ttype_result & TCONF) + tst_resm(TINFO, "Child process returned TCONF"); + + } else { + tst_brkm(TBROK, cleanup, "child process(%d) killed by " + "unexpected signal %s(%d)", child, + tst_strsig(WTERMSIG(status)), WTERMSIG(status)); + } +} + +/* + * Make tst_brk reentrant so that one can call the SAFE_* macros from within + * user-defined cleanup functions. + */ +static int tst_brk_entered = 0; + +static void tst_brk__(const char *file, const int lineno, int ttype, + void (*func)(void), const char *arg_fmt, ...) +{ + pthread_mutex_lock(&tmutex); + + char tmesg[USERMESG]; + int ttype_result = TTYPE_RESULT(ttype); + + EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG); + + /* + * Only FAIL, BROK, CONF, and RETR are supported by tst_brk(). + */ + if (ttype_result != TFAIL && ttype_result != TBROK && + ttype_result != TCONF) { + sprintf(Warn_mesg, "%s: Invalid Type: %d. Using TBROK", + __func__, ttype_result); + tst_print(TCID, 0, TWARN, Warn_mesg); + /* Keep TERRNO, TTERRNO, etc. */ + ttype = (ttype & ~ttype_result) | TBROK; + } + + tst_res__(file, lineno, ttype, "%s", tmesg); + if (tst_brk_entered == 0) { + if (ttype_result == TCONF) { + tst_res__(file, lineno, ttype, + "Remaining cases not appropriate for " + "configuration"); + } else if (ttype_result == TBROK) { + tst_res__(file, lineno, TBROK, + "Remaining cases broken"); + } + } + + /* + * If no cleanup function was specified, just return to the caller. + * Otherwise call the specified function. + */ + if (func != NULL) { + tst_brk_entered++; + (*func) (); + tst_brk_entered--; + } + if (tst_brk_entered == 0) + tst_exit(); + + pthread_mutex_unlock(&tmutex); +} + +void tst_resm_(const char *file, const int lineno, int ttype, + const char *arg_fmt, ...) +{ + char tmesg[USERMESG]; + + EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG); + + if (tst_test) + tst_res_(file, lineno, ttype, "%s", tmesg); + else + tst_res__(file, lineno, ttype, "%s", tmesg); +} + +typedef void (*tst_res_func_t)(const char *file, const int lineno, + int ttype, const char *fmt, ...); + +void tst_resm_hexd_(const char *file, const int lineno, int ttype, + const void *buf, size_t size, const char *arg_fmt, ...) +{ + char tmesg[USERMESG]; + static const size_t symb_num = 2; /* xx */ + static const size_t size_max = 16; + size_t offset; + size_t i; + char *pmesg = tmesg; + tst_res_func_t res_func; + + if (tst_test) + res_func = tst_res_; + else + res_func = tst_res__; + + EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG); + offset = strlen(tmesg); + + if (size > size_max || size == 0 || + (offset + size * (symb_num + 1)) >= USERMESG) + res_func(file, lineno, ttype, "%s", tmesg); + else + pmesg += offset; + + for (i = 0; i < size; ++i) { + /* add space before byte except first one */ + if (pmesg != tmesg) + *(pmesg++) = ' '; + + sprintf(pmesg, "%02x", ((unsigned char *)buf)[i]); + pmesg += symb_num; + if ((i + 1) % size_max == 0 || i + 1 == size) { + res_func(file, lineno, ttype, "%s", tmesg); + pmesg = tmesg; + } + } +} + +void tst_brkm__(const char *file, const int lineno, int ttype, + void (*func)(void), const char *arg_fmt, ...) +{ + char tmesg[USERMESG]; + + EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG); + + if (tst_test) { + if (func) { + tst_brk_(file, lineno, TBROK, + "Non-NULL cleanup in newlib!"); + } + + tst_brk_(file, lineno, ttype, "%s", tmesg); + } + + tst_brk__(file, lineno, ttype, func, "%s", tmesg); + + /* Shouldn't be reached, but fixes build time warnings about noreturn. */ + abort(); +} + +void tst_require_root(void) +{ + NO_NEWLIB_ASSERT("Unknown", 0); + + if (geteuid() != 0) + tst_brkm(TCONF, NULL, "Test needs to be run as root"); +} diff --git a/ltp/lib/tst_resource.c b/ltp/lib/tst_resource.c new file mode 100644 index 0000000000000000000000000000000000000000..c35d05a25bc8c552811c1e95924dd752fd524e8e --- /dev/null +++ b/ltp/lib/tst_resource.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2012 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. + */ + +#include +#include "test.h" +#include "old_resource.h" +#include "ltp_priv.h" + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +static pthread_mutex_t tmutex = PTHREAD_MUTEX_INITIALIZER; +static char dataroot[PATH_MAX]; +extern char *TCID; + +static void tst_dataroot_init(void) +{ + const char *ltproot = getenv("LTPROOT"); + char curdir[PATH_MAX]; + const char *startdir; + int ret; + + /* 1. if LTPROOT is set, use $LTPROOT/testcases/data/$TCID + * 2. else if startwd is set by tst_tmpdir(), use $STARWD/datafiles + * 3. else use $CWD/datafiles */ + if (ltproot) { + ret = snprintf(dataroot, PATH_MAX, "%s/testcases/data/%s", + ltproot, TCID); + } else { + startdir = tst_get_startwd(); + if (startdir[0] == 0) { + if (getcwd(curdir, PATH_MAX) == NULL) { + tst_brkm(TBROK | TERRNO, NULL, + "tst_dataroot getcwd"); + return; + } + startdir = curdir; + } + ret = snprintf(dataroot, PATH_MAX, "%s/datafiles", startdir); + } + + if (ret < 0 || ret >= PATH_MAX) + tst_brkm(TBROK, NULL, "tst_dataroot snprintf: %d", ret); +} + +const char *tst_dataroot(void) +{ + if (dataroot[0] == 0) { + pthread_mutex_lock(&tmutex); + if (dataroot[0] == 0) + tst_dataroot_init(); + pthread_mutex_unlock(&tmutex); + } + return dataroot; +} + +static int file_copy(const char *file, const int lineno, + void (*cleanup_fn)(void), const char *path, + const char *filename, const char *dest) +{ + size_t len = strlen(path) + strlen(filename) + 2; + char buf[len]; + + snprintf(buf, sizeof(buf), "%s/%s", path, filename); + + /* check if file exists */ + if (access(buf, R_OK)) + return 0; + + safe_cp(file, lineno, cleanup_fn, buf, dest); + + return 1; +} + +void tst_resource_copy(const char *file, const int lineno, + void (*cleanup_fn)(void), + const char *filename, const char *dest) +{ + if (!tst_tmpdir_created()) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Temporary directory doesn't exist"); + return; + } + + if (dest == NULL) + dest = "."; + + const char *ltproot = getenv("LTPROOT"); + const char *dataroot = tst_dataroot(); + + /* look for data files in $LTP_DATAROOT, $LTPROOT/testcases/bin + * and $CWD */ + if (file_copy(file, lineno, cleanup_fn, dataroot, filename, dest)) + return; + + if (ltproot != NULL) { + char buf[strlen(ltproot) + 64]; + + snprintf(buf, sizeof(buf), "%s/testcases/bin", ltproot); + + if (file_copy(file, lineno, cleanup_fn, buf, filename, dest)) + return; + } + + /* try directory test started in as last resort */ + const char *startwd = tst_get_startwd(); + if (file_copy(file, lineno, cleanup_fn, startwd, filename, dest)) + return; + + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Failed to copy resource '%s'", filename); +} diff --git a/ltp/lib/tst_rtctime.c b/ltp/lib/tst_rtctime.c new file mode 100644 index 0000000000000000000000000000000000000000..c62ac731d1510b9be924f1fa395b9b66ec7c76fe --- /dev/null +++ b/ltp/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/ltp/lib/tst_safe_file_at.c b/ltp/lib/tst_safe_file_at.c new file mode 100644 index 0000000000000000000000000000000000000000..257f70291ee76af7f89b3d618422cbf7355377b8 --- /dev/null +++ b/ltp/lib/tst_safe_file_at.c @@ -0,0 +1,240 @@ +// 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, ...) +{ + int fd; + mode_t mode = 0; + + if (TST_OPEN_NEEDS_MODE(oflags)) { + va_list ap; + + 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; +} + +int safe_fchownat(const char *const file, const int lineno, + const int dirfd, const char *const path, uid_t owner, gid_t group, int flags) +{ + int rval; + + rval = fchownat(dirfd, path, owner, group, flags); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "fchownat(%d<%s>, '%s', %d, %d, %d) failed", dirfd, + tst_decode_fd(dirfd), path, owner, group, flags); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid fchownat(%d<%s>, '%s', %d, %d, %d) return value %d", + dirfd, tst_decode_fd(dirfd), path, owner, group, flags, rval); + } + + return rval; +} + +int safe_fstatat(const char *const file, const int lineno, + const int dirfd, const char *const path, struct stat *statbuf, int flags) +{ + int rval; + + rval = fstatat(dirfd, path, statbuf, flags); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "fstatat(%d<%s>, '%s', %p, %d) failed", dirfd, + tst_decode_fd(dirfd), path, statbuf, flags); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid fstatat(%d<%s>, '%s', %p, %d) return value %d", + dirfd, tst_decode_fd(dirfd), path, statbuf, flags, rval); + } + + return rval; +} diff --git a/ltp/lib/tst_safe_io_uring.c b/ltp/lib/tst_safe_io_uring.c new file mode 100644 index 0000000000000000000000000000000000000000..de6869f5015557a126a5ed988a0cd9479de628bb --- /dev/null +++ b/ltp/lib/tst_safe_io_uring.c @@ -0,0 +1,111 @@ +// 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) { + if (errno == EOPNOTSUPP) + tst_brk(TCONF, "CONFIG_IO_URING is not enabled"); + + 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/ltp/lib/tst_safe_macros.c b/ltp/lib/tst_safe_macros.c new file mode 100644 index 0000000000000000000000000000000000000000..cdc8c7dd33cb0f805d40095b732d723497b2adeb --- /dev/null +++ b/ltp/lib/tst_safe_macros.c @@ -0,0 +1,831 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) 2017-2024 Linux Test Project + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "config.h" +#ifdef HAVE_SYS_FANOTIFY_H +# include +#endif +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "lapi/setns.h" +#include "tst_safe_macros.h" +#include "lapi/personality.h" +#include "lapi/pidfd.h" + +int safe_access(const char *file, const int lineno, + const char *pathname, int mode) +{ + int rval; + + rval = access(pathname, mode); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "access(%s,%d) failed", pathname, mode); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid access(%s,%d) return value %d", pathname, + mode, rval); + } + + return rval; +} + +int safe_setpgid(const char *file, const int lineno, pid_t pid, pid_t pgid) +{ + int rval; + + rval = setpgid(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; +} + +pid_t safe_getpgid(const char *file, const int lineno, pid_t pid) +{ + pid_t pgid; + + pgid = getpgid(pid); + + if (pgid == -1) { + 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_setgroups(const char *file, const int lineno, size_t size, const gid_t *list) +{ + int rval; + + rval = setgroups(size, list); + + if (rval == -1) { + 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); + } + + return rval; +} + +int safe_personality(const char *filename, unsigned int lineno, + unsigned long persona) +{ + int prev_persona = personality(persona); + + 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; +} + +int safe_pidfd_open(const char *file, const int lineno, pid_t pid, + unsigned int flags) +{ + int rval; + + rval = pidfd_open(pid, flags); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "pidfd_open(%i, %i) failed", pid, flags); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid pidfd_open(%i, %i) return value %d", + pid, flags, rval); + } + + return rval; +} + +int safe_setregid(const char *file, const int lineno, + gid_t rgid, gid_t egid) +{ + int rval; + + rval = setregid(rgid, egid); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "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); + } 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, + struct sigaction *oldact) +{ + int rval; + + rval = sigaction(signum, act, oldact); + + if (rval == -1) { + 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; +} + +struct group *safe_getgrnam(const char *file, const int lineno, + const char *name) +{ + struct group *rval; + + errno = 0; + rval = getgrnam(name); + if (rval == NULL) { + tst_brk_(file, lineno, TBROK | TERRNO, + "getgrnam(%s) failed", name); + } + + return rval; +} + +struct group *safe_getgrnam_fallback(const char *file, const int lineno, + const char *name, const char *fallback) +{ + struct group *rval; + + errno = 0; + rval = getgrnam(name); + if (rval == NULL) { + tst_res_(file, lineno, TINFO, + "getgrnam(%s) failed - try fallback %s", + name, fallback); + rval = safe_getgrnam(file, lineno, fallback); + } + + return rval; +} + +struct group *safe_getgrgid(const char *file, const int lineno, gid_t gid) +{ + struct group *rval; + + errno = 0; + rval = getgrgid(gid); + if (rval == NULL) { + tst_brk_(file, lineno, TBROK | TERRNO, + "getgrgid(%li) failed", (long)gid); + } + + return rval; +} + +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, + "Invalid chroot(%s) return value %d", path, rval); + } + + return rval; +} + +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, + "unshare(%d) unsupported", flags); + } else { + 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; +} + +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); + } 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, + void *addr, void *data) +{ + long ret; + + errno = 0; + ret = ptrace(req, pid, addr, data); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, "ptrace() failed"); + } else if (ret) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid ptrace() return value %ld", ret); + } + + return ret; +} + +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); + } 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_calloc(const char *file, const int lineno, size_t nmemb, size_t size) +{ + void *rval; + + rval = calloc(nmemb, size); + + if (rval == NULL) { + tst_brk_(file, lineno, TBROK | TERRNO, + "calloc(%zu, %zu) failed", nmemb, size); + } + + 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); + } +} + +int safe_msync(const char *file, const int lineno, void *addr, + size_t length, int flags) +{ + int rval; + + rval = msync(addr, length, flags); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "msync(%p, %zu, %d) failed", addr, length, flags); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid msync(%p, %zu, %d) return value %d", + addr, length, flags, rval); + } + + return rval; +} + +void safe_print_file(const char *file, const int lineno, char *path) +{ + FILE *pfile; + char line[PATH_MAX]; + + tst_res(TINFO, "=== %s ===", path); + + pfile = safe_fopen(file, lineno, NULL, path, "r"); + + while (fgets(line, sizeof(line), pfile)) + fprintf(stderr, "%s", line); + + safe_fclose(file, lineno, NULL, pfile); +} + +int safe_sscanf(const char *file, const int lineno, const char *restrict buffer, const char *restrict format, ...) +{ + va_list args; + + va_start(args, format); + int ret = vsscanf(buffer, format, args); + + va_end(args); + int placeholders = tst_count_scanf_conversions(format); + + if (ret == EOF) + tst_brk_(file, lineno, TBROK | TERRNO, "got EOF from sscanf()"); + + if (ret != placeholders) + tst_brk_(file, lineno, TBROK | TERRNO, "wrong number of conversion, expected %d, got %d", placeholders, ret); + + return ret; +} + +#define PROT_FLAG_STR(f) #f " | " +void tst_prot_to_str(const int prot, char *buf) +{ + char *ptr = buf; + + if (prot == PROT_NONE) { + strcpy(buf, "PROT_NONE"); + return; + } + + if (prot & PROT_READ) { + strcpy(ptr, PROT_FLAG_STR(PROT_READ)); + ptr += sizeof(PROT_FLAG_STR(PROT_READ)) - 1; + } + + if (prot & PROT_WRITE) { + strcpy(ptr, PROT_FLAG_STR(PROT_WRITE)); + ptr += sizeof(PROT_FLAG_STR(PROT_WRITE)) - 1; + } + + if (prot & PROT_EXEC) { + strcpy(ptr, PROT_FLAG_STR(PROT_EXEC)); + ptr += sizeof(PROT_FLAG_STR(PROT_EXEC)) - 1; + } + + if (buf != ptr) + ptr[-3] = 0; +} + +int safe_mprotect(const char *file, const int lineno, + char *addr, size_t len, int prot) +{ + int rval; + char prot_buf[512]; + + tst_prot_to_str(prot, prot_buf); + + tst_res_(file, lineno, TDEBUG, + "mprotect(%p, %zi, %s(%x))", addr, len, prot_buf, prot); + + rval = mprotect(addr, len, prot); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mprotect(%p, %zi, %s(%x))", addr, len, prot_buf, prot); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mprotect(%p, %zi, %s(%x)) return value %d", + addr, len, prot_buf, prot, rval); + } + + return rval; +} + +int safe_prctl(const char *file, const int lineno, + int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) +{ + int rval; + + rval = prctl(option, arg2, arg3, arg4, arg5); + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "prctl(%d, %lu, %lu, %lu, %lu)", + option, arg2, arg3, arg4, arg5); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid prctl(%d, %lu, %lu, %lu, %lu) return value %d", + option, arg2, arg3, arg4, arg5, rval); + } + + return rval; +} + +ssize_t safe_readv(const char *file, const int lineno, char len_strict, + int fildes, const struct iovec *iov, int iovcnt) +{ + ssize_t rval, nbyte; + int i; + + for (i = 0, nbyte = 0; i < iovcnt; i++) + nbyte += iov[i].iov_len; + + rval = readv(fildes, iov, iovcnt); + + if (rval == -1 || (len_strict && rval != nbyte)) { + tst_brk_(file, lineno, TBROK | TERRNO, + "readv(%d,%p,%d) failed", fildes, iov, iovcnt); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid readv(%d,%p,%d) return value %zd", + fildes, iov, iovcnt, rval); + } + + return rval; +} + +int safe_symlinkat(const char *file, const int lineno, + const char *oldpath, const int newdirfd, const char *newpath) +{ + int rval; + + rval = symlinkat(oldpath, newdirfd, newpath); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "symlinkat(%s,%d,%s) failed", oldpath, newdirfd, newpath); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid symlinkat(%s,%d,%s) return value %d", oldpath, + newdirfd, newpath, rval); + } + + return rval; +} + +ssize_t safe_writev(const char *file, const int lineno, char len_strict, + int fildes, const struct iovec *iov, int iovcnt) +{ + ssize_t rval, nbyte; + int i; + + for (i = 0, nbyte = 0; i < iovcnt; i++) + nbyte += iov[i].iov_len; + + rval = writev(fildes, iov, iovcnt); + + if (rval == -1 || (len_strict && rval != nbyte)) { + tst_brk_(file, lineno, TBROK | TERRNO, + "writev(%d,%p,%d) failed", fildes, iov, iovcnt); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid writev(%d,%p,%d) return value %zd", + fildes, iov, iovcnt, rval); + } + + return rval; +} + +char *safe_ptsname(const char *const file, const int lineno, int masterfd) +{ + char *name; + + name = ptsname(masterfd); + + if (!name) { + tst_brk_(file, lineno, TBROK | TERRNO, + "ptsname(%d) failed", masterfd); + } + + return name; +} + +int safe_statvfs(const char *file, const int lineno, + const char *path, struct statvfs *buf) +{ + int rval; + + rval = statvfs(path, buf); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "statvfs(%s,%p) failed", path, buf); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid statvfs(%s,%p) return value %d", path, buf, + rval); + } + + return rval; +} diff --git a/ltp/lib/tst_safe_sysv_ipc.c b/ltp/lib/tst_safe_sysv_ipc.c new file mode 100644 index 0000000000000000000000000000000000000000..a196fc9ce4e3dbde64fb0724ab6b42ebd226ec50 --- /dev/null +++ b/ltp/lib/tst_safe_sysv_ipc.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Xiao yang + */ + +#include +#include +#include +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_safe_sysv_ipc.h" +#include "lapi/ipc.h" +#include "lapi/sem.h" + +/* + * The IPC_STAT, IPC_SET, IPC_RMID can return either 0 or -1. + */ +static int msg_ret_check(int cmd, int ret) +{ + switch (cmd) { + case IPC_STAT: + case IPC_SET: + case IPC_RMID: + return ret != 0; + default: + 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; + } +} + +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_(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; +} + +int safe_msgsnd(const char *file, const int lineno, int msqid, const void *msgp, + size_t msgsz, int msgflg) +{ + int rval; + + rval = msgsnd(msqid, msgp, msgsz, msgflg); + + if (rval == -1) { + 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; +} + +ssize_t safe_msgrcv(const char *file, const int lineno, int msqid, void *msgp, + size_t msgsz, long msgtyp, int msgflg) +{ + ssize_t rval; + + rval = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); + + if (rval == -1) { + 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; +} + +int safe_msgctl(const char *file, const int lineno, int msqid, int cmd, + struct msqid_ds *buf) +{ + int rval; + + rval = msgctl(msqid, cmd, buf); + + 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; +} + +int safe_shmget(const char *file, const int lineno, key_t key, size_t size, + int shmflg) +{ + int rval; + + rval = shmget(key, size, shmflg); + + if (rval == -1) { + 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; +} + +void *safe_shmat(const char *file, const int lineno, int shmid, + const void *shmaddr, int shmflg) +{ + void *rval; + + rval = shmat(shmid, shmaddr, shmflg); + + if (rval == (void *)-1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "shmat(%i, %p, %x) failed", shmid, shmaddr, shmflg); + } + + return rval; +} + +int safe_shmdt(const char *file, const int lineno, const void *shmaddr) +{ + int rval; + + rval = shmdt(shmaddr); + + if (rval == -1) { + 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; +} + +int safe_shmctl(const char *file, const int lineno, int shmid, int cmd, + struct shmid_ds *buf) +{ + int rval; + + rval = shmctl(shmid, cmd, buf); + + 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 = {0}; + + switch (cmd) { + case SETVAL: + case GETALL: + case SETALL: + case IPC_STAT: + case IPC_SET: + case SEM_STAT: + case SEM_STAT_ANY: + case IPC_INFO: + case SEM_INFO: + 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/ltp/lib/tst_safe_timerfd.c b/ltp/lib/tst_safe_timerfd.c new file mode 100644 index 0000000000000000000000000000000000000000..d31f6e35e5d7511140e5fcf0d085626fad1f00a4 --- /dev/null +++ b/ltp/lib/tst_safe_timerfd.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Petr Vorel + */ + +#include "tst_safe_timerfd.h" +#include "lapi/timerfd.h" +#include "tst_clocks.h" +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +#define TTYPE (errno == ENOTSUP ? TCONF : TBROK) + +int safe_timerfd_create(const char *file, const int lineno, + int clockid, int flags) +{ + int fd; + + fd = timerfd_create(clockid, flags); + + 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; +} + +int safe_timerfd_gettime(const char *file, const int lineno, + int fd, struct itimerspec *curr_value) +{ + int rval; + + rval = timerfd_gettime(fd, curr_value); + + 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; +} + +int safe_timerfd_settime(const char *file, const int lineno, + int fd, int flags, + const struct itimerspec *new_value, + struct itimerspec *old_value) +{ + int rval; + + rval = timerfd_settime(fd, flags, new_value, old_value); + + 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/ltp/lib/tst_security.c b/ltp/lib/tst_security.c new file mode 100644 index 0000000000000000000000000000000000000000..7d929fafe729058f55b921bf5cf7806b253496e0 --- /dev/null +++ b/ltp/lib/tst_security.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2020-2024 + */ + +#define TST_NO_DEFAULT_MAIN + +#define PATH_FIPS "/proc/sys/crypto/fips_enabled" +#define PATH_LOCKDOWN "/sys/kernel/security/lockdown" +#define SELINUX_STATUS_PATH "/sys/fs/selinux/enforce" + +#if defined(__powerpc64__) || defined(__ppc64__) +# define SECUREBOOT_VAR "/proc/device-tree/ibm,secure-boot" +# define VAR_DATA_SIZE 4 +#else +# define SECUREBOOT_VAR "/sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c" +# define VAR_DATA_SIZE 5 +#endif + +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "tst_safe_stdio.h" +#include "tst_security.h" +#include "tst_private.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; +} + +int tst_lockdown_enabled(void) +{ + char line[BUFSIZ]; + FILE *file; + int ret; + + if (access(PATH_LOCKDOWN, F_OK) != 0) { + char flag; + + /* SecureBoot enabled could mean integrity lockdown (non-mainline version) */ +#if defined(__powerpc64__) || defined(__ppc64__) + flag = tst_kconfig_get("CONFIG_SECURITY_LOCKDOWN_LSM") == 'y'; + flag |= tst_kconfig_get("CONFIG_SECURITY_LOCKDOWN_LSM_EARLY") == 'y'; +#else + flag = tst_kconfig_get("CONFIG_EFI_SECURE_BOOT_LOCK_DOWN") == 'y'; + flag |= tst_kconfig_get("CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT") == 'y'; +#endif + + if (flag && 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); + + ret = strstr(line, "[none]") == NULL; + tst_res(TINFO, "Kernel lockdown: %s", ret ? "on" : "off"); + + return ret; +} + +int tst_secureboot_enabled(void) +{ + int fd; + char data[5]; + + if (access(SECUREBOOT_VAR, F_OK)) { + tst_res(TINFO, "SecureBoot sysfs file not available"); + return -1; + } + + fd = open(SECUREBOOT_VAR, O_RDONLY); + + if (fd == -1) { + tst_res(TINFO | TERRNO, + "Cannot open SecureBoot file"); + return -1; + } else if (fd < 0) { + tst_brk(TBROK | TERRNO, "Invalid open() return value %d", fd); + return -1; + } + SAFE_READ(1, fd, data, VAR_DATA_SIZE); + SAFE_CLOSE(fd); + tst_res(TINFO, "SecureBoot: %s", data[VAR_DATA_SIZE - 1] ? "on" : "off"); + return data[VAR_DATA_SIZE - 1]; +} + +int tst_selinux_enforcing(void) +{ + int res = 0; + + if (access(SELINUX_STATUS_PATH, F_OK) == 0) + SAFE_FILE_SCANF(SELINUX_STATUS_PATH, "%d", &res); + + tst_res(TINFO, "SELinux enforcing: %s", res ? "on" : "off"); + + return res; +} diff --git a/ltp/lib/tst_sig.c b/ltp/lib/tst_sig.c new file mode 100644 index 0000000000000000000000000000000000000000..6d77aeafdb272dddfac9c26522b5637674beaf92 --- /dev/null +++ b/ltp/lib/tst_sig.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ + +/* $Id: tst_sig.c,v 1.13 2009/08/28 09:29:01 vapier Exp $ */ + +/***************************************************************************** + OS Testing - Silicon Graphics, Inc. + + FUNCTION IDENTIFIER : tst_sig Set up for unexpected signals. + + AUTHOR : David D. Fenner + + CO-PILOT : Bill Roske + + DATE STARTED : 06/06/90 + + This module may be linked with c-modules requiring unexpected + signal handling. The parameters to tst_sig are as follows: + + fork_flag - set to FORK or NOFORK depending upon whether the + calling program executes a fork() system call. It + is normally the case that the calling program treats + SIGCHLD as an expected signal if fork() is being used. + + handler - a pointer to the unexpected signal handler to + be executed after an unexpected signal has been + detected. If handler is set to DEF_HANDLER, a + default handler is used. This routine should be + declared as function returning an int. + + cleanup - a pointer to a cleanup routine to be executed + by the unexpected signal handler before tst_exit is + called. This parameter is set to NULL if no cleanup + routine is required. An external variable, T_cleanup + is set so that other user-defined handlers have + access to the cleanup routine. This routine should be + declared as returning type void. + +***************************************************************************/ + +#include +#include +#include +#include +#include "test.h" +#include "lapi/signal.h" + +#define MAXMESG 150 /* size of mesg string sent to tst_res */ + +static void (*T_cleanup) (); + +static void def_handler(); /* default signal handler */ +static void (*tst_setup_signal(int, void (*)(int))) (int); + +/**************************************************************************** + * tst_sig() : set-up to catch unexpected signals. fork_flag is set to NOFORK + * if SIGCHLD is to be an "unexpected signal", otherwise it is set to + * FORK. cleanup points to a cleanup routine to be executed before + * tst_exit is called (cleanup is set to NULL if no cleanup is desired). + * handler is a pointer to the signal handling routine (if handler is + * set to NULL, a default handler is used). + ***************************************************************************/ + +void tst_sig(int fork_flag, void (*handler) (), void (*cleanup) ()) +{ + int sig; +#ifdef _SC_SIGRT_MIN + long sigrtmin, sigrtmax; +#endif + + /* + * save T_cleanup and handler function pointers + */ + T_cleanup = cleanup; /* used by default handler */ + + if (handler == DEF_HANDLER) { + /* use default handler */ + handler = def_handler; + } +#ifdef _SC_SIGRT_MIN + sigrtmin = sysconf(_SC_SIGRT_MIN); + sigrtmax = sysconf(_SC_SIGRT_MAX); +#endif + + /* + * now loop through all signals and set the handlers + */ + + for (sig = 1; sig < NSIG; sig++) { + /* + * SIGKILL is never unexpected. + * SIGCHLD is only unexpected when + * no forking is being done. + * SIGINFO is used for file quotas and should be expected + */ + +#ifdef _SC_SIGRT_MIN + if (sig >= sigrtmin && sig <= sigrtmax) + continue; +#endif + + switch (sig) { + case SIGKILL: + case SIGSTOP: + case SIGCONT: +#if !defined(_SC_SIGRT_MIN) && defined(__SIGRTMIN) && defined(__SIGRTMAX) + /* Ignore all real-time signals */ + case __SIGRTMIN: + case __SIGRTMIN + 1: + case __SIGRTMIN + 2: + case __SIGRTMIN + 3: + case __SIGRTMIN + 4: + case __SIGRTMIN + 5: + case __SIGRTMIN + 6: + case __SIGRTMIN + 7: + case __SIGRTMIN + 8: + case __SIGRTMIN + 9: + case __SIGRTMIN + 10: + case __SIGRTMIN + 11: + case __SIGRTMIN + 12: + case __SIGRTMIN + 13: + case __SIGRTMIN + 14: + case __SIGRTMIN + 15: +/* __SIGRTMIN is 37 on HPPA rather than 32 * + * as on i386, etc. */ +#if !defined(__hppa__) + case __SIGRTMAX - 15: + case __SIGRTMAX - 14: + case __SIGRTMAX - 13: + case __SIGRTMAX - 12: + case __SIGRTMAX - 11: +#endif + case __SIGRTMAX - 10: + case __SIGRTMAX - 9: + case __SIGRTMAX - 8: + case __SIGRTMAX - 7: + case __SIGRTMAX - 6: + case __SIGRTMAX - 5: + case __SIGRTMAX - 4: + case __SIGRTMAX - 3: + case __SIGRTMAX - 2: + case __SIGRTMAX - 1: + case __SIGRTMAX: +#endif +#ifdef SIGSWAP + case SIGSWAP: +#endif /* SIGSWAP */ + +#ifdef SIGCKPT + case SIGCKPT: +#endif +#ifdef SIGRESTART + case SIGRESTART: +#endif + /* + * pthread-private signals SIGPTINTR and SIGPTRESCHED. + * Setting a handler for these signals is disallowed when + * the binary is linked against libpthread. + */ +#ifdef SIGPTINTR + case SIGPTINTR: +#endif /* SIGPTINTR */ +#ifdef SIGPTRESCHED + case SIGPTRESCHED: +#endif /* SIGPTRESCHED */ +#ifdef _SIGRESERVE + case _SIGRESERVE: +#endif +#ifdef _SIGDIL + case _SIGDIL: +#endif +#ifdef _SIGCANCEL + case _SIGCANCEL: +#endif +#ifdef _SIGGFAULT + case _SIGGFAULT: +#endif + break; + + case SIGCHLD: + if (fork_flag == FORK) + continue; + + default: + if (tst_setup_signal(sig, handler) == SIG_ERR) + tst_resm(TWARN | TERRNO, + "signal failed for signal %d", sig); + break; + } + } +} + +/**************************************************************************** + * def_handler() : default signal handler that is invoked when + * an unexpected signal is caught. + ***************************************************************************/ + +static void def_handler(int sig) +{ + /* + * Break remaining test cases, do any cleanup, then exit + */ + tst_brkm(TBROK, T_cleanup, + "unexpected signal %s(%d) received (pid = %d).", + tst_strsig(sig), sig, getpid()); +} + +/* + * tst_setup_signal - A function like signal(), but we have + * control over its personality. + */ +static void (*tst_setup_signal(int sig, void (*handler) (int))) (int) { + struct sigaction my_act, old_act; + int ret; + + my_act.sa_handler = handler; + my_act.sa_flags = SA_RESTART; + sigemptyset(&my_act.sa_mask); + + ret = sigaction(sig, &my_act, &old_act); + + if (ret == 0) + return old_act.sa_handler; + else + return SIG_ERR; +} diff --git a/ltp/lib/tst_sig_proc.c b/ltp/lib/tst_sig_proc.c new file mode 100644 index 0000000000000000000000000000000000000000..509418af440e104fc7f418aca2e03b470a8ae2f4 --- /dev/null +++ b/ltp/lib/tst_sig_proc.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Linux Test Project + */ + +#include +#include + +#include "tst_sig_proc.h" + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +pid_t create_sig_proc(int sig, int count, unsigned int usec) +{ + pid_t pid, cpid; + + pid = getpid(); + cpid = SAFE_FORK(); + + if (cpid == 0) { + while (count-- > 0) { + usleep(usec); + if (kill(pid, sig) == -1) + break; + } + exit(0); + } + + return cpid; +} diff --git a/ltp/lib/tst_status.c b/ltp/lib/tst_status.c new file mode 100644 index 0000000000000000000000000000000000000000..5d03871f3f986ff11ca3f819aee84c21bb6bf38a --- /dev/null +++ b/ltp/lib/tst_status.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + */ + +#include +#include +#include +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +static char buf[32]; + +const char *exited(int status) +{ + snprintf(buf, sizeof(buf), "exited with %i", WEXITSTATUS(status)); + + return buf; +} + +const char *signaled(int status) +{ + snprintf(buf, sizeof(buf), "killed by %s", + tst_strsig(WTERMSIG(status))); + + return buf; +} + +const char *invalid(int status) +{ + snprintf(buf, sizeof(buf), "invalid status 0x%x", status); + + return buf; +} + +const char *tst_strstatus(int status) +{ + if (WIFEXITED(status)) + return exited(status); + + if (WIFSIGNALED(status)) + return signaled(status); + + if (WIFSTOPPED(status)) + return "is stopped"; + + if (WIFCONTINUED(status)) + return "is resumed"; + + return invalid(status); +} + +int tst_validate_children_(const char *file, const int lineno, + unsigned int count) +{ + unsigned int i; + int status; + pid_t pid; + + for (i = 0; i < count; i++) { + pid = SAFE_WAITPID(-1, &status, 0); + + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + tst_res_(file, lineno, TFAIL, "Child %d: %s", pid, + tst_strstatus(status)); + return 1; + } + } + + return 0; +} diff --git a/ltp/lib/tst_supported_fs_types.c b/ltp/lib/tst_supported_fs_types.c new file mode 100644 index 0000000000000000000000000000000000000000..46165ebc6a5cec1ebc4e97715fd2b1e48ac93d22 --- /dev/null +++ b/ltp/lib/tst_supported_fs_types.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) Linux Test Project, 2018-2023 + */ + +#include +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_fs.h" + +/* + * NOTE: new filesystem should be also added to + * lib/newlib_tests/shell/tst_{all_filesystems_skip,skip_filesystems}.sh + */ +static const char *const fs_type_whitelist[] = { + "ext2", + "ext3", + "ext4", + "xfs", + "btrfs", + "bcachefs", + "vfat", + "exfat", + "ntfs", + "tmpfs", + NULL +}; + +static const char *const fs_type_fuse_blacklist[] = { + "bcachefs", + NULL, +}; + +static const char *fs_types[ARRAY_SIZE(fs_type_whitelist)]; + +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); + + if (WEXITSTATUS(ret) == 127) { + tst_res(TINFO, "mkfs.%s does not exist", fs_type); + return 0; + } + + tst_res(TINFO, "mkfs.%s does exist", fs_type); + return 1; +} + +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 = tst_get_tmpdir_root(); + char buf[128]; + char template[PATH_MAX]; + int ret; + + 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); + SAFE_RMDIR(template); + return TST_FS_KERNEL; + } + + SAFE_RMDIR(template); + + if (tst_fs_in_skiplist(fs_type, fs_type_fuse_blacklist)) { + tst_res(TINFO, "Skipping %s because of FUSE blacklist", fs_type); + return TST_FS_UNSUPPORTED; + } + + /* Is FUSE supported by kernel? */ + if (fuse_supported == -1) { + ret = open("/dev/fuse", O_RDWR); + if (ret < 0) { + fuse_supported = 0; + } else { + fuse_supported = 1; + SAFE_CLOSE(ret); + } + } + + if (!fuse_supported) + return TST_FS_UNSUPPORTED; + + /* Is FUSE implementation installed? */ + sprintf(buf, "mount.%s >/dev/null 2>&1", fs_type); + + ret = tst_system(buf); + if (WEXITSTATUS(ret) == 127) { + tst_res(TINFO, "Filesystem %s is not supported", fs_type); + return TST_FS_UNSUPPORTED; + } + + tst_res(TINFO, "FUSE does support %s", fs_type); + return TST_FS_FUSE; +} + +enum tst_fs_impl tst_fs_is_supported(const char *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; +} + +static int fs_could_be_used(const char *fs_type, const char *const *skiplist, + int skip_fuse) +{ + enum tst_fs_impl sup; + + if (tst_fs_in_skiplist(fs_type, skiplist)) { + tst_res(TINFO, "Skipping %s as requested by the test", + fs_type); + return 0; + } + + sup = tst_fs_is_supported(fs_type); + + if (skip_fuse && sup == TST_FS_FUSE) { + tst_res(TINFO, + "Skipping FUSE based %s as requested by the test", + fs_type); + return 0; + } + + return sup != TST_FS_UNSUPPORTED; +} + +const char **tst_get_supported_fs_types(const char *const *skiplist) +{ + unsigned int i, j = 0; + int skip_fuse; + const char *only_fs, *force_only_fs; + + only_fs = getenv("LTP_SINGLE_FS_TYPE"); + force_only_fs = getenv("LTP_FORCE_SINGLE_FS_TYPE"); + + if (only_fs && force_only_fs) { + tst_brk(TBROK, + "Only one of LTP_SINGLE_FS_TYPE and LTP_FORCE_SINGLE_FS_TYPE can be set"); + return NULL; + } + + skip_fuse = tst_fs_in_skiplist("fuse", skiplist); + + if (only_fs) { + tst_res(TINFO, "WARNING: testing only %s", only_fs); + if (fs_could_be_used(only_fs, skiplist, skip_fuse)) + fs_types[0] = only_fs; + return fs_types; + } + + if (force_only_fs) { + tst_res(TINFO, "WARNING: force testing only %s", force_only_fs); + fs_types[0] = force_only_fs; + return fs_types; + } + + for (i = 0; fs_type_whitelist[i]; i++) { + if (fs_could_be_used(fs_type_whitelist[i], skiplist, skip_fuse)) + fs_types[j++] = fs_type_whitelist[i]; + } + + return fs_types; +} diff --git a/ltp/lib/tst_sys_conf.c b/ltp/lib/tst_sys_conf.c new file mode 100644 index 0000000000000000000000000000000000000000..80cd83569a8d4f6e768681002738940bd73719e3 --- /dev/null +++ b/ltp/lib/tst_sys_conf.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Jan Stancek + */ + +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_sys_conf.h" + +struct tst_sys_conf { + char path[PATH_MAX]; + char value[PATH_MAX]; + struct tst_sys_conf *next; +}; + +static struct tst_sys_conf *save_restore_data; + +static void print_error(const int lineno, int info_only, const char *err, + const char *path) +{ + if (info_only) + tst_res_(__FILE__, lineno, TINFO | TERRNO, err, path); + else + tst_brk_(__FILE__, lineno, TBROK | TERRNO, err, path); +} + +void tst_sys_conf_dump(void) +{ + struct tst_sys_conf *i; + + for (i = save_restore_data; i; i = i->next) + tst_res(TINFO, "%s = %s", i->path, i->value); +} + +void tst_sys_conf_save_str(const char *path, const char *value) +{ + struct tst_sys_conf *n = SAFE_MALLOC(sizeof(*n)); + + strncpy(n->path, path, sizeof(n->path)-1); + strncpy(n->value, value, sizeof(n->value)-1); + + n->path[sizeof(n->path) - 1] = 0; + n->value[sizeof(n->value) - 1] = 0; + + n->next = save_restore_data; + save_restore_data = n; +} + +int tst_sys_conf_save(const struct tst_path_val *conf) +{ + char line[PATH_MAX]; + int ttype, iret; + FILE *fp; + void *ret; + + if (!conf || !conf->path) + tst_brk(TBROK, "path is empty"); + + if (access(conf->path, F_OK) != 0) { + if (conf->flags & TST_SR_SKIP_MISSING) { + tst_res(TINFO | TERRNO, "Path not found: %s", + conf->path); + return 1; + } + + ttype = (conf->flags & TST_SR_TBROK_MISSING) ? TBROK : TCONF; + tst_brk(ttype | TERRNO, "Path not found: %s", conf->path); + } + + if (access(conf->path, W_OK) != 0) { + if (conf->flags & TST_SR_SKIP_RO) { + tst_res(TINFO | TERRNO, "Path is not writable: %s", + conf->path); + return 1; + } + + ttype = (conf->flags & TST_SR_TBROK_RO) ? TBROK : TCONF; + tst_brk(ttype | TERRNO, "Path is not writable: %s", conf->path); + } + + fp = fopen(conf->path, "r"); + + if (fp == NULL) { + print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR, + "Failed to open '%s' for reading", conf->path); + return 1; + } + + ret = fgets(line, sizeof(line), fp); + fclose(fp); + + if (ret == NULL) { + if (conf->flags & TST_SR_IGNORE_ERR) + return 1; + + tst_brk(TBROK | TERRNO, "Failed to read anything from '%s'", + conf->path); + } + + tst_sys_conf_save_str(conf->path, line); + + if (!conf->val) + return 0; + + fp = fopen(conf->path, "w"); + + if (fp == NULL) { + print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR, + "Failed to open '%s' for writing", conf->path); + return 0; + } + + iret = fputs(conf->val, fp); + + if (iret < 0) { + print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR, + "Failed to write into '%s'", conf->path); + } + + iret = fclose(fp); + + if (iret < 0) { + print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR, + "Failed to close '%s'", conf->path); + } + + return 0; +} + +void tst_sys_conf_restore(int verbose) +{ + struct tst_sys_conf *i; + + for (i = save_restore_data; i; i = i->next) { + if (verbose) { + tst_res(TINFO, "Restoring conf.: %s -> %s\n", + i->path, i->value); + } + FILE_PRINTF(i->path, "%s", i->value); + } +} + +int tst_read_bool_sys_param(const char *filename) +{ + char buf[PATH_MAX]; + int i, fd, ret; + + fd = open(filename, O_RDONLY); + + if (fd < 0) + return -1; + + ret = read(fd, buf, PATH_MAX - 1); + SAFE_CLOSE(fd); + + if (ret < 1) + return -1; + + buf[ret] = '\0'; + + for (i = 0; buf[i] && !isspace(buf[i]); i++) + ; + + buf[i] = '\0'; + + if (isdigit(buf[0])) { + tst_parse_int(buf, &ret, INT_MIN, INT_MAX); + return ret; + } + + if (!strcasecmp(buf, "N")) + return 0; + + /* Assume that any other value than 0 or N means the param is enabled */ + return 1; +} + +long tst_sys_conf_long_get_(const char *file, const int lineno, + const char *path) +{ + long ret; + + safe_file_scanf(file, lineno, NULL, path, "%ld", &ret); + + return ret; +} + +void tst_sys_conf_long_set_(const char *file, const int lineno, + const char *path, long val, int check) +{ + tst_res_(file, lineno, TINFO, "Setting %s to %ld", path, val); + + safe_file_printf(file, lineno, NULL, path, "%ld", val); + + if (check) { + long read_val; + + safe_file_scanf(file, lineno, NULL, path, "%ld", &read_val); + + if (val != read_val) + tst_brk_(file, lineno, TBROK, + "Wrote %ld to %s but read back %ld", + val, path, read_val); + } +} diff --git a/ltp/lib/tst_taint.c b/ltp/lib/tst_taint.c new file mode 100644 index 0000000000000000000000000000000000000000..94459523ec8afa556ba12694a052c21a5e2ddc60 --- /dev/null +++ b/ltp/lib/tst_taint.c @@ -0,0 +1,110 @@ +// 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" +#include "tst_taint.h" +#include "tst_safe_stdio.h" + +#define TAINT_FILE "/proc/sys/kernel/tainted" + +static unsigned int taint_mask = -1; + +static const char *const taint_strings[] = { + "G (Propriety module loaded)", + "F (Module force loaded)", + "S (Running on out of spec system)", + "R (Module force unloaded)", + "M (Machine check exception)", + "B (Bad page reference)", + "U (User request)", + "D (OOPS/BUG)", + "A (ACPI table overridden)", + "W (Warning)", + "C (Staging driver loaded)", + "I (Workaround BIOS/FW bug)", + "O (Out of tree module loaded)", + "E (Unsigned module loaded)", + "L (Soft lock up occured)", + "K (Live patched)", + "X (Auxilary)", + "T (Built with struct randomization)", + "N (In-kernel test has been run)", +}; + +static unsigned int tst_taint_read(void) +{ + unsigned int val; + + SAFE_FILE_SCANF(TAINT_FILE, "%u", &val); + + return val; +} + +static int tst_taint_check_kver(unsigned int mask) +{ + int r1; + int r2; + int r3 = 0; + + if (mask & TST_TAINT_N) { + r1 = 6; + r2 = 0; + } else if (mask & TST_TAINT_X) { + r1 = 4; + r2 = 15; + } else if (mask & TST_TAINT_K) { + r1 = 4; + r2 = 0; + } else { + return 1; + } + + return tst_kvercmp(r1, r2, r3); +} + +void tst_taint_init(unsigned int mask) +{ + unsigned int taint = -1; + unsigned long i; + + if (mask == 0) + tst_brk(TBROK, "mask is not allowed to be 0"); + + if (tst_taint_check_kver(mask) < 0) + tst_res(TCONF, "Kernel is too old for requested mask"); + + taint_mask = mask; + taint = tst_taint_read(); + + if (taint & TST_TAINT_W) { + tst_res(TCONF, "Ignoring already set kernel warning taint"); + taint_mask &= ~TST_TAINT_W; + } + + if ((taint & taint_mask) != 0) { + for (i = 0; i < ARRAY_SIZE(taint_strings); i++) { + if (taint & (1 << i)) + tst_res(TINFO, "tainted: %s", taint_strings[i]); + } + + tst_brk(TBROK, "Kernel is already tainted"); + } +} + + +unsigned int tst_taint_check(void) +{ + unsigned int taint = -1; + + if (taint_mask == (unsigned int) -1) + tst_brk(TBROK, "need to call tst_taint_init() first"); + + taint = tst_taint_read(); + + return (taint & taint_mask); +} diff --git a/ltp/lib/tst_test.c b/ltp/lib/tst_test.c new file mode 100644 index 0000000000000000000000000000000000000000..058439f571d13cb472bf6307ffb7139af9a013fe --- /dev/null +++ b/ltp/lib/tst_test.c @@ -0,0 +1,2044 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015-2025 Cyril Hrubis + * Copyright (c) Linux Test Project, 2016-2025 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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" +#include "tst_safe_stdio.h" +#include "tst_timer_test.h" +#include "tst_clocks.h" +#include "tst_timer.h" +#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" +#include "ltp-version.h" + +/* + * Hack to get TCID defined in newlib tests + */ +const char *TCID __attribute__((weak)); + +/* update also doc/conf.py */ +#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 MUSL_GIT_URL "https://git.musl-libc.org/cgit/musl/commit/src/linux/clone.c?id=" +#define CVE_DB_URL "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-" + +#define DEFAULT_TIMEOUT 30 + +/* Magic number is "LTPM" */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define LTP_MAGIC 0x4C54504D +#else +# define LTP_MAGIC 0x4D50544C +#endif + +struct tst_test *tst_test; + +static const char *tcid; +static int iterations = 1; +static float duration = -1; +static float timeout_mul = -1; +static int reproducible_output; + +struct context { + int32_t lib_pid; + int32_t main_pid; + struct timespec start_time; + int32_t runtime; + int32_t overall_time; + /* + * This is set by a call to tst_brk() with TBROK parameter and means + * that the test should exit immediately. + */ + tst_atomic_t abort_flag; + uint32_t mntpoint_mounted:1; + uint32_t ovl_mounted:1; + uint32_t tdebug:1; +}; + +struct results { + tst_atomic_t passed; + tst_atomic_t skipped; + tst_atomic_t failed; + tst_atomic_t warnings; + tst_atomic_t broken; +}; + +struct ipc_region { + int32_t magic; + struct context context; + struct results results; + futex_t futexes[]; +}; + +static struct ipc_region *ipc; +static struct context *context; +static struct results *results; + +extern volatile void *tst_futexes; +extern unsigned int tst_max_futexes; + +static int ipc_fd; +static char ipc_path[1064]; + +static char shm_path[1024]; + +int TST_ERR; +int TST_PASS; +long TST_RET; + +static void do_cleanup(void); +static void do_exit(int ret) __attribute__ ((noreturn)); + +static void setup_ipc(void) +{ + size_t size = getpagesize(); + + if (access("/dev/shm", F_OK) == 0) { + snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d", + tcid, getpid()); + } else { + char *tmpdir; + + if (!tst_tmpdir_created()) + tst_tmpdir(); + + tmpdir = tst_get_tmpdir(); + snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d", + tmpdir, tcid, getpid()); + free(tmpdir); + } + + ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600); + if (ipc_fd < 0) + tst_brk(TBROK | TERRNO, "open(%s)", shm_path); + SAFE_CHMOD(shm_path, 0666); + + SAFE_FTRUNCATE(ipc_fd, size); + + ipc = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0); + + SAFE_CLOSE(ipc_fd); + + memset(ipc, 0, size); + + ipc->magic = LTP_MAGIC; + context = &ipc->context; + results = &ipc->results; + context->lib_pid = getpid(); + + if (tst_test->needs_checkpoints) { + tst_futexes = ipc->futexes; + tst_max_futexes = (size - offsetof(struct ipc_region, futexes)) / sizeof(futex_t); + } + + /* Set environment variable for exec()'d children */ + if (tst_test->needs_checkpoints || tst_test->child_needs_reinit) { + snprintf(ipc_path, sizeof(ipc_path), IPC_ENV_VAR "=%s", shm_path); + putenv(ipc_path); + } else { + SAFE_UNLINK(shm_path); + } +} + +static void cleanup_ipc(void) +{ + size_t size = getpagesize(); + + if (ipc_fd > 0 && close(ipc_fd)) + tst_res(TWARN | TERRNO, "close(ipc_fd) failed"); + + if (shm_path[0] && !access(shm_path, F_OK) && unlink(shm_path)) + tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path); + + if (ipc) { + msync((void *)ipc, size, MS_SYNC); + munmap((void *)ipc, size); + ipc = NULL; + context = NULL; + results = NULL; + } +} + +void tst_reinit(void) +{ + const char *path = getenv(IPC_ENV_VAR); + size_t size = getpagesize(); + int fd; + + if (!path) + tst_brk(TBROK, IPC_ENV_VAR" is not defined"); + + if (access(path, F_OK)) + tst_brk(TBROK, "File %s does not exist!", path); + + fd = SAFE_OPEN(path, O_RDWR); + ipc = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + SAFE_CLOSE(fd); + + if (ipc->magic != LTP_MAGIC) + tst_brk(TBROK, "Invalid shared memory region (bad magic)"); + + /* Restore the parent context from IPC region */ + context = &ipc->context; + results = &ipc->results; + + tst_futexes = ipc->futexes; + tst_max_futexes = (size - offsetof(struct ipc_region, futexes)) / sizeof(futex_t); + + if (context->tdebug) + tst_res(TINFO, "Restored metadata for PID %d", getpid()); +} + +extern char **environ; + +static unsigned int params_array_len(char *const array[]) +{ + unsigned int ret = 0; + + if (!array) + return 0; + + while (*(array++)) + ret++; + + return ret; +} + +int tst_run_script(const char *script_name, char *const params[]) +{ + int pid; + unsigned int i, params_len = params_array_len(params); + char *argv[params_len + 2]; + + if (!tst_test->runs_script) + tst_brk(TBROK, "runs_script flag must be set!"); + + argv[0] = (char *)script_name; + + if (params) { + for (i = 0; i < params_len; i++) + argv[i+1] = params[i]; + } + + argv[params_len+1] = NULL; + + pid = SAFE_FORK(); + if (pid) + return pid; + + execvpe(script_name, argv, environ); + + tst_brk(TBROK | TERRNO, "execvpe(%s, ...) failed!", script_name); + + return -1; +} + +static void update_results(int ttype) +{ + if (!results) + return; + + switch (ttype) { + case TCONF: + tst_atomic_inc(&results->skipped); + break; + case TPASS: + tst_atomic_inc(&results->passed); + break; + case TWARN: + tst_atomic_inc(&results->warnings); + break; + case TFAIL: + tst_atomic_inc(&results->failed); + break; + case TBROK: + tst_atomic_inc(&results->broken); + break; + } +} + +static void print_result(const char *file, const int lineno, int ttype, + const char *fmt, va_list va) +{ + char buf[1024]; + char *str = buf; + int ret, size = sizeof(buf), ssize, int_errno, buflen; + const char *str_errno = NULL; + const char *res; + + switch (TTYPE_RESULT(ttype)) { + case TPASS: + res = "TPASS"; + break; + case TFAIL: + res = "TFAIL"; + break; + case TBROK: + res = "TBROK"; + break; + case TCONF: + res = "TCONF"; + break; + case TWARN: + res = "TWARN"; + break; + case TINFO: + res = "TINFO"; + break; + case TDEBUG: + res = "TDEBUG"; + break; + default: + tst_brk(TBROK, "Invalid ttype value %i", ttype); + abort(); + } + + if (ttype & TERRNO) { + str_errno = tst_strerrno(errno); + int_errno = errno; + } + + if (ttype & TTERRNO) { + str_errno = tst_strerrno(TST_ERR); + int_errno = TST_ERR; + } + + if (ttype & TRERRNO) { + int_errno = TST_RET < 0 ? -(int)TST_RET : (int)TST_RET; + str_errno = tst_strerrno(int_errno); + } + + ret = snprintf(str, size, "%s:%i: ", file, lineno); + str += ret; + size -= ret; + + if (tst_color_enabled(STDERR_FILENO)) + ret = snprintf(str, size, "%s%s: %s", tst_ttype2color(ttype), + res, ANSI_COLOR_RESET); + else + ret = snprintf(str, size, "%s: ", res); + str += ret; + size -= ret; + + if (reproducible_output) + goto print; + + ssize = size - 2; + ret = vsnprintf(str, size, fmt, va); + str += MIN(ret, ssize); + size -= MIN(ret, ssize); + if (ret >= ssize) { + tst_res_(file, lineno, TWARN, + "Next message is too long and truncated:"); + } else if (str_errno) { + ssize = size - 2; + ret = snprintf(str, size, ": %s (%d)", str_errno, int_errno); + str += MIN(ret, ssize); + size -= MIN(ret, ssize); + if (ret >= ssize) + tst_res_(file, lineno, TWARN, + "Next message is too long and truncated:"); + } + +print: + snprintf(str, size, "\n"); + + /* we might be called from signal handler, so use write() */ + buflen = str - buf + 1; + str = buf; + while (buflen) { + ret = write(STDERR_FILENO, str, buflen); + if (ret <= 0) + break; + + str += ret; + buflen -= ret; + } +} + +void tst_vres_(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)); +} + +void tst_vbrk_(const char *file, const int lineno, int ttype, const char *fmt, + va_list va); + +static void (*tst_brk_handler)(const char *file, const int lineno, int ttype, + const char *fmt, va_list va) = tst_vbrk_; + +static void tst_cvres(const char *file, const int lineno, int ttype, + const char *fmt, va_list va) +{ + if (TTYPE_RESULT(ttype) == TBROK) { + ttype &= ~TTYPE_MASK; + ttype |= TWARN; + } + + print_result(file, lineno, ttype, fmt, va); + update_results(TTYPE_RESULT(ttype)); +} + +static void do_test_cleanup(void) +{ + tst_brk_handler = tst_cvres; + + if (tst_test->cleanup) + tst_test->cleanup(); + + tst_free_all(); + + tst_brk_handler = tst_vbrk_; +} + +void tst_vbrk_(const char *file, const int lineno, int ttype, const char *fmt, + va_list va) +{ + print_result(file, lineno, ttype, fmt, va); + + /* + * If tst_brk() is called from some of the C helpers even before the + * library was initialized, just exit. + */ + if (!results || !context->lib_pid) + exit(TTYPE_RESULT(ttype)); + + update_results(TTYPE_RESULT(ttype)); + + /* + * The getpid implementation in some C library versions may cause cloned + * test threads to show the same pid as their parent when CLONE_VM is + * specified but CLONE_THREAD is not. Use direct syscall to avoid + * cleanup running in the child. + */ + if (tst_getpid() == context->main_pid) + do_test_cleanup(); + + /* + * The test library process reports result statistics and exits. + */ + if (getpid() == context->lib_pid) + do_exit(TTYPE_RESULT(ttype)); + + /* + * If we get here we are in a child process, either the main child + * running the test or its children. If any of them called tst_brk() + * with TBROK we need to exit the test. Otherwise we just exit the + * current process. + */ + if (TTYPE_RESULT(ttype) == TBROK) { + if (results) + tst_atomic_inc(&context->abort_flag); + + /* + * If TBROK was called from one of the child processes we kill + * the main test process. That in turn triggers the code that + * kills leftover children once the main test process did exit. + */ + if (context->main_pid && tst_getpid() != context->main_pid) { + tst_res(TINFO, "Child process reported TBROK killing the test"); + kill(context->main_pid, SIGKILL); + } + } + + exit(0); +} + +void tst_res_(const char *file, const int lineno, int ttype, + const char *fmt, ...) +{ + va_list va; + + /* + * Suppress TDEBUG output in these cases: + * 1. No context available (e.g., called before IPC initialization) + * 2. Called from the library process, unless explicitly enabled + * 3. Debug output is not enabled (context->tdebug == 0) + */ + if (ttype == TDEBUG) { + if (!context) + return; + + if (context->lib_pid == getpid()) + return; + + if (!context->tdebug) + return; + } + + va_start(va, fmt); + tst_vres_(file, lineno, ttype, fmt, va); + va_end(va); +} + +void tst_brk_(const char *file, const int lineno, int ttype, + const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + tst_brk_handler(file, lineno, ttype, fmt, va); + 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) +{ + if (WIFSIGNALED(status)) { + tst_brk(TBROK, "Child (%i) killed by signal %s", pid, + tst_strsig(WTERMSIG(status))); + } + + if (!(WIFEXITED(status))) + tst_brk(TBROK, "Child (%i) exited abnormally", pid); + + if (WEXITSTATUS(status)) + tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, WEXITSTATUS(status)); +} + +void tst_reap_children(void) +{ + int status; + pid_t pid; + + for (;;) { + pid = wait(&status); + + if (pid > 0) { + check_child_status(pid, status); + continue; + } + + if (errno == ECHILD) + break; + + if (errno == EINTR) + continue; + + tst_brk(TBROK | TERRNO, "wait() failed"); + } +} + + +pid_t safe_fork(const char *filename, unsigned int lineno) +{ + pid_t pid; + + if (!tst_test->forks_child) + tst_brk(TBROK, "test.forks_child must be set!"); + + tst_flush(); + + pid = fork(); + if (pid < 0) + tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed"); + + if (!pid) + atexit(tst_free_all); + + return pid; +} + +/* too fast creating namespaces => retrying */ +#define TST_CHECK_ENOSPC(x) ((x) >= 0 || !(errno == ENOSPC)) + +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_RETRY_FUNC(tst_clone(args), TST_CHECK_ENOSPC); + + 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 void parse_mul(float *mul, const char *env_name, float min, float max) +{ + char *str_mul; + int ret; + + if (*mul > 0) + return; + + str_mul = getenv(env_name); + + if (!str_mul) { + *mul = 1; + return; + } + + ret = tst_parse_float(str_mul, mul, min, max); + if (ret) { + tst_brk(TBROK, "Failed to parse %s: %s", + env_name, tst_strerrno(ret)); + } +} + +static int multiply_runtime(unsigned int runtime) +{ + static float runtime_mul = -1; + int min_runtime = 1; + + if (tst_test->min_runtime > 0) + min_runtime = tst_test->min_runtime; + + parse_mul(&runtime_mul, "LTP_RUNTIME_MUL", 0.0099, 100); + + return MAX(runtime * runtime_mul, min_runtime); +} + +static struct option { + char *optstr; + char *help; +} options[] = { + {"h", "-h Prints this help"}, + {"i:", "-i n Execute test n times"}, + {"I:", "-I x Execute test for n seconds"}, + {"D", "-D Prints debug information"}, + {"V", "-V Prints LTP version"}, +}; + +static void print_help(void) +{ + unsigned int i; + int timeout, runtime; + + /* see doc/users/setup_tests.rst, 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_REPRODUCIBLE_OUTPUT Values 1 or y discard the actual content of the messages printed by the test\n"); + fprintf(stderr, "LTP_SINGLE_FS_TYPE Specifies filesystem instead all supported (for .all_filesystems)\n"); + fprintf(stderr, "LTP_FORCE_SINGLE_FS_TYPE Testing only. The same as LTP_SINGLE_FS_TYPE but ignores test skiplist.\n"); + fprintf(stderr, "LTP_TIMEOUT_MUL Timeout multiplier (must be a number >=1)\n"); + fprintf(stderr, "LTP_RUNTIME_MUL Runtime multiplier (must be a number >0)\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, "Timeout and runtime\n"); + fprintf(stderr, "-------------------\n"); + + if (tst_test->timeout == TST_UNLIMITED_TIMEOUT) { + fprintf(stderr, "Test timeout is not limited\n"); + } else { + timeout = tst_multiply_timeout(DEFAULT_TIMEOUT + tst_test->timeout); + + fprintf(stderr, "Test timeout (not including runtime) %ih %im %is\n", + timeout/3600, (timeout%3600)/60, timeout % 60); + } + + if (tst_test->runtime) { + runtime = multiply_runtime(tst_test->runtime); + + fprintf(stderr, "Test iteration runtime cap %ih %im %is\n", + runtime/3600, (runtime%3600)/60, runtime % 60); + } + + fprintf(stderr, "\n"); + + fprintf(stderr, "Options\n"); + fprintf(stderr, "-------\n"); + + for (i = 0; i < ARRAY_SIZE(options); i++) + fprintf(stderr, "%s\n", options[i].help); + + if (!tst_test->options) + return; + + 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) +{ + unsigned int i; + const struct tst_tag *tags = tst_test->tags; + + if (!tags) + return; + + fprintf(stderr, "\nTags\n"); + fprintf(stderr, "----\n"); + + for (i = 0; tags[i].name; i++) { + if (!strcmp(tags[i].name, "CVE")) + fprintf(stderr, CVE_DB_URL "%s\n", tags[i].value); + else if (!strcmp(tags[i].name, "linux-git")) + 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 if (!strcmp(tags[i].name, "musl-git")) + fprintf(stderr, MUSL_GIT_URL "%s\n", tags[i].value); + else + fprintf(stderr, "%s: %s\n", tags[i].name, tags[i].value); + } + + fprintf(stderr, "\n"); +} + +static void check_option_collision(void) +{ + unsigned int i, j; + struct tst_option *toptions = tst_test->options; + + if (!toptions) + return; + + for (i = 0; toptions[i].optstr; i++) { + for (j = 0; j < ARRAY_SIZE(options); j++) { + if (toptions[i].optstr[0] == options[j].optstr[0]) { + tst_brk(TBROK, "Option collision '%s'", + options[j].help); + } + } + } +} + +static unsigned int count_options(void) +{ + unsigned int i; + + if (!tst_test->options) + return 0; + + for (i = 0; tst_test->options[i].optstr; i++) + ; + + return i; +} + +static void parse_topt(unsigned int topts_len, int opt, char *optarg) +{ + unsigned int i; + struct tst_option *toptions = tst_test->options; + + for (i = 0; i < topts_len; i++) { + if (toptions[i].optstr[0] == opt) + break; + } + + if (i >= topts_len) + tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt); + + if (*toptions[i].arg) + tst_res(TWARN, "Option -%c passed multiple times", opt); + + *(toptions[i].arg) = optarg ? optarg : ""; +} + +static void parse_opts(int argc, char *argv[]) +{ + unsigned int i, topts_len = count_options(); + char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len]; + int opt; + + check_option_collision(); + + optstr[0] = 0; + + for (i = 0; i < ARRAY_SIZE(options); i++) + strcat(optstr, options[i].optstr); + + for (i = 0; i < topts_len; i++) + strcat(optstr, tst_test->options[i].optstr); + + while ((opt = getopt(argc, argv, optstr)) > 0) { + switch (opt) { + case '?': + print_help(); + tst_brk(TBROK, "Invalid option"); + break; + case 'D': + tst_res(TINFO, "Enabling debug info"); + context->tdebug = 1; + break; + case 'h': + print_help(); + print_test_tags(); + exit(0); + case 'i': + iterations = SAFE_STRTOL(optarg, 0, INT_MAX); + break; + case 'I': + if (tst_test->runtime > 0) + tst_test->runtime = SAFE_STRTOL(optarg, 1, INT_MAX); + else + duration = SAFE_STRTOF(optarg, 0.1, HUGE_VALF); + break; + case 'V': + fprintf(stderr, "LTP version: " LTP_VERSION "\n"); + exit(0); + break; + default: + parse_topt(topts_len, opt, optarg); + } + } + + if (optind < argc) + tst_brk(TBROK, "Unexpected argument(s) '%s'...", argv[optind]); +} + +int tst_parse_int(const char *str, int *val, int min, int max) +{ + long rval; + + if (!str) + return 0; + + int ret = tst_parse_long(str, &rval, min, max); + + if (ret) + return ret; + + *val = (int)rval; + return 0; +} + +int tst_parse_long(const char *str, long *val, long min, long max) +{ + long rval; + char *end; + + if (!str) + return 0; + + errno = 0; + rval = strtol(str, &end, 10); + + if (str == end || *end != '\0') + return EINVAL; + + if (errno) + return errno; + + if (rval > max || rval < min) + return ERANGE; + + *val = rval; + return 0; +} + +int tst_parse_float(const char *str, float *val, float min, float max) +{ + double rval; + char *end; + + if (!str) + return 0; + + errno = 0; + rval = strtod(str, &end); + + if (str == end || *end != '\0') + return EINVAL; + + if (errno) + return errno; + + if (rval > (double)max || rval < (double)min) + return ERANGE; + + *val = (float)rval; + 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)) + fprintf(stderr, "%s%s%s", ANSI_COLOR_YELLOW, str, ANSI_COLOR_RESET); + else + fprintf(stderr, "%s", str); +} + +static void print_failure_hint(const char *tag, const char *hint, + const char *url) +{ + 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, tag)) { + if (!hint_printed) { + hint_printed = 1; + fprintf(stderr, "\n"); + print_colored("HINT: "); + fprintf(stderr, "You _MAY_ be %s:\n\n", hint); + } + + if (url) + fprintf(stderr, "%s%s\n", url, tags[i].value); + else + fprintf(stderr, "%s\n", tags[i].value); + } + } +} + +static int show_failure_hints; + +/* update also doc/conf.py */ +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("musl-git", "missing musl fixes", MUSL_GIT_URL); + print_failure_hint("CVE", "vulnerable to CVE(s)", CVE_DB_URL); + print_failure_hint("known-fail", "hit by known kernel failures", NULL); + + show_failure_hints = 0; +} + +/* + * Prints results, cleans up after the test library and exits the test library + * process. The ret parameter is used to pass the result flags in a case of a + * failure before we managed to set up the shared memory where we store the + * results. This allows us to use SAFE_MACROS() in the initialization of the + * shared memory. The ret parameter is not used (passed 0) when called + * explicitly from the rest of the library. + */ +static void do_exit(int ret) +{ + if (results) { + if (results->passed && ret == TCONF) + ret = 0; + + if (results->failed) { + ret |= TFAIL; + if (show_failure_hints) + print_failure_hints(); + } + + if (results->skipped && !results->passed) + ret |= TCONF; + + if (results->warnings) + ret |= TWARN; + + if (results->broken) { + ret |= TBROK; + if (show_failure_hints) + print_failure_hints(); + } + + 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(); + + exit(ret); +} + +int check_kver(const char *min_kver, const int brk_nosupp) +{ + char *msg; + int v1, v2, v3; + + if (tst_parse_kver(min_kver, &v1, &v2, &v3)) { + tst_res(TWARN, + "Invalid kernel version %s, expected %%d.%%d.%%d", + min_kver); + } + + if (tst_kvercmp(v1, v2, v3) < 0) { + msg = "The test requires kernel %s or newer"; + + if (brk_nosupp) + tst_brk(TCONF, msg, min_kver); + else + tst_res(TCONF, msg, min_kver); + + return 1; + } + + return 0; +} + +static int results_equal(struct results *a, struct results *b) +{ + if (a->passed != b->passed) + return 0; + + if (a->failed != b->failed) + return 0; + + if (a->skipped != b->skipped) + return 0; + + if (a->broken != b->broken) + return 0; + + return 1; +} + +static int needs_tmpdir(void) +{ + return tst_test->needs_tmpdir || + tst_test->needs_device || + tst_test->mntpoint || + tst_test->resource_files || + tst_test->needs_checkpoints; +} + +static void copy_resources(void) +{ + unsigned int i; + + for (i = 0; tst_test->resource_files[i]; i++) + TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL); +} + +static const char *get_tcid(char *argv[]) +{ + char *p; + + if (!argv[0] || !argv[0][0]) { + tst_res(TINFO, "argv[0] is empty!"); + return "ltp_empty_argv"; + } + + p = strrchr(argv[0], '/'); + if (p) + return p+1; + + return argv[0]; +} + +static struct tst_device tdev; +struct tst_device *tst_device; + +static void assert_test_fn(void) +{ + int cnt = 0; + + if (tst_test->test) + cnt++; + + if (tst_test->test_all) + cnt++; + + if (tst_test->sample) + cnt++; + + if (!cnt) + tst_brk(TBROK, "No test function specified"); + + if (cnt != 1) + tst_brk(TBROK, "You can define only one test function"); + + if (tst_test->test && !tst_test->tcnt) + tst_brk(TBROK, "Number of tests (tcnt) must be > 0"); + + if (!tst_test->test && tst_test->tcnt) + tst_brk(TBROK, "You can define tcnt only for test()"); +} + +static int prepare_and_mount_ro_fs(const char *dev, const char *mntpoint, + const char *fs_type) +{ + char buf[PATH_MAX]; + + if (mount(dev, mntpoint, fs_type, 0, NULL)) { + tst_res(TINFO | TERRNO, "Can't mount %s at %s (%s)", + dev, mntpoint, fs_type); + return 1; + } + + context->mntpoint_mounted = 1; + + snprintf(buf, sizeof(buf), "%s/dir/", mntpoint); + SAFE_MKDIR(buf, 0777); + + snprintf(buf, sizeof(buf), "%s/file", mntpoint); + SAFE_FILE_PRINTF(buf, "file content"); + SAFE_CHMOD(buf, 0777); + + SAFE_MOUNT(dev, mntpoint, fs_type, MS_REMOUNT | MS_RDONLY, NULL); + + return 0; +} + +static void prepare_and_mount_dev_fs(const char *mntpoint) +{ + const char *flags[] = {"nodev", NULL}; + int mounted_nodev; + + mounted_nodev = tst_path_has_mnt_flags(NULL, flags); + if (mounted_nodev) { + tst_res(TINFO, "tmpdir isn't suitable for creating devices, " + "mounting tmpfs without nodev on %s", mntpoint); + SAFE_MOUNT(NULL, mntpoint, "tmpfs", 0, NULL); + context->mntpoint_mounted = 1; + } +} + +static void prepare_and_mount_hugetlb_fs(void) +{ + SAFE_MOUNT("none", tst_test->mntpoint, "hugetlbfs", 0, NULL); + context->mntpoint_mounted = 1; +} + +int tst_creat_unlinked(const char *path, int flags, mode_t mode) +{ + char template[PATH_MAX]; + int len, c, range; + int fd; + int start[3] = {'0', 'a', 'A'}; + + snprintf(template, PATH_MAX, "%s/ltp_%.3sXXXXXX", + path, tcid); + + len = strlen(template) - 1; + while (template[len] == 'X') { + c = rand() % 3; + range = start[c] == '0' ? 10 : 26; + c = start[c] + (rand() % range); + template[len--] = (char)c; + } + + flags |= O_CREAT|O_EXCL|O_RDWR; + fd = SAFE_OPEN(template, flags, mode); + SAFE_UNLINK(template); + return fd; +} + +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(struct tst_fs *fs) +{ + const char *mnt_data; + char buf[1024]; + struct tst_fs dummy = {}; + + fs = fs ?: &dummy; + + const char *const extra[] = {fs->mkfs_size_opt, NULL}; + + if (tst_test->format_device) + SAFE_MKFS(tdev.dev, tdev.fs_type, fs->mkfs_opts, extra); + + if (tst_test->needs_rofs) { + prepare_and_mount_ro_fs(tdev.dev, tst_test->mntpoint, + tdev.fs_type); + return; + } + + if (tst_test->mount_device) { + mnt_data = limit_tmpfs_mount_size(fs->mnt_data, + buf, sizeof(buf), tdev.fs_type); + + SAFE_MOUNT(get_device_name(tdev.fs_type), tst_test->mntpoint, + tdev.fs_type, fs->mnt_flags, mnt_data); + context->mntpoint_mounted = 1; + } +} + +static void do_cgroup_requires(void) +{ + const struct tst_cg_opts cg_opts = { + .needs_ver = tst_test->needs_cgroup_ver, + .needs_nsdelegate = tst_test->needs_cgroup_nsdelegate, + }; + const char *const *ctrl_names = tst_test->needs_cgroup_ctrls; + + for (; *ctrl_names; ctrl_names++) + tst_cg_require(*ctrl_names, &cg_opts); + + tst_cg_init(); +} + +#define tst_set_ulimit(conf) \ + set_ulimit_(__FILE__, __LINE__, (conf)) + +/* + * Set resource limits. + */ +static void set_ulimit_(const char *file, const int lineno, const struct tst_ulimit_val *conf) +{ + struct rlimit rlim; + + safe_getrlimit(file, lineno, conf->resource, &rlim); + + rlim.rlim_cur = conf->rlim_cur; + + if (conf->rlim_cur > rlim.rlim_max) + rlim.rlim_max = conf->rlim_cur; + + tst_res_(file, lineno, TINFO, "Set ulimit resource: %d rlim_cur: %llu rlim_max: %llu", + conf->resource, (long long unsigned int)rlim.rlim_cur, + (long long unsigned int)rlim.rlim_max); + + safe_setrlimit(file, lineno, conf->resource, &rlim); +} + +static unsigned int count_fs_descs(void) +{ + unsigned int ret = 0; + + if (!tst_test->filesystems) + return 0; + + /* + * First entry is special, if it has zero type it's the default entry + * and is either followed by a terminating entry or by filesystem + * description(s) plus terminating entry. + */ + if (!tst_test->filesystems[0].type) + ret = 1; + + while (tst_test->filesystems[ret].type) + ret++; + + return ret; +} + +static const char *default_fs_type(void) +{ + if (!tst_test->filesystems) + return tst_dev_fs_type(); + + if (tst_test->filesystems[0].type) + return tst_test->filesystems[0].type; + + return tst_dev_fs_type(); +} + +static void do_setup(int argc, char *argv[]) +{ + char *tdebug_env = getenv("LTP_ENABLE_DEBUG"); + char *reproducible_env = getenv("LTP_REPRODUCIBLE_OUTPUT"); + + if (!tst_test) + tst_brk(TBROK, "No tests to run"); + + if (tst_test->timeout < -1) { + tst_brk(TBROK, "Invalid timeout value %i", + tst_test->timeout); + } + + if (tst_test->runtime < 0) + tst_brk(TBROK, "Invalid runtime value %i", tst_test->runtime); + + if (tst_test->tconf_msg) + tst_brk(TCONF, "%s", tst_test->tconf_msg); + + 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->sample) + tst_test = tst_timer_test_setup(tst_test); + + if (tst_test->runs_script) { + tst_test->child_needs_reinit = 1; + tst_test->forks_child = 1; + } + + if (reproducible_env && + (!strcmp(reproducible_env, "1") || !strcmp(reproducible_env, "y"))) + reproducible_output = 1; + + assert_test_fn(); + + TCID = tcid = get_tcid(argv); + + setup_ipc(); + + parse_opts(argc, argv); + + if (tdebug_env && (!strcmp(tdebug_env, "1") || !strcmp(tdebug_env, "y"))) { + tst_res(TINFO, "Enabling debug info"); + context->tdebug = 1; + } + + 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(tst_test->min_kver, 1); + + if (tst_test->skip_in_lockdown && tst_lockdown_enabled() > 0) + tst_brk(TCONF, "Kernel is locked down, skipping test"); + + if (tst_test->skip_in_secureboot && tst_secureboot_enabled() > 0) + tst_brk(TCONF, "SecureBoot enabled, skipping test"); + + if (tst_test->skip_in_compat && tst_is_compat_mode()) + tst_brk(TCONF, "Not supported in 32-bit compat mode"); + + if (tst_test->needs_abi_bits && !tst_abi_bits(tst_test->needs_abi_bits)) + tst_brk(TCONF, "%dbit ABI is not supported", tst_test->needs_abi_bits); + + if (tst_test->needs_cmds) { + const char *cmd; + int i; + + for (i = 0; (cmd = tst_test->needs_cmds[i]); ++i) + tst_check_cmd(cmd, 1); + } + + if (tst_test->needs_drivers) { + const char *name; + int i; + + for (i = 0; (name = tst_test->needs_drivers[i]); ++i) + if (tst_check_driver(name)) + tst_brk(TCONF, "%s driver not available", name); + } + + if (tst_test->mount_device) + tst_test->format_device = 1; + + if (tst_test->format_device) + tst_test->needs_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->min_mem_avail > (unsigned long)(tst_available_mem() / 1024)) + tst_brk(TCONF, "Test needs at least %luMB MemAvailable", tst_test->min_mem_avail); + + if (tst_test->min_swap_avail > (unsigned long)(tst_available_swap() / 1024)) + tst_brk(TCONF, "Test needs at least %luMB SwapFree", tst_test->min_swap_avail); + + if (tst_test->hugepages.number) + tst_reserve_hugepages(&tst_test->hugepages); + + if (tst_test->bufs) + tst_buffers_alloc(tst_test->bufs); + + if (needs_tmpdir() && !tst_tmpdir_created()) + tst_tmpdir(); + + if (tst_test->save_restore) { + const struct tst_path_val *pvl = tst_test->save_restore; + + while (pvl->path) { + tst_sys_conf_save(pvl); + pvl++; + } + } + + if (tst_test->ulimit) { + const struct tst_ulimit_val *pvl = tst_test->ulimit; + + while (pvl->resource) { + tst_set_ulimit(pvl); + pvl++; + } + } + + if (tst_test->mntpoint) + SAFE_MKDIR(tst_test->mntpoint, 0777); + + if ((tst_test->needs_devfs || tst_test->needs_rofs || + tst_test->mount_device || tst_test->all_filesystems || + tst_test->needs_hugetlbfs) && + !tst_test->mntpoint) { + tst_brk(TBROK, "tst_test->mntpoint must be set!"); + } + + if (!!tst_test->needs_rofs + !!tst_test->needs_devfs + + !!tst_test->needs_device + !!tst_test->needs_hugetlbfs > 1) { + tst_brk(TBROK, + "Two or more of needs_{rofs, devfs, device, hugetlbfs} are set"); + } + + if (tst_test->needs_devfs) + prepare_and_mount_dev_fs(tst_test->mntpoint); + + if (tst_test->needs_rofs) { + /* If we failed to mount read-only tmpfs. Fallback to + * using a device with read-only filesystem. + */ + if (prepare_and_mount_ro_fs(NULL, tst_test->mntpoint, "tmpfs")) { + tst_res(TINFO, "Can't mount tmpfs read-only, " + "falling back to block device..."); + tst_test->needs_device = 1; + tst_test->format_device = 1; + } + } + + if (tst_test->needs_hugetlbfs) + prepare_and_mount_hugetlb_fs(); + + if (tst_test->needs_device && !context->mntpoint_mounted) { + tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size); + + if (!tdev.dev) + tst_brk(TCONF, "Failed to acquire device"); + + tdev.size = tst_get_device_size(tdev.dev); + + tst_device = &tdev; + + tdev.fs_type = default_fs_type(); + + if (!tst_test->all_filesystems && count_fs_descs() <= 1) { + if (tst_test->filesystems && tst_test->filesystems->mkfs_ver) + tst_check_cmd(tst_test->filesystems->mkfs_ver, 1); + + if (tst_test->filesystems && tst_test->filesystems->min_kver) + check_kver(tst_test->filesystems->min_kver, 1); + + prepare_device(tst_test->filesystems); + } + } + + if (tst_test->needs_overlay && !tst_test->mount_device) + tst_brk(TBROK, "tst_test->mount_device must be set"); + + if (tst_test->needs_overlay && !context->mntpoint_mounted) + tst_brk(TBROK, "tst_test->mntpoint must be mounted"); + + if (tst_test->needs_overlay && !context->ovl_mounted) { + SAFE_MOUNT_OVERLAY(); + context->ovl_mounted = 1; + } + + if (tst_test->resource_files) + copy_resources(); + + if (tst_test->restore_wallclock) + tst_wallclock_save(); + + if (tst_test->taint_check) + tst_taint_init(tst_test->taint_check); + + if (tst_test->needs_cgroup_ctrls) + do_cgroup_requires(); + else if (tst_test->needs_cgroup_ver) + tst_brk(TBROK, "tst_test->needs_cgroup_ctrls must be set"); +} + +static void do_test_setup(void) +{ + context->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); + + if (tst_test->setup) + tst_test->setup(); + + if (context->main_pid != tst_getpid()) + tst_brk(TBROK, "Runaway child in setup()!"); + + if (tst_test->caps) + tst_cap_setup(tst_test->caps, TST_CAP_DROP); +} + +static void do_cleanup(void) +{ + if (tst_test->needs_cgroup_ctrls) + tst_cg_cleanup(); + + if (context->ovl_mounted) + SAFE_UMOUNT(OVL_MNT); + + if (context->mntpoint_mounted) + tst_umount(tst_test->mntpoint); + + if (tst_test->needs_device && tdev.dev) + tst_release_device(tdev.dev); + + if (tst_tmpdir_created()) { + /* avoid munmap() on wrong pointer in tst_rmdir() */ + tst_futexes = NULL; + tst_rmdir(); + } + + tst_sys_conf_restore(0); + + if (tst_test->restore_wallclock) + tst_wallclock_restore(); + + cleanup_ipc(); +} + +static void heartbeat(void) +{ + if (tst_clock_gettime(CLOCK_MONOTONIC, &context->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); +} + +static void run_tests(void) +{ + unsigned int i; + struct results saved_results; + + if (!tst_test->test) { + saved_results = *results; + heartbeat(); + tst_test->test_all(); + + if (tst_getpid() != context->main_pid) + exit(0); + + tst_reap_children(); + + if (results_equal(&saved_results, results)) + tst_brk(TBROK, "Test haven't reported results!"); + + return; + } + + for (i = 0; i < tst_test->tcnt; i++) { + saved_results = *results; + heartbeat(); + tst_test->test(i); + + if (tst_getpid() != context->main_pid) + exit(0); + + tst_reap_children(); + + if (results_equal(&saved_results, results)) + tst_brk(TBROK, "Test %i haven't reported results!", i); + } +} + +static unsigned long long get_time_ms(void) +{ + struct timespec ts; + + if (tst_clock_gettime(CLOCK_MONOTONIC, &ts)) + tst_brk(TBROK | TERRNO, "tst_clock_gettime()"); + + return tst_timespec_to_ms(ts); +} + +static void add_paths(void) +{ + char *old_path = getenv("PATH"); + const char *start_dir; + char *new_path; + + start_dir = tst_get_startwd(); + + if (old_path) + SAFE_ASPRINTF(&new_path, "%s::%s", old_path, start_dir); + else + SAFE_ASPRINTF(&new_path, "::%s", start_dir); + + SAFE_SETENV("PATH", new_path, 1); + free(new_path); +} + +static void testrun(void) +{ + unsigned int i = 0; + unsigned long long stop_time = 0; + int cont = 1; + + heartbeat(); + add_paths(); + do_test_setup(); + + if (duration > 0) + stop_time = get_time_ms() + (unsigned long long)(duration * 1000); + + for (;;) { + cont = 0; + + if (i < (unsigned int)iterations) { + i++; + cont = 1; + } + + if (stop_time && get_time_ms() < stop_time) + cont = 1; + + if (!cont) + break; + + run_tests(); + heartbeat(); + } + + do_test_cleanup(); + exit(0); +} + +static pid_t test_pid; + + +static volatile sig_atomic_t sigkill_retries; + +#define WRITE_MSG(msg) do { \ + if (write(2, msg, sizeof(msg) - 1)) { \ + /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */ \ + } \ +} while (0) + +static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED) +{ + WRITE_MSG("Test timeouted, sending SIGKILL!\n"); + + kill(-test_pid, SIGKILL); + alarm(5); + + if (++sigkill_retries > 10) { + WRITE_MSG("Cannot kill test processes!\n"); + WRITE_MSG("Congratulation, likely test hit a kernel bug.\n"); + WRITE_MSG("Exiting uncleanly...\n"); + _exit(TFAIL); + } +} + +static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED) +{ + alarm(context->overall_time); + sigkill_retries = 0; +} + +static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED) +{ + if (test_pid > 0) { + WRITE_MSG("Sending SIGKILL to test process...\n"); + kill(-test_pid, SIGKILL); + } +} + +unsigned int tst_remaining_runtime(void) +{ + static struct timespec now; + int elapsed; + + if (context->runtime == 0) + tst_brk(TBROK, "Runtime not set!"); + + if (tst_clock_gettime(CLOCK_MONOTONIC, &now)) + tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); + + elapsed = tst_timespec_diff_ms(now, context->start_time) / 1000; + if (context->runtime > elapsed) + return context->runtime - elapsed; + + return 0; +} + + +unsigned int tst_multiply_timeout(unsigned int timeout) +{ + parse_mul(&timeout_mul, "LTP_TIMEOUT_MUL", 0.099, 10000); + + if (timeout < 1) + tst_brk(TBROK, "timeout must to be >= 1! (%d)", timeout); + + if (tst_has_slow_kconfig()) + timeout *= 4; + + return timeout * timeout_mul; +} + +static void set_overall_timeout(void) +{ + unsigned int timeout = DEFAULT_TIMEOUT + tst_test->timeout; + + if (tst_test->timeout == TST_UNLIMITED_TIMEOUT) { + tst_res(TINFO, "Test timeout is not limited"); + return; + } + + context->overall_time = tst_multiply_timeout(timeout) + context->runtime; + + tst_res(TINFO, "Overall timeout per run is %uh %02um %02us", + context->overall_time/3600, (context->overall_time%3600)/60, + context->overall_time % 60); +} + +void tst_set_timeout(int timeout) +{ + int timeout_adj = DEFAULT_TIMEOUT + timeout; + + context->overall_time = tst_multiply_timeout(timeout_adj) + context->runtime; + + tst_res(TINFO, "Overall timeout per run is %uh %02um %02us", + context->overall_time/3600, (context->overall_time%3600)/60, + context->overall_time % 60); + + heartbeat(); +} + +void tst_set_runtime(int runtime) +{ + context->runtime = multiply_runtime(runtime); + tst_res(TINFO, "Updating runtime to %uh %02um %02us", + runtime/3600, (runtime%3600)/60, runtime % 60); + set_overall_timeout(); + heartbeat(); +} + +static int fork_testrun(void) +{ + int status; + + SAFE_SIGNAL(SIGINT, sigint_handler); + SAFE_SIGNAL(SIGTERM, sigint_handler); + + alarm(context->overall_time); + + show_failure_hints = 1; + + test_pid = fork(); + if (test_pid < 0) + 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(SIGTERM, SIG_DFL); + SAFE_SIGNAL(SIGINT, SIG_DFL); + SAFE_SETPGID(0, 0); + testrun(); + } + + SAFE_WAITPID(test_pid, &status, 0); + alarm(0); + SAFE_SIGNAL(SIGTERM, SIG_DFL); + SAFE_SIGNAL(SIGINT, SIG_DFL); + + if (tst_test->taint_check && tst_taint_check()) { + tst_res(TFAIL, "Kernel is now tainted."); + return TFAIL; + } + + if (tst_test->forks_child && kill(-test_pid, SIGKILL) == 0) + tst_res(TINFO, "Killed the leftover descendant processes"); + + if (WIFEXITED(status) && WEXITSTATUS(status)) + tst_brk(TBROK, "Child returned with %i", WEXITSTATUS(status)); + + if (context->abort_flag) + return 0; + + if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { + tst_res(TINFO, "If you are running on slow machine, " + "try exporting LTP_TIMEOUT_MUL > 1"); + tst_brk(TBROK, "Test killed! (timeout?)"); + } + + if (WIFSIGNALED(status)) + tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status))); + + return 0; +} + +static struct tst_fs *lookup_fs_desc(const char *fs_type, int all_filesystems) +{ + struct tst_fs *fs = tst_test->filesystems; + static struct tst_fs empty; + + if (!fs) + goto ret; + + for (; fs->type; fs++) { + + if (!fs->type) + continue; + + if (!strcmp(fs_type, fs->type)) + return fs; + } + +ret: + if (!all_filesystems) + return NULL; + + if (!tst_test->filesystems || tst_test->filesystems[0].type) + return ∅ + + return &tst_test->filesystems[0]; +} + +static int run_tcase_on_fs(struct tst_fs *fs, const char *fs_type) +{ + int ret; + + tst_res(TINFO, "=== Testing on %s ===", fs_type); + tdev.fs_type = fs_type; + + if (fs->mkfs_ver && tst_check_cmd(fs->mkfs_ver, 0)) + return TCONF; + + if (fs->min_kver && check_kver(fs->min_kver, 0)) + return TCONF; + + prepare_device(fs); + + ret = fork_testrun(); + + if (context->mntpoint_mounted) { + tst_umount(tst_test->mntpoint); + context->mntpoint_mounted = 0; + } + + return ret; +} + +static int run_tcases_per_fs(void) +{ + int ret = 0; + unsigned int i; + bool found_valid_fs = false; + const char *const *filesystems = tst_get_supported_fs_types(tst_test->skip_filesystems); + + if (!filesystems[0]) + tst_brk(TCONF, "There are no supported filesystems"); + + for (i = 0; filesystems[i]; i++) { + struct tst_fs *fs = lookup_fs_desc(filesystems[i], tst_test->all_filesystems); + + if (!fs) + continue; + + found_valid_fs = true; + run_tcase_on_fs(fs, filesystems[i]); + + if (tst_atomic_load(&context->abort_flag)) + do_exit(0); + } + + if (!found_valid_fs) + tst_brk(TCONF, "No required filesystems are available"); + + return ret; +} + +unsigned int tst_variant; + +void tst_run_tcases(int argc, char *argv[], struct tst_test *self) +{ + unsigned int test_variants = 1; + struct utsname uval; + + tst_test = self; + + do_setup(argc, argv); + tst_enable_oom_protection(context->lib_pid); + + SAFE_SIGNAL(SIGALRM, alarm_handler); + SAFE_SIGNAL(SIGUSR1, heartbeat_handler); + + tst_res(TINFO, "LTP version: "LTP_VERSION); + + uname(&uval); + tst_res(TINFO, "Tested kernel: %s %s %s", uval.release, uval.version, uval.machine); + + if (tst_test->min_runtime && !tst_test->runtime) + tst_test->runtime = tst_test->min_runtime; + + if (tst_test->runtime) + context->runtime = multiply_runtime(tst_test->runtime); + + set_overall_timeout(); + + if (tst_test->test_variants) + test_variants = tst_test->test_variants; + + for (tst_variant = 0; tst_variant < test_variants; tst_variant++) { + if (tst_test->all_filesystems || count_fs_descs() > 1) + run_tcases_per_fs(); + else + fork_testrun(); + + if (tst_atomic_load(&context->abort_flag)) + do_exit(0); + } + + do_exit(0); +} + +void tst_flush(void) +{ + int rval; + + rval = fflush(stderr); + if (rval != 0) + tst_brk(TBROK | TERRNO, "fflush(stderr) failed"); + + rval = fflush(stdout); + if (rval != 0) + tst_brk(TBROK | TERRNO, "fflush(stdout) failed"); + +} diff --git a/ltp/lib/tst_test_macros.c b/ltp/lib/tst_test_macros.c new file mode 100644 index 0000000000000000000000000000000000000000..79d670af6fad3000f3373609eb58105772b10524 --- /dev/null +++ b/ltp/lib/tst_test_macros.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Cyril Hrubis + */ + +#include +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_test_macros.h" + +bool tst_errno_in_set(int err, const int *exp_errs, int exp_errs_cnt) +{ + int i; + + for (i = 0; i < exp_errs_cnt; i++) { + if (err == exp_errs[i]) + return 1; + } + + return 0; +} + +const char *tst_errno_names(char *buf, const int *exp_errs, int exp_errs_cnt) +{ + int i; + char *cb = buf; + + for (i = 0; i < exp_errs_cnt-1; i++) + cb += sprintf(cb, "%s, ", tst_strerrno(exp_errs[i])); + + cb += sprintf(cb, "%s", tst_strerrno(exp_errs[i])); + + *cb = '\0'; + + return buf; +} diff --git a/ltp/lib/tst_thread_state.c b/ltp/lib/tst_thread_state.c new file mode 100644 index 0000000000000000000000000000000000000000..4d04136ce5283746bb19fd9b41ad956aa08c5de5 --- /dev/null +++ b/ltp/lib/tst_thread_state.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +#include +#include +#include +#include + +#include "tst_safe_file_ops.h" +#include "tst_process_state.h" + +int tst_thread_state_wait(pid_t tid, const char state, + unsigned int msec_timeout) +{ + char proc_path[128], cur_state; + unsigned int msecs = 0; + + snprintf(proc_path, sizeof(proc_path), "/proc/self/task/%i/stat", tid); + + for (;;) { + SAFE_FILE_SCANF(proc_path, "%*[^)]%*c %c", &cur_state); + + if (state == cur_state) + break; + + usleep(1000); + msecs += 1; + + if (msec_timeout && msecs >= msec_timeout) { + errno = ETIMEDOUT; + return -1; + } + } + + return 0; +} diff --git a/ltp/lib/tst_timer.c b/ltp/lib/tst_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..ecf165ca4b39ee4739714cb4c8a866096c344686 --- /dev/null +++ b/ltp/lib/tst_timer.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2015 Cyril Hrubis + */ + +#include + +#define TST_NO_DEFAULT_MAIN + +#include "tst_test.h" +#include "tst_timer.h" +#include "tst_clocks.h" +#include "lapi/posix_clocks.h" + +static struct timespec start_time, stop_time; +static clockid_t clock_id; + +void tst_timer_check(clockid_t clk_id) +{ + if (tst_clock_gettime(clk_id, &start_time)) { + if (errno == EINVAL) { + tst_brk(TCONF, + "Clock id %s(%u) not supported by kernel", + tst_clock_name(clk_id), clk_id); + return; + } + + tst_brk(TBROK | TERRNO, "tst_clock_gettime() failed"); + } +} + +void tst_timer_start(clockid_t clk_id) +{ + clock_id = clk_id; + + if (tst_clock_gettime(clock_id, &start_time)) + tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); +} + +int tst_timer_expired_ms(long long ms) +{ + struct timespec cur_time; + + if (tst_clock_gettime(clock_id, &cur_time)) + tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); + + return tst_timespec_diff_ms(cur_time, start_time) >= ms; +} + +void tst_timer_stop(void) +{ + if (tst_clock_gettime(clock_id, &stop_time)) + tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); +} + +struct timespec tst_timer_elapsed(void) +{ + return tst_timespec_diff(stop_time, start_time); +} diff --git a/ltp/lib/tst_timer_test.c b/ltp/lib/tst_timer_test.c new file mode 100644 index 0000000000000000000000000000000000000000..b5a088a14bdb2ba35a14f6485fa9cb19c6218372 --- /dev/null +++ b/ltp/lib/tst_timer_test.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Cyril Hrubis + */ + +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_clocks.h" +#include "tst_timer_test.h" + +#define MAX_SAMPLES 500 + +static const char *scall; +static void (*setup)(void); +static void (*cleanup)(void); +static int (*sample)(int clk_id, long long usec); +static struct tst_test *test; + +static long long *samples; +static unsigned int cur_sample; +static unsigned int monotonic_resolution; +static unsigned int timerslack; +static int virt_env; + +static char *print_frequency_plot; +static char *file_name; +static char *str_sleep_time; +static char *str_sample_cnt; +static int sleep_time = -1; +static int sample_cnt; + +static void print_line(char c, int len) +{ + while (len-- > 0) + fputc(c, stderr); +} + +static unsigned int ceilu(float f) +{ + if (f - (int)f > 0) + return (unsigned int)f + 1; + + return (unsigned int)f; +} + +static unsigned int flooru(float f) +{ + return (unsigned int)f; +} + +static float bucket_len(unsigned int bucket, unsigned int max_bucket, + unsigned int cols) +{ + return 1.00 * bucket * cols / max_bucket; +} + +static const char *table_heading = " Time: us "; + +/* + * Line Header: '10023 | ' + */ +static unsigned int header_len(long long max_sample) +{ + size_t l = 1; + + while (max_sample/=10) + l++; + + return MAX(strlen(table_heading) + 2, l + 3); +} + +static void frequency_plot(void) +{ + unsigned int cols = 80; + unsigned int rows = 20; + unsigned int i, buckets[rows]; + long long max_sample = samples[0]; + long long min_sample = samples[cur_sample-1]; + unsigned int line_header_len = header_len(max_sample); + unsigned int plot_line_len = cols - line_header_len; + unsigned int bucket_size; + + memset(buckets, 0, sizeof(buckets)); + + /* + * We work with discrete data buckets smaller than 1 does not make + * sense as well as it's a good idea to keep buckets integer sized + * to avoid scaling artifacts. + */ + bucket_size = MAX(1u, ceilu(1.00 * (max_sample - min_sample)/(rows-1))); + + for (i = 0; i < cur_sample; i++) { + unsigned int bucket; + bucket = flooru(1.00 * (samples[i] - min_sample)/bucket_size); + buckets[bucket]++; + } + + unsigned int max_bucket = buckets[0]; + for (i = 1; i < rows; i++) + max_bucket = MAX(max_bucket, buckets[i]); + + fprintf(stderr, "\n%*s| Frequency\n", line_header_len - 2, table_heading); + + print_line('-', cols); + fputc('\n', stderr); + + unsigned int l, r; + + for (l = 0; l < rows; l++) { + if (buckets[l]) + break; + } + + for (r = rows-1; r > l; r--) { + if (buckets[r]) + break; + } + + for (i = l; i <= r; i++) { + float len = bucket_len(buckets[i], max_bucket, plot_line_len); + + fprintf(stderr, "%*lli | ", + line_header_len - 3, min_sample + bucket_size*i); + print_line('*', len); + + if ((len - (int)len) >= 0.5) + fputc('+', stderr); + else if ((len - (int)len) >= 0.25) + fputc('-', stderr); + else if (len < 0.25 && buckets[i]) + fputc('.', stderr); + + fputc('\n', stderr); + } + + print_line('-', cols); + fputc('\n', stderr); + + float scale = 1.00 * plot_line_len / max_bucket; + + fprintf(stderr, + "%*uus | 1 sample = %.5f '*', %.5f '+', %.5f '-', non-zero '.'\n", + line_header_len - 5, bucket_size, scale, scale * 2, scale * 4); + + fputc('\n', stderr); +} + +void tst_timer_sample(void) +{ + samples[cur_sample++] = tst_timer_elapsed_us(); +} + +static int cmp(const void *a, const void *b) +{ + const long long *aa = a, *bb = b; + + return (*bb - *aa); +} + +/* + * The threshold per one syscall is computed as a sum of: + * + * 400 us - accomodates for context switches, process + * migrations between CPUs on SMP, etc. + * 2*monotonic_resolution - accomodates for granurality of the CLOCK_MONOTONIC + * slack_per_scall - max of 0.1% of the sleep capped on 100ms or + * current->timer_slack_ns, which is slack allowed + * in kernel + * + * The formula for slack_per_scall applies to select() and *poll*() syscalls, + * the futex and *nanosleep() use only the timer_slack_ns, so we are a bit + * less strict here that we could be for these two for longer sleep times... + * + * We also allow for outliners, i.e. add some number to the threshold in case + * that the number of iteration is small. For large enoung number of iterations + * outliners are discarded and averaged out. + */ +static long long compute_threshold(long long requested_us, + unsigned int nsamples) +{ + unsigned int slack_per_scall = MIN(100000LL, requested_us / 1000); + + slack_per_scall = MAX(slack_per_scall, timerslack); + + return (400 + 2 * monotonic_resolution + slack_per_scall) * nsamples + + 3000/nsamples; +} + +/* + * Returns number of samples to discard. + * + * We set it to either at least 1 if number of samples > 1 or 5%. + */ +static unsigned int compute_discard(unsigned int nsamples) +{ + if (nsamples == 1) + return 0; + + return MAX(1u, nsamples / 20); +} + +static void write_to_file(void) +{ + unsigned int i; + FILE *f; + + if (!file_name) + return; + + f = fopen(file_name, "w"); + + if (!f) { + tst_res(TWARN | TERRNO, + "Failed to open '%s'", file_name); + return; + } + + for (i = 0; i < cur_sample; i++) + fprintf(f, "%lli\n", samples[i]); + + if (fclose(f)) { + tst_res(TWARN | TERRNO, + "Failed to close file '%s'", file_name); + } +} + + +/* + * Timer testing function. + * + * What we do here is: + * + * * Take nsamples measurements of the timer function, the function + * to be sampled is defined in the actual test. + * + * * We sort the array of samples, then: + * + * - look for outliners which are samples where the sleep time has exceeded + * requested sleep time by an order of magnitude and, at the same time, are + * greater than clock resolution multiplied by three. + * + * - check for samples where the call has woken up too early which is a plain + * old bug + * + * - then we compute truncated mean and compare that with the requested sleep + * time increased by a threshold + */ +void do_timer_test(long long usec, unsigned int nsamples) +{ + long long trunc_mean, median; + unsigned int discard = compute_discard(nsamples); + unsigned int keep_samples = nsamples - discard; + long long threshold = compute_threshold(usec, keep_samples); + int i; + int failed = 0; + + tst_res(TINFO, + "%s sleeping for %llius %u iterations, threshold %.2fus", + scall, usec, nsamples, 1.00 * threshold / (keep_samples)); + + cur_sample = 0; + for (i = 0; i < (int)nsamples; i++) { + if (sample(CLOCK_MONOTONIC, usec)) { + tst_res(TINFO, "sampling function failed, exiting"); + return; + } + } + + qsort(samples, nsamples, sizeof(samples[0]), cmp); + + write_to_file(); + + for (i = 0; samples[i] > 10 * usec && i < (int)nsamples; i++) { + if (samples[i] <= 3 * monotonic_resolution) + break; + } + + if (i > 0) { + tst_res(TINFO, "Found %i outliners in [%lli,%lli] range", + i, samples[0], samples[i-1]); + } + + for (i = nsamples - 1; samples[i] < usec && i > -1; i--); + + if (i < (int)nsamples - 1) { + tst_res(TFAIL, "%s woken up early %u times range: [%lli,%lli]", + scall, nsamples - 1 - i, + samples[i+1], samples[nsamples-1]); + failed = 1; + } + + median = samples[nsamples/2]; + + trunc_mean = 0; + + for (i = discard; i < (int)nsamples; i++) + trunc_mean += samples[i]; + + tst_res(TINFO, + "min %llius, max %llius, median %llius, trunc mean %.2fus (discarded %u)", + samples[nsamples-1], samples[0], median, + 1.00 * trunc_mean / keep_samples, discard); + + if (virt_env) { + tst_res(TINFO, + "Virtualisation detected, skipping oversleep checks"); + } else if (trunc_mean > (nsamples - discard) * usec + threshold) { + tst_res(TFAIL, "%s slept for too long", scall); + + if (!print_frequency_plot) + frequency_plot(); + + failed = 1; + } + + if (print_frequency_plot) + frequency_plot(); + + if (!failed) + tst_res(TPASS, "Measured times are within thresholds"); +} + +static void parse_timer_opts(void); + +static int set_latency(void) +{ + int fd, latency = 0; + + fd = open("/dev/cpu_dma_latency", O_WRONLY); + if (fd < 0) + return fd; + + return write(fd, &latency, sizeof(latency)); +} + +static void timer_setup(void) +{ + struct timespec t; + int ret; + + if (setup) + setup(); + + /* + * Running tests in VM may cause timing issues, disable upper bound + * checks if any hypervisor is detected. + */ + virt_env = tst_is_virt(VIRT_ANY); + tst_clock_getres(CLOCK_MONOTONIC, &t); + + tst_res(TINFO, "CLOCK_MONOTONIC resolution %lins", (long)t.tv_nsec); + + monotonic_resolution = t.tv_nsec / 1000; + timerslack = 50; + +#ifdef PR_GET_TIMERSLACK + ret = prctl(PR_GET_TIMERSLACK); + if (ret < 0) { + tst_res(TINFO, "prctl(PR_GET_TIMERSLACK) = -1, using %uus", + timerslack); + } else { + timerslack = ret / 1000; + tst_res(TINFO, "prctl(PR_GET_TIMERSLACK) = %ius", timerslack); + } +#else + tst_res(TINFO, "PR_GET_TIMERSLACK not defined, using %uus", + timerslack); +#endif /* PR_GET_TIMERSLACK */ + parse_timer_opts(); + + samples = SAFE_MALLOC(sizeof(long long) * MAX(MAX_SAMPLES, sample_cnt)); + if (set_latency() < 0) + tst_res(TINFO, "Failed to set zero latency constraint: %m"); +} + +static void timer_cleanup(void) +{ + free(samples); + + if (cleanup) + cleanup(); +} + +static struct tst_timer_tcase { + long long usec; + unsigned int samples; +} tcases[] = { + {1000, 500}, + {2000, 500}, + {5000, 300}, + {10000, 100}, + {25000, 50}, + {100000, 10}, + {1000000, 2}, +}; + +static void timer_test_fn(unsigned int n) +{ + do_timer_test(tcases[n].usec, tcases[n].samples); +} + +static void single_timer_test(void) +{ + do_timer_test(sleep_time, sample_cnt); +} + +static struct tst_option options[] = { + {"p", &print_frequency_plot, "-p Print frequency plot"}, + {"s:", &str_sleep_time, "-s us Sleep time"}, + {"n:", &str_sample_cnt, "-n uint Number of samples to take"}, + {"f:", &file_name, "-f fname Write measured samples into a file"}, + {NULL, NULL, NULL} +}; + +static void parse_timer_opts(void) +{ + size_t i; + long long runtime_us = 0; + + if (str_sleep_time) { + if (tst_parse_int(str_sleep_time, &sleep_time, 0, INT_MAX)) { + tst_brk(TBROK, + "Invalid sleep time '%s'", str_sleep_time); + } + } + + if (str_sample_cnt) { + if (tst_parse_int(str_sample_cnt, &sample_cnt, 1, INT_MAX)) { + tst_brk(TBROK, + "Invalid sample count '%s'", str_sample_cnt); + } + } + + if (str_sleep_time || str_sample_cnt) { + if (sleep_time < 0) + sleep_time = 10000; + + if (!sample_cnt) + sample_cnt = 500; + + runtime_us = sleep_time * sample_cnt; + + test->test_all = single_timer_test; + test->test = NULL; + test->tcnt = 0; + } else { + for (i = 0; i < ARRAY_SIZE(tcases); i++) + runtime_us += tcases[i].usec * tcases[i].samples; + } + + tst_set_runtime((runtime_us + runtime_us/10)/1000000); +} + +struct tst_test *tst_timer_test_setup(struct tst_test *timer_test) +{ + setup = timer_test->setup; + cleanup = timer_test->cleanup; + scall = timer_test->scall; + sample = timer_test->sample; + + timer_test->scall = NULL; + timer_test->setup = timer_setup; + timer_test->cleanup = timer_cleanup; + timer_test->test = timer_test_fn; + timer_test->tcnt = ARRAY_SIZE(tcases); + timer_test->sample = NULL; + timer_test->options = options; + + test = timer_test; + + return timer_test; +} diff --git a/ltp/lib/tst_tmpdir.c b/ltp/lib/tst_tmpdir.c new file mode 100644 index 0000000000000000000000000000000000000000..6ed2367b92278d11b8408918586eb4f2d258a659 --- /dev/null +++ b/ltp/lib/tst_tmpdir.c @@ -0,0 +1,402 @@ +/********************************************************** + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + *********************************************************/ + +/********************************************************** + * + * OS Testing - Silicon Graphics, Inc. + * + * FUNCTION NAME : tst_tmpdir, tst_rmdir + * + * FUNCTION TITLE : Create/remove a testing temp dir + * + * SYNOPSIS: + * void tst_tmpdir(); + * void tst_rmdir(); + * + * AUTHOR : Dave Fenner + * + * INITIAL RELEASE : UNICOS 8.0 + * + * DESCRIPTION + * tst_tmpdir() is used to create a unique, temporary testing + * directory, and make it the current working directory. + * tst_rmdir() is used to remove the directory created by + * tst_tmpdir(). + * + * RETURN VALUE + * Neither tst_tmpdir() or tst_rmdir() has a return value. + * + *********************************************************/ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "tst_buffers.h" +#include "safe_macros.h" +#include "tst_tmpdir.h" +#include "ltp_priv.h" +#include "lapi/futex.h" + +/* + * Define some useful macros. + */ +#define DIR_MODE (S_IRWXU|S_IRWXG|S_IRWXO) + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +/* + * Define global variables. + */ +extern char *TCID; /* defined/initialized in main() */ +static char *TESTDIR; /* the directory created */ + +static char test_start_work_dir[PATH_MAX]; + +/* lib/tst_checkpoint.c */ +extern futex_t *tst_futexes; + +static int rmobj(const char *obj, char **errmsg); + +int tst_tmpdir_created(void) +{ + return TESTDIR != NULL; +} + +char *tst_get_tmpdir(void) +{ + char *ret = NULL; + + if (TESTDIR == NULL) { + tst_brkm(TBROK, NULL, "you must call tst_tmpdir() first"); + return NULL; + } + + ret = strdup(TESTDIR); + if (!ret) + tst_brkm(TBROK, NULL, "strdup() failed"); + + return ret; +} + +const char *tst_get_tmpdir_root(void) +{ + const char *env_tmpdir = getenv("TMPDIR"); + + if (!env_tmpdir) + env_tmpdir = TEMPDIR; + + if (env_tmpdir[0] != '/') { + tst_brkm(TBROK, NULL, "You must specify an absolute " + "pathname for environment variable TMPDIR"); + return NULL; + } + return env_tmpdir; +} + +const char *tst_get_startwd(void) +{ + return test_start_work_dir; +} + +static int purge_dir(const char *path, char **errptr) +{ + int ret_val = 0; + DIR *dir; + struct dirent *dir_ent; + char dirobj[PATH_MAX]; + static char err_msg[PATH_MAX + 1280]; + + /* Do NOT perform the request if the directory is "/" */ + if (!strcmp(path, "/")) { + if (errptr) { + strcpy(err_msg, "Cannot purge system root directory"); + *errptr = err_msg; + } + + return -1; + } + + errno = 0; + + /* Open the directory to get access to what is in it */ + if (!(dir = opendir(path))) { + if (errptr) { + sprintf(err_msg, + "Cannot open directory %s; errno=%d: %s", + path, errno, tst_strerrno(errno)); + *errptr = err_msg; + } + return -1; + } + + /* Loop through the entries in the directory, removing each one */ + for (dir_ent = readdir(dir); dir_ent; dir_ent = readdir(dir)) { + /* Don't remove "." or ".." */ + if (!strcmp(dir_ent->d_name, ".") + || !strcmp(dir_ent->d_name, "..")) + continue; + + /* Recursively remove the current entry */ + sprintf(dirobj, "%s/%s", path, dir_ent->d_name); + if (rmobj(dirobj, errptr) != 0) + ret_val = -1; + } + + closedir(dir); + return ret_val; +} + +static int rmobj(const char *obj, char **errmsg) +{ + int ret_val = 0; + struct stat statbuf; + static char err_msg[PATH_MAX + 1280]; + int fd; + + fd = open(obj, O_DIRECTORY | O_NOFOLLOW); + if (fd >= 0) { + close(fd); + ret_val = purge_dir(obj, errmsg); + + /* If there were problems removing an entry, don't attempt to + remove the directory itself */ + if (ret_val == -1) + return -1; + + /* Get the link count, now that all the entries have been removed */ + if (lstat(obj, &statbuf) < 0) { + if (errmsg != NULL) { + sprintf(err_msg, + "lstat(%s) failed; errno=%d: %s", obj, + errno, tst_strerrno(errno)); + *errmsg = err_msg; + } + return -1; + } + + /* Remove the directory itself */ + if (statbuf.st_nlink >= 3) { + /* The directory is linked; unlink() must be used */ + if (unlink(obj) < 0) { + if (errmsg != NULL) { + sprintf(err_msg, + "unlink(%s) failed; errno=%d: %s", + obj, errno, tst_strerrno(errno)); + *errmsg = err_msg; + } + return -1; + } + } else { + /* The directory is not linked; remove() can be used */ + if (remove(obj) < 0) { + if (errmsg != NULL) { + sprintf(err_msg, + "remove(%s) failed; errno=%d: %s", + obj, errno, tst_strerrno(errno)); + *errmsg = err_msg; + } + return -1; + } + } + } else { + if (unlink(obj) < 0) { + if (errmsg != NULL) { + sprintf(err_msg, + "unlink(%s) failed; errno=%d: %s", obj, + errno, tst_strerrno(errno)); + *errmsg = err_msg; + } + return -1; + } + } + + return 0; +} + +void tst_tmpdir(void) +{ + char template[PATH_MAX]; + const char *env_tmpdir; + char *errmsg; + + /* + * Create a template for the temporary directory. Use the + * environment variable TMPDIR if it is available, otherwise + * use our default TEMPDIR. + */ + env_tmpdir = tst_get_tmpdir_root(); + snprintf(template, PATH_MAX, "%s/LTP_%.3sXXXXXX", env_tmpdir, TCID); + + /* Make the temporary directory in one shot using mkdtemp. */ + if (mkdtemp(template) == NULL) { + tst_brkm(TBROK | TERRNO, NULL, + "%s: mkdtemp(%s) failed", __func__, template); + return; + } + + if ((TESTDIR = strdup(template)) == NULL) { + tst_brkm(TBROK | TERRNO, NULL, + "%s: strdup(%s) failed", __func__, template); + return; + } + + SAFE_CHOWN(NULL, TESTDIR, -1, getgid()); + + SAFE_CHMOD(NULL, TESTDIR, DIR_MODE); + + if (getcwd(test_start_work_dir, sizeof(test_start_work_dir)) == NULL) { + tst_resm(TINFO, "Failed to record test working dir"); + test_start_work_dir[0] = '\0'; + } + + /* + * Change to the temporary directory. If the chdir() fails, issue + * TBROK messages for all test cases, attempt to remove the + * directory (if it was created), and exit. If the removal also + * fails, also issue a TWARN message. + */ + if (chdir(TESTDIR) == -1) { + tst_resm(TERRNO, "%s: chdir(%s) failed", __func__, TESTDIR); + + /* Try to remove the directory */ + if (rmobj(TESTDIR, &errmsg) == -1) { + tst_resm(TWARN, "%s: rmobj(%s) failed: %s", + __func__, TESTDIR, errmsg); + } + + tst_exit(); + } + + tst_resm(TINFO, "Using %s as tmpdir (%s filesystem)", TESTDIR, + tst_fs_type_name(tst_fs_type(NULL, TESTDIR))); +} + +void tst_rmdir(void) +{ + char *errmsg; + + /* + * Check that TESTDIR is not NULL. + */ + if (TESTDIR == NULL) { + tst_resm(TWARN, + "%s: TESTDIR was NULL; no removal attempted", + __func__); + return; + } + + /* + * Unmap the backend file. + * This is needed to overcome the NFS "silly rename" feature. + */ + if (tst_futexes) { + msync((void *)tst_futexes, getpagesize(), MS_SYNC); + munmap((void *)tst_futexes, getpagesize()); + } + + /* + * Attempt to remove the "TESTDIR" directory, using rmobj(). + */ + if (rmobj(TESTDIR, &errmsg) == -1) { + tst_resm(TWARN, "%s: rmobj(%s) failed: %s", + __func__, TESTDIR, errmsg); + } +} + +void tst_purge_dir(const char *path) +{ + char *err; + + if (purge_dir(path, &err)) + tst_brkm(TBROK, NULL, "%s: %s", __func__, err); +} + +char *tst_tmpdir_path(void) +{ + static char *tmpdir; + + if (!TESTDIR) + tst_brkm(TBROK, NULL, ".needs_tmpdir must be set!"); + + if (tmpdir) + return tmpdir; + + tmpdir = tst_strdup(TESTDIR); + + return tmpdir; +} + +char *tst_tmpdir_genpath(const char *fmt, ...) +{ + size_t testdir_len, path_len; + va_list va, vac; + char *ret; + + if (!TESTDIR) + tst_brkm(TBROK, NULL, ".needs_tmpdir must be set!"); + + testdir_len = strlen(TESTDIR); + path_len = testdir_len; + + va_start(va, fmt); + va_copy(vac, va); + path_len += vsnprintf(NULL, 0, fmt, va) + 2; + va_end(va); + + ret = tst_alloc(path_len); + + strcpy(ret, TESTDIR); + + ret[testdir_len] = '/'; + + vsprintf(ret + testdir_len + 1, fmt, vac); + va_end(vac); + + return ret; +} diff --git a/ltp/lib/tst_uid.c b/ltp/lib/tst_uid.c new file mode 100644 index 0000000000000000000000000000000000000000..af4ef8cf72d507c0ca91eac40b06ac0a1aa6f583 --- /dev/null +++ b/ltp/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/ltp/lib/tst_virt.c b/ltp/lib/tst_virt.c new file mode 100644 index 0000000000000000000000000000000000000000..0fda20a17c2a9db07d4d880ec9ea408651c4cdbd --- /dev/null +++ b/ltp/lib/tst_virt.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2013 Linux Test Project + * + * 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. + */ + +#include +#include "test.h" +#include "safe_macros.h" + +static int is_kvm(void) +{ + FILE *cpuinfo; + char line[64]; + int found; + + /* this doesn't work with custom -cpu values, since there's + * no easy, reasonable or reliable way to work around those */ + cpuinfo = SAFE_FOPEN(NULL, "/proc/cpuinfo", "r"); + found = 0; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + if (strstr(line, "QEMU Virtual CPU")) { + found = 1; + break; + } + } + + SAFE_FCLOSE(NULL, cpuinfo); + return found; +} + +static int is_xen(void) +{ + char hypervisor_type[4]; + + if (access("/proc/xen", F_OK) == 0) + return 1; + + if (access("/sys/hypervisor/type", F_OK) == 0) { + SAFE_FILE_SCANF(NULL, "/sys/hypervisor/type", "%3s", + hypervisor_type); + return strncmp("xen", hypervisor_type, + sizeof(hypervisor_type)) == 0; + } + + 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_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); + + f = popen("systemd-detect-virt", "r"); + if (!f) { + signal(SIGCHLD, old_handler); + return 0; + } + + if (!fgets(virt_type, sizeof(virt_type), f)) + virt_type[0] = '\0'; + + ret = pclose(f); + + signal(SIGCHLD, old_handler); + + /* + * systemd-detect-virt not found by shell or no virtualization detected + * (systemd-detect-virt returns non-zero) + */ + if (ret < 0 || (WIFEXITED(ret) && WEXITSTATUS(ret) == 127)) + return -1; + + 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; +} + +int tst_is_virt(int virt_type) +{ + int ret = try_systemd_detect_virt(); + + if (ret > 0) { + if (virt_type == VIRT_ANY) + return 1; + else + return ret == virt_type; + } + + switch (virt_type) { + case VIRT_ANY: + 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; + } + + tst_brkm(TBROK, NULL, "invalid virt_type flag: %d", virt_type); + return -1; +} diff --git a/ltp/lib/tst_wallclock.c b/ltp/lib/tst_wallclock.c new file mode 100644 index 0000000000000000000000000000000000000000..ee53e2b7f3790278cade9e35b48ad12f91acb80a --- /dev/null +++ b/ltp/lib/tst_wallclock.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Linaro Limited. All rights reserved. + * Author: Rafael David Tinoco + */ + +#include + +#define TST_NO_DEFAULT_MAIN + +#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) +{ + /* save initial monotonic time to restore it when needed */ + + if (tst_clock_gettime(CLOCK_REALTIME, &real_begin)) + tst_brk(TBROK | TERRNO, "tst_clock_gettime() realtime failed"); + + if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_begin)) { + if (errno == EINVAL) { + tst_brk(TCONF | TERRNO, + "tst_clock_gettime() didn't support CLOCK_MONOTONIC_RAW"); + } + + tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed"); + } + + clock_saved = 1; +} + +void tst_wallclock_restore(void) +{ + static const char *localtime = "/etc/localtime"; + static struct timespec mono_end, elapsed, adjust; + int ret; + + 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); + + adjust = tst_timespec_add(real_begin, elapsed); + + /* restore realtime clock based on monotonic delta */ + + 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/ltp/libs/Makefile b/ltp/libs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..16ed3aa6d439729fa7317accdd79a6ae16665f48 --- /dev/null +++ b/ltp/libs/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) Cyril Hrubis + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/generic_trunk_target.mk diff --git a/ltp/libs/ipc/Makefile b/ltp/libs/ipc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ad8f5a23b0c0e2f8949fc193cc78d4de8a0c61ee --- /dev/null +++ b/ltp/libs/ipc/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) International Business Machines Corp., 2001 + +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := libltpipc.a + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/libs/ipc/libipc.c b/ltp/libs/ipc/libipc.c new file mode 100644 index 0000000000000000000000000000000000000000..c2ecbf02d926808ca295aaafb2a57191c8e8d5b6 --- /dev/null +++ b/ltp/libs/ipc/libipc.c @@ -0,0 +1,218 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2001 + * + * 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 + * libmsg.c + * + * DESCRIPTION + * common routines for the IPC system call tests. + * + * The library contains the following routines: + * + * getipckey() + * rm_queue() + * init_buf() + * rm_sema() + * getuserid() + * rm_shm() + */ + +#define LIBIPC +#include "ipcmsg.h" +#include "ipcsem.h" + +#include +#include +#include + +/* + * getipckey() - generates and returns a message key used by the "get" + * calls to create an IPC resource. + */ +key_t getipckey(void) +{ + const char a = 'a'; + int ascii_a = (int)a; + char *curdir = NULL; + size_t size = 0; + key_t ipc_key; + int proj_id; + static int count = 0; + + if (NULL == (curdir = getcwd(curdir, size))) { + tst_brkm(TBROK, cleanup, "Can't get current directory " + "in getipckey()"); + } + + /* + * Get a Sys V IPC key + * + * ftok() requires a character as a second argument. This is + * refered to as a "project identifier" in the man page. + */ + proj_id = count % 26 + ascii_a; + count++; + + if ((ipc_key = ftok(curdir, proj_id)) == -1) { + tst_brkm(TBROK, cleanup, "Can't get msgkey from ftok()"); + } + + return (ipc_key); +} + +/* + * rm_queue() - removes a message queue. + */ +void rm_queue(int queue_id) +{ + if (queue_id == -1) { /* no queue to remove */ + return; + } + + if (msgctl(queue_id, IPC_RMID, NULL) == -1) { + tst_resm(TINFO, "WARNING: message queue deletion failed."); + tst_resm(TINFO, "This could lead to IPC resource problems."); + tst_resm(TINFO, "id = %d", queue_id); + } +} + +/* + * init_buf() - initialize the message buffer with some text and a type. + */ +void init_buf(MSGBUF * m_buf, int type, int size) +{ + int i; + int ascii_a = (int)'a'; /* the ascii value for 'a' */ + + /* this fills the message with a repeating alphabet string */ + for (i = 0; i < size; i++) { + m_buf->mtext[i] = ascii_a + (i % 26); + } + + /* terminate the message */ + m_buf->mtext[i] = '\0'; + + /* if the type isn't valid, set it to 1 */ + if (type < 1) { + m_buf->mtype = 1; + } else { + m_buf->mtype = type; + } +} + +/* + * rm_sema() - removes a semaphore. + */ +void rm_sema(int sem_id) +{ + if (sem_id == -1) { /* no semaphore to remove */ + return; + } + + 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); + } +} + +/* + * getuserid() - return the integer value for the "user" id + */ +int getuserid(char *user) +{ + struct passwd *ent; + + /* get the uid value for the user */ + if ((ent = getpwnam(user)) == NULL) { + tst_brkm(TBROK, cleanup, "Couldn't get password entry for %s", + user); + } + + return (ent->pw_uid); +} + +/* + * rm_shm() - removes a shared memory segment. + */ +void rm_shm(int shm_id) +{ + if (shm_id == -1) { /* no segment to remove */ + return; + } + + /* + * check for # of attaches ? + */ + + if (shmctl(shm_id, IPC_RMID, NULL) == -1) { + tst_resm(TINFO, "WARNING: shared memory deletion failed."); + tst_resm(TINFO, "This could lead to IPC resource problems."); + tst_resm(TINFO, "id = %d", shm_id); + } +} + +#define BUFSIZE 512 + +/* + * Get the number of message queues already in use + */ +int get_used_msgqueues(void) +{ + FILE *f; + int used_queues; + char buff[BUFSIZE]; + + f = popen("ipcs -q", "r"); + if (!f) { + tst_brkm(TBROK | TERRNO, NULL, "pipe failed"); + } + /* FIXME: Start at -4 because ipcs prints four lines of header */ + for (used_queues = -4; fgets(buff, BUFSIZE, f); used_queues++) ; + pclose(f); + if (used_queues < 0) { + tst_brkm(TBROK, NULL, "Could not read output of 'ipcs' to " + "calculate used message queues"); + } + return used_queues; +} + +/* + * Get the max number of message queues allowed on system + */ +int get_max_msgqueues(void) +{ + FILE *f; + char buff[BUFSIZE]; + + /* Get the max number of message queues allowed on system */ + f = fopen("/proc/sys/kernel/msgmni", "r"); + if (!f) { + tst_resm(TBROK, "Could not open /proc/sys/kernel/msgmni"); + return -1; + } + if (!fgets(buff, BUFSIZE, f)) { + fclose(f); + tst_resm(TBROK, "Could not read /proc/sys/kernel/msgmni"); + return -1; + } + fclose(f); + return atoi(buff); +} diff --git a/ltp/libs/ipc/libmsgctl.c b/ltp/libs/ipc/libmsgctl.c new file mode 100644 index 0000000000000000000000000000000000000000..ae459d480218063102d391c4ebe5d2dbd6fe8fdd --- /dev/null +++ b/ltp/libs/ipc/libmsgctl.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * + * 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 would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libmsgctl.h" + +int doreader(long key, int tid, long type, int child, int nreps) +{ + int i, size; + int id; + struct mbuffer buffer; + + id = msgget(key, 0); + if (id < 0) { + printf("msgget() error in the reader of child group %d: %s\n", + child, strerror(errno)); + + return FAIL; + } + if (id != tid) { + printf("Message queue mismatch in the reader of child group %d for message queue id %d\n", + child, id); + + return FAIL; + } + for (i = 0; i < nreps; i++) { + memset(&buffer, 0, sizeof(buffer)); + + size = msgrcv(id, &buffer, 100, type, 0); + if (size < 0) { + printf("msgrcv() error in child %d, read # = %d: %s\n", + child, (i + 1), strerror(errno)); + + return FAIL; + } + if (buffer.type != type) { + printf("Type mismatch in child %d, read #d = %d: ", + child, (i + 1)); + printf("for message got %ld, expected - %ld\n", + buffer.type, type); + + return FAIL; + } + if (buffer.data.len + 1 != size) { + printf("Size mismatch in child %d, read # = %d: ", + child, (i + 1)); + printf("for message got %d, expected - %d\n", + buffer.data.len + 1, size); + + return FAIL; + } + if (verify(buffer.data.pbytes, (key % 255), size - 1, child)) { + printf("Verify failed in child %d read # = %d, key = %lx\n", + child, (i + 1), key); + + return FAIL; + } + key++; + } + return PASS; +} + +int dowriter(long key, int tid, long type, int child, int nreps) +{ + int i, size; + int id; + struct mbuffer buffer; + + id = msgget(key, 0); + if (id < 0) { + printf("msgget() error in the writer of child group %d: %s\n", + child, strerror(errno)); + + return FAIL; + } + if (id != tid) { + printf("Message queue mismatch in the reader of child group %d for message queue id %d\n", + child, id); + + return FAIL; + } + + for (i = 0; i < nreps; i++) { + memset(&buffer, 0, sizeof(buffer)); + + do { + size = (lrand48() % 99); + } while (size == 0); + fill_buffer(buffer.data.pbytes, (key % 255), size); + buffer.data.len = size; + buffer.type = type; + if (msgsnd(id, &buffer, size + 1, 0) < 0) { + printf("msgsnd() error in child %d, write # = %d, key = %lx: %s\n", + child, nreps, key, strerror(errno)); + + return FAIL; + } + key++; + } + return PASS; +} + +int fill_buffer(char *buf, char val, int size) +{ + int i; + + for (i = 0; i < size; i++) + buf[i] = val; + return 0; +} + +/* Check a buffer for correct values */ +int verify(char *buf, char val, int size, int child) +{ + while (size-- > 0) { + if (*buf++ != val) { + printf("Verify error in child %d, *buf = %x, val = %x, size = %d\n", + child, *buf, val, size); + + return FAIL; + } + } + return PASS; +} diff --git a/ltp/libs/newipc/Makefile b/ltp/libs/newipc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..741c78f81c89b7f3bbc69da04f252b312a26d5a8 --- /dev/null +++ b/ltp/libs/newipc/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2016 Xiao Yang + +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := libltpnewipc.a + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/libs/newipc/libnewipc.c b/ltp/libs/newipc/libnewipc.c new file mode 100644 index 0000000000000000000000000000000000000000..331f1b1f503ccf476dba49b9f7bdd22a53337410 --- /dev/null +++ b/ltp/libs/newipc/libnewipc.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Xiao Yang + */ + +/* + * DESCRIPTION + * common routines for the IPC system call tests. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN + +#include "tst_test.h" +#include "libnewipc.h" +#include "tst_safe_stdio.h" +#include "tst_safe_sysv_ipc.h" + +#define BUFSIZE 1024 + +key_t getipckey(const char *file, const int lineno) +{ + char buf[BUFSIZE]; + key_t key; + int id; + static int count; + + safe_getcwd(file, lineno, NULL, buf, BUFSIZE); + + id = count % 26 + (int) 'a'; + count++; + + key = ftok(buf, id); + if (key == -1) { + tst_brk(TBROK | TERRNO, + "ftok() failed at %s:%d", file, lineno); + } + + return key; +} + +int get_used_sysvipc(const char *file, const int lineno, const char *sysvipc_file) +{ + FILE *fp; + int used = -1; + char buf[BUFSIZE]; + + fp = safe_fopen(file, lineno, NULL, sysvipc_file, "r"); + + while (fgets(buf, BUFSIZE, fp) != NULL) + used++; + + fclose(fp); + + 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; +} + +void *probe_free_addr(const char *file, const int lineno) +{ + void *addr; + int shm_id = -1; + key_t probe_key = 0; + + probe_key = GETIPCKEY(); + + 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)); + + return addr; +} diff --git a/ltp/libs/numa/Makefile b/ltp/libs/numa/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a6856758d511d0f2073dc8220678a1d3ad6fcbac --- /dev/null +++ b/ltp/libs/numa/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) Cyril Hrubis + +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := libltpnuma.a + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/libs/numa/tst_numa.c b/ltp/libs/numa/tst_numa.c new file mode 100644 index 0000000000000000000000000000000000000000..c3297013befcf13ba60ecc203557b8d9ce4c5e1d --- /dev/null +++ b/ltp/libs/numa/tst_numa.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018 Cyril Hrubis + */ + +#include +#include +#include +#include "config.h" +#ifdef HAVE_NUMA_V2 +# include +# include +#endif + +#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) +{ + unsigned int i; + + for (i = 0; i < nodes->cnt; i++) { + tst_res(TINFO, "Node %i allocated %u pages", + nodes->map[i], nodes->counters[i]); + } +} + +void tst_nodemap_reset_counters(struct tst_nodemap *nodes) +{ + size_t arr_size = sizeof(unsigned int) * nodes->cnt; + + if (!nodes->counters) + nodes->counters = SAFE_MALLOC(arr_size); + + memset(nodes->counters, 0, arr_size); +} + +void tst_nodemap_free(struct tst_nodemap *nodes) +{ + free(nodes->counters); + free(nodes); +} + +#ifdef HAVE_NUMA_V2 + +const char *tst_mempolicy_mode_name(int mode) +{ + switch (mode) { + case MPOL_DEFAULT: + return "MPOL_DEFAULT"; + 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 "???"; + } +} + + +static void inc_counter(unsigned int node, struct tst_nodemap *nodes) +{ + unsigned int i; + + for (i = 0; i < nodes->cnt; i++) { + if (nodes->map[i] == node) { + nodes->counters[i]++; + break; + } + } +} + +void tst_nodemap_count_pages(struct tst_nodemap *nodes, + void *ptr, size_t size) +{ + size_t page_size = getpagesize(); + unsigned int i; + int node; + long ret; + unsigned int pages = (size + page_size - 1)/page_size; + + for (i = 0; i < pages; i++) { + ret = get_mempolicy(&node, NULL, 0, ptr + i * page_size, MPOL_F_NODE | MPOL_F_ADDR); + if (ret < 0) + tst_brk(TBROK | TERRNO, "get_mempolicy() failed"); + + if (node < 0) { + tst_res(TWARN, + "get_mempolicy(...) returned invalid node %i\n", node); + continue; + } + + inc_counter(node, nodes); + } +} + +void *tst_numa_map(const char *path, size_t size) +{ + char *ptr; + int fd = -1; + int flags = MAP_PRIVATE|MAP_ANONYMOUS; + + if (path) { + fd = SAFE_OPEN(path, O_CREAT | O_EXCL | O_RDWR, 0666); + SAFE_FTRUNCATE(fd, size); + flags = MAP_SHARED; + } + + ptr = SAFE_MMAP(NULL, size, + PROT_READ|PROT_WRITE, flags, fd, 0); + + if (path) { + SAFE_CLOSE(fd); + SAFE_UNLINK(path); + } + + return ptr; +} + +static int node_has_enough_memory(int node, size_t min_kb) +{ + char path[1024]; + char buf[1024]; + long mem_total = -1; + long mem_used = -1; + long file_pages = 0; + long mem_avail; + + /* Make sure there is some space for kernel upkeeping as well */ + min_kb += 4096; + + snprintf(path, sizeof(path), "/sys/devices/system/node/node%i/meminfo", node); + + if (access(path, F_OK)) { + tst_res(TINFO, "File '%s' does not exist! NUMA not enabled?", path); + return 0; + } + + FILE *fp = fopen(path, "r"); + if (!fp) + tst_brk(TBROK | TERRNO, "Failed to open '%s'", path); + + while (fgets(buf, sizeof(buf), fp)) { + long val; + + if (sscanf(buf, "%*s %*i MemTotal: %li", &val) == 1) + mem_total = val; + + if (sscanf(buf, "%*s %*i MemUsed: %li", &val) == 1) + mem_used = val; + + if (sscanf(buf, "%*s %*i FilePages: %li", &val) == 1) + file_pages = val; + } + + fclose(fp); + + if (mem_total == -1 || mem_used == -1) { + tst_res(TWARN, "Failed to parse '%s'", path); + return 0; + } + + mem_avail = mem_total - mem_used + (9 * file_pages)/10; + + if (mem_avail < (long)min_kb) { + tst_res(TINFO, + "Not enough free RAM on node %i, have %likB needs %zukB", + node, mem_avail, min_kb); + return 0; + } + + return 1; +} + +struct tst_nodemap *tst_get_nodemap(int type, size_t min_mem_kb) +{ + struct bitmask *membind; + struct tst_nodemap *nodes; + unsigned int i, cnt; + + if (type & ~(TST_NUMA_MEM)) + tst_brk(TBROK, "Invalid type %i\n", type); + + membind = numa_get_membind(); + + cnt = 0; + for (i = 0; i < membind->size; i++) { + if (type & TST_NUMA_MEM && !numa_bitmask_isbitset(membind, i)) + continue; + + cnt++; + } + + tst_res(TINFO, "Found %u NUMA memory nodes", cnt); + + nodes = SAFE_MALLOC(sizeof(struct tst_nodemap) + + sizeof(unsigned int) * cnt); + nodes->cnt = cnt; + nodes->counters = NULL; + + cnt = 0; + for (i = 0; i < membind->size; i++) { + if (type & TST_NUMA_MEM && + (!numa_bitmask_isbitset(membind, i) || + !node_has_enough_memory(i, min_mem_kb))) + continue; + + nodes->map[cnt++] = i; + } + + nodes->cnt = cnt; + + numa_bitmask_free(membind); + + return nodes; +} + +#endif diff --git a/ltp/libs/sigwait/Makefile b/ltp/libs/sigwait/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e0ea025ade2b3f0c02cb18d5dd4cc2e15eef6f64 --- /dev/null +++ b/ltp/libs/sigwait/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/ltp/libs/sigwait/sigwait.c b/ltp/libs/sigwait/sigwait.c new file mode 100644 index 0000000000000000000000000000000000000000..a9fd62d73ce480c0e67cc0263ad86984e6613a2a --- /dev/null +++ b/ltp/libs/sigwait/sigwait.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) Jiri Palecek, 2009 */ + +#define TST_NO_DEFAULT_MAIN +#include +#include +#include +#include "libsigwait.h" +#include "tst_sig_proc.h" +#include "lapi/syscalls.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); + + SAFE_SIGPROCMASK(SIG_SETMASK, &sigs, &oldmask); + + /* 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); + + TST_EXP_FAIL(sigwaitinfo(&sigs, (void *)1, NULL), EFAULT); + SAFE_SIGPROCMASK(SIG_SETMASK, &oldmask, NULL); + + 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; + pid_t pid; + int status; + + pid = SAFE_FORK(); + if (pid == 0) { + SAFE_SIGEMPTYSET(&sigs); + TST_EXP_FAIL(sigwaitinfo(&sigs, NULL, (void *)1), EFAULT); + _exit(0); + } + + SAFE_WAITPID(pid, &status, 0); + + if (WIFEXITED(status) && !WEXITSTATUS(status)) + return; + + if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) { + tst_res(TPASS, "Child killed by expected signal"); + return; + } + + tst_res(TFAIL, "Child %s", tst_strstatus(status)); +} + +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/ltp/libs/swap/Makefile b/ltp/libs/swap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d8e692d17cc4abe798f5c3337f986c58ceba1343 --- /dev/null +++ b/ltp/libs/swap/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/ltp/libs/swap/libswap.c b/ltp/libs/swap/libswap.c new file mode 100644 index 0000000000000000000000000000000000000000..e10355502916fcf19085146a15bb08ea81c4e6d7 --- /dev/null +++ b/ltp/libs/swap/libswap.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) Linux Test Project, 2014-2024 + * Author: Stanislav Kholmanskikh + */ + +#include +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#define DEFAULT_MAX_SWAPFILE 32 +#define BUFSIZE 200 + +#include "tst_test.h" +#include "libswap.h" +#include "lapi/syscalls.h" +#include "tst_kconfig.h" +#include "tst_kvercmp.h" +#include "tst_safe_stdio.h" + +static const char *const swap_supported_fs[] = { + "btrfs", + "ext2", + "ext3", + "ext4", + "xfs", + "vfat", + "exfat", + "ntfs", + NULL +}; + +static void set_nocow_attr(const char *filename) +{ + int fd; + int attrs; + + tst_res(TINFO, "FS_NOCOW_FL attribute set on %s", filename); + + fd = SAFE_OPEN(filename, O_RDONLY); + + SAFE_IOCTL(fd, FS_IOC_GETFLAGS, &attrs); + + attrs |= FS_NOCOW_FL; + + SAFE_IOCTL(fd, FS_IOC_SETFLAGS, &attrs); + + SAFE_CLOSE(fd); +} + +static int prealloc_contiguous_file(const char *path, size_t bs, size_t bcount) +{ + int fd; + + fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0600); + if (fd < 0) + return -1; + + /* Btrfs file need set 'nocow' attribute */ + if (tst_fs_type(path) == TST_BTRFS_MAGIC) + set_nocow_attr(path); + + if (tst_prealloc_size_fd(fd, bs, bcount)) { + close(fd); + unlink(path); + return -1; + } + + if (close(fd) < 0) { + unlink(path); + return -1; + } + + return 0; +} + +static int file_is_contiguous(const char *filename) +{ + int fd, contiguous = 0; + struct fiemap *fiemap; + + if (tst_fibmap(filename) == 0) { + contiguous = 1; + goto out; + } + + if (tst_fs_type(filename) == TST_TMPFS_MAGIC) + goto out; + + fd = SAFE_OPEN(filename, O_RDONLY); + + fiemap = (struct fiemap *)SAFE_MALLOC(sizeof(struct fiemap) + + sizeof(struct fiemap_extent)); + + memset(fiemap, 0, sizeof(struct fiemap) + sizeof(struct fiemap_extent)); + + fiemap->fm_start = 0; + fiemap->fm_length = ~0; + fiemap->fm_flags = 0; + fiemap->fm_extent_count = 1; + + SAFE_IOCTL(fd, FS_IOC_FIEMAP, fiemap); + + /* + * fiemap->fm_mapped_extents != 1: + * This checks if the file does not have exactly one extent. If there are more + * or zero extents, the file is not stored in a single contiguous block. + * + * fiemap->fm_extents[0].fe_logical != 0: + * This checks if the first extent does not start at the logical offset 0 of + * the file. If it doesn't, it indicates that the file's first block of data + * is not at the beginning of the file, which implies non-contiguity. + * + * (fiemap->fm_extents[0].fe_flags & FIEMAP_EXTENT_LAST) != FIEMAP_EXTENT_LAST: + * This checks if the first extent does not have the FIEMAP_EXTENT_LAST flag set. + * If the flag isn't set, it means that this extent is not the last one, suggesting + * that there are more extents and the file is not contiguous. + */ + if (fiemap->fm_mapped_extents != 1 || + fiemap->fm_extents[0].fe_logical != 0 || + (fiemap->fm_extents[0].fe_flags & FIEMAP_EXTENT_LAST) != FIEMAP_EXTENT_LAST) { + + tst_res(TINFO, "File '%s' is not contiguous", filename); + contiguous = 0; + } + + SAFE_CLOSE(fd); + free(fiemap); + +out: + return contiguous; +} + +int make_swapfile(const char *file, const int lineno, + const char *swapfile, unsigned int num, + int safe, enum swapfile_method method) +{ + struct statvfs fs_info; + unsigned long blk_size; + unsigned int blocks = 0; + size_t pg_size = sysconf(_SC_PAGESIZE); + char mnt_path[PATH_MAX]; + + if (statvfs(".", &fs_info) == -1) + tst_brk_(file, lineno, TBROK, "statvfs failed"); + + blk_size = fs_info.f_bsize; + + if (method == SWAPFILE_BY_SIZE) { + tst_res_(file, lineno, TINFO, "create a swapfile size of %u megabytes (MB)", num); + blocks = num * 1024 * 1024 / blk_size; + } else if (method == SWAPFILE_BY_BLKS) { + blocks = num; + tst_res_(file, lineno, TINFO, "create a swapfile with %u block numbers", blocks); + } else { + tst_brk_(file, lineno, TBROK, "Invalid method, please see include/libswap.h"); + } + + /* To guarantee at least one page can be swapped out */ + if (blk_size * blocks < pg_size) { + tst_res_(file, lineno, TWARN, "Swapfile size is less than the system page size. " + "Using page size (%lu bytes) instead of block size (%lu bytes).", + (unsigned long)pg_size, blk_size); + blk_size = pg_size; + } + + if (sscanf(swapfile, "%[^/]", mnt_path) != 1) + tst_brk_(file, lineno, TBROK, "sscanf failed"); + + if (!tst_fs_has_free(mnt_path, blk_size * blocks, TST_BYTES)) + tst_brk_(file, lineno, TCONF, "Insufficient disk space to create swap file"); + + /* create file */ + if (prealloc_contiguous_file(swapfile, blk_size, blocks) != 0) + tst_brk_(file, lineno, TBROK, "Failed to create swapfile"); + + /* Fill the file if needed (specific to old xfs filesystems) */ + if (tst_fs_type(swapfile) == TST_XFS_MAGIC) { + if (tst_fill_file(swapfile, 0, blk_size, blocks) != 0) + tst_brk_(file, lineno, TBROK, "Failed to fill swapfile"); + } + + /* make the file swapfile */ + const char *const argv[] = {"mkswap", swapfile, NULL}; + + return tst_cmd(argv, "/dev/null", "/dev/null", safe ? + TST_CMD_PASS_RETVAL | TST_CMD_TCONF_ON_MISSING : 0); +} + +bool is_swap_supported(const char *filename) +{ + int i, sw_support = 0; + int ret = SAFE_MAKE_SMALL_SWAPFILE(filename); + int fi_contiguous = file_is_contiguous(filename); + long fs_type = tst_fs_type(filename); + const char *fstype = tst_fs_type_name(fs_type); + + if (fs_type == TST_BTRFS_MAGIC && + tst_kvercmp(5, 0, 0) < 0) + tst_brk(TCONF, "Swapfile on Btrfs (kernel < 5.0) not implemented"); + + for (i = 0; swap_supported_fs[i]; i++) { + if (strstr(fstype, swap_supported_fs[i])) { + sw_support = 1; + break; + } + } + + if (ret != 0) { + if (fi_contiguous == 0 && sw_support == 0) { + tst_brk(TCONF, "mkswap on %s not supported", fstype); + } else { + tst_res(TFAIL, "mkswap on %s failed", fstype); + return false; + } + } + + TEST(tst_syscall(__NR_swapon, filename, 0)); + if (TST_RET == -1) { + if (errno == EPERM) { + tst_brk(TCONF, "Permission denied for swapon()"); + } else if (errno == EINVAL && fi_contiguous == 0 && sw_support == 0) { + tst_brk(TCONF, "Swapfile on %s not implemented", fstype); + } else { + tst_res(TFAIL | TTERRNO, "swapon() on %s failed", fstype); + return false; + } + } + + TEST(tst_syscall(__NR_swapoff, filename, 0)); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, "swapoff on %s failed", fstype); + return false; + } + + return true; +} + +int tst_max_swapfiles(void) +{ + unsigned int swp_migration_num = 0, swp_hwpoison_num = 0, + swp_device_num = 0, swp_pte_marker_num = 0, + swp_swapin_error_num = 0; + struct tst_kconfig_var migration = TST_KCONFIG_INIT("CONFIG_MIGRATION"); + struct tst_kconfig_var memory = TST_KCONFIG_INIT("CONFIG_MEMORY_FAILURE"); + struct tst_kconfig_var device = TST_KCONFIG_INIT("CONFIG_DEVICE_PRIVATE"); + struct tst_kconfig_var marker = TST_KCONFIG_INIT("CONFIG_PTE_MARKER"); + struct tst_kern_exv kvers_marker_migration[] = { + /* RHEL9 kernel has patch 6c287605f and 679d10331 since 5.14.0-179 */ + { "RHEL9", "5.14.0-179" }, + { NULL, NULL}, + }; + + struct tst_kern_exv kvers_marker_migration2[] = { + /* RHEL9 kernel has patch ca92ea3dc5a since 5.14.0-441 */ + { "RHEL9", "5.14.0-441" }, + { NULL, NULL}, + }; + + struct tst_kern_exv kvers_device[] = { + /* SLES12-SP4 has patch 5042db43cc26 since 4.12.14-5.5 */ + { "SLES", "4.12.14-5.5" }, + { NULL, NULL}, + }; + + tst_kconfig_read(&migration, 1); + tst_kconfig_read(&memory, 1); + tst_kconfig_read(&device, 1); + tst_kconfig_read(&marker, 1); + + if (migration.choice == 'y') { + if (tst_kvercmp2(5, 19, 0, kvers_marker_migration) < 0) + swp_migration_num = 2; + else + swp_migration_num = 3; + } + + if (memory.choice == 'y') + swp_hwpoison_num = 1; + + if (device.choice == 'y') { + if (tst_kvercmp2(4, 14, 0, kvers_device) >= 0) + swp_device_num = 2; + if (tst_kvercmp(5, 14, 0) >= 0) + swp_device_num = 4; + if (tst_kvercmp(6, 15, 0) >= 0) + swp_device_num = 3; + } + + if ((marker.choice == 'y' && + tst_kvercmp2(5, 19, 0, kvers_marker_migration) >= 0) + || tst_kvercmp2(6, 2, 0, kvers_marker_migration2) >= 0) { + swp_pte_marker_num = 1; + } + + if ((tst_kvercmp(5, 19, 0) >= 0) && (tst_kvercmp(6, 2, 0) < 0)) + swp_swapin_error_num = 1; + + return DEFAULT_MAX_SWAPFILE - swp_migration_num - swp_hwpoison_num + - swp_device_num - swp_pte_marker_num - swp_swapin_error_num; +} + +int tst_count_swaps(void) +{ + FILE *fp; + int used = -1; + char buf[BUFSIZE]; + + fp = SAFE_FOPEN("/proc/swaps", "r"); + if (fp == NULL) + return -1; + + while (fgets(buf, BUFSIZE, fp) != NULL) + used++; + + SAFE_FCLOSE(fp); + if (used < 0) + tst_brk(TBROK, "can't read /proc/swaps to get used swapfiles resource total"); + + return used; +} diff --git a/ltp/libs/uinput/Makefile b/ltp/libs/uinput/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c72dd2e1e6953f689d1055037f6a84f172a611bc --- /dev/null +++ b/ltp/libs/uinput/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) Cyril Hrubis + +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := libltpuinput.a + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/libs/uinput/tst_uinput.c b/ltp/libs/uinput/tst_uinput.c new file mode 100644 index 0000000000000000000000000000000000000000..16e6891535c30d59ba7ca9bd8da910b745e10d52 --- /dev/null +++ b/ltp/libs/uinput/tst_uinput.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Cedric Hnyda + * Copyright (c) 2019 Cyril Hrubis + */ + +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +#include "tst_uinput.h" +#include "tst_safe_stdio.h" + +#define VIRTUAL_DEVICE "virtual-device-ltp" + +static const char *uinput_paths[] = { + "/dev/input/uinput", + "/dev/uinput", +}; + +int open_uinput(void) +{ + unsigned int i; + int fd; + + for (i = 0; i < ARRAY_SIZE(uinput_paths); i++) { + fd = open(uinput_paths[i], O_WRONLY | O_NONBLOCK); + + if (fd > 0) { + tst_res(TINFO, "Found uinput dev at %s", uinput_paths[i]); + return fd; + } + + if (fd < 0 && errno != ENOENT) { + tst_brk(TBROK | TERRNO, "open(%s)", uinput_paths[i]); + } + } + + return -1; +} + + +#define SYSFS_PREFIX "Sysfs=" +#define HANDLERS_PREFIX "Handlers=" + +static char *parse_field(char *line, char field) +{ + char *value; + + switch (field) { + case 'H': + value = strstr(line, HANDLERS_PREFIX) + sizeof(HANDLERS_PREFIX) - 1; + break; + case 'S': + value = strstr(line, SYSFS_PREFIX) + sizeof(SYSFS_PREFIX) - 1; + break; + default: + return NULL; + } + + value[strlen(value) - 1] = 0; + + return strdup(value); +} + +char *get_input_field_value(char field) +{ + FILE *file; + char line[1024]; + int flag = 0; + + file = fopen("/proc/bus/input/devices", "r"); + if (!file) + return NULL; + + while (fgets(line, sizeof(line), file)) { + if (strstr(line, "N: Name=\""VIRTUAL_DEVICE"\"")) + flag = 1; + + if (flag) { + if (line[0] == field) + return parse_field(line, field); + + if (line[0] == '\n') + flag = 0; + } + } + + fclose(file); + return NULL; +} + +static int check_device(void) +{ + FILE *file; + char line[256]; + + file = fopen("/proc/bus/input/devices", "r"); + if (!file) + return 0; + + while (fgets(line, sizeof(line), file)) { + if (strstr(line, "Name=\""VIRTUAL_DEVICE"\"")) + return 1; + } + + fclose(file); + + return 0; +} + +void setup_mouse_events(int fd) +{ + SAFE_IOCTL(fd, UI_SET_EVBIT, EV_KEY); + SAFE_IOCTL(fd, UI_SET_KEYBIT, BTN_LEFT); + SAFE_IOCTL(fd, UI_SET_EVBIT, EV_REL); + SAFE_IOCTL(fd, UI_SET_RELBIT, REL_X); + SAFE_IOCTL(fd, UI_SET_RELBIT, REL_Y); +} + +void destroy_input_device(int fd) +{ + SAFE_IOCTL(fd, UI_DEV_DESTROY, NULL); + SAFE_CLOSE(fd); +} + +static void check_ui_get_sysname_ioctl(int fd) +{ + char sys_name[256]; + char dev_name[256]; + char *path; + + SAFE_IOCTL(fd, UI_GET_SYSNAME(sizeof(sys_name)), sys_name, NULL); + SAFE_ASPRINTF(&path, "/sys/devices/virtual/input/%s/name", sys_name); + + if (FILE_SCANF(path, "%s", dev_name)) { + free(path); + tst_brk(TBROK|TERRNO, "Failed to read '%s'", path); + return; + } + + if (strcmp(VIRTUAL_DEVICE, dev_name)) { + free(path); + tst_brk(TBROK, "ioctl UI_GET_SYSNAME returned wrong name"); + } + + free(path); +} + +void create_input_device(int fd) +{ + int nb; + struct uinput_user_dev uidev = { + .name = VIRTUAL_DEVICE, + .id = { + .bustype = BUS_USB, + .vendor = 0x1, + .product = 0x1, + .version = 1, + } + }; + + SAFE_WRITE(SAFE_WRITE_ALL, fd, &uidev, sizeof(uidev)); + SAFE_IOCTL(fd, UI_DEV_CREATE, NULL); + + for (nb = 100; nb > 0; nb--) { + if (check_device()) { + check_ui_get_sysname_ioctl(fd); + return; + } + usleep(10000); + } + + destroy_input_device(fd); + tst_brk(TBROK, "Failed to create device"); +} diff --git a/ltp/libs/ujson/Makefile b/ltp/libs/ujson/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4c8508010718fdf40fd6712ad092ac922ced31a8 --- /dev/null +++ b/ltp/libs/ujson/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) Cyril Hrubis + +top_srcdir ?= ../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INTERNAL_LIB := libujson.a + +include $(top_srcdir)/include/mk/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/libs/ujson/ujson_common.c b/ltp/libs/ujson/ujson_common.c new file mode 100644 index 0000000000000000000000000000000000000000..639955229337569d4174ea5f3746dad239424090 --- /dev/null +++ b/ltp/libs/ujson/ujson_common.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2021-2024 Cyril Hrubis + */ + +#include +#include "ujson_common.h" + +void ujson_err_handler(void *err_print_priv, const char *line) +{ + fputs(line, err_print_priv); + putc('\n', err_print_priv); +} + +const char *ujson_type_name(enum ujson_type type) +{ + switch (type) { + case UJSON_VOID: + return "void"; + case UJSON_INT: + return "integer"; + case UJSON_FLOAT: + return "float"; + case UJSON_BOOL: + return "boolean"; + case UJSON_NULL: + return "null"; + case UJSON_STR: + return "string"; + case UJSON_OBJ: + return "object"; + case UJSON_ARR: + return "array"; + default: + return "invalid"; + } +} diff --git a/ltp/libs/ujson/ujson_reader.c b/ltp/libs/ujson/ujson_reader.c new file mode 100644 index 0000000000000000000000000000000000000000..9f86f25b797e2783c44e92226b3bfa811e9efb1d --- /dev/null +++ b/ltp/libs/ujson/ujson_reader.c @@ -0,0 +1,1085 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2021-2024 Cyril Hrubis + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ujson_utf.h" +#include "ujson_reader.h" + +static const struct ujson_obj empty = {}; +const struct ujson_obj *ujson_empty_obj = ∅ + +static inline int buf_empty(ujson_reader *buf) +{ + return buf->off >= buf->len; +} + +static int eatws(ujson_reader *buf) +{ + while (!buf_empty(buf)) { + switch (buf->json[buf->off]) { + case ' ': + case '\t': + case '\n': + case '\r': + break; + default: + goto ret; + } + + buf->off += 1; + } +ret: + return buf_empty(buf); +} + +static char getb(ujson_reader *buf) +{ + if (buf_empty(buf)) + return 0; + + return buf->json[buf->off++]; +} + +static char peekb_off(ujson_reader *buf, size_t off) +{ + if (buf->off + off >= buf->len) + return 0; + + return buf->json[buf->off + off]; +} + +static char peekb(ujson_reader *buf) +{ + if (buf_empty(buf)) + return 0; + + return buf->json[buf->off]; +} + +static int eatb(ujson_reader *buf, char ch) +{ + if (peekb(buf) != ch) + return 0; + + getb(buf); + return 1; +} + +static int eatb2(ujson_reader *buf, char ch1, char ch2) +{ + if (peekb(buf) != ch1 && peekb(buf) != ch2) + return 0; + + getb(buf); + return 1; +} + +static int eatstr(ujson_reader *buf, const char *str) +{ + while (*str) { + if (!eatb(buf, *str)) + return 0; + str++; + } + + return 1; +} + +static int hex2val(unsigned char b) +{ + switch (b) { + case '0' ... '9': + return b - '0'; + case 'a' ... 'f': + return b - 'a' + 10; + case 'A' ... 'F': + return b - 'A' + 10; + default: + return -1; + } +} + +static int32_t parse_ucode_cp(ujson_reader *buf) +{ + int ret = 0, v, i; + + for (i = 0; i < 4; i++) { + if ((v = hex2val(getb(buf))) < 0) + goto err; + ret *= 16; + ret += v; + } + + return ret; +err: + ujson_err(buf, "Expected four hexadecimal digits"); + return -1; +} + +static unsigned int parse_ucode_esc(ujson_reader *buf, char *str, + size_t off, size_t len) +{ + int32_t ucode = parse_ucode_cp(buf); + + if (ucode < 0) + return 0; + + if (!str) + return ucode; + + if (ujson_utf8_bytes(ucode) + 1 >= len - off) { + ujson_err(buf, "String buffer too short!"); + return 0; + } + + return ujson_to_utf8(ucode, str+off); +} + +static int copy_str(ujson_reader *buf, char *str, size_t len) +{ + size_t pos = 0; + int esc = 0; + unsigned int l; + + eatb(buf, '"'); + + for (;;) { + if (buf_empty(buf)) { + ujson_err(buf, "Unterminated string"); + return 1; + } + + if (!esc && eatb(buf, '"')) { + if (str) + str[pos] = 0; + return 0; + } + + unsigned char b = getb(buf); + + if (b < 0x20) { + if (!peekb(buf)) + ujson_err(buf, "Unterminated string"); + else + ujson_err(buf, "Invalid string character 0x%02x", b); + return 1; + } + + if (!esc && b == '\\') { + esc = 1; + continue; + } + + if (esc) { + switch (b) { + case '"': + case '\\': + case '/': + break; + case 'b': + b = '\b'; + break; + case 'f': + b = '\f'; + break; + case 'n': + b = '\n'; + break; + case 'r': + b = '\r'; + break; + case 't': + b = '\t'; + break; + case 'u': + if (!(l = parse_ucode_esc(buf, str, pos, len))) + return 1; + pos += l; + b = 0; + break; + default: + ujson_err(buf, "Invalid escape \\%c", b); + return 1; + } + esc = 0; + } + + if (str && b) { + if (pos + 1 >= len) { + ujson_err(buf, "String buffer too short!"); + return 1; + } + + str[pos++] = b; + } + } + + return 1; +} + +static int copy_id_str(ujson_reader *buf, char *str, size_t len) +{ + size_t pos = 0; + + if (eatws(buf)) + goto err0; + + if (!eatb(buf, '"')) + goto err0; + + for (;;) { + if (buf_empty(buf)) { + ujson_err(buf, "Unterminated ID string"); + return 1; + } + + if (eatb(buf, '"')) { + str[pos] = 0; + break; + } + + if (pos >= len-1) { + ujson_err(buf, "ID string too long"); + return 1; + } + + str[pos++] = getb(buf); + } + + if (eatws(buf)) + goto err1; + + if (!eatb(buf, ':')) + goto err1; + + return 0; +err0: + ujson_err(buf, "Expected ID string"); + return 1; +err1: + ujson_err(buf, "Expected ':' after ID string"); + return 1; +} + +static int is_digit(char b) +{ + switch (b) { + case '0' ... '9': + return 1; + default: + return 0; + } +} + +static int get_int(ujson_reader *buf, struct ujson_val *res) +{ + long val = 0; + int sign = 1; + + if (eatb(buf, '-')) { + sign = -1; + if (!is_digit(peekb(buf))) { + ujson_err(buf, "Expected digit(s)"); + return 1; + } + } + + if (peekb(buf) == '0' && is_digit(peekb_off(buf, 1))) { + ujson_err(buf, "Leading zero in number!"); + return 1; + } + + while (is_digit(peekb(buf))) { + val *= 10; + val += getb(buf) - '0'; + //TODO: overflow? + } + + if (sign < 0) + val = -val; + + res->val_int = val; + res->val_float = val; + + return 0; +} + +static int eat_digits(ujson_reader *buf) +{ + if (!is_digit(peekb(buf))) { + ujson_err(buf, "Expected digit(s)"); + return 1; + } + + while (is_digit(peekb(buf))) + getb(buf); + + return 0; +} + +static int get_float(ujson_reader *buf, struct ujson_val *res) +{ + off_t start = buf->off; + + eatb(buf, '-'); + + if (peekb(buf) == '0' && is_digit(peekb_off(buf, 1))) { + ujson_err(buf, "Leading zero in float"); + return 1; + } + + if (eat_digits(buf)) + return 1; + + switch (getb(buf)) { + case '.': + if (eat_digits(buf)) + return 1; + + if (!eatb2(buf, 'e', 'E')) + break; + + /* fallthrough */ + case 'e': + case 'E': + eatb2(buf, '+', '-'); + + if (eat_digits(buf)) + return 1; + break; + } + + size_t len = buf->off - start; + char tmp[len+1]; + + memcpy(tmp, buf->json + start, len); + + tmp[len] = 0; + + res->val_float = strtod(tmp, NULL); + + return 0; +} + +static int get_bool(ujson_reader *buf, struct ujson_val *res) +{ + switch (peekb(buf)) { + case 'f': + if (!eatstr(buf, "false")) { + ujson_err(buf, "Expected 'false'"); + return 1; + } + + res->val_bool = 0; + break; + case 't': + if (!eatstr(buf, "true")) { + ujson_err(buf, "Expected 'true'"); + return 1; + } + + res->val_bool = 1; + break; + } + + return 0; +} + +static int get_null(ujson_reader *buf) +{ + if (!eatstr(buf, "null")) { + ujson_err(buf, "Expected 'null'"); + return 1; + } + + return 0; +} + +int ujson_obj_skip(ujson_reader *buf) +{ + struct ujson_val res = {}; + + UJSON_OBJ_FOREACH(buf, &res) { + switch (res.type) { + case UJSON_OBJ: + if (ujson_obj_skip(buf)) + return 1; + break; + case UJSON_ARR: + if (ujson_arr_skip(buf)) + return 1; + break; + default: + break; + } + } + + return 0; +} + +int ujson_arr_skip(ujson_reader *buf) +{ + struct ujson_val res = {}; + + UJSON_ARR_FOREACH(buf, &res) { + switch (res.type) { + case UJSON_OBJ: + if (ujson_obj_skip(buf)) + return 1; + break; + case UJSON_ARR: + if (ujson_arr_skip(buf)) + return 1; + break; + default: + break; + } + } + + return 0; +} + +static enum ujson_type next_num_type(ujson_reader *buf) +{ + size_t off = 0; + + for (;;) { + char b = peekb_off(buf, off++); + + switch (b) { + case 0: + case ',': + return UJSON_INT; + case '.': + case 'e': + case 'E': + return UJSON_FLOAT; + } + } + + return UJSON_VOID; +} + +enum ujson_type ujson_next_type(ujson_reader *buf) +{ + if (eatws(buf)) { + ujson_err(buf, "Unexpected end"); + return UJSON_VOID; + } + + char b = peekb(buf); + + switch (b) { + case '{': + return UJSON_OBJ; + case '[': + return UJSON_ARR; + case '"': + return UJSON_STR; + case '-': + case '0' ... '9': + return next_num_type(buf); + case 'f': + case 't': + return UJSON_BOOL; + break; + case 'n': + return UJSON_NULL; + break; + default: + ujson_err(buf, "Expected object, array, number or string"); + return UJSON_VOID; + } +} + +enum ujson_type ujson_reader_start(ujson_reader *buf) +{ + enum ujson_type type = ujson_next_type(buf); + + switch (type) { + case UJSON_ARR: + case UJSON_OBJ: + case UJSON_VOID: + break; + default: + ujson_err(buf, "JSON can start only with array or object"); + type = UJSON_VOID; + break; + } + + return type; +} + +static int get_value(ujson_reader *buf, struct ujson_val *res) +{ + int ret = 0; + + res->type = ujson_next_type(buf); + + switch (res->type) { + case UJSON_STR: + if (copy_str(buf, res->buf, res->buf_size)) { + res->type = UJSON_VOID; + return 0; + } + res->val_str = res->buf; + return 1; + case UJSON_INT: + ret = get_int(buf, res); + break; + case UJSON_FLOAT: + ret = get_float(buf, res); + break; + case UJSON_BOOL: + ret = get_bool(buf, res); + break; + case UJSON_NULL: + ret = get_null(buf); + break; + case UJSON_VOID: + return 0; + case UJSON_ARR: + case UJSON_OBJ: + buf->sub_off = buf->off; + return 1; + } + + if (ret) { + res->type = UJSON_VOID; + return 0; + } + + return 1; +} + +static int pre_next(ujson_reader *buf, struct ujson_val *res) +{ + if (!eatb(buf, ',')) { + ujson_err(buf, "Expected ','"); + res->type = UJSON_VOID; + return 1; + } + + if (eatws(buf)) { + ujson_err(buf, "Unexpected end"); + res->type = UJSON_VOID; + return 1; + } + + return 0; +} + +static int check_end(ujson_reader *buf, struct ujson_val *res, char b) +{ + if (eatws(buf)) { + ujson_err(buf, "Unexpected end"); + return 1; + } + + if (eatb(buf, b)) { + res->type = UJSON_VOID; + eatws(buf); + eatb(buf, 0); + buf->depth--; + return 1; + } + + return 0; +} + +/* + * This is supposed to return a pointer to a string stored as a first member of + * a structure given an array. + * + * e.g. + * + * struct foo { + * const char *key; + * ... + * }; + * + * const struct foo bar[10] = {...}; + * + * // Returns a pointer to the key string in a second structure in bar[]. + * const char *key = list_elem(bar, sizeof(struct foo), 1); + */ +static inline const char *list_elem(const void *arr, size_t memb_size, size_t idx) +{ + return *(const char**)(arr + idx * memb_size); +} + +size_t ujson_lookup(const void *arr, size_t memb_size, size_t list_len, + const char *key) +{ + size_t l = 0; + size_t r = list_len-1; + size_t mid = -1; + + if (!list_len) + return (size_t)-1; + + while (r - l > 1) { + mid = (l+r)/2; + + int ret = strcmp(list_elem(arr, memb_size, mid), key); + if (!ret) + return mid; + + if (ret < 0) + l = mid; + else + r = mid; + } + + if (r != mid && !strcmp(list_elem(arr, memb_size, r), key)) + return r; + + if (l != mid && !strcmp(list_elem(arr, memb_size, l), key)) + return l; + + return -1; +} + +static int skip_obj_val(ujson_reader *buf) +{ + struct ujson_val dummy = {}; + + if (!get_value(buf, &dummy)) + return 0; + + switch (dummy.type) { + case UJSON_OBJ: + return !ujson_obj_skip(buf); + case UJSON_ARR: + return !ujson_arr_skip(buf); + default: + return 1; + } +} + +static int obj_next(ujson_reader *buf, struct ujson_val *res) +{ + if (copy_id_str(buf, res->id, sizeof(res->id))) + return 0; + + return get_value(buf, res); +} + +static int obj_pre_next(ujson_reader *buf, struct ujson_val *res) +{ + if (ujson_reader_err(buf)) + return 1; + + if (check_end(buf, res, '}')) + return 1; + + if (pre_next(buf, res)) + return 1; + + return 0; +} + +static int obj_next_filter(ujson_reader *buf, struct ujson_val *res, + const struct ujson_obj *obj, const struct ujson_obj *ign) +{ + const struct ujson_obj_attr *attr; + + for (;;) { + if (copy_id_str(buf, res->id, sizeof(res->id))) + return 0; + + res->idx = obj ? ujson_obj_lookup(obj, res->id) : (size_t)-1; + + if (res->idx != (size_t)-1) { + if (!get_value(buf, res)) + return 0; + + attr = &obj->attrs[res->idx]; + + if (attr->type == UJSON_VOID) + return 1; + + if (attr->type == res->type) + return 1; + + if (attr->type == UJSON_FLOAT && + res->type == UJSON_INT) + return 1; + + ujson_warn(buf, "Wrong '%s' type expected %s", + attr->key, ujson_type_name(attr->type)); + } else { + if (!skip_obj_val(buf)) + return 0; + + if (ign && ujson_obj_lookup(ign, res->id) == (size_t)-1) + ujson_warn(buf, "Unexpected key '%s'", res->id); + } + + if (obj_pre_next(buf, res)) + return 0; + } +} + +static int check_err(ujson_reader *buf, struct ujson_val *res) +{ + if (ujson_reader_err(buf)) { + res->type = UJSON_VOID; + return 1; + } + + return 0; +} + +int ujson_obj_next_filter(ujson_reader *buf, struct ujson_val *res, + const struct ujson_obj *obj, const struct ujson_obj *ign) +{ + if (check_err(buf, res)) + return 0; + + if (obj_pre_next(buf, res)) + return 0; + + return obj_next_filter(buf, res, obj, ign); +} + +int ujson_obj_next(ujson_reader *buf, struct ujson_val *res) +{ + if (check_err(buf, res)) + return 0; + + if (obj_pre_next(buf, res)) + return 0; + + return obj_next(buf, res); +} + +static int any_first(ujson_reader *buf, char b) +{ + if (eatws(buf)) { + ujson_err(buf, "Unexpected end"); + return 1; + } + + if (!eatb(buf, b)) { + ujson_err(buf, "Expected '%c'", b); + return 1; + } + + buf->depth++; + + if (buf->depth > buf->max_depth) { + ujson_err(buf, "Recursion too deep"); + return 1; + } + + return 0; +} + +int ujson_obj_first_filter(ujson_reader *buf, struct ujson_val *res, + const struct ujson_obj *obj, const struct ujson_obj *ign) +{ + if (check_err(buf, res)) + return 0; + + if (any_first(buf, '{')) + return 0; + + if (check_end(buf, res, '}')) + return 0; + + return obj_next_filter(buf, res, obj, ign); +} + +int ujson_obj_first(ujson_reader *buf, struct ujson_val *res) +{ + if (check_err(buf, res)) + return 0; + + if (any_first(buf, '{')) + return 0; + + if (check_end(buf, res, '}')) + return 0; + + return obj_next(buf, res); +} + +static int arr_next(ujson_reader *buf, struct ujson_val *res) +{ + return get_value(buf, res); +} + +int ujson_arr_first(ujson_reader *buf, struct ujson_val *res) +{ + if (check_err(buf, res)) + return 0; + + if (any_first(buf, '[')) + return 0; + + if (check_end(buf, res, ']')) + return 0; + + return arr_next(buf, res); +} + +int ujson_arr_next(ujson_reader *buf, struct ujson_val *res) +{ + if (check_err(buf, res)) + return 0; + + if (check_end(buf, res, ']')) + return 0; + + if (pre_next(buf, res)) + return 0; + + return arr_next(buf, res); +} + +static void ujson_err_va(ujson_reader *buf, const char *fmt, va_list va) +{ + vsnprintf(buf->err, UJSON_ERR_MAX, fmt, va); +} + +void ujson_err(ujson_reader *buf, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + ujson_err_va(buf, fmt, va); + va_end(va); +} + +static void vprintf_line(ujson_reader *buf, const char *fmt, va_list va) +{ + char line[UJSON_ERR_MAX+1]; + + vsnprintf(line, sizeof(line), fmt, va); + + line[UJSON_ERR_MAX] = 0; + + buf->err_print(buf->err_print_priv, line); +} + +static void printf_line(ujson_reader *buf, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + vprintf_line(buf, fmt, va); + va_end(va); +} + +static void printf_json_line(ujson_reader *buf, size_t line_nr, const char *buf_pos) +{ + char line[UJSON_ERR_MAX+1]; + size_t plen, i; + + plen = sprintf(line, "%03zu: ", line_nr); + + for (i = 0; i < UJSON_ERR_MAX-plen && buf_pos[i] && buf_pos[i] != '\n'; i++) + line[i+plen] = buf_pos[i]; + + line[i+plen] = 0; + + buf->err_print(buf->err_print_priv, line); +} + +static void print_arrow(ujson_reader *buf, const char *buf_pos, size_t count) +{ + char line[count + 7]; + size_t i; + + /* The '000: ' prefix */ + for (i = 0; i <= 5; i++) + line[i] = ' '; + + for (i = 0; i < count; i++) + line[i+5] = buf_pos[i] == '\t' ? '\t' : ' '; + + line[count+5] = '^'; + line[count+6] = 0; + + buf->err_print(buf->err_print_priv, line); +} + +#define ERR_LINES 10 + +#define MIN(A, B) ((A < B) ? (A) : (B)) + +static void print_snippet(ujson_reader *buf, const char *type) +{ + ssize_t i; + const char *lines[ERR_LINES] = {}; + size_t cur_line = 0; + size_t cur_off = 0; + size_t last_off = buf->off; + + for (;;) { + lines[(cur_line++) % ERR_LINES] = buf->json + cur_off; + + while (cur_off < buf->len && buf->json[cur_off] != '\n') + cur_off++; + + if (cur_off >= buf->off) + break; + + cur_off++; + last_off = buf->off - cur_off; + } + + printf_line(buf, "%s at line %03zu", type, cur_line); + buf->err_print(buf->err_print_priv, ""); + + size_t idx = 0; + + for (i = MIN(ERR_LINES, cur_line); i > 0; i--) { + idx = (cur_line - i) % ERR_LINES; + printf_json_line(buf, cur_line - i + 1, lines[idx]); + } + + print_arrow(buf, lines[idx], last_off); +} + +void ujson_err_print(ujson_reader *buf) +{ + if (!buf->err_print) + return; + + print_snippet(buf, "Parse error"); + buf->err_print(buf->err_print_priv, buf->err); +} + +void ujson_warn(ujson_reader *buf, const char *fmt, ...) +{ + va_list va; + + if (buf->flags & UJSON_READER_STRICT) { + va_start(va, fmt); + ujson_err_va(buf, fmt, va); + va_end(va); + return; + } + + if (!buf->err_print) + return; + + print_snippet(buf, "Warning"); + + va_start(va, fmt); + vprintf_line(buf, fmt, va); + va_end(va); +} + +void ujson_print(void *err_print_priv, const char *line) +{ + fputs(line, err_print_priv); + putc('\n', err_print_priv); +} + +ujson_reader *ujson_reader_load(const char *path) +{ + int fd = open(path, O_RDONLY); + ujson_reader *ret; + ssize_t res; + off_t len, off = 0; + + if (fd < 0) + return NULL; + + len = lseek(fd, 0, SEEK_END); + if (len == (off_t)-1) { + fprintf(stderr, "lseek() failed\n"); + goto err0; + } + + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + fprintf(stderr, "lseek() failed\n"); + goto err0; + } + + ret = malloc(sizeof(ujson_reader) + len + 1); + if (!ret) { + fprintf(stderr, "malloc() failed\n"); + goto err0; + } + + memset(ret, 0, sizeof(*ret)); + + ret->buf[len] = 0; + ret->len = len; + ret->max_depth = UJSON_RECURSION_MAX; + ret->json = ret->buf; + ret->err_print = UJSON_ERR_PRINT; + ret->err_print_priv = UJSON_ERR_PRINT_PRIV; + + while (off < len) { + res = read(fd, ret->buf + off, len - off); + if (res < 0) { + fprintf(stderr, "read() failed\n"); + goto err1; + } + + off += res; + } + + close(fd); + + return ret; +err1: + free(ret); +err0: + close(fd); + return NULL; +} + +void ujson_reader_finish(ujson_reader *self) +{ + if (ujson_reader_err(self)) + ujson_err_print(self); + else if (!ujson_reader_consumed(self)) { + ujson_warn(self, "Garbage after JSON string!"); + + if (ujson_reader_err(self)) + ujson_err_print(self); + } +} + +void ujson_reader_free(ujson_reader *buf) +{ + free(buf); +} + +ujson_val *ujson_val_alloc(size_t buf_size) +{ + buf_size = buf_size == 0 ? 4096 : buf_size; + ujson_val *ret; + + ret = malloc(sizeof(ujson_val) + buf_size); + if (!ret) + return NULL; + + memset(ret, 0, sizeof(ujson_val) + buf_size); + + ret->buf = ret->buf__; + ret->buf_size = buf_size; + + return ret; +} + +void ujson_val_free(ujson_val *self) +{ + free(self); +} diff --git a/ltp/libs/ujson/ujson_utf.c b/ltp/libs/ujson/ujson_utf.c new file mode 100644 index 0000000000000000000000000000000000000000..2c08a39a80b6110621f00d0f1acebe1e5980a394 --- /dev/null +++ b/ltp/libs/ujson/ujson_utf.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2022-2024 Cyril Hrubis + */ + +#include +#include + +int8_t ujson_utf8_next_chsz(const char *str, size_t off) +{ + char ch = str[off]; + uint8_t len = 0; + + if (!ch) + return 0; + + if (UJSON_UTF8_IS_ASCII(ch)) + return 1; + + if (UJSON_UTF8_IS_2BYTE(ch)) { + len = 2; + goto ret; + } + + if (UJSON_UTF8_IS_3BYTE(ch)) { + len = 3; + goto ret; + } + + if (UJSON_UTF8_IS_4BYTE(ch)) { + len = 4; + goto ret; + } + + return -1; +ret: + if (!UJSON_UTF8_IS_NBYTE(str[off+1])) + return -1; + + if (len > 2 && !UJSON_UTF8_IS_NBYTE(str[off+2])) + return -1; + + if (len > 3 && !UJSON_UTF8_IS_NBYTE(str[off+3])) + return -1; + + return len; +} + +int8_t ujson_utf8_prev_chsz(const char *str, size_t off) +{ + char ch; + + if (!off) + return 0; + + ch = str[--off]; + + if (UJSON_UTF8_IS_ASCII(ch)) + return 1; + + if (!UJSON_UTF8_IS_NBYTE(ch)) + return -1; + + if (off < 1) + return -1; + + ch = str[--off]; + + if (UJSON_UTF8_IS_2BYTE(ch)) + return 2; + + if (!UJSON_UTF8_IS_NBYTE(ch)) + return -1; + + if (off < 1) + return -1; + + ch = str[--off]; + + if (UJSON_UTF8_IS_3BYTE(ch)) + return 3; + + if (!UJSON_UTF8_IS_NBYTE(ch)) + return -1; + + if (off < 1) + return -1; + + ch = str[--off]; + + if (UJSON_UTF8_IS_4BYTE(ch)) + return 4; + + return -1; +} + +size_t ujson_utf8_strlen(const char *str) +{ + size_t cnt = 0; + + while (ujson_utf8_next(&str)) + cnt++; + + return cnt; +} diff --git a/ltp/libs/ujson/ujson_writer.c b/ltp/libs/ujson/ujson_writer.c new file mode 100644 index 0000000000000000000000000000000000000000..c86a3b2af3976a8946520eaaa6756f713b958442 --- /dev/null +++ b/ltp/libs/ujson/ujson_writer.c @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2021-2024 Cyril Hrubis + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ujson_utf.h" +#include "ujson_writer.h" + +static inline int get_depth_bit(ujson_writer *self, char *mask) +{ + int depth = self->depth - 1; + + if (depth < 0) + return -1; + + return !!(mask[depth/8] & (1<<(depth%8))); +} + +static inline void set_depth_bit(ujson_writer *self, int val) +{ + if (val) + self->depth_type[self->depth/8] |= (1<<(self->depth%8)); + else + self->depth_type[self->depth/8] &= ~(1<<(self->depth%8)); + + self->depth_first[self->depth/8] |= (1<<(self->depth%8)); + + self->depth++; +} + +static inline void clear_depth_bit(ujson_writer *self) +{ + self->depth--; +} + +static inline int in_arr(ujson_writer *self) +{ + return !get_depth_bit(self, self->depth_type); +} + +static inline int in_obj(ujson_writer *self) +{ + return get_depth_bit(self, self->depth_type); +} + +static inline void clear_depth_first(ujson_writer *self) +{ + int depth = self->depth - 1; + + self->depth_first[depth/8] &= ~(1<<(depth%8)); +} + +static inline int is_first(ujson_writer *self) +{ + int ret = get_depth_bit(self, self->depth_first); + + if (ret == 1) + clear_depth_first(self); + + return ret; +} + +static inline void err(ujson_writer *buf, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + vsnprintf(buf->err, UJSON_ERR_MAX, fmt, va); + va_end(va); +} + +static inline int is_err(ujson_writer *buf) +{ + return buf->err[0]; +} + +static inline int out(ujson_writer *self, const char *buf, size_t len) +{ + return self->out(self, buf, len); +} + +static inline int out_str(ujson_writer *self, const char *str) +{ + return out(self, str, strlen(str)); +} + +static inline int out_ch(ujson_writer *self, char ch) +{ + return out(self, &ch, 1); +} + +#define ESC_FLUSH(esc_char) do {\ + out(self, val, i); \ + val += i + 1; \ + i = 0; \ + out_str(self, esc_char); \ +} while (0) + +static inline int out_esc_str(ujson_writer *self, const char *val) +{ + if (out_ch(self, '"')) + return 1; + + size_t i = 0; + int8_t next_chsz; + + do { + next_chsz = ujson_utf8_next_chsz(val, i); + + if (next_chsz == 1) { + switch (val[i]) { + case '\"': + ESC_FLUSH("\\\""); + break; + case '\\': + ESC_FLUSH("\\\\"); + break; + case '/': + ESC_FLUSH("\\/"); + break; + case '\b': + ESC_FLUSH("\\b"); + break; + case '\f': + ESC_FLUSH("\\f"); + break; + case '\n': + ESC_FLUSH("\\n"); + break; + case '\r': + ESC_FLUSH("\\r"); + break; + case '\t': + ESC_FLUSH("\\t"); + break; + default: + i += next_chsz; + } + } else { + i += next_chsz; + } + } while (next_chsz); + + if (i) { + if (out(self, val, i)) + return 1; + } + + if (out_ch(self, '"')) + return 1; + + return 0; +} + +static int do_padd(ujson_writer *self) +{ + unsigned int i; + + for (i = 0; i < self->depth; i++) { + if (out_ch(self, ' ')) + return 1; + } + + return 0; +} + +static int newline(ujson_writer *self) +{ + if (out_ch(self, '\n')) + return 0; + + if (do_padd(self)) + return 1; + + return 0; +} + +static int add_common(ujson_writer *self, const char *id) +{ + if (is_err(self)) + return 1; + + if (!self->depth) { + err(self, "Object/Array has to be started first"); + return 1; + } + + if (in_arr(self)) { + if (id) { + err(self, "Array entries can't have id"); + return 1; + } + } else { + if (!id) { + err(self, "Object entries must have id"); + return 1; + } + } + + if (!is_first(self) && out_ch(self, ',')) + return 1; + + if (self->depth && newline(self)) + return 1; + + if (id) { + if (out_esc_str(self, id)) + return 1; + + if (out_str(self, ": ")) + return 1; + } + + return 0; +} + +int ujson_obj_start(ujson_writer *self, const char *id) +{ + if (self->depth >= UJSON_RECURSION_MAX) + return 1; + + if (!self->depth && id) { + err(self, "Top level object cannot have id"); + return 1; + } + + if (self->depth && add_common(self, id)) + return 1; + + if (out_ch(self, '{')) + return 1; + + set_depth_bit(self, 1); + + return 0; +} + +int ujson_obj_finish(ujson_writer *self) +{ + if (is_err(self)) + return 1; + + if (!in_obj(self)) { + err(self, "Not in object!"); + return 1; + } + + int first = is_first(self); + + clear_depth_bit(self); + + if (!first) + newline(self); + + return out_ch(self, '}'); +} + +int ujson_arr_start(ujson_writer *self, const char *id) +{ + if (self->depth >= UJSON_RECURSION_MAX) { + err(self, "Recursion too deep"); + return 1; + } + + if (!self->depth && id) { + err(self, "Top level array cannot have id"); + return 1; + } + + if (self->depth && add_common(self, id)) + return 1; + + if (out_ch(self, '[')) + return 1; + + set_depth_bit(self, 0); + + return 0; +} + +int ujson_arr_finish(ujson_writer *self) +{ + if (is_err(self)) + return 1; + + if (!in_arr(self)) { + err(self, "Not in array!"); + return 1; + } + + int first = is_first(self); + + clear_depth_bit(self); + + if (!first) + newline(self); + + return out_ch(self, ']'); +} + +int ujson_null_add(ujson_writer *self, const char *id) +{ + if (add_common(self, id)) + return 1; + + return out_str(self, "null"); +} + +int ujson_int_add(ujson_writer *self, const char *id, long val) +{ + char buf[64]; + + if (add_common(self, id)) + return 1; + + snprintf(buf, sizeof(buf), "%li", val); + + return out_str(self, buf); +} + +int ujson_bool_add(ujson_writer *self, const char *id, int val) +{ + if (add_common(self, id)) + return 1; + + if (val) + return out_str(self, "true"); + else + return out_str(self, "false"); +} + +int ujson_str_add(ujson_writer *self, const char *id, const char *val) +{ + if (add_common(self, id)) + return 1; + + if (out_esc_str(self, val)) + return 1; + + return 0; +} + +int ujson_float_add(ujson_writer *self, const char *id, double val) +{ + char buf[64]; + + if (add_common(self, id)) + return 1; + + snprintf(buf, sizeof(buf), "%lg", val); + + return out_str(self, buf); +} + +int ujson_writer_finish(ujson_writer *self) +{ + if (is_err(self)) + goto err; + + if (self->depth) { + err(self, "Objects and/or Arrays not finished"); + goto err; + } + + if (newline(self)) + return 1; + + return 0; +err: + if (self->err_print) + self->err_print(self->err_print_priv, self->err); + + return 1; +} + +struct json_writer_file { + int fd; + size_t buf_used; + char buf[1024]; +}; + +static int out_writer_file_write(ujson_writer *self, int fd, const char *buf, ssize_t buf_len) +{ + do { + ssize_t ret = write(fd, buf, buf_len); + if (ret <= 0) { + err(self, "Failed to write to a file"); + return 1; + } + + if (ret > buf_len) { + err(self, "Wrote more bytes than requested?!"); + return 1; + } + + buf_len -= ret; + } while (buf_len); + + return 0; +} + +static int out_writer_file(ujson_writer *self, const char *buf, size_t buf_len) +{ + struct json_writer_file *writer_file = self->out_priv; + size_t buf_size = sizeof(writer_file->buf); + size_t buf_avail = buf_size - writer_file->buf_used; + + if (buf_len > buf_size/4) + return out_writer_file_write(self, writer_file->fd, buf, buf_len); + + if (buf_len >= buf_avail) { + if (out_writer_file_write(self, writer_file->fd, + writer_file->buf, writer_file->buf_used)) + return 1; + + memcpy(writer_file->buf, buf, buf_len); + writer_file->buf_used = buf_len; + return 0; + } + + memcpy(writer_file->buf + writer_file->buf_used, buf, buf_len); + writer_file->buf_used += buf_len; + + return 0; +} + +int ujson_writer_file_close(ujson_writer *self) +{ + struct json_writer_file *writer_file = self->out_priv; + int saved_errno = 0; + + if (writer_file->buf_used) { + if (out_writer_file_write(self, writer_file->fd, + writer_file->buf, writer_file->buf_used)) + + saved_errno = errno; + } + + if (close(writer_file->fd)) { + if (!saved_errno) + saved_errno = errno; + } + + free(self); + + if (saved_errno) { + errno = saved_errno; + return 1; + } + + return 0; +} + +ujson_writer *ujson_writer_file_open(const char *path) +{ + ujson_writer *ret; + struct json_writer_file *writer_file; + + ret = malloc(sizeof(ujson_writer) + sizeof(struct json_writer_file)); + if (!ret) + return NULL; + + writer_file = (void*)ret + sizeof(ujson_writer); + + writer_file->fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0664); + if (!writer_file->fd) { + free(ret); + return NULL; + } + + writer_file->buf_used = 0; + + memset(ret, 0, sizeof(*ret)); + + ret->err_print = UJSON_ERR_PRINT; + ret->err_print_priv = UJSON_ERR_PRINT_PRIV; + ret->out = out_writer_file; + ret->out_priv = writer_file; + + return ret; +} diff --git a/ltp/libs/vdso/Makefile b/ltp/libs/vdso/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6b35bdf877b0ef0b925fd72c47f221a4e22902ed --- /dev/null +++ b/ltp/libs/vdso/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/ltp/libs/vdso/README b/ltp/libs/vdso/README new file mode 100644 index 0000000000000000000000000000000000000000..e208f7ef395e97771176906c83379a30e25cfcf6 --- /dev/null +++ b/ltp/libs/vdso/README @@ -0,0 +1 @@ +Copied from kernel tree: tools/testing/selftests/vDSO/parse_vdso.c diff --git a/ltp/libs/vdso/parse_vdso.c b/ltp/libs/vdso/parse_vdso.c new file mode 100644 index 0000000000000000000000000000000000000000..cd75a89453bb1820f19100cd6c6fa9268e17f73a --- /dev/null +++ b/ltp/libs/vdso/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/ltp/libs/vdso/vdso_helpers.c b/ltp/libs/vdso/vdso_helpers.c new file mode 100644 index 0000000000000000000000000000000000000000..208c12f658c5b06296180d9e225e4c088726d139 --- /dev/null +++ b/ltp/libs/vdso/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/ltp/m4/GNUmakefile b/ltp/m4/GNUmakefile new file mode 100644 index 0000000000000000000000000000000000000000..a76308ef7b2a2f6d55a7cb65269afa1077383332 --- /dev/null +++ b/ltp/m4/GNUmakefile @@ -0,0 +1,37 @@ +# +# m4 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. +# +# Ngie Cooper, July 2009 +# + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk + +M4MACROS := $(notdir $(wildcard *.m4)) + +INSTALL_DIR := $(datarootdir)/aclocal + +INSTALL_MODE := 00644 + +INSTALL_TARGETS := $(M4_MACROS) + +MAKE_TARGETS := + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/m4/Makefile.am b/ltp/m4/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..87c304b429dd3395c816f428ab0878e4ac24db6a --- /dev/null +++ b/ltp/m4/Makefile.am @@ -0,0 +1 @@ +# bogus makefile to appease automake diff --git a/ltp/m4/ax_check_compile_flag.m4 b/ltp/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000000000000000000000000000000000000..bd753b34d7dc57063b0b65f1441dde0889e1cd26 --- /dev/null +++ b/ltp/m4/ax_check_compile_flag.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# 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 6 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/ltp/m4/ax_compare_version.m4 b/ltp/m4/ax_compare_version.m4 new file mode 100644 index 0000000000000000000000000000000000000000..ffb4997e8b146e1e40f5da58fee4f4150290f4a4 --- /dev/null +++ b/ltp/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/ltp/m4/ltp-acl.m4 b/ltp/m4/ltp-acl.m4 new file mode 100644 index 0000000000000000000000000000000000000000..7059125f934e4e56e4db270aa18c07e0c83975b8 --- /dev/null +++ b/ltp/m4/ltp-acl.m4 @@ -0,0 +1,12 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Linux Test Project, 2011 +dnl Author: Cyril Hrubis + +AC_DEFUN([LTP_CHECK_ACL_SUPPORT], [ + AC_CHECK_LIB([acl], [acl_init], [have_libacl=yes], [AC_MSG_WARN(missing libacl)]) + AC_CHECK_HEADERS([sys/acl.h], [have_acl=yes], [AC_MSG_WARN(missing libacl headers)]) + if test "x$have_libacl" = "xyes" -a "x$have_acl" = "xyes"; then + AC_DEFINE(HAVE_LIBACL, 1, [Define to 1 if you have libacl and it's headers installed]) + AC_SUBST(ACL_LIBS, "-lacl") + fi +]) diff --git a/ltp/m4/ltp-atomic.m4 b/ltp/m4/ltp-atomic.m4 new file mode 100644 index 0000000000000000000000000000000000000000..87e1224b757961869779f0edfd6f749f95e10ccc --- /dev/null +++ b/ltp/m4/ltp-atomic.m4 @@ -0,0 +1,22 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Linux Test Project, 2016 + +AC_DEFUN([LTP_CHECK_ATOMIC_MEMORY_MODEL],[ + AC_MSG_CHECKING([for __atomic_* compiler builtins]) + AC_LINK_IFELSE([AC_LANG_SOURCE([ +int main(void) { + int i = 0, j = 0; + __atomic_add_fetch(&i, 1, __ATOMIC_ACQ_REL); + __atomic_load_n(&i, __ATOMIC_SEQ_CST); + __atomic_store_n(&i, 0, __ATOMIC_RELAXED); + return i; +}])],[has_atomic_mm="yes"]) + +if test "x$has_atomic_mm" = xyes; then + AC_DEFINE(HAVE_ATOMIC_MEMORY_MODEL,1, + [Define to 1 if you have the __atomic_* compiler builtins]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +]) diff --git a/ltp/m4/ltp-builtin_clear_cache.m4 b/ltp/m4/ltp-builtin_clear_cache.m4 new file mode 100644 index 0000000000000000000000000000000000000000..86e1cfc914d27054ae2ba89263b3d769f2c1f6fe --- /dev/null +++ b/ltp/m4/ltp-builtin_clear_cache.m4 @@ -0,0 +1,19 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Linux Test Project, 2016 + +AC_DEFUN([LTP_CHECK_BUILTIN_CLEAR_CACHE],[ + AC_MSG_CHECKING([for __builtin___clear_cache]) + AC_LINK_IFELSE([AC_LANG_SOURCE([[ +int main(void) { + char arr[16]; + __builtin___clear_cache(arr, arr + sizeof(arr)); + return 0; +}]])],[has_bcc="yes"]) + +if test "x$has_bcc" = xyes; then + AC_DEFINE(HAVE_BUILTIN_CLEAR_CACHE,1,[Define to 1 if you have __builtin___clear_cache]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +]) diff --git a/ltp/m4/ltp-cap.m4 b/ltp/m4/ltp-cap.m4 new file mode 100644 index 0000000000000000000000000000000000000000..4981e843da52ffcc10792d1316f85b60dde9b6fe --- /dev/null +++ b/ltp/m4/ltp-cap.m4 @@ -0,0 +1,32 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Cisco Systems Inc., 2009 +dnl Copyright (c) Linux Test Project, 2019 +dnl Author: Ngie Cooper + +AC_DEFUN([LTP_CHECK_CAPABILITY_SUPPORT],[ +AH_TEMPLATE(HAVE_LIBCAP, +[Define to 1 if you have libcap-2 installed.]) +AC_CHECK_HEADERS([sys/capability.h],[capability_header_prefix="sys"]) +if test "x$capability_header_prefix" != x; then + AC_CHECK_LIB(cap,cap_compare,[cap_libs="-lcap"]) +fi +if test "x$cap_libs" != x; then + AC_DEFINE(HAVE_LIBCAP) +fi +AC_SUBST(CAP_LIBS,$cap_libs) + +AH_TEMPLATE(HAVE_NEWER_LIBCAP, +[Define to 1 if you have newer libcap-2 installed.]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +#include +#include +int main(void) { + __u16 a; + __u32 b; + return 0; +}])],[has_newer_libcap="yes"]) + +if test "x$has_newer_libcap" = xyes; then + AC_DEFINE(HAVE_NEWER_LIBCAP) +fi +]) diff --git a/ltp/m4/ltp-crypto.m4 b/ltp/m4/ltp-crypto.m4 new file mode 100644 index 0000000000000000000000000000000000000000..42f0d85677650a5893d6ecfb35caeccd4064d493 --- /dev/null +++ b/ltp/m4/ltp-crypto.m4 @@ -0,0 +1,11 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Linux Test Project, 2009-2017 + +AC_DEFUN([LTP_CHECK_CRYPTO], [ + AC_CHECK_LIB([crypto], [SHA1_Init], [have_libcrypto=yes], [AC_MSG_WARN(missing libcrypto)]) + AC_CHECK_HEADERS([openssl/sha.h], [have_sha=yes], [AC_MSG_WARN(missing openssl headers)]) + if test "x$have_libcrypto" = "xyes" -a "x$have_sha" = "xyes"; then + AC_DEFINE(HAVE_LIBCRYPTO, 1, [Define whether libcrypto and openssl headers are installed]) + AC_SUBST(CRYPTO_LIBS, "-lcrypto") + fi +]) diff --git a/ltp/m4/ltp-eventfd.m4 b/ltp/m4/ltp-eventfd.m4 new file mode 100644 index 0000000000000000000000000000000000000000..1e0ec688a7e5838f51f49e3e952a30958d119ca6 --- /dev/null +++ b/ltp/m4/ltp-eventfd.m4 @@ -0,0 +1,23 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Red Hat Inc., 2008 +dnl Copyright (c) 2017-2022 Petr Vorel +dnl Author: Masatake YAMATO + +AC_DEFUN([LTP_CHECK_SYSCALL_EVENTFD], [ + AC_CHECK_HEADERS(libaio.h, [have_libaio=yes]) + AC_CHECK_LIB(aio, io_setup, [have_aio=yes]) + + if test "x$have_libaio" = "xyes" -a "x$have_aio" = "xyes"; then + AC_DEFINE(HAVE_LIBAIO, 1, [Define to 1 if you have libaio and it's headers installed.]) + AC_SUBST(AIO_LIBS, "-laio") + + AC_MSG_CHECKING([io_set_eventfd is defined in aio library or aio header]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include + #include + ]], + [[io_set_eventfd(NULL, 0); return 0;]])], + [AC_DEFINE(HAVE_IO_SET_EVENTFD, 1, [Define to 1 if you have `io_set_eventfd' function.]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)]) + fi +]) diff --git a/ltp/m4/ltp-fcntl.m4 b/ltp/m4/ltp-fcntl.m4 new file mode 100644 index 0000000000000000000000000000000000000000..90ab5fd0fc6a43761d1a64083b1d01557af1e55f --- /dev/null +++ b/ltp/m4/ltp-fcntl.m4 @@ -0,0 +1,21 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2014 Fujitsu Ltd. +dnl Author: Xiaoguang Wang + +AC_DEFUN([LTP_CHECK_SYSCALL_FCNTL],[ + AC_MSG_CHECKING([for fcntl f_owner_ex]) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +#define _GNU_SOURCE +#include +int main(void) { + struct f_owner_ex tst_own_ex; + return 0; +}])],[has_f_owner_ex="yes"]) + +if test "x$has_f_owner_ex" = xyes; then + AC_DEFINE(HAVE_STRUCT_F_OWNER_EX,1,[Define to 1 if you have struct f_owner_ex]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +]) diff --git a/ltp/m4/ltp-fortify_source.m4 b/ltp/m4/ltp-fortify_source.m4 new file mode 100644 index 0000000000000000000000000000000000000000..4c191796eae1f419b3d822ca09edd69bc042b70b --- /dev/null +++ b/ltp/m4/ltp-fortify_source.m4 @@ -0,0 +1,20 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2013 Cyril Hrubis + +AC_DEFUN([LTP_CHECK_FORTIFY_SOURCE],[ + AC_MSG_CHECKING(whether to define _FORTIFY_SOURCE=2) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +#include + +int main(void) +{ +#if !defined _FORTIFY_SOURCE && defined __OPTIMIZE__ && __OPTIMIZE__ + return 0; +#else +# error Compiling without optimalizations +#endif +} +])],[CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2" +AC_MSG_RESULT(yes)], +[AC_MSG_RESULT(no)]) +]) diff --git a/ltp/m4/ltp-fsverity.m4 b/ltp/m4/ltp-fsverity.m4 new file mode 100644 index 0000000000000000000000000000000000000000..71048865c1e3775c38ca53dc817ce39755540d26 --- /dev/null +++ b/ltp/m4/ltp-fsverity.m4 @@ -0,0 +1,10 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2022 Fujitsu Ltd. +dnl Author: Dai Shili + +AC_DEFUN([LTP_CHECK_FSVERITY],[ + AC_CHECK_HEADERS([linux/fsverity.h], [have_fsverity=yes], [AC_MSG_WARN(missing linux/fsverity.h header)]) + if test "x$have_fsverity" = "xyes"; then + AC_CHECK_TYPES(struct fsverity_enable_arg,,,[#include ]) + fi +]) diff --git a/ltp/m4/ltp-host-cpu.m4 b/ltp/m4/ltp-host-cpu.m4 new file mode 100644 index 0000000000000000000000000000000000000000..85b894c3b25d2bc2c5a67dea9e11a3411617949d --- /dev/null +++ b/ltp/m4/ltp-host-cpu.m4 @@ -0,0 +1,13 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2018 Petr Vorel + +AC_DEFUN([LTP_DETECT_HOST_CPU], [ +AC_SUBST([HOST_CPU], [$host_cpu]) +AS_CASE([$host_cpu], + [amd64], [HOST_CPU=x86_64], + [arm*], [HOST_CPU=arm], + [i?86|x86], [HOST_CPU=x86], + [s390*], [HOST_CPU=s390], +) +AC_SUBST([HOST_CPU]) +]) diff --git a/ltp/m4/ltp-kernel_devel.m4 b/ltp/m4/ltp-kernel_devel.m4 new file mode 100644 index 0000000000000000000000000000000000000000..d46d54775a587558933cf4e2aa834c36b702bd60 --- /dev/null +++ b/ltp/m4/ltp-kernel_devel.m4 @@ -0,0 +1,53 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. +dnl Author: Alexey Kodanev +dnl Building kernel modules +dnl kernel development headers installed + +AC_DEFUN([LTP_CHECK_KERNEL_DEVEL],[ + +AC_MSG_CHECKING([for kernel-devel]) +AC_ARG_WITH( + [linux-version], + [AS_HELP_STRING([--with-linux-version=VERSION], + [specify the Linux version to build modules for])], + [LINUX_VERSION="${withval}"], + AS_IF([test "$cross_compiling" = "no"], + [LINUX_VERSION=`uname -r`])) + +AC_SUBST(LINUX_VERSION) + +AC_ARG_WITH([linux-dir], + [AS_HELP_STRING([--with-linux-dir=DIR], + [specify path to kernel-devel directory])], + [LINUX_DIR="${withval}"], + AS_IF([test -n "$LINUX_VERSION"], + [LINUX_DIR="/lib/modules/$LINUX_VERSION/build"])) + +AC_SUBST(LINUX_DIR) + +if test -f "$LINUX_DIR/Makefile"; then + LINUX_VERSION_MAJOR=`make -C ${LINUX_DIR} -s kernelversion | cut -d. -f1` + LINUX_VERSION_PATCH=`make -C ${LINUX_DIR} -s kernelversion | cut -d. -f2` +fi + +if test -n "$LINUX_VERSION_MAJOR" -a -n "$LINUX_VERSION_PATCH"; then + WITH_MODULES="yes" +else + WITH_MODULES="no" +fi + +AC_SUBST(LINUX_VERSION_MAJOR) +AC_SUBST(LINUX_VERSION_PATCH) + +AC_MSG_RESULT([$WITH_MODULES]) + +AC_ARG_WITH( + [modules], + [AS_HELP_STRING([--without-modules], + [disable auto-building kernel modules])], + [WITH_MODULES="no"], + []) + +AC_SUBST(WITH_MODULES) +]) diff --git a/ltp/m4/ltp-keyutils.m4 b/ltp/m4/ltp-keyutils.m4 new file mode 100644 index 0000000000000000000000000000000000000000..451c549f380b0ecf2c2565deacce63d06a478787 --- /dev/null +++ b/ltp/m4/ltp-keyutils.m4 @@ -0,0 +1,10 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2016 Fujitsu Ltd. +dnl Copyright (c) 2017 Petr Vorel +dnl Author: Xiao Yang + +AC_DEFUN([LTP_CHECK_KEYUTILS_SUPPORT], [ + AC_CHECK_LIB([keyutils], [add_key], + [AC_DEFINE(HAVE_LIBKEYUTILS, 1, [Define to 1 if you have libkeyutils installed.]) + AC_SUBST(KEYUTILS_LIBS, "-lkeyutils")]) +]) diff --git a/ltp/m4/ltp-libmnl.m4 b/ltp/m4/ltp-libmnl.m4 new file mode 100644 index 0000000000000000000000000000000000000000..c6e357baebf3e673be11a51f7cfe0d964488891e --- /dev/null +++ b/ltp/m4/ltp-libmnl.m4 @@ -0,0 +1,8 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2020 Petr Vorel + +AC_DEFUN([LTP_CHECK_LIBMNL], [ + PKG_CHECK_MODULES([LIBMNL], [libmnl], [ + AC_DEFINE([HAVE_LIBMNL], [1], [Define to 1 if you have libmnl library and headers]) + ], [have_libmnl=no]) +]) diff --git a/ltp/m4/ltp-numa.m4 b/ltp/m4/ltp-numa.m4 new file mode 100644 index 0000000000000000000000000000000000000000..483f5711587199143f434cce32e2759eab72ba40 --- /dev/null +++ b/ltp/m4/ltp-numa.m4 @@ -0,0 +1,24 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Cisco Systems Inc., 2009 +dnl Copyright (c) 2017 Petr Vorel +dnl Author: Ngie Cooper + +AC_DEFUN([LTP_CHECK_SYSCALL_NUMA], [ + AC_CHECK_LIB(numa, numa_available, [have_libnuma=yes]) + AC_CHECK_HEADERS([numa.h numaif.h], [], [have_numa_headers=no]) + + if test "x$have_numa_headers" != "xno"; then + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include + ], [ +#if LIBNUMA_API_VERSION < 2 +# error Required numa headers >= 2 +#endif + ])], [have_numa_headers_v2=yes]) + fi + + if test "x$have_libnuma" = "xyes" -a "x$have_numa_headers" != "xno" -a "x$have_numa_headers_v2" = "xyes"; then + AC_SUBST(NUMA_LIBS, "-lnuma") + AC_DEFINE(HAVE_NUMA_V2, 1, [Define to 1 if you have libnuma and it's headers version >= 2 installed.]) + fi +]) diff --git a/ltp/m4/ltp-selinux.m4 b/ltp/m4/ltp-selinux.m4 new file mode 100644 index 0000000000000000000000000000000000000000..fd0aeee86043ab85328126b5cf0e6ef14b4c515d --- /dev/null +++ b/ltp/m4/ltp-selinux.m4 @@ -0,0 +1,13 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Red Hat Inc., 2009 + +AC_DEFUN([LTP_CHECK_SELINUX], +[ +AH_TEMPLATE(HAVE_LIBSELINUX_DEVEL, +[Define to 1 if you have both SELinux libraries and headers.]) +AC_CHECK_HEADERS(selinux/selinux.h,[ + AC_CHECK_LIB(selinux,is_selinux_enabled,[ + AC_DEFINE(HAVE_LIBSELINUX_DEVEL) SELINUX_LIBS="-lselinux"],[ + SELINUX_LIBS=""])],[ + SELINUX_LIBS=""]) +AC_SUBST(SELINUX_LIBS)]) diff --git a/ltp/m4/ltp-signalfd.m4 b/ltp/m4/ltp-signalfd.m4 new file mode 100644 index 0000000000000000000000000000000000000000..5aac395bd7a0e8da0a73bb20eacf18f5ce8e820f --- /dev/null +++ b/ltp/m4/ltp-signalfd.m4 @@ -0,0 +1,17 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Red Hat Inc., 2008 +dnl Copyright (c) 2019 Fujitsu Ltd. +dnl Author: Masatake YAMATO + +AC_DEFUN([LTP_CHECK_SYSCALL_SIGNALFD],[ + +AC_CHECK_FUNCS(signalfd,,) +AC_CHECK_HEADERS([sys/signalfd.h],,) +AC_CHECK_HEADERS([linux/signalfd.h],,) +AC_CHECK_MEMBERS([struct signalfd_siginfo.ssi_signo],,,[ +#if defined HAVE_SYS_SIGNALFD_H +#include +#elif defined HAVE_LINUX_SIGNALFD_H +#include +#endif]) +]) diff --git a/ltp/m4/ltp-sync_add_and_fetch.m4 b/ltp/m4/ltp-sync_add_and_fetch.m4 new file mode 100644 index 0000000000000000000000000000000000000000..3815a0775f022ee59e0df0c47f692c217e8e09ff --- /dev/null +++ b/ltp/m4/ltp-sync_add_and_fetch.m4 @@ -0,0 +1,18 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Linux Test Project, 2016 + +AC_DEFUN([LTP_CHECK_SYNC_ADD_AND_FETCH],[ + AC_MSG_CHECKING([for __sync_add_and_fetch]) + AC_LINK_IFELSE([AC_LANG_SOURCE([ +int main(void) { + int i = 0; + return __sync_add_and_fetch(&i, 1); +}])],[has_saac="yes"]) + +if test "x$has_saac" = xyes; then + AC_DEFINE(HAVE_SYNC_ADD_AND_FETCH,1,[Define to 1 if you have __sync_add_and_fetch]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +]) diff --git a/ltp/m4/ltp-taskstats.m4 b/ltp/m4/ltp-taskstats.m4 new file mode 100644 index 0000000000000000000000000000000000000000..361daf552624653b4ae77bf43a3b65bfbd861e40 --- /dev/null +++ b/ltp/m4/ltp-taskstats.m4 @@ -0,0 +1,20 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) Jiri Palecek 2009 + +AC_DEFUN([LTP_CHECK_TASKSTATS], +_LTP_CHECK_TASKSTATS_FREEPAGES +) + +dnl Check for taskstat.freepages_* members, introduced to the kernel +dnl in commit 016ae219 in July 2008 + +AC_DEFUN([_LTP_CHECK_TASKSTATS_FREEPAGES],[ +AC_CHECK_HEADERS([linux/taskstats.h],[ + AC_CHECK_MEMBERS([struct taskstats.freepages_count, struct taskstats.nvcsw, struct taskstats.read_bytes], + [],[],[ +#include +]) +],[],[ +#include +]) +]) diff --git a/ltp/m4/ltp-tirpc.m4 b/ltp/m4/ltp-tirpc.m4 new file mode 100644 index 0000000000000000000000000000000000000000..0fa706771776cc7f4dd32b10e28a18c74f6aa7c7 --- /dev/null +++ b/ltp/m4/ltp-tirpc.m4 @@ -0,0 +1,23 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2020 Petr Vorel +dnl Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved. + +AC_DEFUN([LTP_CHECK_TIRPC], [ + dnl libtirpc library and headers + PKG_CHECK_MODULES([LIBTIRPC], [libtirpc >= 0.2.4], [ + have_libtirpc=yes + ], [have_libtirpc=no]) + + dnl TI-RPC headers (in glibc, since 2.26 installed only when configured + dnl with --enable-obsolete-rpc) + dnl NOTE: To port tests for ntirpc would require use non-deprecated + dnl functions as it does not have the deprecated ones any more (e.g. use + dnl rpc_broadcast() instead of clnt_broadcast()), but glibc implementation + dnl does not have the new ones. We could either provide the deprecated + dnl functions (copy from libtirpc src/rpc_soc.c) or drop glibc tests. + AC_CHECK_FUNCS([xdr_char clnttcp_create], [have_rpc_glibc=yes]) + + if test "x$have_libtirpc" = "xyes" -o "x$have_rpc_glibc" = "xyes"; then + AC_SUBST(HAVE_RPC, 1) + fi +]) diff --git a/ltp/m4/ltp-utimensat.m4 b/ltp/m4/ltp-utimensat.m4 new file mode 100644 index 0000000000000000000000000000000000000000..0ababef0fcfef335de8cbaaeadee5c895b2470f7 --- /dev/null +++ b/ltp/m4/ltp-utimensat.m4 @@ -0,0 +1,25 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + +AC_DEFUN([LTP_CHECK_SYSCALL_UTIMENSAT],[ + AC_MSG_CHECKING([for utimensat]) + AC_LINK_IFELSE([AC_LANG_SOURCE([ +#include +#include +#include + +int main(void) { + long tv_nsec; + tv_nsec = UTIME_NOW; + tv_nsec = UTIME_OMIT; + + return utimensat(AT_FDCWD, NULL, NULL, 0); +}])],[has_utimensat="yes"]) + +if test "x$has_utimensat" = "xyes"; then + AC_DEFINE(HAVE_UTIMENSAT, 1, [Define to 1 if you have utimensat(2)]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +]) diff --git a/ltp/m4/ltp-warn_oldstyle.m4 b/ltp/m4/ltp-warn_oldstyle.m4 new file mode 100644 index 0000000000000000000000000000000000000000..fa6de7c03baec3af9c48617ca4da2a50850ece98 --- /dev/null +++ b/ltp/m4/ltp-warn_oldstyle.m4 @@ -0,0 +1,23 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved. +dnl Author: Alexey Kodanev + +AC_DEFUN([LTP_CHECK_CC_WARN_OLDSTYLE],[ + +wflag="-Wold-style-definition" +AC_MSG_CHECKING([if $CC supports $wflag]) + +backup_cflags="$CFLAGS" +CFLAGS="$CFLAGS $wflag" + +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([])], + [GCC_WARN_OLDSTYLE="$wflag"] + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])] +) + +AC_SUBST(GCC_WARN_OLDSTYLE) +CFLAGS="$backup_cflags" + +]) diff --git a/ltp/metadata/.gitignore b/ltp/metadata/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..bb6399e5ce4f19e9259b10e24f6e2560d27817e6 --- /dev/null +++ b/ltp/metadata/.gitignore @@ -0,0 +1,3 @@ +metaparse +metaparse-sh +ltp.json diff --git a/ltp/metadata/Makefile b/ltp/metadata/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6939b9f76ccc5612e9f6b56e88bc0a2f60a03234 --- /dev/null +++ b/ltp/metadata/Makefile @@ -0,0 +1,21 @@ +# 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 metaparse-sh +INSTALL_DIR = metadata + +.PHONY: ltp.json + +ltp.json: metaparse metaparse-sh + $(abs_srcdir)/parse.sh > ltp.json + +test: + $(MAKE) -C $(abs_srcdir)/tests/ test + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/metadata/README.md b/ltp/metadata/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c71062759df7a47833b12b9c368537da95e3fe12 --- /dev/null +++ b/ltp/metadata/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 than +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 still 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/ltp/metadata/data_storage.h b/ltp/metadata/data_storage.h new file mode 100644 index 0000000000000000000000000000000000000000..6ca5d7d909acd57dc64439c9abe6cfc1de5e11e0 --- /dev/null +++ b/ltp/metadata/data_storage.h @@ -0,0 +1,449 @@ +// 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 +#include + +enum data_type { + DATA_ARRAY, + DATA_HASH, + DATA_STRING, + DATA_INT, + DATA_NULL, +}; + +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"; + case DATA_NULL: + return "null"; + 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; +} + +static inline struct data_node *data_node_null(void) +{ + struct data_node *node = malloc(sizeof(struct data_node)); + + if (!node) + return NULL; + + node->type = DATA_NULL; + + 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: + case DATA_NULL: + 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 inline 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 unsigned int data_node_hash_len(struct data_node *self) +{ + struct data_node_hash *hash = &self->hash; + + return hash->elems_used; +} + +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 struct data_node *data_node_array_last(struct data_node *self) +{ + if (self->type != DATA_ARRAY) + return NULL; + + unsigned int array_used = self->array.array_used; + if (!array_used) + return NULL; + + return self->array.array[array_used-1]; +} + +static inline void data_node_array_last_rem(struct data_node *self) +{ + if (self->type != DATA_ARRAY) + return; + + unsigned int array_used = self->array.array_used; + if (!array_used) + return; + + data_node_free(self->array.array[array_used-1]); + + self->array.array[array_used-1] = NULL; + self->array.array_used--; +} + +static inline void data_print_padd(unsigned int i) +{ + while (i-- > 0) + putchar(' '); +} + +static inline bool data_node_is_empty(struct data_node *self) +{ + switch (self->type) { + case DATA_ARRAY: + return data_node_array_len(self) == 0; + case DATA_HASH: + return data_node_hash_len(self) == 0; + default: + return false; + } +} + +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_NULL: + data_print_padd(padd); + printf("null\n"); + 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_NULL: + padd = do_padd ? padd : 0; + data_fprintf(f, padd, "null"); + break; + case DATA_HASH: + data_fprintf(f, do_padd ? padd : 0, "{\n"); + for (i = 0; i < self->hash.elems_used; i++) { + data_fprintf(f, padd+1, "\"%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"); + } + data_fprintf(f, padd, "}"); + 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) +{ + data_to_json_(self, f, padd, 0); +} + +#endif /* DATA_STORAGE_H__ */ diff --git a/ltp/metadata/metaparse-sh.c b/ltp/metadata/metaparse-sh.c new file mode 100644 index 0000000000000000000000000000000000000000..d9b30b98f36ad54f6e20838fc8f9f422a2204450 --- /dev/null +++ b/ltp/metadata/metaparse-sh.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Cyril Hrubis + */ + +#include +#include +#include +#include + +#include "data_storage.h" + +static int started; + +static void json_start(char *path) +{ + if (started) + return; + + started = 1; + + printf(" \"%s\": {\n", basename(path)); +} + +static void json_finish(const char *path) +{ + if (!started) + return; + + printf(" \"fname\": \"%s\"\n", path); + printf(" }"); +} + +enum state { + NONE, + START, + DOC_FIRST, + DOC, + ENV_START, + ENV_FIRST, + ENV +}; + +static void parse_shell(char *path) +{ + char line[4096]; + FILE *f = fopen(path, "r"); + enum state state = NONE; + + if (!f) { + fprintf(stderr, "Failed to open '%s': %s\n", + path, strerror(errno)); + exit(1); + } + + while (fgets(line, sizeof(line), f)) { + /* Strip newline */ + line[strlen(line)-1] = 0; + + switch (state) { + case NONE: + if (!strcmp(line, "# ---")) + state = START; + break; + case START: + if (!strcmp(line, "# doc")) { + json_start(path); + state = DOC_FIRST; + printf(" \"doc\": [\n"); + } else if (!strcmp(line, "# env")) { + json_start(path); + state = ENV_START; + } else { + state = NONE; + } + break; + case DOC: + case DOC_FIRST: + if (!strcmp(line, "# ---")) { + state = NONE; + printf("\n ],\n"); + continue; + } + + if (state == DOC_FIRST) + state = DOC; + else + printf(",\n"); + + data_fprintf_esc(stdout, 4, line+2); + break; + case ENV_START: + if (!strcmp(line, "# {")) { + state = ENV_FIRST; + } else { + fprintf(stderr, + "%s: Invalid line in JSON block '%s'", + path, line); + } + break; + case ENV: + case ENV_FIRST: + if (!strcmp(line, "# }")) { + state = NONE; + printf(",\n"); + continue; + } + + if (state == ENV_FIRST) + state = ENV; + else + printf("\n"); + + line[0] = ' '; + line[1] = ' '; + + printf("%s", line); + break; + } + } + + json_finish(path); +} + +int main(int argc, char *argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + parse_shell(argv[i]); + + return 0; +} diff --git a/ltp/metadata/metaparse.c b/ltp/metadata/metaparse.c new file mode 100644 index 0000000000000000000000000000000000000000..36736ac06f5f0ee18b00661996a07d09f601f92d --- /dev/null +++ b/ltp/metadata/metaparse.c @@ -0,0 +1,1146 @@ +// 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 remove_to_newline(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 '/': + remove_to_newline(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 '#': + 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; +} + +/** + * List of includes to be skipped. + * + * These define many macros or include many include files that are mostly + * useless to values expanded in tst_test structure. Or macros that shouldn't + * be expanded at all. + */ +static const char *skip_includes[] = { + "\"tst_test.h\"", + "\"config.h\"", + "\"tst_taint.h\"", + NULL +}; + +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; + + for (i = 0; skip_includes[i]; i++) { + if (!strcmp(skip_includes[i], buf)) { + if (verbose) + fprintf(stderr, "INCLUDE SKIP %s\n", buf); + return NULL; + } + } + + if (!strncmp(buf, "\"lapi/", 6)) { + if (verbose) + fprintf(stderr, "INCLUDE SKIP %s\n", buf); + 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 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 void finalize_array_entry(char **val, char **id, struct data_node *node) +{ + if (!*val) + return; + + if (*id) + data_node_hash_add(node, *id+1, data_node_string(*val)); + else + data_node_array_add(node, data_node_string(*val)); + + free(*id); + free(*val); + *id = NULL; + *val = NULL; +} + +static void str_append(char **res, char *append) +{ + char *cur_str = *res; + + if (!cur_str) { + *res = strdup(append); + if (!*res) + goto err; + return; + } + + if (asprintf(res, "%s%s", cur_str, append) < 0) + goto err; + + free(cur_str); + return; +err: + fprintf(stderr, "Allocation failed :(\n"); + exit(1); +} + +static int array_is_hash(FILE *f) +{ + long pos = ftell(f); + int has_ids = 1; + int elem_seen = 0; + int comma_last = 0; + int in_id = 1; + char *token; + + while ((token = next_token(f, NULL))) { + + if (!strcmp(token, "}")) { + if (in_id && !comma_last) + has_ids = 0; + goto ret; + } + + elem_seen = 1; + + if (!strcmp(token, "{")) { + if (in_id) { + has_ids = 0; + goto ret; + } + + int level = 1; + + for (;;) { + token = next_token(f, NULL); + + if (!token) + goto ret; + + if (!strcmp(token, "{")) + level++; + + if (!strcmp(token, "}")) + level--; + + if (!level) + break; + } + } else if (!strcmp(token, ",")) { + if (in_id) { + has_ids = 0; + goto ret; + } + + in_id = 1; + + comma_last = 1; + } else if (!strcmp(token, "=")) { + in_id = 0; + } else { + comma_last = 0; + } + } + +ret: + fseek(f, pos, SEEK_SET); + return elem_seen && has_ids; +} + +static int parse_array(FILE *f, const char *arr_id, struct data_node **ret) +{ + char *token; + char *val = NULL, *id = NULL; + int parent_cnt = 0; + int is_hash = array_is_hash(f); + + if (verbose) + fprintf(stderr, "PARSING ARRAY (%s) is_hash = %i\n", arr_id, is_hash); + + if (is_hash) + *ret = data_node_hash(); + else + *ret = data_node_array(); + + for (;;) { + if (!(token = next_token(f, NULL))) + return 1; + + if (!strcmp(token, "{")) { + struct data_node *sub_ret; + + parse_array(f, id, &sub_ret); + + if (data_node_is_empty(sub_ret)) { + data_node_free(sub_ret); + } else { + if (is_hash) + data_node_hash_add(*ret, id+1, sub_ret); + else + data_node_array_add(*ret, sub_ret); + } + + free(id); + id = NULL; + free(val); + val = NULL; + + continue; + } + + if (!strcmp(token, "}")) { + struct data_node *arr_last; + + finalize_array_entry(&val, &id, *ret); + /* Remove NULL terminating entry, if present. */ + if (!is_hash) { + arr_last = data_node_array_last(*ret); + if (arr_last && arr_last->type == DATA_NULL) + data_node_array_last_rem(*ret); + } + + return 0; + } + + if (is_hash && !strcmp(token, "=") && !id) { + id = val; + val = NULL; + continue; + } + + if (!strcmp(token, ",") && parent_cnt <= 0) { + finalize_array_entry(&val, &id, *ret); + continue; + } + + if (!strcmp(token, "NULL")) { + if (is_hash) + data_node_hash_add(*ret, id, data_node_null()); + else + data_node_array_add(*ret, data_node_null()); + continue; + } + + if (!strcmp(token, "(")) + parent_cnt++; + + if (!strcmp(token, ")")) + parent_cnt--; + + try_apply_macro(&token); + str_append(&val, token); + } + + return 0; +} + +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; + + if (!strcmp(token, "#")) { + remove_to_newline(f); + continue; + } + + 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, "{")) { + parse_array(f, id, &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, int level) +{ + FILE *inc; + const char *token; + int hash = 0; + + /** + * Allow only three levels of include indirection. + * + * Should be more than enough (TM). + */ + if (level >= 3) + return; + + 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); + else if (!strcmp(token, "include")) + parse_include_macros(inc, level+1); + + hash = 0; + } + + close_include(inc); +} + +/* pre-defined macros that makes the output cleaner. */ +static const struct macro { + char *from; + char *to; +} internal_macros[] = { + {"TST_CG_V2", "2"}, + {"TST_CG_V1", "1"}, + {"TST_KB", "1024"}, + {"TST_MB", "1048576"}, + {"TST_GB", "1073741824"}, + {"TST_SR_TBROK", "TBROK"}, + {"TST_SR_TCONF", "TCONF"}, + {"TST_SR_SKIP", "SKIP"}, + {"TST_SR_TBROK_MISSING", "TBROK_MISSING"}, + {"TST_SR_TCONF_MISSING", "TCONF_MISSING"}, + {"TST_SR_SKIP_MISSING", "SKIP_MISSING"}, + {"TST_SR_TBROK_RO", "TBROK_RO"}, + {"TST_SR_TCONF_RO", "TCONF_RO"}, + {"TST_SR_SKIP_RO", "SKIP_RO"}, + {} +}; + +static void load_internal_macros(void) +{ + unsigned int i; + + if (verbose) + fprintf(stderr, "PREDEFINED MACROS\n"); + + for (i = 0; internal_macros[i].from; i++) { + ENTRY e = { + .key = internal_macros[i].from, + .data = internal_macros[i].to, + }; + + if (verbose) + fprintf(stderr, " MACRO %s=%s\n", e.key, (char*)e.data); + + hsearch(e, ENTER); + } + + if (verbose) + fprintf(stderr, "END PREDEFINED MACROS\n"); +} + +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(); + + load_internal_macros(); + + 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, 0); + } + } + + 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[optind], 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/ltp/metadata/parse.sh b/ltp/metadata/parse.sh new file mode 100755 index 0000000000000000000000000000000000000000..45776e4d0512cbdc6af441b1c5271848b56d58a3 --- /dev/null +++ b/ltp/metadata/parse.sh @@ -0,0 +1,60 @@ +#!/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": 30' +echo ' },' +echo ' "tests": {' + +first=1 + +for test in `find testcases/ -name '*.c'|sort`; do + a=$($top_builddir/metadata/metaparse -Iinclude -Itestcases/kernel/syscalls/utils/ -Itestcases/kernel/include "$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/ltp/pan/Makefile b/ltp/pan/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e8596ec26b3172e4c69b6e210bf24cd2ea7e1eb6 --- /dev/null +++ b/ltp/pan/Makefile @@ -0,0 +1,51 @@ +# +# pan 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. +# +# Ngie Cooper, July 2009 +# + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/functions.mk + +# XXX (garrcoop): some versions of flex/bison generate crap code that doesn't +# check the return code from fwrite(3). +CPPFLAGS += -Wno-error + +CPPFLAGS += -I$(abs_srcdir) + +LDLIBS += -lm + +LFLAGS += -l + +INSTALL_DIR := bin + +MAKE_TARGETS := ltp-bump ltp-pan + +ltp-bump: ltp-bump.o zoolib.o + +ltp-pan: ltp-pan.o zoolib.o splitstr.o + +# flex does some whacky junk when it generates files on the fly, so let's make +# sure gcc doesn't get lost... +vpath %.c $(abs_srcdir):$(abs_builddir))) +vpath %.l $(abs_srcdir) + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/pan/cgi/README b/ltp/pan/cgi/README new file mode 100644 index 0000000000000000000000000000000000000000..544c5466b531be9b2e438f9f1ec8e93e4da8974f --- /dev/null +++ b/ltp/pan/cgi/README @@ -0,0 +1,59 @@ +Here are some CGI scripts I was using to view and compare RTS style output. +It will probably need a little more tweaking to be useful to LTP. + +Expectations: + + A directory that contains all output. It expects file names in the format + + ... + + The hostname the tests were run on + ISO standard format date. i.e. YYYYmmDDHHMM + The name of the pan file that was used + One of driver, scanner, or summary + + driver - the raw output from pan with <<>> + scanner - the output from scanner + summary - a very brief table listing how many tests passed, + failed, didn't run, etc. This wasn't released. + +Scripts: + + results.cgi + + This lists out all of the results that are the results directory. It + provides links to the driver output, scanned results, and summary for + each suite. The sort order is host, date, suite. On the results + page, which looks at the .scanner files, there are links that extract + the test tag output from the .driver file. + + browse.cgi + + This is a more complex form that I started working on. It allows you + to compare as many results as you want, side by side. Also, I started + working on sorting the results different ways, but didn't get too far. + The side by side comparison is done with in reconsile.cgi + + reconsile.cgi + + This script compares multiple scanner files and shows the differences + side by side in a table. It expects to find .scanner files for the + results it is comparing. + +Notes: + + The driver I was using with these scripts collects some system information + before running the tests. I use this information to display the `uname + -a` output in browse.cgi and reconsile.cgi. You will be missing this + information, but the scripts should still run. + + I apologize in advance for the use of Perl. I've managed to steer clear + of Perl for five years until I started writing these scripts. IMHO, the + people who learn programming with Perl write the ugliest code. Luckily, I + learned programming mostly with Pascal. Hopefully the code makes sense. + + +-- +Nate Straz nstraz@sgi.com +sgi, inc http://www.sgi.com/ +Linux Test Project http://ltp.sf.net/ diff --git a/ltp/pan/cgi/browse.cgi b/ltp/pan/cgi/browse.cgi new file mode 100755 index 0000000000000000000000000000000000000000..49fda6fbd211d43a5b40f9d63c2579e64f4d0d6a --- /dev/null +++ b/ltp/pan/cgi/browse.cgi @@ -0,0 +1,225 @@ +#!/usr/bin/perl + +use CGI qw(:standard); + +# keep a copy of each 'uname -a' string so we don't have to search for it every time. +%uname_cache = {}; + +# When something goes wrong before we start output, use this +# function so there is still output +sub failure { + print header("text/html"),start_html; + print "$_[0]\n"; + print end_html; + exit; +} +# get the UNAME line for a host, date, suite +sub get_result_uname { + my($inhost, $indate, $insuite, $filename); + my(@possible_files, $pf, $line); + my($host, $datestr, $suite, $type, $gz); + # build a filename + $inhost = $_[0]; + $indate = $_[1]; + if ($#_ >= 2) { + $insuite = $_[2]; + } else { + $insuite = "*"; + } + # check to see if we've done this already + if (exists($uname_cache{"$inhost.$indate"})) { + return $uname_cache{"$inhost.$indate"}; + } + $filename = "$inhost.$indate.$insuite.*"; + @possible_files = <${filename}>; + if ($#possible_files < 1) { + return ""; + } + foreach $pf (@possible_files) { + ($host, $datestr, $suite, $type, $gz) = split(/\./, $pf); + if ($type eq "summary") { + next; + } elsif ($type eq "scanner") { + open (UF, $pf) || next; + while ($line = ) { + if ($line =~ /^UNAME/) { + close(UF); + $line =~ s/UNAME *//; + $line =~ s/$inhost//; + $uname_cache{"$inhost.$indate"} = $line; + return $line; + } + } + } elsif ($type eq "driver") { + if ($gz) { + open (UF, "gunzip -c $pf|") || next; + } else { + open (UF, "$pf") || next; + } + while ($line = ) { + if ($line =~ /^UNAME/) { + close(UF); + $line =~ s/UNAME="(.*)"/\1/; + $line =~ s/$inhost//; + $uname_cache{"$inhost.$indate"} = $line; + return $line; + } + } + } else { + next; + } + } + return ""; +} + +# Create the headers row, adding links for sorting options +sub print_headers { + + print "\n"; + + for($i = 0; $i <= $#rso; $i++) { + print "$rso[$i]\n"; + } + + print "\n"; +} + +############ +# main() # +############ + +# Most of the work is done in this directory +unless (chdir("/usr/tests/ltp/results")) { + failure("Could not get to the results directory\n"); +} + +@extra_path = split(/\//, $ENV{PATH_INFO}); + +# rso = Result Sort Order +# rsd = Result Sort Direction +#@rso = (HOST,SUITE, DATE, UNAME); +@rso = (SUITE, HOST, DATE, UNAME); +@rsd = (1, 1, -1, 1); + +# allow the user to specify the sort order +if ($sort_order = param("sort")) { + @so = split(/,/, $sort_order); + print $so; + @rso = (); + for($i = 0; $i <= $#so; $i++) { + # parse the field + if ($so[$i] =~ /host/i) { push(@rso, HOST); } + elsif ($so[$i] =~ /date/i) { push(@rso, DATE); } + elsif ($so[$i] =~ /suite/i) { push(@rso, SUITE); } + elsif ($so[$i] =~ /uname/i) { push(@rso, UNAME); } + # parse the direction + if ($so[$i] =~ /-/) { $rsd[$i] = -1; } + else { $rsd[$i] = 1; } + } +} + +if ($#extra_path > 0) { + +} else { + + %results = (); + + # run through the files in the results directory + @driver_files = <*driver*>; + foreach $df (@driver_files) { + + ($host, $datestr, $suite, $type, $gz) = split(/\./, $df); + + $a_rec = (); + $a_rec->{HOST} = $host; + $a_rec->{DATE} = $datestr; + $a_rec->{SUITE} = $suite; + $a_rec->{DRIVER_FILE} = $df; + $a_rec->{UNAME} = get_result_uname($host, $datestr); + + $results{ $a_rec->{DRIVER_FILE} } = $a_rec; + } + + # write the HTML file + print header("text/html"),start_html; + print "This is a demo page for browsing the Linux LTP results. Select the results you want to compare and click the \"Compare\" button.", p, h2("Warning"), "The results are placed in a large table which may take a long time to render on some browsers", p; + @ri = values %results; + @ri = sort { ($a->{$rso[0]} cmp $b->{$rso[0]})*$rsd[0] + || ($a->{$rso[1]} cmp $b->{$rso[1]})*$rsd[1] + || ($a->{$rso[2]} cmp $b->{$rso[2]})*$rsd[2] + || ($a->{$rso[3]} cmp $b->{$rso[3]})*$rsd[3] } @ri; + + $last = (); + $last->{$rso[0]} = ""; + $last->{$rso[1]} = ""; + $last->{$rso[2]} = ""; + $lasthost = ""; + $lastdate = ""; + $lastsuite = ""; + #$lastindent = 0; + $thisindent = 0; + print "
"; + print "\n"; + #print "\n"; + print_headers(); + foreach $rp ( @ri ) { + + $this = (); + $this->{$rso[0]} = $rp->{$rso[0]}; + $this->{$rso[1]} = $rp->{$rso[1]}; + $this->{$rso[2]} = $rp->{$rso[2]}; + $this->{$rso[3]} = $rp->{$rso[3]}; + + # figure out the first column that is different + for ($i = 0; $i <= $#rso; $i++) { + if ($last->{$rso[$i]} ne $this->{$rso[$i]}) { + $thisindent = $i; + last; + } + } + + print "\n"; + for ($i = 0; $i < $thisindent; $i++) { + print "\n"; + + # make sure we update the $last... variables + $last->{$rso[0]} = $this->{$rso[0]}; + $last->{$rso[1]} = $this->{$rso[1]}; + $last->{$rso[2]} = $this->{$rso[2]}; + } + print "
HostnameDateSuite
"; + + } + for ($i = $thisindent; $i <= $#rso; $i++) { + print ""; + if ($i == $#rso) { + print "{HOST}.$this->{DATE}.$this->{SUITE}.scanner\">"; + } + print "$this->{$rso[$i]}"; + if ($i == $#rso) { + print ""; + } + if ($i == $#rso) { + # last column + print " {HOST}.$this->{DATE}.$this->{SUITE}\">"; + + } + + + } + print "
\n"; + print "\n"; + print "\n"; + print "
"; + print end_html; + +} + diff --git a/ltp/pan/cgi/reconsile.cgi b/ltp/pan/cgi/reconsile.cgi new file mode 100755 index 0000000000000000000000000000000000000000..da131f4716d08b78248af42db586b0236ff0329c --- /dev/null +++ b/ltp/pan/cgi/reconsile.cgi @@ -0,0 +1,250 @@ +#!/usr/bin/perl + +# +# reconsile.cgi - reconsile two or more scanner files +# + +use CGI qw(:standard); + +chdir("/usr/tests/ltp/results/"); + +# Get the list of results to compare. +@results = param("results"); + +print header("text/html"); +print start_html, "
\n";
+
+# Give a warning if the suites do not match
+($a, $b, $lastsuite) = split(/\./, $results[0]);
+for ($i = 1; $i <= $#results; $i++) {
+	($a, $b, $thissuite) = split(/\./, $results[$i]);
+	if ($lastsuite ne $thissuite) {
+		print "Warning: Suites do not match!\n";
+		last;
+	}
+}
+
+# check that each requested result exists.  If one does not exist,
+# print a warning and continue.  If the number of available results
+# is less than two, halt with an error
+@result_filenames = ();
+foreach $a_result (@results) {
+	if (-f "$a_result.scanner") {
+		push(@result_filenames, "$a_result.scanner");
+	} else {
+		print "Could not find a scanner file for $a_result\n";
+	}
+}
+if ($#result_filenames < 1) {
+	print "Not enough result files to compare\n";
+	die;
+}
+
+# for each result file read in and store the header information in
+# an associative array.  Take the rest of the input file and store
+# it as a list.
+@result_details = ();
+@result_testcases = ();
+$i = 0;
+foreach $result_filename (@result_filenames) {
+	unless (open(F, $result_filename)) {
+		print "failed openning $result_filename\n";
+		next;
+	}
+	# advance past the header then read in the rest
+	$result_testcases->[$i] = ();
+	$result_details->[$i] = {};
+	($host, $datestr, $suite, $ext) = split(/\./, $result_filename);
+	$result_details->[$i]->{HOST} = $host;
+	$result_details->[$i]->{DATESTR} = $datestr;
+	$result_details->[$i]->{SUITE} = $suite;
+	while ($line = ) {
+		# check for the end of the header
+		if ($line =~ /^-+/) {
+			# we've reached the top of the scanner output
+			# grab the rest and stop the while loop;
+			@rest = ;
+			close(F);
+			last;
+		}
+		# grab information from the header
+		if ($line =~ /^UNAME/) {
+			$line =~ s/UNAME *//;
+			$result_details->[$i]->{UNAME} = $line;
+			next;
+		}
+	}
+	# convert the results to records and add them to the list
+	foreach $line (@rest) {
+		($tag, $tcid, $tc, $status, $contact) = split(/\s+/, $line);
+		# fix some of the fields so they sort properly
+		$tcid = '{' if ($tcid eq '*');
+		$tcid = '}' if ($tcid eq '-');
+		$tc = '{' if ($tc eq '*');
+		$tc = '}' if ($tc eq '-');
+		$rec = ();
+		$rec->{TAG} = $tag;
+		$rec->{TCID} = $tcid;
+		$rec->{TC} = $tc;
+		$rec->{STATUS} = $status;
+		$rec->{CONTACT} = $contact;
+		push(@{$result_testcases[$i]}, $rec);
+	}
+	$i++;
+}
+
+# sort each set of results.
+# This is the most important step since walking the data depends on
+# correctly sorting the data.  Some substitutions are made to keep
+# the test cases in each test tag in the proper order.  i.e.
+# s/\*/{/
+#$i = 0;
+foreach $rtcs (@result_testcases) {
+	@$rtcs = sort { $a->{TAG} cmp $b->{TAG}
+					|| $a->{TCID} cmp $b->{TCID}
+					|| $a->{TC} <=> $b->{TC}
+					|| $a->{TC} cmp $b->{TC}
+					|| $a->{STATUS} cmp $b->{STATUS}} @$rtcs;
+	#print "sorted file $i\n";
+	#print "=" x 50 . "\n";
+	#foreach (@$rtcs) {
+	#	print "$_->{TAG}:$_->{TCID}:$_->{TC}:$_->{STATUS}\n";
+	#}
+	#print "=" x 50 . "\n";
+	#$i++;
+}
+
+# here is the loop that prints the data into a multi-column table with the test
+# tags grouped together.
+
+print "
"; +print "\n"; + +print "\n"; + +print "\n"; + +# while the result lists still have test cases +# Find the smallest record from the top of the lists +# remove matching records from the lists and output them +$last_tag = ""; +while (1) { + + # if there wasn't anything left, leave + $somethingleft = 0; + foreach $rtcs (@result_testcases) { + if ($#$rtcs > -1) { + $somethingleft = 1; + last; + } + } + unless ($somethingleft) { last; } + + # find the Lowest Common Record + @tops = (); + foreach $rtcs (@result_testcases) { + if (@$rtcs[0]) { + push(@tops, copy_record(@$rtcs[0])); + } + } + @tops = sort { $a->{TAG} cmp $b->{TAG} + || $a->{TCID} cmp $b->{TCID} + || $a->{TC} <=> $b->{TC} + || $a->{TC} cmp $b->{TC} + || $a->{STATUS} cmp $b->{STATUS}} @tops; + + $LCR = $tops[0]; + + # check to see if everyone matches + $matches = 0; + foreach $rtcs (@result_testcases) { + if (! @$rtcs[0]) { next; } + if (@$rtcs[0]->{TAG} eq $LCR->{TAG} + && @$rtcs[0]->{TCID} eq $LCR->{TCID} + && @$rtcs[0]->{TC} eq $LCR->{TC} + && @$rtcs[0]->{STATUS} eq $LCR->{STATUS}) { + + $matches++; + } + } + # if everyone does match (status included) shift them + # and move on. + if ($matches == ($#result_testcases+1)) { + foreach $rtcs (@result_testcases) { shift(@$rtcs); } + next; + } + + # if we've already output stuff related to this test tag, + # skip that column, otherwise print the tag + if ($LCR->{TAG} eq $lasttag) { + print "\n"; +} +print "
"; +for($i=0; $i <= $#result_testcases; $i++) { + print "$result_details->[$i]->{HOST}.$result_details->[$i]->{DATESTR}.$result_details->[$i]->{SUITE}"; +} +print "
Test Tag"; +for($i=0; $i <= $#result_testcases; $i++) { + print "TCIDTest CaseStatus"; +} +print "Contact
"; + } else { + print "
$LCR->{TAG}"; + $lasttag = $LCR->{TAG}; + } + + # walk through the lists again outputting as we match + $column = 0; + foreach $rtcs (@result_testcases) { + if (! @$rtcs[0]) { + print ""; + $column++; + next; + } elsif (@$rtcs[0]->{TAG} eq $LCR->{TAG} + && @$rtcs[0]->{TCID} eq $LCR->{TCID} + && @$rtcs[0]->{TC} eq $LCR->{TC}) { + + $match = shift(@$rtcs); + $match->{TCID} = '*' if ($match->{TCID} eq '{'); + $match->{TCID} = '-' if ($match->{TCID} eq '}'); + $match->{TC} = '*' if ($match->{TC} eq '{'); + $match->{TC} = '-' if ($match->{TC} eq '}'); + print ""; + $rd = $result_details->[$column]; + print "{HOST}.$rd->{DATESTR}.$rd->{SUITE}.driver&zoom_tag=$match->{TAG}\">"; + print "$match->{TCID}"; + print "$match->{TC}"; + print ""; + if ($match->{STATUS} =~ /PASS/) { + print ""; + } elsif ($match->{STATUS} =~ /FAIL/) { + print ""; + } elsif ($match->{STATUS} =~ /CONF/) { + print ""; + } elsif ($match->{STATUS} =~ /BROK/) { + print ""; + } else { + print ""; + } + print "$match->{STATUS}"; + } else { + print ""; + } + $column++; + } + print "$LCR->{CONTACT}
"; + +print end_html; + + +sub copy_record { + my $copy, $rec = shift; + + $copy->{TAG} = $rec->{TAG}; + $copy->{TCID} = $rec->{TCID}; + $copy->{TC} = $rec->{TC}; + $copy->{STATUS} = $rec->{STATUS}; + $copy->{CONTACT} = $rec->{CONTACT}; + return $copy; + +} diff --git a/ltp/pan/cgi/results.cgi b/ltp/pan/cgi/results.cgi new file mode 100755 index 0000000000000000000000000000000000000000..f84a92c7d1de5cb49a6d0c70c6467e6176093ea7 --- /dev/null +++ b/ltp/pan/cgi/results.cgi @@ -0,0 +1,164 @@ +#!/usr/bin/perl + +use CGI qw(:standard escapeHTML); + +# When something goes wrong before we start output, use this function +# so there is still output +sub failure { + print header("text/html"),start_html; + print "$_[0]\n"; + print end_html; + exit; +} + +# Most of the work is done in this directory +unless (chdir("/usr/tests/ltp/results")) { + failure("Could not get to the results directory\n"); +} + + +# grab the parameters that determine what's going on then branch +$get_df = param("get_df"); +if ($get_df) { + # copy a driver file and output it. + $get_df = (<$get_df*>)[0]; + ($host, $datestr, $suite, $type, $gz) = split(/\./, $get_df); + #print start_html, "
\n";
+	if ($gz) {
+		open (DF, "gunzip -c $get_df|") || print "$get_df not found\n";
+	} else {
+		open (DF, "$get_df") || print "$get_df not found";
+	}
+	if ($type eq "driver" || $type eq "summary") {
+		print header("text/plain");
+		$zoom_tag = param("zoom_tag");
+		if ($zoom_tag) {
+			while () {
+				# find the start of a test
+				while () {
+					if (/\<\<\\>\>/) {
+						$line = ;
+						if ($line =~ /^tag=$zoom_tag /) {
+							print "<<>>\n";
+							print $line;
+
+							do {
+								$line = ;
+								print $line;
+							} until ($line =~ /\<\<\\>\>/);
+							exit;
+						}
+					}
+				}
+			}
+			print "Did not find tag $zoom_tag\n";
+		} else {
+			while () {
+				print $_;
+			}
+		}
+	} elsif ($type eq "scanner") {
+		print header("text/html");
+		print start_html, "
\n";
+		while () {
+			print;
+			if (/^-+/) { last;}
+		}
+		@rest = ;
+		# this is just to put the * at the end of the test case list
+		unless (param("raw")) {
+			foreach (@rest) { s/\*/{/; }
+			foreach (@rest) { s/(\s)-(\s)/\1}\2/; }
+			@rest = sort @rest;
+			foreach (@rest) { s/{/*/; }
+			foreach (@rest) { s/}/-/; }
+		}
+
+		foreach (@rest) {
+			s/(\S+)/\1<\/a>/;
+			# colorize the status column
+			s/\bPASS\b/\PASS\<\/font\>/i;
+			s/\bFAIL\b/\FAIL\<\/font\>/i;
+			s/\bCONF\b/\CONF\<\/font\>/i;
+			s/\bBROK\b/\BROK\<\/font\>/i;
+			print;
+		}
+		print "\n
",end_html; + } + close(DF); + #print "\n
\n",end_html; +} else { + %results = (); + + # run through the files in the results directory + @driver_files = <*driver*>; + foreach $df (sort(@driver_files)) { + + ($host, $datestr, $suite, $type, $gz) = split(/\./, $df); + + $a_rec = (); + $a_rec->{HOST} = $host; + $a_rec->{DATE} = $datestr; + $a_rec->{SUITE} = $suite; + $a_rec->{DRIVER_FILE} = $df; + + $results{ $a_rec->{DRIVER_FILE} } = $a_rec; + } + + # write the HTML file + print header("text/html"),start_html; + + @ri = values %results; + @ri = sort { $a->{HOST} cmp $b->{HOST} + ||$b->{DATE} <=> $a->{DATE} + ||$a->{SUITE} cmp $b->{SUITE} } @ri; + $lasthost = ""; + $lastdate = ""; + $lastsuite = ""; + $indent = 0; + print "\n"; + print "\n"; + foreach $rp ( @ri ) { + $thishost = $rp->{HOST}; + $thisdate = $rp->{DATE}; + $thissuite = $rp->{SUITE}; + + # figure out where is the table we need to start + if ($lasthost ne $thishost) { + $indent = 0; + } elsif ($lastdate ne $thisdate) { + $indent = 1; + } elsif ($lastsuite ne $thissuite) { + $indent = 2; + } + + # write the rows we need depending on the starting point + # host level + if ($indent <= 0) { + print "
HostnameDateSuite
$thishost\n"; + } + # date level + if ($indent <= 1) { + ($year, $month, $day, $hour, $min) = ($thisdate =~ /(\d+)(\d{2})(\d{2})(\d{2})(\d{2})/); + print "
$year-$month-$day $hour:$min\n"; + } + # suite level + if ($indent <= 2) { + print "
"; + print "$thissuite"; + print " [{DRIVER_FILE}\">driver output]"; + print " [results]"; + print " [summary]"; + + print "\n"; + } + + # make sure we update the $last... variables + $lasthost = $thishost; + $lastdate = $thisdate; + $lastsuite = $thissuite; + } + print "
\n"; + print end_html; +} + diff --git a/ltp/pan/ltp-bump.c b/ltp/pan/ltp-bump.c new file mode 100644 index 0000000000000000000000000000000000000000..b6d676f423054bb02f79595617253e343af04cb3 --- /dev/null +++ b/ltp/pan/ltp-bump.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * + */ +/* $Id: ltp-bump.c,v 1.1 2009/05/19 09:39:11 subrata_modak Exp $ */ +#include +#include +#include +#include +#include +#include + +#include "zoolib.h" + +pid_t read_active(FILE * fp, char *name); + +int main(int argc, char **argv) +{ + int c; + char *active = NULL; + pid_t nanny; + zoo_t zoo; + int sig = SIGINT; + + while ((c = getopt(argc, argv, "a:s:12")) != -1) { + switch (c) { + case 'a': + active = malloc(strlen(optarg) + 1); + strcpy(active, optarg); + break; + case 's': + sig = atoi(optarg); + break; + case '1': + sig = SIGUSR1; + break; + case '2': + sig = SIGUSR2; + break; + } + } + + if (active == NULL) { + active = zoo_getname(); + if (active == NULL) { + fprintf(stderr, + "ltp-bump: Must supply -a or set ZOO env variable\n"); + exit(1); + } + } + + if (optind == argc) { + fprintf(stderr, "ltp-bump: Must supply names\n"); + exit(1); + } + + /* need r+ here because we're using write-locks */ + if ((zoo = zoo_open(active)) == NULL) { + fprintf(stderr, "ltp-bump: %s\n", zoo_error); + exit(1); + } + + while (optind < argc) { + /*printf("argv[%d] = (%s)\n", optind, argv[optind] ); */ + nanny = zoo_getpid(zoo, argv[optind]); + if (nanny == -1) { + fprintf(stderr, "ltp-bump: Did not find tag '%s'\n", + argv[optind]); + } else { + if (kill(nanny, sig) == -1) { + if (errno == ESRCH) { + fprintf(stderr, + "ltp-bump: Tag %s (pid %d) seems to be dead already.\n", + argv[optind], nanny); + if (zoo_clear(zoo, nanny)) + fprintf(stderr, + "ltp-bump: %s\n", + zoo_error); + } + } + } + ++optind; + } + zoo_close(zoo); + + exit(0); +} diff --git a/ltp/pan/ltp-pan.c b/ltp/pan/ltp-pan.c new file mode 100644 index 0000000000000000000000000000000000000000..0bdb5147717f151c67df6ba2bd4c78b20bd79bc5 --- /dev/null +++ b/ltp/pan/ltp-pan.c @@ -0,0 +1,1485 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * + * Changelog: + * + * Added timer options: William Jay Huie, IBM + * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu + * - option '-p' (pretty printing)i to enabled formatted printing + * of results. + * + * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu + * - added code to print system information + * + * 01/28/03 - Added: Manoj Iyer, manjo@mail.utexas.edu + * - added code to print test exit value. + * + * 01/29/03 - Added: Manoj Iyer, manjo@mail.utexas.edu + * - added code supresses test start and test end tags. + * + * 07/22/07 - Added: Ricardo Salveti de Araujo, rsalveti@linux.vnet.ibm.com + * - added option to create a command file with all failed tests. + * + */ +/* $Id: ltp-pan.c,v 1.4 2009/10/15 18:45:55 yaberauneya Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "splitstr.h" +#include "zoolib.h" +#include "tst_res_flags.h" + +/* One entry in the command line collection. */ +struct coll_entry { + char *name; /* tag name */ + char *cmdline; /* command line */ + char *pcnt_f; /* location of %f in the command line args, flag */ + struct coll_entry *next; +}; + +struct collection { + int cnt; + struct coll_entry **ary; +}; + +struct tag_pgrp { + int pgrp; + int stopping; + time_t mystime; + struct coll_entry *cmd; + char output[PATH_MAX]; +}; + +struct orphan_pgrp { + int pgrp; + struct orphan_pgrp *next; +}; + +static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active, + int quiet_mode, int *failcnt, int fmt_print, + FILE * logfile, int no_kmsg); +static char *slurp(char *file); +static struct collection *get_collection(char *file, int optind, int argc, + char **argv); +static void pids_running(struct tag_pgrp *running, int keep_active); +static int check_pids(struct tag_pgrp *running, int *num_active, + int keep_active, FILE * logfile, FILE * failcmdfile, + FILE *tconfcmdfile, struct orphan_pgrp *orphans, + int fmt_print, int *failcnt, int *tconfcnt, + int quiet_mode, int no_kmsg); +static void propagate_signal(struct tag_pgrp *running, int keep_active, + struct orphan_pgrp *orphans); +static void dump_coll(struct collection *coll); +static char *subst_pcnt_f(struct coll_entry *colle); +static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid); +static void orphans_running(struct orphan_pgrp *orphans); +static void check_orphans(struct orphan_pgrp *orphans, int sig); + +static void copy_buffered_output(struct tag_pgrp *running); +static void write_test_start(struct tag_pgrp *running, int no_kmsg); +static void write_test_end(struct tag_pgrp *running, const char *init_status, + time_t exit_time, char *term_type, int stat_loc, + int term_id, struct tms *tms1, struct tms *tms2); + +//wjh +static char PAN_STOP_FILE[] = "PAN_STOP_FILE"; + +static char *panname = NULL; +static char *test_out_dir = NULL; /* dir to buffer output to */ +zoo_t zoofile; +static char *reporttype = NULL; + +/* Common format string for ltp-pan results */ +#define ResultFmt "%-50s %-10.10s" + +/* zoolib */ +int rec_signal; /* received signal */ +int send_signal; /* signal to send */ + +/* Debug Bits */ +int Debug = 0; +#define Dbuffile 0x000400 /* buffer file use */ +#define Dsetup 0x000200 /* one-time set-up */ +#define Dshutdown 0x000100 /* killed by signal */ +#define Dexit 0x000020 /* exit status */ +#define Drunning 0x000010 /* current pids running */ +#define Dstartup 0x000004 /* started command */ +#define Dstart 0x000002 /* started command */ +#define Dwait 0x000001 /* wait interrupted */ + +int main(int argc, char **argv) +{ + extern char *optarg; + extern int optind; + char *zooname = NULL; /* name of the zoo file to use */ + char *filename = "/dev/null"; /* filename to read test tags from */ + char *logfilename = NULL; + char *failcmdfilename = NULL; + char *tconfcmdfilename = NULL; + char *outputfilename = NULL; + struct collection *coll = NULL; + struct tag_pgrp *running; + struct orphan_pgrp *orphans, *orph; + struct utsname unamebuf; + FILE *logfile = NULL; + FILE *failcmdfile = NULL; + FILE *tconfcmdfile = NULL; + int keep_active = 1; + int num_active = 0; + int failcnt = 0; /* count of total testcases that failed. */ + int tconfcnt = 0; /* count of total testcases that return TCONF */ + int err, i; + int starts = -1; + int timed = 0; + int run_time = -1; + char modifier = 'm'; + int ret = 0; + int stop; + int go_idle; + int has_brakes = 0; /* stop everything if a test case fails */ + int sequential = 0; /* run tests sequentially */ + int fork_in_road = 0; + int exit_stat; + int track_exit_stats = 0; /* exit non-zero if any test exits non-zero */ + int fmt_print = 0; /* enables formatted printing of logfiles. */ + int quiet_mode = 0; /* supresses test start and test end tags. */ + int no_kmsg = 0; /* don't log into /dev/kmsg */ + int c; + pid_t cpid; + struct sigaction sa; + + while ((c = + getopt(argc, argv, "AO:Sa:C:QT:d:ef:hl:n:o:pqr:s:t:x:y")) + != -1) { + switch (c) { + case 'A': /* all-stop flag */ + has_brakes = 1; + track_exit_stats = 1; + break; + case 'O': /* output buffering directory */ + test_out_dir = strdup(optarg); + break; + case 'S': /* run tests sequentially */ + sequential = 1; + break; + case 'a': /* name of the zoo file to use */ + zooname = strdup(optarg); + break; + case 'C': /* name of the file where all failed commands will be */ + failcmdfilename = strdup(optarg); + break; + case 'Q': + no_kmsg = 1; + break; + case 'T': + /* + * test cases that are not fully tested will be recorded + * in this file + */ + tconfcmdfilename = strdup(optarg); + break; + case 'd': /* debug options */ + sscanf(optarg, "%i", &Debug); + break; + case 'e': /* exit non-zero if any test exists non-zero */ + track_exit_stats = 1; + break; + case 'f': /* filename to read test tags from */ + filename = strdup(optarg); + break; + case 'h': /* help */ + fprintf(stdout, + "Usage: pan -n name [ -SyAehpqQ ] [ -s starts ]" + " [-t time[s|m|h|d] [ -x nactive ] [ -l logfile ]\n\t" + "[ -a active-file ] [ -f command-file ] " + "[ -C fail-command-file ] " + "[ -d debug-level ]\n\t[-o output-file] " + "[-O output-buffer-directory] [cmd]\n"); + exit(0); + case 'l': /* log file */ + logfilename = strdup(optarg); + break; + case 'n': /* tag given to pan */ + panname = strdup(optarg); + break; + case 'o': /* send test output here */ + outputfilename = strdup(optarg); + break; + case 'p': /* formatted printing. */ + fmt_print = 1; + break; + case 'q': /* supress test start and test end messages */ + quiet_mode = 1; + break; + case 'r': /* reporting type: none, rts */ + reporttype = strdup(optarg); + break; + case 's': /* number of tags to run */ + starts = atoi(optarg); + break; + case 't': /* run_time to run */ + ret = sscanf(optarg, "%d%c", &run_time, &modifier); + if (ret == 0) { + fprintf(stderr, + "Need proper time input: ####x where " + "x is one of s,m,h,d\n"); + break; + } else if (ret == 1) { + fprintf(stderr, "Only got a time value of %d " + "modifiers need to come immediately after #" + " assuming %c\n", run_time, modifier); + } else { + switch (modifier) { + case 's': + run_time = run_time; + break; + case 'm': + run_time = run_time * 60; + break; + case 'h': + run_time = run_time * 60 * 60; + break; + case 'd': + run_time = run_time * 60 * 60 * 24; + break; + default: + fprintf(stderr, + "Invalid time modifier, try: s|h|m|d\n"); + exit(-1); + } + if (!quiet_mode) + printf("PAN will run for %d seconds\n", + run_time); + } + timed = 1; //-t implies run as many starts as possible, by default + break; + case 'x': /* number of tags to keep running */ + keep_active = atoi(optarg); + break; + case 'y': /* restart on failure or signal */ + fork_in_road = 1; + break; + } + } + + if (panname == NULL) { + fprintf(stderr, "pan: Must supply -n\n"); + exit(1); + } + if (zooname == NULL) { + zooname = zoo_getname(); + if (zooname == NULL) { + fprintf(stderr, + "pan(%s): Must supply -a or set ZOO env variable\n", + panname); + exit(1); + } + } + if (reporttype) { + /* make sure we understand the report type */ + if (strcasecmp(reporttype, "rts") + && strcasecmp(reporttype, "none") + /* && strcasecmp(reporttype, "xml") */ + ) + reporttype = "rts"; + } else { + /* set the default */ + reporttype = "rts"; + } + + if (logfilename != NULL) { + time_t startup; + char *s; + + if (!strcmp(logfilename, "-")) { + logfile = stdout; + } else { + if ((logfile = fopen(logfilename, "a+e")) == NULL) { + fprintf(stderr, + "pan(%s): Error %s (%d) opening log file '%s'\n", + panname, strerror(errno), errno, + logfilename); + exit(1); + } + } + + time(&startup); + s = ctime(&startup); + *(s + strlen(s) - 1) = '\0'; + if (!fmt_print) + fprintf(logfile, "startup='%s'\n", s); + else { + fprintf(logfile, "Test Start Time: %s\n", s); + fprintf(logfile, + "-----------------------------------------\n"); + fprintf(logfile, ResultFmt" %-10.10s\n", + "Testcase", "Result", "Exit Value"); + fprintf(logfile, ResultFmt" %-10.10s\n", + "--------", "------", "------------"); + } + fflush(logfile); + } + + coll = get_collection(filename, optind, argc, argv); + if (!coll) + exit(1); + if (coll->cnt == 0) { + fprintf(stderr, + "pan(%s): Must supply a file collection or a command\n", + panname); + exit(1); + } + + if (Debug & Dsetup) + dump_coll(coll); + + /* a place to store the pgrps we're watching */ + running = + malloc((keep_active + 1) * + sizeof(struct tag_pgrp)); + if (running == NULL) { + fprintf(stderr, "pan(%s): Failed to allocate memory: %s\n", + panname, strerror(errno)); + exit(2); + } + memset(running, 0, keep_active * sizeof(struct tag_pgrp)); + running[keep_active].pgrp = -1; /* end sentinel */ + + /* a head to the orphaned pgrp list */ + orphans = malloc(sizeof(struct orphan_pgrp)); + memset(orphans, 0, sizeof(struct orphan_pgrp)); + + srand48(time(NULL) ^ (getpid() + (getpid() << 15))); + + /* Supply a default for starts. If we are in sequential mode, use + * the number of commands available; otherwise 1. + */ + if (timed == 1 && starts == -1) { /* timed, infinite by default */ + starts = -1; + } else if (starts == -1) { + if (sequential) { + starts = coll->cnt; + } else { + starts = 1; + } + } else if (starts == 0) { /* if the user specified infinite, set it */ + starts = -1; + } else { /* else, make sure we are starting at least keep_active processes */ + if (starts < keep_active) + starts = keep_active; + } + + /* if we're buffering output, but we're only running on process at a time, + * then essentially "turn off buffering" + */ + if (test_out_dir && (keep_active == 1)) { + free(test_out_dir); + test_out_dir = NULL; + } + + if (test_out_dir) { + struct stat sbuf; + + if (stat(test_out_dir, &sbuf) < 0) { + fprintf(stderr, + "pan(%s): stat of -O arg '%s' failed. errno: %d %s\n", + panname, test_out_dir, errno, strerror(errno)); + exit(1); + } + if (!S_ISDIR(sbuf.st_mode)) { + fprintf(stderr, + "pan(%s): -O arg '%s' must be a directory.\n", + panname, test_out_dir); + exit(1); + } + if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) { + fprintf(stderr, + "pan(%s): permission denied on -O arg '%s'. errno: %d %s\n", + panname, test_out_dir, errno, strerror(errno)); + exit(1); + } + } + + if (outputfilename) { + if (!freopen(outputfilename, "a+", stdout)) { + fprintf(stderr, + "pan(%s): Error %s (%d) opening output file '%s'\n", + panname, strerror(errno), errno, + outputfilename); + exit(1); + } + } + + if (failcmdfilename) { + if (!(failcmdfile = fopen(failcmdfilename, "a+e"))) { + fprintf(stderr, + "pan(%s): Error %s (%d) opening fail cmd file '%s'\n", + panname, strerror(errno), errno, + failcmdfilename); + exit(1); + } + } + + if (tconfcmdfilename) { + tconfcmdfile = fopen(tconfcmdfilename, "a+e"); + if (!tconfcmdfile) { + fprintf(stderr, "pan(%s): Error %s (%d) opening " + "tconf cmd file '%s'\n", panname, + strerror(errno), errno, tconfcmdfilename); + exit(1); + } + } + + if ((zoofile = zoo_open(zooname)) == NULL) { + fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); + exit(1); + } + if (zoo_mark_args(zoofile, getpid(), panname, argc, argv)) { + fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); + exit(1); + } + + /* Allocate N spaces for max-arg commands. + * this is an "active file cleanliness" thing + */ + { + for (c = 0; c < keep_active; c++) { + if (zoo_mark_cmdline(zoofile, c, panname, "")) { + fprintf(stderr, "pan(%s): %s\n", panname, + zoo_error); + exit(1); + } + } + for (c = 0; c < keep_active; c++) { + if (zoo_clear(zoofile, c)) { + fprintf(stderr, "pan(%s): %s\n", panname, + zoo_error); + exit(1); + } + } + } + + rec_signal = send_signal = 0; + if (run_time != -1) { + alarm(run_time); + } + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = wait_handler; + + sigaction(SIGALRM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); /* ignore fork_in_road */ + sigaction(SIGUSR2, &sa, NULL); /* stop the scheduler */ + + c = 0; /* in this loop, c is the command index */ + stop = 0; + exit_stat = 0; + go_idle = 0; + while (1) { + + while ((num_active < keep_active) && (starts != 0)) { + if (stop || rec_signal || go_idle) + break; + + if (!sequential) + c = lrand48() % coll->cnt; + + /* find a slot for the child */ + for (i = 0; i < keep_active; ++i) { + if (running[i].pgrp == 0) + break; + } + if (i == keep_active) { + fprintf(stderr, + "pan(%s): Aborting: i == keep_active = %d\n", + panname, i); + wait_handler(SIGINT); + exit_stat++; + break; + } + + cpid = + run_child(coll->ary[c], running + i, quiet_mode, + &failcnt, fmt_print, logfile, no_kmsg); + if (cpid != -1) + ++num_active; + if ((cpid != -1 || sequential) && starts > 0) + --starts; + + if (sequential) + if (++c >= coll->cnt) + c = 0; + + } /* while ((num_active < keep_active) && (starts != 0)) */ + + if (starts == 0) { + if (!quiet_mode) + printf("incrementing stop\n"); + ++stop; + } else if (starts == -1) //wjh + { + FILE *f = (FILE *) - 1; + if ((f = fopen(PAN_STOP_FILE, "r")) != 0) { + printf("Got %s Stopping!\n", PAN_STOP_FILE); + fclose(f); + unlink(PAN_STOP_FILE); + stop++; + } + } + + if (rec_signal) { + /* propagate everything except sigusr2 */ + + if (rec_signal == SIGUSR2) { + if (fork_in_road) + ++go_idle; + else + ++stop; + rec_signal = send_signal = 0; + } else { + if (rec_signal == SIGUSR1) + fork_in_road = 0; + propagate_signal(running, keep_active, orphans); + if (fork_in_road) + ++go_idle; + else + ++stop; + } + } + + err = check_pids(running, &num_active, keep_active, logfile, + failcmdfile, tconfcmdfile, orphans, fmt_print, + &failcnt, &tconfcnt, quiet_mode, no_kmsg); + if (Debug & Drunning) { + pids_running(running, keep_active); + orphans_running(orphans); + } + if (err) { + if (fork_in_road) + ++go_idle; + if (track_exit_stats) + exit_stat++; + if (has_brakes) { + fprintf(stderr, "pan(%s): All stop!%s\n", + panname, go_idle ? " (idling)" : ""); + wait_handler(SIGINT); + } + } + + if (stop && (num_active == 0)) + break; + + if (go_idle && (num_active == 0)) { + go_idle = 0; /* It is idle, now resume scheduling. */ + wait_handler(0); /* Reset the signal ratchet. */ + } + } + + /* Wait for orphaned pgrps */ + while (1) { + for (orph = orphans; orph != NULL; orph = orph->next) { + if (orph->pgrp == 0) + continue; + /* Yes, we have orphaned pgrps */ + sleep(5); + if (!rec_signal) { + /* force an artificial signal, move us + * through the signal ratchet. + */ + wait_handler(SIGINT); + } + propagate_signal(running, keep_active, orphans); + if (Debug & Drunning) + orphans_running(orphans); + break; + } + if (orph == NULL) + break; + } + + if (zoo_clear(zoofile, getpid())) { + fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); + ++exit_stat; + } + fclose(zoofile); + if (logfile && fmt_print) { + if (uname(&unamebuf) == -1) + fprintf(stderr, "ERROR: uname(): %s\n", + strerror(errno)); + fprintf(logfile, + "\n-----------------------------------------------\n"); + fprintf(logfile, "Total Tests: %d\n", coll->cnt); + fprintf(logfile, "Total Skipped Tests: %d\n", tconfcnt); + fprintf(logfile, "Total Failures: %d\n", failcnt); + fprintf(logfile, "Kernel Version: %s\n", unamebuf.release); + fprintf(logfile, "Machine Architecture: %s\n", + unamebuf.machine); + fprintf(logfile, "Hostname: %s\n\n", unamebuf.nodename); + } + if (logfile && (logfile != stdout)) + fclose(logfile); + + if (failcmdfile) + fclose(failcmdfile); + + if (tconfcmdfile) + fclose(tconfcmdfile); + exit(exit_stat); +} + +static void +propagate_signal(struct tag_pgrp *running, int keep_active, + struct orphan_pgrp *orphans) +{ + int i; + + if (Debug & Dshutdown) + fprintf(stderr, "pan was signaled with sig %d...\n", + rec_signal); + + if (rec_signal == SIGALRM) { + printf("PAN stop Alarm was received\n"); + rec_signal = SIGTERM; + } + + for (i = 0; i < keep_active; ++i) { + if (running[i].pgrp == 0) + continue; + + if (Debug & Dshutdown) + fprintf(stderr, " propagating sig %d to %d\n", + send_signal, -running[i].pgrp); + if (kill(-running[i].pgrp, send_signal) != 0) { + fprintf(stderr, + "pan(%s): kill(%d,%d) failed on tag (%s). errno:%d %s\n", + panname, -running[i].pgrp, send_signal, + running[i].cmd->name, errno, strerror(errno)); + } + running[i].stopping = 1; + } + + check_orphans(orphans, send_signal); + + rec_signal = send_signal = 0; +} + +static int +check_pids(struct tag_pgrp *running, int *num_active, int keep_active, + FILE *logfile, FILE *failcmdfile, FILE *tconfcmdfile, + struct orphan_pgrp *orphans, int fmt_print, int *failcnt, + int *tconfcnt, int quiet_mode, int no_kmsg) +{ + int w; + pid_t cpid; + int stat_loc; + int ret = 0; + int i; + time_t t; + char *status; + char *result_str; + int signaled = 0; + struct tms tms1, tms2; + clock_t tck; + + check_orphans(orphans, 0); + + tck = times(&tms1); + if (tck == -1) { + fprintf(stderr, "pan(%s): times(&tms1) failed. errno:%d %s\n", + panname, errno, strerror(errno)); + } + cpid = wait(&stat_loc); + tck = times(&tms2); + if (tck == -1) { + fprintf(stderr, "pan(%s): times(&tms2) failed. errno:%d %s\n", + panname, errno, strerror(errno)); + } + + if (cpid < 0) { + if (errno == EINTR) { + if (Debug) + fprintf(stderr, "pan(%s): wait() interrupted\n", + panname); + } else if (errno != ECHILD) { + fprintf(stderr, + "pan(%s): wait() failed. errno:%d %s\n", + panname, errno, strerror(errno)); + } + } else if (cpid > 0) { + + if (WIFSIGNALED(stat_loc)) { + w = WTERMSIG(stat_loc); + status = "signaled"; + if (Debug & Dexit) + fprintf(stderr, + "child %d terminated with signal %d\n", + cpid, w); + --*num_active; + signaled = 1; + } else if (WIFEXITED(stat_loc)) { + w = WEXITSTATUS(stat_loc); + status = "exited"; + if (Debug & Dexit) + fprintf(stderr, + "child %d exited with status %d\n", + cpid, w); + --*num_active; + if (w != 0 && w != TCONF) + ret++; + } else if (WIFSTOPPED(stat_loc)) { /* should never happen */ + w = WSTOPSIG(stat_loc); + status = "stopped"; + ret++; + } else { /* should never happen */ + w = 0; + status = "unknown"; + ret++; + } + + for (i = 0; i < keep_active; ++i) { + if (running[i].pgrp == cpid) { + if ((w == 130) && running[i].stopping && + (strcmp(status, "exited") == 0)) { + /* The child received sigint, but + * did not trap for it? Compensate + * for it here. + */ + w = 0; + ret--; /* undo */ + if (Debug & Drunning) + fprintf(stderr, + "pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n", + panname, + running[i].cmd->name); + } + time(&t); + if (logfile != NULL) { + if (!fmt_print) + fprintf(logfile, + "tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n", + running[i].cmd->name, + (int)(running[i]. + mystime), + (int)(t - + running[i]. + mystime), status, + w, + (stat_loc & 0200) ? + "yes" : "no", + (int)(tms2.tms_cutime - + tms1.tms_cutime), + (int)(tms2.tms_cstime - + tms1.tms_cstime)); + else { + if (strcmp(status, "exited") == + 0 && w == TCONF) { + ++*tconfcnt; + result_str = "CONF"; + } else if (w != 0) { + ++*failcnt; + result_str = "FAIL"; + } else { + result_str = "PASS"; + } + + fprintf(logfile, + ResultFmt" %-5d\n", + running[i].cmd->name, + result_str, + w); + } + + fflush(logfile); + } + + if (w != 0) { + if (tconfcmdfile != NULL && + w == TCONF) { + fprintf(tconfcmdfile, "%s %s\n", + running[i].cmd->name, + running[i].cmd->cmdline); + } else if (failcmdfile != NULL) { + fprintf(failcmdfile, "%s %s\n", + running[i].cmd->name, + running[i].cmd->cmdline); + } + } + + if (running[i].stopping) + status = "driver_interrupt"; + + if (test_out_dir) { + if (!quiet_mode) + write_test_start(running + i, no_kmsg); + copy_buffered_output(running + i); + unlink(running[i].output); + } + if (!quiet_mode) + write_test_end(running + i, "ok", t, + status, stat_loc, w, + &tms1, &tms2); + + /* If signaled and we weren't expecting + * this to be stopped then the proc + * had a problem. + */ + if (signaled && !running[i].stopping) + ret++; + + running[i].pgrp = 0; + if (zoo_clear(zoofile, cpid)) { + fprintf(stderr, "pan(%s): %s\n", + panname, zoo_error); + exit(1); + } + + /* Check for orphaned pgrps */ + if ((kill(-cpid, 0) == 0) || (errno == EPERM)) { + if (zoo_mark_cmdline + (zoofile, cpid, "panorphan", + running[i].cmd->cmdline)) { + fprintf(stderr, "pan(%s): %s\n", + panname, zoo_error); + exit(1); + } + mark_orphan(orphans, cpid); + /* status of kill doesn't matter */ + kill(-cpid, SIGTERM); + } + + break; + } + } + } + return ret; +} + +static pid_t +run_child(struct coll_entry *colle, struct tag_pgrp *active, int quiet_mode, + int *failcnt, int fmt_print, FILE * logfile, int no_kmsg) +{ + ssize_t errlen; + int cpid; + int c_stdout = -1; /* child's stdout, stderr */ + int capturing = 0; /* output is going to a file instead of stdout */ + char *c_cmdline; + static long cmdno = 0; + int errpipe[2]; /* way to communicate to parent that the tag */ + char errbuf[1024]; /* didn't actually start */ + + /* Try to open the file that will be stdout for the test */ + if (test_out_dir) { + capturing = 1; + do { + sprintf(active->output, "%s/%s.%ld", + test_out_dir, colle->name, cmdno++); + c_stdout = + open(active->output, + O_CREAT | O_RDWR | O_EXCL | O_SYNC, 0666); + } while (c_stdout < 0 && errno == EEXIST); + if (c_stdout < 0) { + fprintf(stderr, + "pan(%s): open of stdout file failed (tag %s). errno: %d %s\n file: %s\n", + panname, colle->name, errno, strerror(errno), + active->output); + return -1; + } + } + + /* get the tag's command line arguments ready. subst_pcnt_f() uses a + * static counter, that's why we do it here instead of after we fork. + */ + if (colle->pcnt_f) { + c_cmdline = subst_pcnt_f(colle); + } else { + c_cmdline = colle->cmdline; + } + + if (pipe(errpipe) < 0) { + fprintf(stderr, "pan(%s): pipe() failed. errno:%d %s\n", + panname, errno, strerror(errno)); + if (capturing) { + close(c_stdout); + unlink(active->output); + } + return -1; + } + + time(&active->mystime); + active->cmd = colle; + + if (!test_out_dir && !quiet_mode) + write_test_start(active, no_kmsg); + + fflush(NULL); + + if ((cpid = fork()) == -1) { + fprintf(stderr, + "pan(%s): fork failed (tag %s). errno:%d %s\n", + panname, colle->name, errno, strerror(errno)); + if (capturing) { + unlink(active->output); + close(c_stdout); + } + close(errpipe[0]); + close(errpipe[1]); + return -1; + } else if (cpid == 0) { + /* child */ + + fclose(zoofile); + close(errpipe[0]); + fcntl(errpipe[1], F_SETFD, 1); /* close the pipe if we succeed */ + setpgrp(); + + umask(0); + +#define WRITE_OR_DIE(fd, buf, buflen) do { \ + if (write((fd), (buf), (buflen)) != (buflen)) { \ + err(1, "failed to write out %zd bytes at line %d", \ + buflen, __LINE__); \ + } \ +} while(0) + + /* if we're putting output into a buffer file, we need to do the + * redirection now. If we fail + */ + if (capturing) { + if (dup2(c_stdout, fileno(stdout)) == -1) { + errlen = + sprintf(errbuf, + "pan(%s): couldn't redirect stdout for tag %s. errno:%d %s", + panname, colle->name, errno, + strerror(errno)); + WRITE_OR_DIE(errpipe[1], &errlen, + sizeof(errlen)); + WRITE_OR_DIE(errpipe[1], errbuf, errlen); + exit(2); + } + if (dup2(c_stdout, fileno(stderr)) == -1) { + errlen = + sprintf(errbuf, + "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s", + panname, colle->name, errno, + strerror(errno)); + WRITE_OR_DIE(errpipe[1], &errlen, + sizeof(errlen)); + WRITE_OR_DIE(errpipe[1], errbuf, errlen); + exit(2); + } + } else { /* stderr still needs to be redirected */ + if (dup2(fileno(stdout), fileno(stderr)) == -1) { + errlen = + sprintf(errbuf, + "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s", + panname, colle->name, errno, + strerror(errno)); + WRITE_OR_DIE(errpipe[1], &errlen, + sizeof(errlen)); + WRITE_OR_DIE(errpipe[1], errbuf, errlen); + exit(2); + } + } + /* If there are any shell-type characters in the cmdline + * such as '>', '<', '$', '|', etc, then we exec a shell and + * run the cmd under a shell. + * + * Otherwise, break the cmdline at white space and exec the + * cmd directly. + */ + if (strpbrk(c_cmdline, "\"';|<>$\\")) { + execlp("sh", "sh", "-c", c_cmdline, NULL); + errlen = sprintf(errbuf, + "pan(%s): execlp of '%s' (tag %s) failed. errno:%d %s", + panname, c_cmdline, colle->name, errno, + strerror(errno)); + } else { + char **arg_v; + + arg_v = (char **)splitstr(c_cmdline, NULL, NULL); + + execvp(arg_v[0], arg_v); + errlen = sprintf(errbuf, + "pan(%s): execvp of '%s' (tag %s) failed. errno:%d %s", + panname, arg_v[0], colle->name, errno, + strerror(errno)); + } + WRITE_OR_DIE(errpipe[1], &errlen, sizeof(errlen)); + WRITE_OR_DIE(errpipe[1], errbuf, errlen); + exit(errno); + } + + /* parent */ + + /* subst_pcnt_f() allocates the command line dynamically + * free the malloc to prevent a memory leak + */ + if (colle->pcnt_f) + free(c_cmdline); + + close(errpipe[1]); + + /* if the child couldn't go through with the exec, + * clean up the mess, note it, and move on + */ + if (read(errpipe[0], &errlen, sizeof(errlen))) { + int status; + time_t end_time; + int termid; + char *termtype; + struct tms notime = { 0, 0, 0, 0 }; + + if (read(errpipe[0], errbuf, errlen) < 0) + fprintf(stderr, "Failed to read from errpipe[0]\n"); + close(errpipe[0]); + errbuf[errlen] = '\0'; + /* fprintf(stderr, "%s", errbuf); */ + waitpid(cpid, &status, 0); + if (WIFSIGNALED(status)) { + termid = WTERMSIG(status); + termtype = "signaled"; + } else if (WIFEXITED(status)) { + termid = WEXITSTATUS(status); + termtype = "exited"; + } else if (WIFSTOPPED(status)) { + termid = WSTOPSIG(status); + termtype = "stopped"; + } else { + termid = 0; + termtype = "unknown"; + } + time(&end_time); + if (logfile != NULL) { + if (!fmt_print) { + fprintf(logfile, + "tag=%s stime=%d dur=%d exit=%s " + "stat=%d core=%s cu=%d cs=%d\n", + colle->name, (int)(active->mystime), + (int)(end_time - active->mystime), + termtype, termid, + (status & 0200) ? "yes" : "no", 0, 0); + } else { + if (termid != 0) + ++ * failcnt; + + fprintf(logfile, ResultFmt" %-5d\n", + colle->name, + ((termid != 0) ? "FAIL" : "PASS"), + termid); + } + fflush(logfile); + } + + if (!quiet_mode) { + write_test_end(active, errbuf, end_time, termtype, + status, termid, ¬ime, ¬ime); + } + if (capturing) { + close(c_stdout); + unlink(active->output); + } + return -1; + } + + close(errpipe[0]); + if (capturing) + close(c_stdout); + + active->pgrp = cpid; + active->stopping = 0; + + if (zoo_mark_cmdline(zoofile, cpid, colle->name, colle->cmdline)) { + fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); + exit(1); + } + + if (Debug & Dstartup) + fprintf(stderr, "started %s cpid=%d at %s", + colle->name, cpid, ctime(&active->mystime)); + + if (Debug & Dstart) { + fprintf(stderr, "Executing test = %s as %s", colle->name, + colle->cmdline); + if (capturing) + fprintf(stderr, "with output file = %s\n", + active->output); + else + fprintf(stderr, "\n"); + } + + return cpid; +} + +static char *subst_pcnt_f(struct coll_entry *colle) +{ + static int counter = 1; + char pid_and_counter[20]; + char new_cmdline[1024]; + + /* if we get called falsely, do the right thing anyway */ + if (!colle->pcnt_f) + return colle->cmdline; + + snprintf(pid_and_counter, 20, "%d_%d", getpid(), counter++); + snprintf(new_cmdline, 1024, colle->cmdline, pid_and_counter); + return strdup(new_cmdline); +} + +static struct collection *get_collection(char *file, int optind, int argc, + char **argv) +{ + char *buf, *a, *b; + struct coll_entry *head, *p, *n; + struct collection *coll; + int i; + + buf = slurp(file); + if (!buf) + return NULL; + + coll = malloc(sizeof(struct collection)); + coll->cnt = 0; + + head = p = n = NULL; + a = b = buf; + while (a) { + /* set b to the start of the next line and add a NULL character + * to separate the two lines */ + if ((b = strchr(a, '\n')) != NULL) + *b++ = '\0'; + + /* If this is line isn't a comment */ + if ((*a != '#') && (*a != '\0') && (*a != ' ')) { + n = malloc(sizeof(struct coll_entry)); + if ((n->pcnt_f = strstr(a, "%f"))) { + n->pcnt_f[1] = 's'; + } + n->name = strdup(strsep(&a, " \t")); + while (a != NULL && isspace(*a)) + a++; + if (a == NULL || a[0] == 0) { + fprintf(stderr, + "pan(%s): Testcase '%s' requires a command to execute.\n", + panname, n->name); + return NULL; + } + n->cmdline = strdup(a); + n->next = NULL; + + if (p) { + p->next = n; + } + if (head == NULL) { + head = n; + } + p = n; + coll->cnt++; + } + a = b; + } + free(buf); + + /* is there something on the commandline to be counted? */ + if (optind < argc) { + char workstr[1024] = ""; + int workstr_left = 1023; + + /* fill arg list */ + for (i = 0; optind < argc; ++optind, ++i) { + strncat(workstr, argv[optind], workstr_left); + workstr_left = workstr_left - strlen(argv[optind]); + strncat(workstr, " ", workstr_left); + workstr_left--; + } + + n = malloc(sizeof(struct coll_entry)); + if ((n->pcnt_f = strstr(workstr, "%f"))) { + n->pcnt_f[1] = 's'; + } + n->cmdline = strdup(workstr); + n->name = "cmdln"; + n->next = NULL; + if (p) { + p->next = n; + } + if (head == NULL) { + head = n; + } + coll->cnt++; + } + + /* get an array */ + coll->ary = malloc(coll->cnt * sizeof(struct coll_entry *)); + + /* fill the array */ + i = 0; + n = head; + while (n != NULL) { + coll->ary[i] = n; + n = n->next; + ++i; + } + if (i != coll->cnt) + fprintf(stderr, "pan(%s): i doesn't match cnt\n", panname); + + return coll; +} + +static char *slurp(char *file) +{ + char *buf; + int fd; + struct stat sbuf; + + if ((fd = open(file, O_RDONLY)) < 0) { + fprintf(stderr, + "pan(%s): open(%s,O_RDONLY) failed. errno:%d %s\n", + panname, file, errno, strerror(errno)); + return NULL; + } + + if (fstat(fd, &sbuf) < 0) { + fprintf(stderr, "pan(%s): fstat(%s) failed. errno:%d %s\n", + panname, file, errno, strerror(errno)); + return NULL; + } + + buf = malloc(sbuf.st_size + 1); + if (read(fd, buf, sbuf.st_size) != sbuf.st_size) { + fprintf(stderr, "pan(%s): slurp failed. errno:%d %s\n", + panname, errno, strerror(errno)); + free(buf); + return NULL; + } + buf[sbuf.st_size] = '\0'; + + close(fd); + return buf; +} + +static void check_orphans(struct orphan_pgrp *orphans, int sig) +{ + struct orphan_pgrp *orph; + + for (orph = orphans; orph != NULL; orph = orph->next) { + if (orph->pgrp == 0) + continue; + + if (Debug & Dshutdown) + fprintf(stderr, + " propagating sig %d to orphaned pgrp %d\n", + sig, -(orph->pgrp)); + if (kill(-(orph->pgrp), sig) != 0) { + if (errno == ESRCH) { + /* This pgrp is now empty */ + if (zoo_clear(zoofile, orph->pgrp)) { + fprintf(stderr, "pan(%s): %s\n", + panname, zoo_error); + } + orph->pgrp = 0; + } else { + fprintf(stderr, + "pan(%s): kill(%d,%d) on orphaned pgrp failed. errno:%d %s\n", + panname, -(orph->pgrp), sig, errno, + strerror(errno)); + } + } + } +} + +static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid) +{ + struct orphan_pgrp *orph; + + for (orph = orphans; orph != NULL; orph = orph->next) { + if (orph->pgrp == 0) + break; + } + if (orph == NULL) { + /* make a new struct */ + orph = malloc(sizeof(struct orphan_pgrp)); + + /* plug in the new struct just after the head */ + orph->next = orphans->next; + orphans->next = orph; + } + orph->pgrp = cpid; +} + +static void copy_buffered_output(struct tag_pgrp *running) +{ + char *tag_output; + + tag_output = slurp(running->output); + if (tag_output) { + printf("%s", tag_output); + /* make sure the output ends with a newline */ + if (tag_output[strlen(tag_output) - 1] != '\n') + printf("\n"); + fflush(stdout); + free(tag_output); + } +} + +static void write_kmsg(const char *fmt, ...) +{ + FILE *kmsg; + va_list ap; + + if ((kmsg = fopen("/dev/kmsg", "r+")) == NULL) { + fprintf(stderr, "Error %s: (%d) opening /dev/kmsg\n", + strerror(errno), errno); + exit(1); + } + + va_start(ap, fmt); + vfprintf(kmsg, fmt, ap); + va_end(ap); + fclose(kmsg); +} + +static void write_test_start(struct tag_pgrp *running, int no_kmsg) +{ + if (!strcmp(reporttype, "rts")) { + + printf + ("%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); + if (no_kmsg) + return; + + if (strcmp(running->cmd->name, running->cmd->cmdline)) + write_kmsg("LTP: starting %s (%s)\n", running->cmd->name, + running->cmd->cmdline); + else + write_kmsg("LTP: starting %s\n", running->cmd->name); +} + +static void +write_test_end(struct tag_pgrp *running, const char *init_status, + time_t exit_time, char *term_type, int stat_loc, + int term_id, struct tms *tms1, struct tms *tms2) +{ + if (!strcmp(reporttype, "rts")) { + printf + ("%s\ninitiation_status=\"%s\"\nduration=%ld termination_type=%s " + "termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n", + "<<>>", init_status, + (long)(exit_time - running->mystime), term_type, term_id, + (stat_loc & 0200) ? "yes" : "no", + (int)(tms2->tms_cutime - tms1->tms_cutime), + (int)(tms2->tms_cstime - tms1->tms_cstime), + "<<>>"); + } + fflush(stdout); +} + +/* The functions below are all debugging related */ + +static void pids_running(struct tag_pgrp *running, int keep_active) +{ + int i; + + fprintf(stderr, "pids still running: "); + for (i = 0; i < keep_active; ++i) { + if (running[i].pgrp != 0) + fprintf(stderr, "%d ", running[i].pgrp); + } + fprintf(stderr, "\n"); +} + +static void orphans_running(struct orphan_pgrp *orphans) +{ + struct orphan_pgrp *orph; + + fprintf(stderr, "orphans still running: "); + for (orph = orphans; orph != NULL; orph = orph->next) { + if (orph->pgrp != 0) + fprintf(stderr, "%d ", -(orph->pgrp)); + } + fprintf(stderr, "\n"); +} + +static void dump_coll(struct collection *coll) +{ + int i; + + for (i = 0; i < coll->cnt; ++i) { + fprintf(stderr, "coll %d\n", i); + fprintf(stderr, " name=%s cmdline=%s\n", coll->ary[i]->name, + coll->ary[i]->cmdline); + } +} + +void wait_handler(int sig) +{ + static int lastsent = 0; + + if (sig == 0) { + lastsent = 0; + } else { + rec_signal = sig; + if (sig == SIGUSR2) + return; + if (lastsent == 0) + send_signal = sig; + else if (lastsent == SIGUSR1) + send_signal = SIGINT; + else if (lastsent == sig) + send_signal = SIGTERM; + else if (lastsent == SIGTERM) + send_signal = SIGHUP; + else if (lastsent == SIGHUP) + send_signal = SIGKILL; + lastsent = send_signal; + } +} diff --git a/ltp/pan/splitstr.c b/ltp/pan/splitstr.c new file mode 100644 index 0000000000000000000000000000000000000000..39b469856d1fce7eceffce8a959a63509a401c3c --- /dev/null +++ b/ltp/pan/splitstr.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * + */ +/* $Id: splitstr.c,v 1.2 2000/09/21 20:42:31 nstraz Exp $ */ +/* + * Synopsis + * + * const char **splitstr(const char *str, const char *separator, int *argcount) + * + * Description + * This function splits a string (str) into components that are separated by + * one or more of the characters in the (separator) string. An array of + * strings is returned, along with argcount being set to the number of strings + * found. Argcount can be NULL. There will always be a NULL element in the + * array after the last valid element. If an error occurs, NULL will be + * returned and argcount will be set to zero. + * + * To rid yourself of the memory allocated for splitstr(), pass the return + * value from splitstr() unmodified to splitstr_free(): + * + * void splitstr_free( const char ** return_from_splitstr ); + * + */ +#include +#include +#include /* for string functions */ +#ifdef UNIT_TEST +#include +#endif /* UNIT_TEST */ +#include "splitstr.h" + +const char **splitstr(const char *str, const char *separator, int *argcount) +{ + char *arg_string = NULL, **arg_array = NULL, *cur_tok = NULL; + + int num_toks = 0, max_toks = 20, i; + + /* + * In most recoverable errors, if argcount is not NULL, + * set argcount to 0. Then return NULL. + */ + if (str == NULL) { + if (argcount != NULL) + *argcount = 0; + return (NULL); + } + + /* + * set aside temporary space to work on the string. + */ + arg_string = strdup(str); + + if (arg_string == NULL) { + if (argcount != NULL) + *argcount = 0; + return (NULL); + } + + /* + * set aside an initial char ** array for string array. + */ + arg_array = malloc(sizeof(char *) * max_toks); + + if (arg_array == NULL) { + if (argcount != NULL) + *argcount = 0; + free(arg_string); + return (NULL); + } + + if (separator == NULL) + separator = " \t"; + + /* + * Use strtok() to parse 'arg_string', placing pointers to the + * individual tokens into the elements of 'arg_array'. Expand + * 'arg_array' if necessary. + */ + cur_tok = strtok(arg_string, separator); + while (cur_tok != NULL) { + arg_array[num_toks++] = cur_tok; + cur_tok = strtok(NULL, separator); + if (num_toks == max_toks) { + max_toks += 20; + arg_array = + (char **)realloc((void *)arg_array, + sizeof(char *) * max_toks); + if (arg_array == NULL) { + fprintf(stderr, "realloc: New memory allocation failed \n"); + free(arg_string); + exit(1); + } + } + } + arg_array[num_toks] = NULL; + + /* + * If there are any spaces left in our array, make them NULL + */ + for (i = num_toks + 1; i < max_toks; i++) + arg_array[i] = NULL; + + /* This seems nice, but since memory is allocated on a page basis, this + * isn't really helpful: + * arg_array = (char **)realloc((void *)arg_array, sizeof(char *)*num_toks+1 );*/ + + if (argcount != NULL) + *argcount = num_toks; + + /* + * Return the argument array. + */ + return ((const char **)arg_array); +} + +/* + * splitster_free( const char ** ) + * + * This takes the return value from splitster() and free()s memory + * allocated by splitster. Assuming: ret=splitster(...), this + * requires that ret and *ret returned from splitster() have not + * been modified. + */ +void splitstr_free(const char **p_return) +{ + if (*p_return != NULL) + free((char *)*p_return); + if (p_return != NULL) + free((char **)p_return); +} + +#ifdef UNIT_TEST + +int main() +{ + int i, y, test_size = 1000, size_ret; + char test_str[32768]; + char buf[16]; + char *test_str_array[test_size]; + const char **ret; + + for (i = 0; i < test_size; i++) { + snprintf(buf, 16, "arg%d", i); + test_str_array[i] = strdup(buf); + } + + for (i = 0; i < test_size; i++) { + test_str[0] = '\0'; + for (y = 0; y < i; y++) { + snprintf(buf, 16, "arg%d ", y); + strncat(test_str, buf, 16); + } + ret = splitstr(test_str, NULL, &size_ret); + assert(size_ret == i); + for (y = 0; y < i; y++) + assert(strcmp(ret[y], test_str_array[y]) == 0); + + splitstr_free(ret); + } + return 0; +} + +#endif diff --git a/ltp/pan/splitstr.h b/ltp/pan/splitstr.h new file mode 100644 index 0000000000000000000000000000000000000000..2ffa24f432698ae3735e15ef5a54e2a44e912441 --- /dev/null +++ b/ltp/pan/splitstr.h @@ -0,0 +1,36 @@ +#ifndef _SPLITSTR_H_ +#define _SPLITSTR_H_ +/* + * Synopsis + * + * const char **splitstr(const char *str, const char *separator, int *argcount) + * + * Description + * This function splits a string (str) into components that are separated by + * one or more of the characters in the (separator) string. An array of + * strings is returned, along with argcount being set to the number of strings + * found. Argcount can be NULL. There will always be a NULL element in the + * array after the last valid element. If an error occurs, NULL will be + * returned and argcount will be set to zero. + * + * To rid yourself of the memory allocated for splitstr(), pass the return + * value from splitstr() unmodified to splitstr_free(): + * + * void splitstr_free( const char ** return_from_splitstr ); + * + */ +const char ** +splitstr(const char *, const char *, int *); + +/* + * splitster_free( const char ** ) + * + * This takes the return value from splitster() and free()s memory + * allocated by splitster. Assuming: ret=splitster(...), this + * requires that ret and *ret returned from splitster() have not + * been modified. + */ +void +splitstr_free( const char ** ); + +#endif diff --git a/ltp/pan/tag_report.h b/ltp/pan/tag_report.h new file mode 100644 index 0000000000000000000000000000000000000000..df838e8c9d8bfdf872dd06156543e2db6be7830d --- /dev/null +++ b/ltp/pan/tag_report.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * + */ +/* $Id: tag_report.h,v 1.1 2000/09/21 21:35:06 alaffin Exp $ */ +#ifndef _TAG_REPORT_H_ +#define _TAG_REPORT_H_ + +#include +#include +#include +#include /* strftime */ +#include /* getopt */ +#include "symbol.h" +#include "splitstr.h" + +int test_result( char *, char *, char *, char *, SYM ); +int cuts_report( SYM, SYM, char *, char * ); +int tag_report( SYM, SYM, SYM ); +int print_header( SYM ); +int cuts_testcase( SYM, SYM ); + +#endif diff --git a/ltp/pan/zoolib.c b/ltp/pan/zoolib.c new file mode 100644 index 0000000000000000000000000000000000000000..0ac78526619720a80482d573a198f883c0eef045 --- /dev/null +++ b/ltp/pan/zoolib.c @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * + */ +/* $Id: zoolib.c,v 1.8 2009/06/09 17:59:46 subrata_modak Exp $ */ +/* + * ZooLib + * + * A Zoo is a file used to record what test tags are running at the moment. + * If the system crashes, we should be able to look at the zoo file to find out + * what was currently running. This is especially helpful when running multiple + * tests at the same time. + * + * The zoo file is meant to be a text file that fits on a standard console. + * You should be able to watch it with `cat zoofile` + * + * zoo file format: + * 80 characters per line, ending with a \n + * available lines start with '#' + * expected line fromat: pid_t,tag,cmdline + * + */ + +#include +#include /* for getenv */ +#include +#include "zoolib.h" + +char zoo_error[ZELEN]; + +#ifdef __linux__ +/* glibc2.2 definition needs -D_XOPEN_SOURCE, which breaks other things. */ +extern int sighold(int __sig); +extern int sigrelse(int __sig); +#endif + +/* zoo_mark(): private function to make an entry to the zoo + * returns 0 on success, -1 on error */ +static int zoo_mark(zoo_t z, char *entry); +static int zoo_lock(zoo_t z); +static int zoo_unlock(zoo_t z); +/* cat_args(): helper function to make cmdline from argc, argv */ +char *cat_args(int argc, char **argv); + +/* zoo_getname(): create a filename to use for the zoo */ +char *zoo_getname(void) +{ + char buf[1024]; + char *zoo; + + zoo = getenv("ZOO"); + if (zoo) { + snprintf(buf, 1024, "%s/%s", zoo, "active"); + return strdup(buf); + } else { + /* if there is no environment variable, we don't know where to put it */ + return NULL; + } +} + +/* zoo_open(): open a zoo for use */ +zoo_t zoo_open(char *zooname) +{ + zoo_t new_zoo; + + new_zoo = (zoo_t) fopen(zooname, "r+"); + if (!new_zoo) { + if (errno == ENOENT) { + /* file doesn't exist, try fopen(xxx, "a+") */ + new_zoo = (zoo_t) fopen(zooname, "a+"); + if (!new_zoo) { + /* total failure */ + snprintf(zoo_error, ZELEN, + "Could not open zoo as \"%s\", errno:%d %s", + zooname, errno, strerror(errno)); + return 0; + } + fclose(new_zoo); + new_zoo = fopen(zooname, "r+"); + } else { + snprintf(zoo_error, ZELEN, + "Could not open zoo as \"%s\", errno:%d %s", + zooname, errno, strerror(errno)); + } + } + return new_zoo; +} + +int zoo_close(zoo_t z) +{ + int ret; + + ret = fclose(z); + if (ret) { + snprintf(zoo_error, ZELEN, + "closing zoo caused error, errno:%d %s", + errno, strerror(errno)); + } + return ret; +} + +static int zoo_mark(zoo_t z, char *entry) +{ + FILE *fp = (FILE *) z; + int found = 0; + long pos; + char buf[BUFLEN]; + + if (fp == NULL) + return -1; + + if (zoo_lock(z)) + return -1; + + /* first fit */ + rewind(fp); + + do { + pos = ftell(fp); + + if (fgets(buf, BUFLEN, fp) == NULL) + break; + + if (buf[0] == '#') { + rewind(fp); + if (fseek(fp, pos, SEEK_SET)) { + /* error */ + snprintf(zoo_error, ZELEN, + "seek error while writing to zoo file, errno:%d %s", + errno, strerror(errno)); + return -1; + } + /* write the entry, left justified, and padded/truncated to the + * same size as the previous entry */ + fprintf(fp, "%-*.*s\n", (int)strlen(buf) - 1, + (int)strlen(buf) - 1, entry); + found = 1; + break; + } + } while (1); + + if (!found) { + if (fseek(fp, 0, SEEK_END)) { + snprintf(zoo_error, ZELEN, + "error seeking to end of zoo file, errno:%d %s", + errno, strerror(errno)); + return -1; + } + fprintf(fp, "%-*.*s\n", 79, 79, entry); + } + fflush(fp); + + if (zoo_unlock(z)) + return -1; + return 0; +} + +int zoo_mark_cmdline(zoo_t z, pid_t p, char *tag, char *cmdline) +{ + char new_entry[BUFLEN]; + + snprintf(new_entry, 80, "%d,%s,%s", p, tag, cmdline); + return zoo_mark(z, new_entry); +} + +int zoo_mark_args(zoo_t z, pid_t p, char *tag, int ac, char **av) +{ + char *cmdline; + int ret; + + cmdline = cat_args(ac, av); + ret = zoo_mark_cmdline(z, p, tag, cmdline); + + free(cmdline); + return ret; +} + +int zoo_clear(zoo_t z, pid_t p) +{ + FILE *fp = (FILE *) z; + long pos; + char buf[BUFLEN]; + pid_t that_pid; + int found = 0; + + if (fp == NULL) + return -1; + + if (zoo_lock(z)) + return -1; + rewind(fp); + + do { + pos = ftell(fp); + + if (fgets(buf, BUFLEN, fp) == NULL) + break; + + if (buf[0] == '#') + continue; + + that_pid = atoi(buf); + if (that_pid == p) { + if (fseek(fp, pos, SEEK_SET)) { + /* error */ + snprintf(zoo_error, ZELEN, + "seek error while writing to zoo file, errno:%d %s", + errno, strerror(errno)); + return -1; + } + if (ftell(fp) != pos) { + printf("fseek failed\n"); + } + fputs("#", fp); + found = 1; + break; + } + } while (1); + + fflush(fp); + + /* FIXME: unlock zoo file */ + if (zoo_unlock(z)) + return -1; + + if (!found) { + snprintf(zoo_error, ZELEN, + "zoo_clear() did not find pid(%d)", p); + return 1; + } + return 0; + +} + +pid_t zoo_getpid(zoo_t z, char *tag) +{ + FILE *fp = (FILE *) z; + char buf[BUFLEN], *s; + pid_t this_pid = -1; + + if (fp == NULL) + return -1; + + if (zoo_lock(z)) + return -1; + + rewind(fp); + do { + if (fgets(buf, BUFLEN, fp) == NULL) + break; + + if (buf[0] == '#') + continue; /* recycled line */ + + if ((s = strchr(buf, ',')) == NULL) + continue; /* line was not expected format */ + + if (strncmp(s + 1, tag, strlen(tag))) + continue; /* tag does not match */ + + this_pid = atoi(buf); + break; + } while (1); + + if (zoo_unlock(z)) + return -1; + return this_pid; +} + +int zoo_lock(zoo_t z) +{ + FILE *fp = (FILE *) z; + struct flock zlock; + sigset_t block_these; + int ret; + + if (fp == NULL) + return -1; + + zlock.l_whence = zlock.l_start = zlock.l_len = 0; + zlock.l_type = F_WRLCK; + + sigemptyset(&block_these); + sigaddset(&block_these, SIGINT); + sigaddset(&block_these, SIGTERM); + sigaddset(&block_these, SIGHUP); + sigaddset(&block_these, SIGUSR1); + sigaddset(&block_these, SIGUSR2); + sigprocmask(SIG_BLOCK, &block_these, NULL); + + do { + ret = fcntl(fileno(fp), F_SETLKW, &zlock); + } while (ret == -1 && errno == EINTR); + + sigprocmask(SIG_UNBLOCK, &block_these, NULL); + if (ret == -1) { + snprintf(zoo_error, ZELEN, + "failed to unlock zoo file, errno:%d %s", + errno, strerror(errno)); + return -1; + } + return 0; + +} + +int zoo_unlock(zoo_t z) +{ + FILE *fp = (FILE *) z; + struct flock zlock; + sigset_t block_these; + int ret; + + if (fp == NULL) + return -1; + + zlock.l_whence = zlock.l_start = zlock.l_len = 0; + zlock.l_type = F_UNLCK; + + sigemptyset(&block_these); + sigaddset(&block_these, SIGINT); + sigaddset(&block_these, SIGTERM); + sigaddset(&block_these, SIGHUP); + sigaddset(&block_these, SIGUSR1); + sigaddset(&block_these, SIGUSR2); + sigprocmask(SIG_BLOCK, &block_these, NULL); + + do { + ret = fcntl(fileno(fp), F_SETLKW, &zlock); + } while (ret == -1 && errno == EINTR); + + sigprocmask(SIG_UNBLOCK, &block_these, NULL); + + if (ret == -1) { + snprintf(zoo_error, ZELEN, + "failed to lock zoo file, errno:%d %s", + errno, strerror(errno)); + return -1; + } + return 0; +} + +char *cat_args(int argc, char **argv) +{ + int a, size; + char *cmd; + + for (size = a = 0; a < argc; a++) { + size += strlen(argv[a]); + size++; + } + + if ((cmd = malloc(size)) == NULL) { + snprintf(zoo_error, ZELEN, + "Malloc Error, %s/%d", __FILE__, __LINE__); + return NULL; + } + + *cmd = '\0'; + for (a = 0; a < argc; a++) { + if (a != 0) + strcat(cmd, " "); + strcat(cmd, argv[a]); + } + + return cmd; +} + +#if defined(UNIT_TEST) + +void zt_add(zoo_t z, int n) +{ + char cmdline[200]; + char tag[10]; + + snprintf(tag, 10, "%s%d", "test", n); + snprintf(cmdline, 200, "%s%d %s %s %s", "runtest", n, "one", "two", + "three"); + + zoo_mark_cmdline(z, n, tag, cmdline); +} + +int main(int argc, char *argv[]) +{ + + char *zooname; + zoo_t test_zoo; + char *test_tag = "unittest"; + int i, j; + + zooname = zoo_getname(); + + if (!zooname) { + zooname = strdup("test_zoo"); + } + printf("Test zoo filename is %s\n", zooname); + + if ((test_zoo = zoo_open(zooname)) == NULL) { + printf("Error opennning zoo\n"); + exit(-1); + } + + zoo_mark_args(test_zoo, getpid(), test_tag, argc, argv); + + for (j = 0; j < 5; j++) { + for (i = 0; i < 20; i++) { + zt_add(test_zoo, i); + } + + for (; i >= 0; i--) { + zoo_clear(test_zoo, i); + } + } + + zoo_clear(test_zoo, getpid()); + + return 0; +} + +#endif diff --git a/ltp/pan/zoolib.h b/ltp/pan/zoolib.h new file mode 100644 index 0000000000000000000000000000000000000000..6fb01fa41172bca4d499057d32f7caf8c2d9fe8e --- /dev/null +++ b/ltp/pan/zoolib.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * + */ +/* $Id: zoolib.h,v 1.5 2006/06/27 09:37:34 vapier Exp $ */ +#ifndef ZOOLIB_H +#define ZOOLIB_H + +#include +#include +#include +#include +#include +#include + +typedef FILE *zoo_t; +#define ZELEN 512 +extern char zoo_error[ZELEN]; +#define BUFLEN 81 + +int lock_file( FILE *fp, short ltype, char **errmsg ); +/* FILE *open_file( char *file, char *mode, char **errmsg ); */ + +void wait_handler(); + +/* char *zoo_active( void ); */ +/* zoo_getname(): create a filename to use for the zoo + * returns NULL on error */ +char *zoo_getname(void); + +/* zoo_open(): open a zoo file for use + * returns NULL on error */ +zoo_t zoo_open(char *zooname); + +/* zoo_close(): close an open zoo file */ +int zoo_close(zoo_t z); + +/* zoo_mark_cmdline(): make an entry to the zoo + * returns 0 on success, -1 on error */ +int zoo_mark_cmdline(zoo_t z, pid_t p, char *tag, char *cmdline); + +/* zoo_mark_args(): make an entry to the zoo using argc argv + * returns 0 on success, -1 on error */ +int zoo_mark_args(zoo_t z, pid_t p, char *tag, int ac, char **av); + +/* zoo_clear(): mark a pid as completed + * returns 0 on success, -1 on error, 1 as warning */ +int zoo_clear(zoo_t z, pid_t p); + +/* zoo_getpid(): get the pid for a specified tag + * returns pid_t on success and 0 on error */ +pid_t zoo_getpid(zoo_t z, char *tag); + + +#endif /* ZOOLIB_H */ diff --git a/ltp/runltp b/ltp/runltp new file mode 100755 index 0000000000000000000000000000000000000000..0d90625691412abb738ffbe583ec187f0d3ea719 --- /dev/null +++ b/ltp/runltp @@ -0,0 +1,959 @@ +#!/bin/sh +################################################################################ +## ## +## Copyright (c) International Business Machines Corp., 2001 ## +## ## +## 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 ## +## ## +################################################################################ +# File: runltp +# +# Description: This script can be used to the tests in the LTP test suite +# +# Authors: Manoj Iyer - manjo@mail.utexas.edu +# Robbe Williamson - robbiew@us.ibm.com +# +# History: Oct 07 2003 - Modified - Manoj Iyer +# - use functions +# - clean up on script exit +# - error checking etc. +# +# Oct 08 2003 - Modified - Manoj Iyer +# - fixed bug in creating results directory +# - all checks should be enlclosed in " " to avoid bash error +# - exit with error if ltp-pan is not found in pan directory +# +# Jul 22 2007 - Modified - Ricardo Salveti de Araujo +# - added support to put more then one file at CMDLINE (-f) +# - added a new option, that the user can pass the address of +# the command file, and it'll use wget to get it (-w) +# - now -s does the grep at the selected command files (default, +# -f or -w) +# +# Jul 23 2007 - Modified - Ricardo Salveti de Araujo +# - added flag to get the command file that has all failed tests +# +# Sep 11 2007 - Modified - Subrata Modak +# - added option to create Failed File if it is not an absolute path +# - added option to create Output File if it is not an absolute path +# - added option to create Failed File compulsory, even if user has not mentioned it +# +# Sep 14 2007 - Modified - Ricardo Salveti de Araujo +# - cleaning and removing duplicated code +# +# Oct 27 2007 - Modified - Ricardo Salveti de Araujo and Subrata Modak +# - better ways to integrate "ltp/tools/genload/stress" with "ltp/runltp" +# Nov 24 2007 - Modified - Subrata Modak +# - Added a new option to generate output in HTML format also. Also retaining +# the original test format +# Nov 28 2007 - Modified - Subrata Modak +# - Added a new option to mail back LTP reports +# May 19 2008 - Modified - Subrata Modak +# - Added capability for default Log file generation +# Aug 17 2009 - Modified - Subrata Modak +# - Added Fault Injection generation Capability through -F Option +# +################################################################################# + + +deprecated() +{ + echo "-------------------------------------------" >&2 + echo "INFO: runltp script is deprecated, try kirk" >&2 + echo "https://github.com/linux-test-project/kirk" >&2 + echo "-------------------------------------------" >&2 +} + + +setup() +{ + deprecated + + cd `dirname $0` || \ + { + echo "FATAL: unable to change directory to $(dirname $0)" + exit 1 + } + export LTPROOT=${PWD} + export TMPBASE="/tmp" + export PATH="${PATH}:${LTPROOT}/testcases/bin:${LTPROOT}/bin" + + export LTP_DEV_FS_TYPE="ext2" + + [ -d "$LTPROOT/testcases/bin" ] || + { + echo "FATAL: LTP not installed correctly" + echo "INFO: Follow directions in INSTALL!" + exit 1 + } + + [ -e "$LTPROOT/bin/ltp-pan" ] || + { + echo "FATAL: Test suite driver 'ltp-pan' not found" + echo "INFO: Follow directions in INSTALL!" + exit 1 + } +} + +version_of_ltp() +{ + cat "$LTPROOT/Version" + exit 0 +} + +usage() +{ + cat <<-EOF >&2 + + usage: ${0##*/} [ -a EMAIL_TO ] [ -c NUM_PROCS ] [ -C FAILCMDFILE ] [ -T TCONFCMDFILE ] + [ -d TMPDIR ] [ -D NUM_PROCS,NUM_FILES,NUM_BYTES,CLEAN_FLAG ] -e [ -f CMDFILES(,...) ] + [ -g HTMLFILE] [ -i NUM_PROCS ] [ -l LOGFILE ] [ -m NUM_PROCS,CHUNKS,BYTES,HANGUP_FLAG ] + -N -n [ -o OUTPUTFILE ] -p -q -Q [ -r LTPROOT ] [ -s PATTERN ] [ -t DURATION ] + -v [ -w CMDFILEADDR ] [ -x INSTANCES ] [ -b DEVICE ] [-B LTP_DEV_FS_TYPE] + [ -F LOOPS,PERCENTAGE ] [ -z BIG_DEVICE ] [-Z LTP_BIG_DEV_FS_TYPE] + + -a EMAIL_TO EMAIL all your Reports to this E-mail Address + -c NUM_PROCS Run LTP under additional background CPU load + [NUM_PROCS = no. of processes creating the CPU Load by spinning over sqrt() + (Defaults to 1 when value)] + -C FAILCMDFILE Command file with all failed test cases. + -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 (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)] + [CLEAN_FLAG = unlink file to which random data written, when value 1] + -e Prints the date of the current LTP release + -f CMDFILES Execute user defined list of testcases (separate with ',') + -F LOOPS,PERCENTAGE Induce PERCENTAGE Fault in the Kernel Subsystems, and, run each test for LOOPS loop + -g HTMLFILE Create an additional HTML output format + -h Help. Prints all available options. + -i NUM_PROCS Run LTP under additional background Load on IO Bus + [NUM_PROCS = no. of processes creating IO Bus Load by spinning over sync()] + -K DMESG_LOG_DIR + 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 (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) ] + [HANGUP_FLAG = hang in a sleep loop after memory allocated, when value 1] + -M CHECK_TYPE + [CHECK_TYPE=1 => Full Memory Leak Check tracing children as well] + [CHECK_TYPE=2 => Thread Concurrency Check tracing children as well] + [CHECK_TYPE=3 => Full Memory Leak & Thread Concurrency Check tracing children as well] + -N Run all the networking tests. + -o OUTPUTFILE Redirect test output to a file. + -p Human readable format logfiles. + -q Print less verbose output to screen. This implies + not logging start of the test in kernel log. + -Q Don't log start of test in kernel log. + -r LTPROOT Fully qualified path where testsuite is installed. + -R Randomize test order. + -s PATTERN Only run test cases which match PATTERN. + -S SKIPFILE Skip tests specified in SKIPFILE + -t DURATION Execute the testsuite for given duration. Examples: + -t 60s = 60 seconds + -t 45m = 45 minutes + -t 24h = 24 hours + -t 2d = 2 days + -I ITERATIONS Execute the testsuite ITERATIONS times. + -w CMDFILEADDR Uses wget to get the user's list of testcases. + -x INSTANCES Run multiple instances of this testsuite. + -b DEVICE Some tests require an unmounted block device + to run correctly. + -B LTP_DEV_FS_TYPE The file system of test block devices. + -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) + + + + example: ${0##*/} -c 2 -i 2 -m 2,4,10240,1 -D 2,10,10240,1 -p -q -l /tmp/result-log.$$ -o /tmp/result-output.$$ -C /tmp/result-failed.$$ -d ${PWD} + + + EOF +exit 0 +} + +main() +{ + local CMDFILES= + local PRETTY_PRT= + local ALT_DIR_OUT=0 + local ALT_DIR_RES=0 + local ALT_HTML_OUT=0 + local ALT_EMAIL_OUT=0 + local ALT_DMESG_OUT=0 + local RUN_NETEST=0 + local RUN_REPEATED=0 + local QUIET_MODE= + local NO_KMSG= + local NETPIPE=0 + local GENLOAD=0 + local MEMSIZE=0 + local DURATION= + local CMDFILEADDR= + local FAILCMDFILE= + local TCONFCMDFILE= + local INJECT_KERNEL_FAULT= + local INJECT_KERNEL_FAULT_PERCENTAGE= + local INJECT_FAULT_LOOPS_PER_TEST= + local VALGRIND_CHECK= + local VALGRIND_CHECK_TYPE= + local LOGFILE_NAME= + local LOGFILE= + local OUTPUTFILE_NAME= + local OUTPUTFILE= + local HTMLFILE_NAME= + local HTMLFILE= + local DMESG_DIR= + local EMAIL_TO= + local TAG_RESTRICT_STRING= + local PAN_COMMAND= + 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:W: arg + do case $arg in + a) EMAIL_TO=$OPTARG + ALT_EMAIL_OUT=1;; + c) + NUM_PROCS=$(($OPTARG)) + if [ "$NUM_PROCS" -eq 0 ]; then + # User Did not Define the Value ,or, User Defined Zero, + # hence, prevent from creating infinite processes + NUM_PROCS=1 + fi + $LTPROOT/testcases/bin/genload --cpu $NUM_PROCS >/dev/null 2>&1 & + GENLOAD=1 ;; + + C) + case $OPTARG in + /*) + FAILCMDFILE="-C $OPTARG" ;; + *) + FAILCMDFILE="-C $LTPROOT/output/$OPTARG" + ALT_DIR_OUT=1 ;; + esac ;; + + T) + case $OPTARG in + /*) + TCONFCMDFILE="-T $OPTARG" ;; + *) + TCONFCMDFILE="-T $LTPROOT/output/$OPTARG" + ALT_DIR_OUT=1 ;; + esac ;; + + d) # convert the user path to absolute path. + export TMPBASE=$(readlink -f ${OPTARG}) ;; + + D) NUM_PROCS=1; NUM_FILES=1; NUM_BYTES=$((1024 * 1024 * 1024)); CLEAN_FLAG=0 + ARGUMENT_LIST=$OPTARG + TOTAL_ARGUMENTS=1 + for ARGUMENT in `echo "$ARGUMENT_LIST" | tr ',' ' '` + do + case $TOTAL_ARGUMENTS in + 1) NUM_PROCS="$ARGUMENT" ;; + 2) NUM_FILES="$ARGUMENT" ;; + 3) NUM_BYTES="$ARGUMENT" ;; + 4) CLEAN_FLAG="$ARGUMENT" ;; + esac + TOTAL_ARGUMENTS=`expr $TOTAL_ARGUMENTS + 1` + done + # just to get the default values if the user passed 0 + if [ "$NUM_PROCS" -eq 0 ]; then + NUM_PROCS=1 + fi + if [ "$NUM_FILES" -eq 0 ]; then + NUM_FILES=1 + fi + if [ "$NUM_BYTES" -eq 0 ]; then + NUM_BYTES=$((1024 * 1024 * 1024)) + fi + if [ "$CLEAN_FLAG" -ne 1 ]; then + CLEAN_FLAG=0 + fi + if [ "$CLEAN_FLAG" -eq 1 ]; then + # Do not unlink file in this case + $LTPROOT/testcases/bin/genload --hdd $NUM_PROCS --hdd-files \ + $NUM_FILES --hdd-bytes $NUM_BYTES >/dev/null 2>&1 & + else + # Cleanup otherwise + $LTPROOT/testcases/bin/genload --hdd $NUM_PROCS --hdd-files \ + $NUM_FILES --hdd-bytes $NUM_BYTES --hdd-noclean >/dev/null 2>&1 & + fi + GENLOAD=1;; + + e) # Print out the version of LTP + version_of_ltp + ;; + f) # Execute user defined set of testcases. + # Can be more than one file, just separate it with ',', like: + # -f nfs,commands,/tmp/testfile + CMDFILES=$OPTARG;; + F) INJECT_KERNEL_FAULT=1 + # 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 + echo "Loops not properly defined. Resorting to default 5..." + export INJECT_FAULT_LOOPS_PER_TEST=5 + fi + if [ ! $INJECT_KERNEL_FAULT_PERCENTAGE ]; then + echo "Fault Persentage not properly defined. Resorting to default 10..." + export INJECT_KERNEL_FAULT_PERCENTAGE=10 + fi;; + g) HTMLFILE_NAME="$OPTARG" + case $OPTARG in + /*) + HTMLFILE="$OPTARG";; + *) + HTMLFILE="$LTPROOT/output/$OPTARG" + ALT_DIR_OUT=1;; + esac + ALT_HTML_OUT=1;; + h) usage;; + + i) + NUM_PROCS=$(($OPTARG)) + if [ "$NUM_PROCS" -eq 0 ]; then + # User Did not Define the Value ,or, User Defined Zero, + # hence, prevent from creating infinite processes + NUM_PROCS=1 + fi + $LTPROOT/testcases/bin/genload --io $NUM_PROCS >/dev/null 2>&1 & + GENLOAD=1 ;; + + K) + case $OPTARG in + /*) + DMESG_DIR="$OPTARG-dmesg-output-`echo $$-``date +%X | tr -d ' '`";; + *) + DMESG_DIR="$LTPROOT/output/$OPTARG-dmesg-output-`echo $$-``date +%X | tr -d ' '`";; + esac + mkdir -p $DMESG_DIR + ALT_DMESG_OUT=1;; + l) + LOGFILE_NAME="$OPTARG" + case $OPTARG in + /*) + LOGFILE="-l $OPTARG" ;; + *) + LOGFILE="-l $LTPROOT/results/$OPTARG" + ALT_DIR_RES=1 ;; + esac ;; + + m) NUM_PROCS=1; CHUNKS=1; BYTES=$((256 * 1024 * 1024)); HANGUP_FLAG=0 + ARGUMENT_LIST=$OPTARG + TOTAL_ARGUMENTS=1 + for ARGUMENT in `echo "$ARGUMENT_LIST" | tr ',' ' '` + do + case $TOTAL_ARGUMENTS in + 1) NUM_PROCS="$ARGUMENT" ;; + 2) CHUNKS="$ARGUMENT" ;; + 3) BYTES="$ARGUMENT" ;; + 4) HANGUP_FLAG="$ARGUMENT" ;; + esac + TOTAL_ARGUMENTS=`expr $TOTAL_ARGUMENTS + 1` + done + # just to get the default values if the user passed 0 + if [ "$NUM_PROCS" -eq 0 ]; then + NUM_PROCS=1 + fi + if [ "$CHUNKS" -eq 0 ]; then + CHUNKS=1 + fi + if [ "$BYTES" -eq 0 ]; then + BYTES=$((256 * 1024 * 1024)) + fi + if [ "$HANGUP_FLAG" -ne 1 ]; then + HANGUP_FLAG=0 + fi + if [ "$HANGUP_FLAG" -eq 1 ]; then + # Hang in a Sleep loop after memory allocated + $LTPROOT/testcases/bin/genload --vm $NUM_PROCS --vm-chunks \ + $CHUNKS --vm-bytes $BYTES --vm-hang >/dev/null 2>&1 & + else + # Otherwise Do not Hangup + $LTPROOT/testcases/bin/genload --vm $NUM_PROCS --vm-chunks \ + $CHUNKS --vm-bytes $BYTES >/dev/null 2>&1 & + fi + GENLOAD=1;; + M) + VALGRIND_CHECK=1 + VALGRIND_CHECK_TYPE="$OPTARG";; + + N) RUN_NETEST=1;; + + o) OUTPUTFILE_NAME="$OPTARG" + case $OPTARG in + /*) + OUTPUTFILE="-o $OPTARG";; + *) + OUTPUTFILE="-o $LTPROOT/output/$OPTARG" + ALT_DIR_OUT=1 ;; + esac ;; + + p) PRETTY_PRT="-p";; + + q) QUIET_MODE="-q";; + + Q) NO_KMSG="-Q";; + + r) LTPROOT=$OPTARG;; + + R) RANDOMRUN=1;; + + s) TAG_RESTRICT_STRING=$OPTARG;; + + S) case $OPTARG in + /*) + SKIPFILE=$OPTARG;; + *) + SKIPFILE="$LTPROOT/$OPTARG";; + esac ;; + + t) # In case you want to specify the time + # to run from the command line + # (2m = two minutes, 2h = two hours, etc) + DURATION="-t $OPTARG" ;; + + I) # In case you want the testcases to runsequentially RUN_REPEATED times + RUN_REPEATED=$OPTARG;; + + w) CMDFILEADDR=$OPTARG;; + + x) # number of ltp's to run + cat <<-EOF >&1 + WARNING: The use of -x can cause unpredictable failures, as a + result of concurrently running multiple tests designed + to be ran exclusively. + Pausing for 10 seconds..." + EOF + sleep 10 + INSTANCES="-x $OPTARG";; + b) DEVICE=$OPTARG;; + B) LTP_DEV_FS_TYPE=$OPTARG;; + z) BIG_DEVICE=$OPTARG;; + Z) BIG_DEVICE_FS_TYPE=$OPTARG;; + W) ZOOFILE=$OPTARG;; + \?) usage;; + esac + done + + ## It would be nice to create a default log file even if the user has not mentioned + if [ ! "$LOGFILE" ]; then ## User has not mentioned about Log File name + LOGFILE_NAME="$DEFAULT_FILE_NAME_GENERATION_TIME" + LOGFILE="-l $LTPROOT/results/LTP_RUN_ON-$LOGFILE_NAME.log" + ALT_DIR_RES=1 + PRETTY_PRT="-p" + fi + + ## It would be nice if a Failed File is compulsorily created (gives User better Idea of Tests that failed) + + if [ ! "$FAILCMDFILE" ]; then ## User has not mentioned about Failed File name + ALT_DIR_OUT=1 + if [ ! "$OUTPUTFILE" ]; then ## User has not mentioned about Output File name either + if [ ! "$LOGFILE" ]; then ## User has not mentioned about Log File name either + FAILED_FILE_NAME="$DEFAULT_FILE_NAME_GENERATION_TIME" + FAILCMDFILE="-C $LTPROOT/output/LTP_RUN_ON-$FAILED_FILE_NAME.failed" + else ## User Fortunately wanted a log file, + FAILED_FILE_NAME=`basename $LOGFILE_NAME` ## Extract log file name and use it to construct Failed file name + FAILCMDFILE="-C $LTPROOT/output/LTP_RUN_ON-$FAILED_FILE_NAME.failed" + fi + else ## User Fortunately wanted a Output file + FAILED_FILE_NAME=`basename $OUTPUTFILE_NAME` ## Extract output file name and use it to construct Failed file name + FAILCMDFILE="-C $LTPROOT/output/LTP_RUN_ON-$FAILED_FILE_NAME.failed" + fi + fi + + if [ ! "$TCONFCMDFILE" ]; then + ALT_DIR_OUT=1 + if [ ! "$OUTPUTFILE" ]; then + if [ ! "$LOGFILE" ]; then + TCONF_FILE_NAME="$DEFAULT_FILE_NAME_GENERATION_TIME" + TCONFCMDFILE="-T $LTPROOT/output/LTP_RUN_ON-${TCONF_FILE_NAME}.tconf" + else + TCONF_FILE_NAME=`basename $LOGFILE_NAME` + TCONFCMDFILE="-T $LTPROOT/output/LTP_RUN_ON-${TCONF_FILE_NAME}.tconf" + fi + else + TCONF_FILE_NAME=`basename $OUTPUTFILE_NAME` + TCONFCMDFILE="-T $LTPROOT/output/LTP_RUN_ON-${TCONF_FILE_NAME}.tconf" + fi + fi + + if [ "$ALT_HTML_OUT" -eq 1 ] ; then ## User wants the HTML version of the output + QUIET_MODE="" ## Suppressing this guy as it will prevent generation of proper output + ## which the HTML parser will require + if [ ! "$OUTPUTFILE" ]; then ## User has not mentioned about the Outputfile name, then we need to definitely generate one + OUTPUTFILE_NAME="$DEFAULT_FILE_NAME_GENERATION_TIME" + OUTPUTFILE="-o $LTPROOT/output/LTP_RUN_ON-$OUTPUTFILE_NAME.output" + ALT_DIR_OUT=1 + fi + fi + + # If we need, create the output directory + [ "$ALT_DIR_OUT" -eq 1 ] && \ + { + [ ! -d $LTPROOT/output ] && \ + { + echo "INFO: creating $LTPROOT/output directory" + mkdir -p $LTPROOT/output || \ + { + echo "ERROR: failed to create $LTPROOT/output" + exit 1 + } + } + } + + # If we need, create the results directory + [ "$ALT_DIR_RES" -eq 1 ] && \ + { + [ ! -d $LTPROOT/results ] && \ + { + echo "INFO: creating $LTPROOT/results directory" + mkdir -p $LTPROOT/results || \ + { + echo "ERROR: failed to create $LTPROOT/results" + exit 1 + } + } + } + + # Added -m 777 for tests that call tst_tmpdir() and try to + # write to it as user nobody + mkdir -m 777 -p $TMPBASE || \ + { + echo "FATAL: Unable to make temporary directory $TMPBASE" + exit 1 + } + # use mktemp to create "safe" temporary directories + export TMPTEMPLATE="${TMPBASE}/ltp-XXXXXXXXXX" + TMP=`mktemp -d $TMPTEMPLATE` || \ + { + echo "FATAL: Unable to make temporary directory: $TMP" + exit 1 + } + export TMP + # To be invoked by tst_tmpdir() + # write to it as user nobody + export TMPDIR=$TMP + + trap "cleanup" 0 + + chmod 777 $TMP || \ + { + echo "unable to chmod 777 $TMP ... aborting" + exit 1 + } + + cd $TMP || \ + { + echo "could not cd ${TMP} ... exiting" + exit 1 + } + + [ -n "$INSTANCES" ] && \ + { + INSTANCES="$INSTANCES -O ${TMP}" + } + + # If user does not provide a command file select a default set of testcases + # to execute. + if [ -z "$CMDFILES" ] && [ -z "$CMDFILEADDR" ]; then + + SCENARIO_LISTS="$LTPROOT/scenario_groups/default" + if [ "$RUN_NETEST" -eq 1 ]; then + SCENARIO_LISTS="$LTPROOT/scenario_groups/network" + fi + + cat <<-EOF >&1 +INFO: no command files were provided. Executing following runtest scenario files: +`cat $SCENARIO_LISTS | tr '\012' ' '` + +EOF + cat_ok_sentinel=$TMP/cat_ok.$$ + touch "$cat_ok_sentinel" + cat $SCENARIO_LISTS | while read scenfile; do + scenfile=${LTPROOT}/runtest/$scenfile + [ -f "$scenfile" ] || continue + + cat $scenfile >> "$TMP/alltests" || { + echo "FATAL: unable to append to command file" + rm -Rf "$TMP" + rm -f "$cat_ok_sentinel" + exit 1 + } + done + rm -f "$cat_ok_sentinel" + fi + + [ -n "$CMDFILES" ] && \ + { + for scenfile in `echo "$CMDFILES" | tr ',' ' '` + do + [ -f "$scenfile" ] || scenfile="$LTPROOT/runtest/$scenfile" + cat "$scenfile" >> ${TMP}/alltests || \ + { + echo "FATAL: unable to create command file" + rm -Rf "$TMP" + exit 1 + } + done + } + + [ -n "$CMDFILEADDR" ] && \ + { + wget -q "${CMDFILEADDR}" -O ${TMP}/wgetcmdfile + if [ $? -ne 0 ]; then + echo "FATAL: error while getting the command file with wget (address $CMDFILEADDR)" + exit 1 + fi + cat "${TMP}/wgetcmdfile" >> ${TMP}/alltests || \ + { + echo "FATAL: unable to create command file" + exit 1 + } + } + + # If enabled, execute only test cases that match the PATTERN + if [ -n "$TAG_RESTRICT_STRING" ] + then + mv -f ${TMP}/alltests ${TMP}/alltests.orig + grep $TAG_RESTRICT_STRING ${TMP}/alltests.orig > ${TMP}/alltests #Not worth checking return codes for this case + fi + + # Blacklist or skip tests if a SKIPFILE was specified with -S + if [ -n "${SKIPFILE}" ]; then + for test_name in $(awk '{print $1}' "${SKIPFILE}"); do + case "${test_name}" in \#*) continue;; esac + sed -i "/\<${test_name}\>/c\\${test_name} exit 32;" alltests + done + fi + + # check for required users and groups + ${LTPROOT}/IDcheck.sh || \ + { + echo "WARNING: required users and groups not present" + echo "WARNING: some test cases may fail" + } + + # display versions of installed software + [ -z "$QUIET_MODE" ] && \ + { + ${LTPROOT}/ver_linux || \ + { + echo "WARNING: unable to display versions of software installed" + exit 1 + } + } + + set_block_device + + # here even if the user don't specify a big block device, we + # also don't create the big block device. + if [ -z "$BIG_DEVICE" ]; then + echo "no big block device was specified on commandline." + echo "Tests which require a big block device are disabled." + echo "You can specify it with option -z" + else + export LTP_BIG_DEV=$BIG_DEVICE + if [ -z "$BIG_DEVICE_FS_TYPE" ]; then + export LTP_BIG_DEV_FS_TYPE="ext2" + else + export LTP_BIG_DEV_FS_TYPE=$BIG_DEVICE_FS_TYPE + fi + fi + + if [ $RUN_REPEATED -gt 1 ]; then # You need to specify at least more than 1 sequential run, else it runs default + echo "PAN will run these test cases $RUN_REPEATED times....." + echo "Test Tags will be Prepended with ITERATION NO.s....." + inc=1 + sed -e '/^$/ d' -e 's/^[ ,\t]*//' -e '/^#/ d' < ${TMP}/alltests > ${TMP}/alltests.temp ##This removes all newlines, leading spaces, tabs, # + sed 's/^[0-9,a-z,A-Z]*/'"$inc"'_ITERATION_&/' < ${TMP}/alltests.temp > ${TMP}/alltests ## .temp is kept as Base file + while [ $inc -lt $RUN_REPEATED ] ; do + inc=`expr $inc + 1` + sed 's/^[0-9,a-z,A-Z]*/'"$inc"'_ITERATION_&/' < ${TMP}/alltests.temp >> ${TMP}/alltests #Keep appending with Iteration No.s + done + fi + + if [ "$RANDOMRUN" != "0" ]; then + sort -R ${TMP}/alltests -o ${TMP}/alltests + 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 ${ZOOFILE} \ + -n $$ $PRETTY_PRT -f ${TMP}/alltests $LOGFILE $OUTPUTFILE $FAILCMDFILE $TCONFCMDFILE" + echo "COMMAND: $PAN_COMMAND" + if [ ! -z "$TAG_RESTRICT_STRING" ] ; then + echo "INFO: Restricted to $TAG_RESTRICT_STRING" + fi + #$PAN_COMMAND #Duplicated code here, because otherwise if we fail, only "PAN_COMMAND" gets output + + ## Display the Output/Log/Failed/HTML file names here + printf "LOG File: " + echo $LOGFILE | cut -b4- + + if [ "$OUTPUTFILE" ]; then + printf "OUTPUT File: " + echo $OUTPUTFILE | cut -b4- + fi + + printf "FAILED COMMAND File: " + echo $FAILCMDFILE | cut -b4- + + printf "TCONF COMMAND File: " + echo $TCONFCMDFILE | cut -b4- + + if [ "$HTMLFILE" ]; then + echo "HTML File: $HTMLFILE" + fi + + echo "Running tests......." + test_start_time=$(date) + + # User wants testing with Kernel Fault Injection + if [ $INJECT_KERNEL_FAULT ] ; then + #See if Debugfs is mounted, and + #Fault Injection Framework available through Debugfs + use_faultinjection=true + for debug_subdir in \ + fail_io_timeout \ + fail_make_request \ + fail_page_alloc \ + failslab \ + ; do + if [ -d "/sys/kernel/debug/$debug_subdir" ] + then + use_faultinjection=true + break + fi + done + if $use_faultinjection; then + #If at least one of the Framework is available + #Go ahead to Inject Fault & Create required + #Command Files for LTP run + echo Running tests with Fault Injection Enabled in the Kernel... + awk -v LOOPS=$INJECT_FAULT_LOOPS_PER_TEST \ + -v PERCENTAGE=$INJECT_KERNEL_FAULT_PERCENTAGE \ + -f ${LTPROOT}/bin/create_kernel_faults_in_loops_and_probability.awk \ + ${TMP}/alltests > ${TMP}/alltests.tmp + cp ${TMP}/alltests.tmp ${TMP}/alltests + rm -rf ${TMP}/alltests.tmp + else + echo Fault Injection not enabled in the Kernel.. + echo Running tests normally... + fi + fi + + ## Valgrind Check will work only when Kernel Fault Injection is not expected, + ## We do not want to test Faults when valgrind is running + if [ $VALGRIND_CHECK ]; then + if [ ! $INJECT_KERNEL_FAULT ]; then + which valgrind || VALGRIND_CHECK_TYPE=XYZ + case $VALGRIND_CHECK_TYPE in + [1-3]) + awk -v CHECK_LEVEL=$VALGRIND_CHECK_TYPE \ + -f ${LTPROOT}/bin/create_valgrind_check.awk \ + ${TMP}/alltests $VALGRIND_CHECK_TYPE > \ + ${TMP}/alltests.tmp + cp ${TMP}/alltests.tmp ${TMP}/alltests + rm -rf ${TMP}/alltests.tmp + ;; + *) + echo "Invalid Memory Check Type, or, Valgrind is not available" + ;; + esac + fi + fi + + if [ $ALT_DMESG_OUT -eq 1 ] ; then + #We want to print dmesg output for each test,lets do the trick inside the script + echo Enabling dmesg output logging for each test... + awk -v DMESG_DIR=$DMESG_DIR \ + -f ${LTPROOT}/bin/create_dmesg_entries_for_each_test.awk \ + ${TMP}/alltests > ${TMP}/alltests.tmp + cp ${TMP}/alltests.tmp ${TMP}/alltests + rm -rf ${TMP}/alltests.tmp + 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 ${ZOOFILE} -n $$ $PRETTY_PRT -f ${TMP}/alltests $LOGFILE $OUTPUTFILE $FAILCMDFILE $TCONFCMDFILE + + if [ $? -eq 0 ]; then + echo "INFO: ltp-pan reported all tests PASS" + VALUE=0 + export LTP_EXIT_VALUE=0; + else + echo "INFO: ltp-pan reported some tests FAIL" + VALUE=1 + export LTP_EXIT_VALUE=1; + fi + cd .. + echo "LTP Version: $version_date" + + # $DMESG_DIR is used to cache messages obtained from dmesg after a test run. + # Proactively reap all of the 0-byte files in $DMESG_DIR as they have zero value + # and only clutter up the filesystem. + + if [ $ALT_DMESG_OUT -eq 1 ] ; then + if ! find "$DMESG_DIR" -size 0 -exec rm {} + ; then + echo "cd to $DMESG_DIR failed: $?" + fi + if [ -n "$(ls "$DMESG_DIR")" ] ; then + echo "Kernel messages were generated for LTP tests $version_date" + else + echo "No Kernel messages were generated for LTP tests $version_date" + fi + fi + + if [ "$ALT_HTML_OUT" -eq 1 ] ; then #User wants the HTML output to be created, it then needs to be generated + export LTP_VERSION=$version_date + export TEST_START_TIME="$test_start_time" + export TEST_END_TIME="$(date)" + 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_FILE > $HTMLFILE; ) + echo "Generated HTML Output.....!!" + echo "Location: $HTMLFILE"; + + fi + + if [ "$ALT_EMAIL_OUT" -eq 1 ] ; then ## User wants reports to be e-mailed + TAR_FILE_NAME=LTP_RUN_$version_date$DEFAULT_FILE_NAME_GENERATION_TIME.tar + if [ "$HTMLFILE_NAME" ] ; then ## HTML file Exists + if [ "$ALT_HTML_OUT" -ne 1 ] ; then ## The HTML file path is absolute and not $LTPROOT/output + mkdir -p $LTPROOT/output ## We need to create this Directory + cp $HTMLFILE_NAME $LTPROOT/output/ + fi + fi + if [ "$OUTPUTFILE_NAME" ] ; then ## Output file exists + if [ "$ALT_DIR_OUT" -ne 1 ] ; then ## The Output file path is absolute and not $LTPROOT/output + mkdir -p $LTPROOT/output ## We need to create this Directory + cp $OUTPUTFILE_NAME $LTPROOT/output/ + fi + fi + if [ "$LOGFILE_NAME" ] ; then ## Log file exists + if [ "$ALT_DIR_RES" -ne 1 ] ; then ## The Log file path is absolute and not $LTPROOT/results + mkdir -p $LTPROOT/results ## We need to create this Directory + cp $LOGFILE_NAME $LTPROOT/results/ + fi + fi + if [ -d $LTPROOT/output ] ; then + tar -cf ./$TAR_FILE_NAME $LTPROOT/output + if [ $? -eq 0 ]; then + echo "Created TAR File: ./$TAR_FILE_NAME successfully, added $LTPROOT/output" + else + echo "Cannot Create TAR File: ./$TAR_FILE_NAME for adding $LTPROOT/output" + fi + fi + if [ -d $LTPROOT/results ] ; then + tar -uf ./$TAR_FILE_NAME $LTPROOT/results + if [ $? -eq 0 ]; then + echo "Updated TAR File: ./$TAR_FILE_NAME successfully, added $LTPROOT/results" + else + echo "Cannot Update TAR File: ./$TAR_FILE_NAME for adding $LTPROOT/results" + fi + fi + if [ -e $LTPROOT/nohup.out ] ; then ## If User would have Chosen nohup to do ltprun + tar -uf ./$TAR_FILE_NAME $LTPROOT/nohup.out + if [ $? -eq 0 ]; then + echo "Updated TAR File: ./$TAR_FILE_NAME successfully, added $LTPROOT/nohup.out" + else + echo "Cannot Update TAR File: ./$TAR_FILE_NAME for adding $LTPROOT/nohup.out" + fi + fi + gzip ./$TAR_FILE_NAME ## gzip this guy + if [ $? -eq 0 ]; then + echo "Gunzipped TAR File: ./$TAR_FILE_NAME" + else + echo "Cannot Gunzip TAR File: ./$TAR_FILE_NAME" + fi + if which mutt >/dev/null 2>&1; then + echo "Starting mailing reports to: $EMAIL_TO, file: ./$TAR_FILE_NAME.gz" + mutt -a ./$TAR_FILE_NAME.gz -s "LTP Reports on $test_start_time" -- $EMAIL_TO < /dev/null + if [ $? -eq 0 ]; then + echo "Reports Successfully mailed to: $EMAIL_TO" + else + echo "Reports cannot be mailed to: $EMAIL_TO" + fi + else ## Use our Ageold mail program + echo "Starting mailing reports to: $EMAIL_TO, file: ./$TAR_FILE_NAME.gz" + uuencode ./$TAR_FILE_NAME.gz $TAR_FILE_NAME.gz | mail $EMAIL_TO -s "LTP Reports on $test_start_time" + if [ $? -eq 0 ]; then + echo "Reports Successfully mailed to: $EMAIL_TO" + else + echo "Reports cannot be mailed to: $EMAIL_TO" + fi + fi + fi + + [ ! -z "$QUIET_MODE" ] && { echo "INFO: Test end time: $(date)" ; } + + [ "$GENLOAD" -eq 1 ] && { killall -9 genload >/dev/null 2>&1; } + [ "$NETPIPE" -eq 1 ] && { killall -9 NPtcp >/dev/null 2>&1; } + + [ "$ALT_DIR_OUT" -eq 1 ] || [ "$ALT_DIR_RES" -eq 1 ] && \ + { + cat <<-EOF >&1 + + ############################################################### + + Done executing testcases. + LTP Version: $version_date + ############################################################### + + EOF + } + + deprecated + + exit $VALUE +} + +set_block_device() +{ + if [ -n "$DEVICE" ]; then + export LTP_DEV=$DEVICE + fi +} + +cleanup() +{ + [ "$LOOP_DEV" ] && losetup -d $LOOP_DEV + rm -rf ${TMP} +} + + +LTP_SCRIPT="$(basename $0)" + +if [ "$LTP_SCRIPT" = "runltp" ]; then + setup + main "$@" +fi diff --git a/ltp/runtest/Makefile b/ltp/runtest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0f95e69fad832ad41e97335b367e90168c0813c4 --- /dev/null +++ b/ltp/runtest/Makefile @@ -0,0 +1,39 @@ +# +# runtest 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. +# +# Ngie Cooper, July 2009 +# + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk + +INSTALL_DIR := runtest + +# We don't want to copy over directories like CVS, STAX, etc, or the Makefile +# itself. +UNWANTED_FILES := Makefile CVS STAX + +INSTALL_MODE := 00644 + +INSTALL_TARGETS := $(filter-out $(UNWANTED_FILES),$(notdir $(patsubst $(abs_srcdir)/%,%,$(sort $(wildcard $(abs_srcdir)/*))))) + +MAKE_TARGETS := + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/runtest/can b/ltp/runtest/can new file mode 100644 index 0000000000000000000000000000000000000000..23cbf9acd51210403ae846d942227d7d016ff2a5 --- /dev/null +++ b/ltp/runtest/can @@ -0,0 +1,3 @@ +can_filter can_filter +can_rcv_own_msgs can_rcv_own_msgs +can_bcm01 can_bcm01 diff --git a/ltp/runtest/capability b/ltp/runtest/capability new file mode 100644 index 0000000000000000000000000000000000000000..c7af1235e1bc59e6010053bcea932cb706f50d95 --- /dev/null +++ b/ltp/runtest/capability @@ -0,0 +1,7 @@ +# various capability related tests +cap_bounds run_capbounds.sh +filecaps filecapstest.sh + +check_keepcaps01 check_keepcaps 1 +check_keepcaps02 check_keepcaps 2 +check_keepcaps03 check_keepcaps 3 diff --git a/ltp/runtest/commands b/ltp/runtest/commands new file mode 100644 index 0000000000000000000000000000000000000000..cfbaf214c83929606bfb9059332232fed8cefc80 --- /dev/null +++ b/ltp/runtest/commands @@ -0,0 +1,37 @@ +#DESCRIPTION:General Linux commands +ar_sh export TCdat=$LTPROOT/testcases/bin; ar01.sh +ld01_sh ld01.sh +ldd01_sh ldd01.sh +nm01_sh nm01.sh +file01_sh file01.sh +tar01_sh tar_tests.sh +cpio01_sh cpio_tests.sh +unzip01_sh unzip01.sh +gzip01_sh gzip_tests.sh +cp01_sh cp_tests.sh +ln01_sh ln_tests.sh +mkdir01_sh mkdir_tests.sh +mv01_sh mv_tests.sh +du01_sh du01.sh +df01_sh df01.sh +mkfs01_sh mkfs01.sh +mkfs01_ext2_sh mkfs01.sh -f ext2 +mkfs01_ext3_sh mkfs01.sh -f ext3 +mkfs01_ext4_sh mkfs01.sh -f ext4 +mkfs01_xfs_sh mkfs01.sh -f xfs +mkfs01_btrfs_sh mkfs01.sh -f btrfs +mkfs01_minix_sh mkfs01.sh -f minix +mkfs01_msdos_sh mkfs01.sh -f msdos +mkfs01_vfat_sh mkfs01.sh -f vfat +mkfs01_ntfs_sh mkfs01.sh -f ntfs +mkswap01_sh mkswap01.sh +which01_sh which01.sh +lsmod01_sh lsmod01.sh +insmod01_sh insmod01.sh +wc01_sh wc01.sh +keyctl01_sh keyctl01.sh +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/ltp/runtest/containers b/ltp/runtest/containers new file mode 100644 index 0000000000000000000000000000000000000000..5dcceab35a5fae66c62fce87cfa148c1216cb232 --- /dev/null +++ b/ltp/runtest/containers @@ -0,0 +1,93 @@ +#DESCRIPTION:Resource namespaces +pidns01 pidns01 +pidns02 pidns02 +pidns03 pidns03 +pidns04 pidns04 +pidns05 pidns05 +pidns06 pidns06 +pidns10 pidns10 +pidns12 pidns12 +pidns13 pidns13 +pidns16 pidns16 +pidns17 pidns17 +pidns20 pidns20 +pidns30 pidns30 +pidns31 pidns31 +pidns32 pidns32 + +mqns_01 mqns_01 +mqns_01_clone mqns_01 -m clone +mqns_01_unshare mqns_01 -m unshare +mqns_02 mqns_02 +mqns_02_clone mqns_02 -m clone +mqns_02_unshare mqns_02 -m unshare +mqns_03_unshare mqns_03 -m unshare +mqns_03_clone mqns_03 -m clone +mqns_04_unshare mqns_04 -m unshare +mqns_04_clone mqns_04 -m clone + +netns_netlink netns_netlink +netns_breakns_ip_ipv4_netlink netns_breakns.sh +netns_breakns_ip_ipv6_netlink netns_breakns.sh -6 +netns_breakns_ip_ipv4_ioctl netns_breakns.sh -I +netns_breakns_ip_ipv6_ioctl netns_breakns.sh -6I +netns_breakns_ns_exec_ipv4_netlink netns_breakns.sh -e +netns_breakns_ns_exec_ipv6_netlink netns_breakns.sh -6e +netns_breakns_ns_exec_ipv4_ioctl netns_breakns.sh -eI +netns_breakns_ns_exec_ipv6_ioctl netns_breakns.sh -6eI +netns_comm_ip_ipv4_netlink netns_comm.sh +netns_comm_ip_ipv6_netlink netns_comm.sh -6 +netns_comm_ip_ipv4_ioctl netns_comm.sh -I +netns_comm_ip_ipv6_ioctl netns_comm.sh -6I +netns_comm_ns_exec_ipv4_netlink netns_comm.sh -e +netns_comm_ns_exec_ipv6_netlink netns_comm.sh -6e +netns_comm_ns_exec_ipv4_ioctl netns_comm.sh -eI +netns_comm_ns_exec_ipv6_ioctl netns_comm.sh -6eI +netns_sysfs netns_sysfs.sh + +shmnstest_none shmnstest -m none +shmnstest_clone shmnstest -m clone +shmnstest_unshare shmnstest -m unshare +shmem_2nstest_none shmem_2nstest -m none +shmem_2nstest_clone shmem_2nstest -m clone +shmem_2nstest_unshare shmem_2nstest -m unshare +shm_comm shm_comm +mesgq_nstest_none mesgq_nstest -m none +mesgq_nstest_clone mesgq_nstest -m clone +mesgq_nstest_unshare mesgq_nstest -m unshare +msg_comm msg_comm +sem_nstest_none sem_nstest -m none +sem_nstest_clone sem_nstest -m clone +sem_nstest_unshare sem_nstest -m unshare +semtest_2ns_none semtest_2ns -m none +semtest_2ns_clone semtest_2ns -m clone +semtest_2ns_unshare semtest_2ns -m unshare +sem_comm sem_comm + +utsname01 utsname01 +utsname02 utsname02 +utsname03_clone utsname03 -m clone +utsname03_unshare utsname03 -m unshare +utsname04_clone utsname04 -m clone +utsname04_unshare utsname04 -m unshare + +mountns01 mountns01 +mountns02 mountns02 +mountns03 mountns03 +mountns04 mountns04 + +userns01 userns01 +userns02 userns02 +userns03 userns03 +userns04 userns04 +userns05 userns05 +userns06 userns06 +userns07 userns07 +userns08 userns08 + +# time namespaces +sysinfo03 sysinfo03 +clock_nanosleep03 clock_nanosleep03 +clock_gettime03 clock_gettime03 +timens01 timens01 +timerfd04 timerfd04 diff --git a/ltp/runtest/controllers b/ltp/runtest/controllers new file mode 100644 index 0000000000000000000000000000000000000000..93c52c43985b83ae3c1fcb16e227ce12a786d19c --- /dev/null +++ b/ltp/runtest/controllers @@ -0,0 +1,407 @@ +#DESCRIPTION:Resource Management testing +cgroup_core01 cgroup_core01 +cgroup_core02 cgroup_core02 +cgroup_core03 cgroup_core03 +cgroup cgroup_regression_test.sh +memcg_regression memcg_regression_test.sh +memcg_test_3 memcg_test_3 +memcg_failcnt memcg_failcnt.sh +memcg_force_empty memcg_force_empty.sh +memcg_limit_in_bytes memcg_limit_in_bytes.sh +memcg_stat_rss memcg_stat_rss.sh +memcg_subgroup_charge memcg_subgroup_charge.sh +memcg_max_usage_in_bytes memcg_max_usage_in_bytes_test.sh +memcg_move_charge_at_immigrate memcg_move_charge_at_immigrate_test.sh +memcg_memsw_limit_in_bytes memcg_memsw_limit_in_bytes_test.sh +memcg_stat memcg_stat_test.sh +memcg_use_hierarchy memcg_use_hierarchy_test.sh +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 +memcontrol03 memcontrol03 +memcontrol04 memcontrol04 + +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 +cgroup_fj_function_cpuacct cgroup_fj_function.sh cpuacct +cgroup_fj_function_memory cgroup_fj_function.sh memory +cgroup_fj_function_freezer cgroup_fj_function.sh freezer +cgroup_fj_function_devices cgroup_fj_function.sh devices +cgroup_fj_function_blkio cgroup_fj_function.sh blkio +cgroup_fj_function_net_cls cgroup_fj_function.sh net_cls +cgroup_fj_function_perf_event cgroup_fj_function.sh perf_event +cgroup_fj_function_net_prio cgroup_fj_function.sh net_prio +cgroup_fj_function_hugetlb cgroup_fj_function.sh hugetlb + +# Stress test for debug cgroup +cgroup_fj_stress_debug_2_2_none cgroup_fj_stress.sh debug 2 2 none +cgroup_fj_stress_debug_3_3_none cgroup_fj_stress.sh debug 3 3 none +cgroup_fj_stress_debug_4_4_none cgroup_fj_stress.sh debug 4 4 none +cgroup_fj_stress_debug_2_9_none cgroup_fj_stress.sh debug 2 9 none +cgroup_fj_stress_debug_10_3_none cgroup_fj_stress.sh debug 10 3 none +cgroup_fj_stress_debug_1_200_none cgroup_fj_stress.sh debug 1 200 none +cgroup_fj_stress_debug_200_1_none cgroup_fj_stress.sh debug 200 1 none + +cgroup_fj_stress_debug_2_2_one cgroup_fj_stress.sh debug 2 2 one +cgroup_fj_stress_debug_3_3_one cgroup_fj_stress.sh debug 3 3 one +cgroup_fj_stress_debug_4_4_one cgroup_fj_stress.sh debug 4 4 one +cgroup_fj_stress_debug_2_9_one cgroup_fj_stress.sh debug 2 9 one +cgroup_fj_stress_debug_10_3_one cgroup_fj_stress.sh debug 10 3 one +cgroup_fj_stress_debug_1_200_one cgroup_fj_stress.sh debug 1 200 one +cgroup_fj_stress_debug_200_1_one cgroup_fj_stress.sh debug 200 1 one + +cgroup_fj_stress_debug_2_2_each cgroup_fj_stress.sh debug 2 2 each +cgroup_fj_stress_debug_3_3_each cgroup_fj_stress.sh debug 3 3 each +cgroup_fj_stress_debug_4_4_each cgroup_fj_stress.sh debug 4 4 each +cgroup_fj_stress_debug_2_9_each cgroup_fj_stress.sh debug 2 9 each +cgroup_fj_stress_debug_10_3_each cgroup_fj_stress.sh debug 10 3 each +cgroup_fj_stress_debug_1_200_each cgroup_fj_stress.sh debug 1 200 each +cgroup_fj_stress_debug_200_1_each cgroup_fj_stress.sh debug 200 1 each + +# Stress test for cpuset cgroup +cgroup_fj_stress_cpuset_2_2_none cgroup_fj_stress.sh cpuset 2 2 none +cgroup_fj_stress_cpuset_3_3_none cgroup_fj_stress.sh cpuset 3 3 none +cgroup_fj_stress_cpuset_4_4_none cgroup_fj_stress.sh cpuset 4 4 none +cgroup_fj_stress_cpuset_2_9_none cgroup_fj_stress.sh cpuset 2 9 none +cgroup_fj_stress_cpuset_10_3_none cgroup_fj_stress.sh cpuset 10 3 none +cgroup_fj_stress_cpuset_1_200_none cgroup_fj_stress.sh cpuset 1 200 none +cgroup_fj_stress_cpuset_200_1_none cgroup_fj_stress.sh cpuset 200 1 none + +cgroup_fj_stress_cpuset_2_2_one cgroup_fj_stress.sh cpuset 2 2 one +cgroup_fj_stress_cpuset_3_3_one cgroup_fj_stress.sh cpuset 3 3 one +cgroup_fj_stress_cpuset_4_4_one cgroup_fj_stress.sh cpuset 4 4 one +cgroup_fj_stress_cpuset_2_9_one cgroup_fj_stress.sh cpuset 2 9 one +cgroup_fj_stress_cpuset_10_3_one cgroup_fj_stress.sh cpuset 10 3 one +cgroup_fj_stress_cpuset_1_200_one cgroup_fj_stress.sh cpuset 1 200 one +cgroup_fj_stress_cpuset_200_1_one cgroup_fj_stress.sh cpuset 200 1 one + +cgroup_fj_stress_cpuset_2_2_each cgroup_fj_stress.sh cpuset 2 2 each +cgroup_fj_stress_cpuset_3_3_each cgroup_fj_stress.sh cpuset 3 3 each +cgroup_fj_stress_cpuset_4_4_each cgroup_fj_stress.sh cpuset 4 4 each +cgroup_fj_stress_cpuset_2_9_each cgroup_fj_stress.sh cpuset 2 9 each +cgroup_fj_stress_cpuset_10_3_each cgroup_fj_stress.sh cpuset 10 3 each +cgroup_fj_stress_cpuset_1_200_each cgroup_fj_stress.sh cpuset 1 200 each +cgroup_fj_stress_cpuset_200_1_each cgroup_fj_stress.sh cpuset 200 1 each + +# Stress test for cpu cgroup +cgroup_fj_stress_cpu_2_2_none cgroup_fj_stress.sh cpu 2 2 none +cgroup_fj_stress_cpu_3_3_none cgroup_fj_stress.sh cpu 3 3 none +cgroup_fj_stress_cpu_4_4_none cgroup_fj_stress.sh cpu 4 4 none +cgroup_fj_stress_cpu_2_9_none cgroup_fj_stress.sh cpu 2 9 none +cgroup_fj_stress_cpu_10_3_none cgroup_fj_stress.sh cpu 10 3 none +cgroup_fj_stress_cpu_1_200_none cgroup_fj_stress.sh cpu 1 200 none +cgroup_fj_stress_cpu_200_1_none cgroup_fj_stress.sh cpu 200 1 none + +cgroup_fj_stress_cpu_2_2_one cgroup_fj_stress.sh cpu 2 2 one +cgroup_fj_stress_cpu_3_3_one cgroup_fj_stress.sh cpu 3 3 one +cgroup_fj_stress_cpu_4_4_one cgroup_fj_stress.sh cpu 4 4 one +cgroup_fj_stress_cpu_2_9_one cgroup_fj_stress.sh cpu 2 9 one +cgroup_fj_stress_cpu_10_3_one cgroup_fj_stress.sh cpu 10 3 one +cgroup_fj_stress_cpu_1_200_one cgroup_fj_stress.sh cpu 1 200 one +cgroup_fj_stress_cpu_200_1_one cgroup_fj_stress.sh cpu 200 1 one + +cgroup_fj_stress_cpu_2_2_each cgroup_fj_stress.sh cpu 2 2 each +cgroup_fj_stress_cpu_3_3_each cgroup_fj_stress.sh cpu 3 3 each +cgroup_fj_stress_cpu_4_4_each cgroup_fj_stress.sh cpu 4 4 each +cgroup_fj_stress_cpu_2_9_each cgroup_fj_stress.sh cpu 2 9 each +cgroup_fj_stress_cpu_10_3_each cgroup_fj_stress.sh cpu 10 3 each +cgroup_fj_stress_cpu_1_200_each cgroup_fj_stress.sh cpu 1 200 each +cgroup_fj_stress_cpu_200_1_each cgroup_fj_stress.sh cpu 200 1 each + +# Stress test for cpuacct cgroup +cgroup_fj_stress_cpuacct_2_2_none cgroup_fj_stress.sh cpuacct 2 2 none +cgroup_fj_stress_cpuacct_3_3_none cgroup_fj_stress.sh cpuacct 3 3 none +cgroup_fj_stress_cpuacct_4_4_none cgroup_fj_stress.sh cpuacct 4 4 none +cgroup_fj_stress_cpuacct_2_9_none cgroup_fj_stress.sh cpuacct 2 9 none +cgroup_fj_stress_cpuacct_10_3_none cgroup_fj_stress.sh cpuacct 10 3 none +cgroup_fj_stress_cpuacct_1_200_none cgroup_fj_stress.sh cpuacct 1 200 none +cgroup_fj_stress_cpuacct_200_1_none cgroup_fj_stress.sh cpuacct 200 1 none + +cgroup_fj_stress_cpuacct_2_2_one cgroup_fj_stress.sh cpuacct 2 2 one +cgroup_fj_stress_cpuacct_3_3_one cgroup_fj_stress.sh cpuacct 3 3 one +cgroup_fj_stress_cpuacct_4_4_one cgroup_fj_stress.sh cpuacct 4 4 one +cgroup_fj_stress_cpuacct_2_9_one cgroup_fj_stress.sh cpuacct 2 9 one +cgroup_fj_stress_cpuacct_10_3_one cgroup_fj_stress.sh cpuacct 10 3 one +cgroup_fj_stress_cpuacct_1_200_one cgroup_fj_stress.sh cpuacct 1 200 one +cgroup_fj_stress_cpuacct_200_1_one cgroup_fj_stress.sh cpuacct 200 1 one + +cgroup_fj_stress_cpuacct_2_2_each cgroup_fj_stress.sh cpuacct 2 2 each +cgroup_fj_stress_cpuacct_3_3_each cgroup_fj_stress.sh cpuacct 3 3 each +cgroup_fj_stress_cpuacct_4_4_each cgroup_fj_stress.sh cpuacct 4 4 each +cgroup_fj_stress_cpuacct_2_9_each cgroup_fj_stress.sh cpuacct 2 9 each +cgroup_fj_stress_cpuacct_10_3_each cgroup_fj_stress.sh cpuacct 10 3 each +cgroup_fj_stress_cpuacct_1_200_each cgroup_fj_stress.sh cpuacct 1 200 each +cgroup_fj_stress_cpuacct_200_1_each cgroup_fj_stress.sh cpuacct 200 1 each + +# Stress test for memory cgroup +cgroup_fj_stress_memory_2_2_none cgroup_fj_stress.sh memory 2 2 none +cgroup_fj_stress_memory_3_3_none cgroup_fj_stress.sh memory 3 3 none +cgroup_fj_stress_memory_4_4_none cgroup_fj_stress.sh memory 4 4 none +cgroup_fj_stress_memory_2_9_none cgroup_fj_stress.sh memory 2 9 none +cgroup_fj_stress_memory_10_3_none cgroup_fj_stress.sh memory 10 3 none +cgroup_fj_stress_memory_1_200_none cgroup_fj_stress.sh memory 1 200 none +cgroup_fj_stress_memory_200_1_none cgroup_fj_stress.sh memory 200 1 none + +cgroup_fj_stress_memory_2_2_one cgroup_fj_stress.sh memory 2 2 one +cgroup_fj_stress_memory_3_3_one cgroup_fj_stress.sh memory 3 3 one +cgroup_fj_stress_memory_4_4_one cgroup_fj_stress.sh memory 4 4 one +cgroup_fj_stress_memory_2_9_one cgroup_fj_stress.sh memory 2 9 one +cgroup_fj_stress_memory_10_3_one cgroup_fj_stress.sh memory 10 3 one +cgroup_fj_stress_memory_1_200_one cgroup_fj_stress.sh memory 1 200 one +cgroup_fj_stress_memory_200_1_one cgroup_fj_stress.sh memory 200 1 one + +cgroup_fj_stress_memory_2_2_each cgroup_fj_stress.sh memory 2 2 each +cgroup_fj_stress_memory_3_3_each cgroup_fj_stress.sh memory 3 3 each +cgroup_fj_stress_memory_4_4_each cgroup_fj_stress.sh memory 4 4 each +cgroup_fj_stress_memory_2_9_each cgroup_fj_stress.sh memory 2 9 each +cgroup_fj_stress_memory_10_3_each cgroup_fj_stress.sh memory 10 3 each +cgroup_fj_stress_memory_1_200_each cgroup_fj_stress.sh memory 1 200 each +cgroup_fj_stress_memory_200_1_each cgroup_fj_stress.sh memory 200 1 each + +# Stress test for freezer cgroup +cgroup_fj_stress_freezer_2_2_none cgroup_fj_stress.sh freezer 2 2 none +cgroup_fj_stress_freezer_3_3_none cgroup_fj_stress.sh freezer 3 3 none +cgroup_fj_stress_freezer_4_4_none cgroup_fj_stress.sh freezer 4 4 none +cgroup_fj_stress_freezer_2_9_none cgroup_fj_stress.sh freezer 2 9 none +cgroup_fj_stress_freezer_10_3_none cgroup_fj_stress.sh freezer 10 3 none +cgroup_fj_stress_freezer_1_200_none cgroup_fj_stress.sh freezer 1 200 none +cgroup_fj_stress_freezer_200_1_none cgroup_fj_stress.sh freezer 200 1 none + +cgroup_fj_stress_freezer_2_2_one cgroup_fj_stress.sh freezer 2 2 one +cgroup_fj_stress_freezer_3_3_one cgroup_fj_stress.sh freezer 3 3 one +cgroup_fj_stress_freezer_4_4_one cgroup_fj_stress.sh freezer 4 4 one +cgroup_fj_stress_freezer_2_9_one cgroup_fj_stress.sh freezer 2 9 one +cgroup_fj_stress_freezer_10_3_one cgroup_fj_stress.sh freezer 10 3 one +cgroup_fj_stress_freezer_1_200_one cgroup_fj_stress.sh freezer 1 200 one +cgroup_fj_stress_freezer_200_1_one cgroup_fj_stress.sh freezer 200 1 one + +cgroup_fj_stress_freezer_2_2_each cgroup_fj_stress.sh freezer 2 2 each +cgroup_fj_stress_freezer_3_3_each cgroup_fj_stress.sh freezer 3 3 each +cgroup_fj_stress_freezer_4_4_each cgroup_fj_stress.sh freezer 4 4 each +cgroup_fj_stress_freezer_2_9_each cgroup_fj_stress.sh freezer 2 9 each +cgroup_fj_stress_freezer_10_3_each cgroup_fj_stress.sh freezer 10 3 each +cgroup_fj_stress_freezer_1_200_each cgroup_fj_stress.sh freezer 1 200 each +cgroup_fj_stress_freezer_200_1_each cgroup_fj_stress.sh freezer 200 1 each + +# Stress test for devices cgroup +cgroup_fj_stress_devices_2_2_none cgroup_fj_stress.sh devices 2 2 none +cgroup_fj_stress_devices_3_3_none cgroup_fj_stress.sh devices 3 3 none +cgroup_fj_stress_devices_4_4_none cgroup_fj_stress.sh devices 4 4 none +cgroup_fj_stress_devices_2_9_none cgroup_fj_stress.sh devices 2 9 none +cgroup_fj_stress_devices_10_3_none cgroup_fj_stress.sh devices 10 3 none +cgroup_fj_stress_devices_1_200_none cgroup_fj_stress.sh devices 1 200 none +cgroup_fj_stress_devices_200_1_none cgroup_fj_stress.sh devices 200 1 none + +cgroup_fj_stress_devices_2_2_one cgroup_fj_stress.sh devices 2 2 one +cgroup_fj_stress_devices_3_3_one cgroup_fj_stress.sh devices 3 3 one +cgroup_fj_stress_devices_4_4_one cgroup_fj_stress.sh devices 4 4 one +cgroup_fj_stress_devices_2_9_one cgroup_fj_stress.sh devices 2 9 one +cgroup_fj_stress_devices_10_3_one cgroup_fj_stress.sh devices 10 3 one +cgroup_fj_stress_devices_1_200_one cgroup_fj_stress.sh devices 1 200 one +cgroup_fj_stress_devices_200_1_one cgroup_fj_stress.sh devices 200 1 one + +cgroup_fj_stress_devices_2_2_each cgroup_fj_stress.sh devices 2 2 each +cgroup_fj_stress_devices_3_3_each cgroup_fj_stress.sh devices 3 3 each +cgroup_fj_stress_devices_4_4_each cgroup_fj_stress.sh devices 4 4 each +cgroup_fj_stress_devices_2_9_each cgroup_fj_stress.sh devices 2 9 each +cgroup_fj_stress_devices_10_3_each cgroup_fj_stress.sh devices 10 3 each +cgroup_fj_stress_devices_1_200_each cgroup_fj_stress.sh devices 1 200 each +cgroup_fj_stress_devices_200_1_each cgroup_fj_stress.sh devices 200 1 each + +# Stress test for blkio cgroup +cgroup_fj_stress_blkio_2_2_none cgroup_fj_stress.sh blkio 2 2 none +cgroup_fj_stress_blkio_3_3_none cgroup_fj_stress.sh blkio 3 3 none +cgroup_fj_stress_blkio_4_4_none cgroup_fj_stress.sh blkio 4 4 none +cgroup_fj_stress_blkio_2_9_none cgroup_fj_stress.sh blkio 2 9 none +cgroup_fj_stress_blkio_10_3_none cgroup_fj_stress.sh blkio 10 3 none +cgroup_fj_stress_blkio_1_200_none cgroup_fj_stress.sh blkio 1 200 none +cgroup_fj_stress_blkio_200_1_none cgroup_fj_stress.sh blkio 200 1 none + +cgroup_fj_stress_blkio_2_2_one cgroup_fj_stress.sh blkio 2 2 one +cgroup_fj_stress_blkio_3_3_one cgroup_fj_stress.sh blkio 3 3 one +cgroup_fj_stress_blkio_4_4_one cgroup_fj_stress.sh blkio 4 4 one +cgroup_fj_stress_blkio_2_9_one cgroup_fj_stress.sh blkio 2 9 one +cgroup_fj_stress_blkio_10_3_one cgroup_fj_stress.sh blkio 10 3 one +cgroup_fj_stress_blkio_1_200_one cgroup_fj_stress.sh blkio 1 200 one +cgroup_fj_stress_blkio_200_1_one cgroup_fj_stress.sh blkio 200 1 one + +cgroup_fj_stress_blkio_2_2_each cgroup_fj_stress.sh blkio 2 2 each +cgroup_fj_stress_blkio_3_3_each cgroup_fj_stress.sh blkio 3 3 each +cgroup_fj_stress_blkio_4_4_each cgroup_fj_stress.sh blkio 4 4 each +cgroup_fj_stress_blkio_2_9_each cgroup_fj_stress.sh blkio 2 9 each +cgroup_fj_stress_blkio_10_3_each cgroup_fj_stress.sh blkio 10 3 each +cgroup_fj_stress_blkio_1_200_each cgroup_fj_stress.sh blkio 1 200 each +cgroup_fj_stress_blkio_200_1_each cgroup_fj_stress.sh blkio 200 1 each + +# Stress test for net_cls cgroup +cgroup_fj_stress_net_cls_2_2_none cgroup_fj_stress.sh net_cls 2 2 none +cgroup_fj_stress_net_cls_3_3_none cgroup_fj_stress.sh net_cls 3 3 none +cgroup_fj_stress_net_cls_4_4_none cgroup_fj_stress.sh net_cls 4 4 none +cgroup_fj_stress_net_cls_2_9_none cgroup_fj_stress.sh net_cls 2 9 none +cgroup_fj_stress_net_cls_10_3_none cgroup_fj_stress.sh net_cls 10 3 none +cgroup_fj_stress_net_cls_1_200_none cgroup_fj_stress.sh net_cls 1 200 none +cgroup_fj_stress_net_cls_200_1_none cgroup_fj_stress.sh net_cls 200 1 none + +cgroup_fj_stress_net_cls_2_2_one cgroup_fj_stress.sh net_cls 2 2 one +cgroup_fj_stress_net_cls_3_3_one cgroup_fj_stress.sh net_cls 3 3 one +cgroup_fj_stress_net_cls_4_4_one cgroup_fj_stress.sh net_cls 4 4 one +cgroup_fj_stress_net_cls_2_9_one cgroup_fj_stress.sh net_cls 2 9 one +cgroup_fj_stress_net_cls_10_3_one cgroup_fj_stress.sh net_cls 10 3 one +cgroup_fj_stress_net_cls_1_200_one cgroup_fj_stress.sh net_cls 1 200 one +cgroup_fj_stress_net_cls_200_1_one cgroup_fj_stress.sh net_cls 200 1 one + +cgroup_fj_stress_net_cls_2_2_each cgroup_fj_stress.sh net_cls 2 2 each +cgroup_fj_stress_net_cls_3_3_each cgroup_fj_stress.sh net_cls 3 3 each +cgroup_fj_stress_net_cls_4_4_each cgroup_fj_stress.sh net_cls 4 4 each +cgroup_fj_stress_net_cls_2_9_each cgroup_fj_stress.sh net_cls 2 9 each +cgroup_fj_stress_net_cls_10_3_each cgroup_fj_stress.sh net_cls 10 3 each +cgroup_fj_stress_net_cls_1_200_each cgroup_fj_stress.sh net_cls 1 200 each +cgroup_fj_stress_net_cls_200_1_each cgroup_fj_stress.sh net_cls 200 1 each + +# Stress test for perf_event cgroup +cgroup_fj_stress_perf_event_2_2_none cgroup_fj_stress.sh perf_event 2 2 none +cgroup_fj_stress_perf_event_3_3_none cgroup_fj_stress.sh perf_event 3 3 none +cgroup_fj_stress_perf_event_4_4_none cgroup_fj_stress.sh perf_event 4 4 none +cgroup_fj_stress_perf_event_2_9_none cgroup_fj_stress.sh perf_event 2 9 none +cgroup_fj_stress_perf_event_10_3_none cgroup_fj_stress.sh perf_event 10 3 none +cgroup_fj_stress_perf_event_1_200_none cgroup_fj_stress.sh perf_event 1 200 none +cgroup_fj_stress_perf_event_200_1_none cgroup_fj_stress.sh perf_event 200 1 none + +cgroup_fj_stress_perf_event_2_2_one cgroup_fj_stress.sh perf_event 2 2 one +cgroup_fj_stress_perf_event_3_3_one cgroup_fj_stress.sh perf_event 3 3 one +cgroup_fj_stress_perf_event_4_4_one cgroup_fj_stress.sh perf_event 4 4 one +cgroup_fj_stress_perf_event_2_9_one cgroup_fj_stress.sh perf_event 2 9 one +cgroup_fj_stress_perf_event_10_3_one cgroup_fj_stress.sh perf_event 10 3 one +cgroup_fj_stress_perf_event_1_200_one cgroup_fj_stress.sh perf_event 1 200 one +cgroup_fj_stress_perf_event_200_1_one cgroup_fj_stress.sh perf_event 200 1 one + +cgroup_fj_stress_perf_event_2_2_each cgroup_fj_stress.sh perf_event 2 2 each +cgroup_fj_stress_perf_event_3_3_each cgroup_fj_stress.sh perf_event 3 3 each +cgroup_fj_stress_perf_event_4_4_each cgroup_fj_stress.sh perf_event 4 4 each +cgroup_fj_stress_perf_event_2_9_each cgroup_fj_stress.sh perf_event 2 9 each +cgroup_fj_stress_perf_event_10_3_each cgroup_fj_stress.sh perf_event 10 3 each +cgroup_fj_stress_perf_event_1_200_each cgroup_fj_stress.sh perf_event 1 200 each +cgroup_fj_stress_perf_event_200_1_each cgroup_fj_stress.sh perf_event 200 1 each + +# Stress test for net_prio cgroup +cgroup_fj_stress_net_prio_2_2_none cgroup_fj_stress.sh net_prio 2 2 none +cgroup_fj_stress_net_prio_3_3_none cgroup_fj_stress.sh net_prio 3 3 none +cgroup_fj_stress_net_prio_4_4_none cgroup_fj_stress.sh net_prio 4 4 none +cgroup_fj_stress_net_prio_2_9_none cgroup_fj_stress.sh net_prio 2 9 none +cgroup_fj_stress_net_prio_10_3_none cgroup_fj_stress.sh net_prio 10 3 none +cgroup_fj_stress_net_prio_1_200_none cgroup_fj_stress.sh net_prio 1 200 none +cgroup_fj_stress_net_prio_200_1_none cgroup_fj_stress.sh net_prio 200 1 none + +cgroup_fj_stress_net_prio_2_2_one cgroup_fj_stress.sh net_prio 2 2 one +cgroup_fj_stress_net_prio_3_3_one cgroup_fj_stress.sh net_prio 3 3 one +cgroup_fj_stress_net_prio_4_4_one cgroup_fj_stress.sh net_prio 4 4 one +cgroup_fj_stress_net_prio_2_9_one cgroup_fj_stress.sh net_prio 2 9 one +cgroup_fj_stress_net_prio_10_3_one cgroup_fj_stress.sh net_prio 10 3 one +cgroup_fj_stress_net_prio_1_200_one cgroup_fj_stress.sh net_prio 1 200 one +cgroup_fj_stress_net_prio_200_1_one cgroup_fj_stress.sh net_prio 200 1 one + +cgroup_fj_stress_net_prio_2_2_each cgroup_fj_stress.sh net_prio 2 2 each +cgroup_fj_stress_net_prio_3_3_each cgroup_fj_stress.sh net_prio 3 3 each +cgroup_fj_stress_net_prio_4_4_each cgroup_fj_stress.sh net_prio 4 4 each +cgroup_fj_stress_net_prio_2_9_each cgroup_fj_stress.sh net_prio 2 9 each +cgroup_fj_stress_net_prio_10_3_each cgroup_fj_stress.sh net_prio 10 3 each +cgroup_fj_stress_net_prio_1_200_each cgroup_fj_stress.sh net_prio 1 200 each +cgroup_fj_stress_net_prio_200_1_each cgroup_fj_stress.sh net_prio 200 1 each + +# Stress test for hugetlb cgroup +cgroup_fj_stress_hugetlb_2_2_none cgroup_fj_stress.sh hugetlb 2 2 none +cgroup_fj_stress_hugetlb_3_3_none cgroup_fj_stress.sh hugetlb 3 3 none +cgroup_fj_stress_hugetlb_4_4_none cgroup_fj_stress.sh hugetlb 4 4 none +cgroup_fj_stress_hugetlb_2_9_none cgroup_fj_stress.sh hugetlb 2 9 none +cgroup_fj_stress_hugetlb_10_3_none cgroup_fj_stress.sh hugetlb 10 3 none +cgroup_fj_stress_hugetlb_1_200_none cgroup_fj_stress.sh hugetlb 1 200 none +cgroup_fj_stress_hugetlb_200_1_none cgroup_fj_stress.sh hugetlb 200 1 none + +cgroup_fj_stress_hugetlb_2_2_one cgroup_fj_stress.sh hugetlb 2 2 one +cgroup_fj_stress_hugetlb_3_3_one cgroup_fj_stress.sh hugetlb 3 3 one +cgroup_fj_stress_hugetlb_4_4_one cgroup_fj_stress.sh hugetlb 4 4 one +cgroup_fj_stress_hugetlb_2_9_one cgroup_fj_stress.sh hugetlb 2 9 one +cgroup_fj_stress_hugetlb_10_3_one cgroup_fj_stress.sh hugetlb 10 3 one +cgroup_fj_stress_hugetlb_1_200_one cgroup_fj_stress.sh hugetlb 1 200 one +cgroup_fj_stress_hugetlb_200_1_one cgroup_fj_stress.sh hugetlb 200 1 one + +cgroup_fj_stress_hugetlb_2_2_each cgroup_fj_stress.sh hugetlb 2 2 each +cgroup_fj_stress_hugetlb_3_3_each cgroup_fj_stress.sh hugetlb 3 3 each +cgroup_fj_stress_hugetlb_4_4_each cgroup_fj_stress.sh hugetlb 4 4 each +cgroup_fj_stress_hugetlb_2_9_each cgroup_fj_stress.sh hugetlb 2 9 each +cgroup_fj_stress_hugetlb_10_3_each cgroup_fj_stress.sh hugetlb 10 3 each +cgroup_fj_stress_hugetlb_1_200_each cgroup_fj_stress.sh hugetlb 1 200 each +cgroup_fj_stress_hugetlb_200_1_each cgroup_fj_stress.sh hugetlb 200 1 each + +controllers test_controllers.sh + +cpuacct_1_1 cpuacct.sh 1 1 +cpuacct_1_10 cpuacct.sh 1 10 +cpuacct_10_10 cpuacct.sh 10 10 +cpuacct_1_100 cpuacct.sh 1 100 +cpuacct_100_1 cpuacct.sh 100 1 +cpuacct_100_100 cpuacct.sh 100 100 + +cpuset_base_ops cpuset_base_ops_testset.sh +cpuset_inherit cpuset_inherit_testset.sh +cpuset_exclusive cpuset_exclusive_test.sh +cpuset_hierarchy cpuset_hierarchy_test.sh +cpuset_syscall cpuset_syscall_testset.sh +cpuset_sched_domains cpuset_sched_domains_test.sh +cpuset_load_balance cpuset_load_balance_test.sh +cpuset_hotplug cpuset_hotplug_test.sh +cpuset_memory cpuset_memory_testset.sh +cpuset_memory_pressure cpuset_memory_pressure_testset.sh +cpuset_memory_spread cpuset_memory_spread_testset.sh + +cpuset_regression_test cpuset_regression_test.sh + +cgroup_xattr cgroup_xattr + +# V2 IO controller (was blkio) +io_control01 io_control01 + +pids_1_1 pids.sh 1 1 0 +pids_1_2 pids.sh 1 2 0 +pids_1_10 pids.sh 1 10 0 +pids_1_50 pids.sh 1 50 0 +pids_1_100 pids.sh 1 100 0 +pids_2_1 pids.sh 2 1 0 +pids_2_2 pids.sh 2 2 0 +pids_2_10 pids.sh 2 10 0 +pids_2_50 pids.sh 2 50 0 +pids_2_100 pids.sh 2 100 0 +pids_3_0 pids.sh 3 0 0 +pids_3_1 pids.sh 3 1 0 +pids_3_10 pids.sh 3 10 0 +pids_3_50 pids.sh 3 50 0 +pids_3_100 pids.sh 3 100 0 +pids_4_1 pids.sh 4 1 0 +pids_4_2 pids.sh 4 2 0 +pids_4_10 pids.sh 4 10 0 +pids_4_50 pids.sh 4 50 0 +pids_4_100 pids.sh 4 100 0 +pids_5_1 pids.sh 5 1 0 +pids_6_1 pids.sh 6 1 0 +pids_6_2 pids.sh 6 2 0 +pids_6_10 pids.sh 6 10 0 +pids_6_50 pids.sh 6 50 0 +pids_6_100 pids.sh 6 100 0 +pids_7_10 pids.sh 7 10 5 +pids_7_50 pids.sh 7 50 10 +pids_7_100 pids.sh 7 100 10 +pids_7_500 pids.sh 7 500 50 +pids_7_1000 pids.sh 7 1000 100 +pids_8_2 pids.sh 8 2 0 +pids_8_10 pids.sh 8 10 0 +pids_8_50 pids.sh 8 50 0 +pids_8_100 pids.sh 8 100 0 +pids_9_2 pids.sh 9 2 0 +pids_9_10 pids.sh 9 10 0 +pids_9_50 pids.sh 9 50 0 +pids_9_100 pids.sh 9 100 0 diff --git a/ltp/runtest/cpuhotplug b/ltp/runtest/cpuhotplug new file mode 100644 index 0000000000000000000000000000000000000000..ec7f11ed1b8a29df6eedc319e1410ba55d7a44bb --- /dev/null +++ b/ltp/runtest/cpuhotplug @@ -0,0 +1,9 @@ +## Run the CPUHOTPLUG tests here + +#cpuhotplug01 cpuhotplug01.sh -c 1 -l 1 -n 1 -f 1 -e 6 +cpuhotplug02 cpuhotplug02.sh -c 1 -l 1 +cpuhotplug03 cpuhotplug03.sh -c 1 -l 1 +cpuhotplug04 cpuhotplug04.sh -l 1 +cpuhotplug05 cpuhotplug05.sh -c 1 -l 1 -d /tmp +cpuhotplug06 cpuhotplug06.sh -c 1 -l 1 +cpuhotplug07 cpuhotplug07.sh -c 1 -l 1 -d /usr/src/linux diff --git a/ltp/runtest/crashme b/ltp/runtest/crashme new file mode 100644 index 0000000000000000000000000000000000000000..af45d29bc2ed9ec0179d8f9d5a084984b0d9ca71 --- /dev/null +++ b/ltp/runtest/crashme @@ -0,0 +1,12 @@ +#DESCRIPTION:Utility to crash your machine +# Before running these: BACKUP YOUR SYSTEM! you've been warned! +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. +crash01 crash01 +# Generate random code and execute it. Read f00f comment, +# this test lockup SunOS,WindowsNT,etc. in seconds.. +crash02 crash02 +# 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/ltp/runtest/crypto b/ltp/runtest/crypto new file mode 100644 index 0000000000000000000000000000000000000000..446559efcd7d2addbad8a88c38fac00ae5cfa92d --- /dev/null +++ b/ltp/runtest/crypto @@ -0,0 +1,10 @@ +af_alg01 af_alg01 +af_alg02 af_alg02 +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/ltp/runtest/cve b/ltp/runtest/cve new file mode 100644 index 0000000000000000000000000000000000000000..1d1d875974f0ce545005faedb78125d33ec7c989 --- /dev/null +++ b/ltp/runtest/cve @@ -0,0 +1,93 @@ +# Tests which check for vulnerabilities by CVE number +cve-2011-0999 thp01 -I 120 +cve-2011-2183 ksm05 -I 10 +cve-2011-2496 vma03 +cve-2012-0957 uname04 +cve-2014-0196 cve-2014-0196 +cve-2015-0235 gethostbyname_r01 +cve-2015-3290 cve-2015-3290 +cve-2015-7550 keyctl02 +cve-2016-4470 keyctl01.sh +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-5754 meltdown +cve-2017-6951 request_key05 +cve-2017-7308 setsockopt02 +cve-2017-7472 keyctl04 +cve-2017-7616 set_mempolicy05 +cve-2017-8890 accept02 +cve-2017-10661 timerfd_settime02 +cve-2017-12192 keyctl07 +cve-2017-12193 add_key04 +cve-2017-15274 add_key02 +cve-2017-15299 request_key03 -b cve-2017-15299 +cve-2017-15537 ptrace07 +cve-2017-15649 fanout01 +cve-2017-15951 request_key03 -b cve-2017-15951 +cve-2017-16939 cve-2017-16939 +cve-2017-16995 bpf_prog03 +cve-2017-17052 cve-2017-17052 +cve-2017-17053 cve-2017-17053 +cve-2017-17712 sendmsg03 +cve-2017-17805 af_alg02 +cve-2017-17806 af_alg01 +cve-2017-17807 request_key04 +cve-2017-18075 pcrypt_aead01 +cve-2017-18344 timer_create03 +cve-2017-1000111 setsockopt07 +cve-2017-1000112 setsockopt05 +cve-2017-1000364 stack_clash +cve-2017-1000380 snd_timer01 +cve-2017-1000405 thp04 +cve-2018-5803 sctp_big_chunk +cve-2018-6927 futex_cmp_requeue02 +cve-2018-7566 snd_seq01 +cve-2018-8897 ptrace09 +cve-2018-9568 connect02 +cve-2018-10124 kill13 +cve-2018-11508 adjtimex03 +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-2018-1000001 realpath01 +cve-2018-1000199 ptrace08 +cve-2018-1000204 ioctl_sg01 +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-2020-36557 pty06 +cve-2021-3444 bpf_prog05 +cve-2021-3609 can_bcm01 +cve-2021-4034 execve06 +cve-2021-4197_1 cgroup_core01 +cve-2021-4197_2 cgroup_core02 +cve-2021-4204 bpf_prog06 +cve-2021-22555 setsockopt08 -i 100 +cve-2021-26708 vsock01 +cve-2021-22600 setsockopt09 +cve-2021-38604 mq_notify03 +cve-2022-0847 dirtypipe +cve-2022-2590 dirtyc0w_shmem +cve-2022-23222 bpf_prog07 +cve-2023-1829 tcindex01 +cve-2023-0461 setsockopt10 +cve-2023-31248 nft02 +# Tests below may cause kernel memory leak +cve-2020-25704 perf_event_open03 +cve-2022-0185 fsconfig03 +cve-2022-4378 cve-2022-4378 diff --git a/ltp/runtest/dio b/ltp/runtest/dio new file mode 100644 index 0000000000000000000000000000000000000000..185cd579c8be4f6bc914814c4394c685b92271af --- /dev/null +++ b/ltp/runtest/dio @@ -0,0 +1,70 @@ +#DESCRIPTION:Direct IO tests +## Complete a default run. +dio01 diotest1 +dio02 diotest2 +dio03 diotest3 +dio04 diotest4 +dio05 diotest5 +dio06 diotest6 + +## Run the tests with larger buffersize +dio07 diotest1 -b 65536 +dio08 diotest2 -b 65536 +dio09 diotest3 -b 65536 +dio10 diotest4 -b 65536 +dio11 diotest5 -b 65536 +dio12 diotest6 -b 65536 + +### Run the tests with larger iterations +dio13 diotest1 -b 65536 -n 2000 +dio14 diotest2 -b 65536 -i 1000 +dio15 diotest3 -b 65536 -i 1000 +dio16 diotest5 -b 65536 -i 1000 +dio17 diotest6 -b 65536 -i 1000 + +## Run the tests with larger offset - 1MB +dio18 diotest2 -b 65536 -i 1000 -o 1024000 +dio19 diotest3 -b 65536 -i 1000 -o 1024000 +dio20 diotest5 -b 65536 -i 1000 -o 1024000 +dio21 diotest6 -b 65536 -i 1000 -o 1024000 + +## Run the tests with larger offset - 100 MB +dio22 diotest2 -b 65536 -i 1000 -o 104857600 +dio23 diotest3 -b 65536 -i 1000 -o 104857600 +dio24 diotest5 -b 65536 -i 1000 -o 104857600 +dio25 diotest6 -b 65536 -i 1000 -o 104857600 + +### Run tests with larger vector array +dio26 diotest6 -b 8192 -v 100 +dio27 diotest6 -b 8192 -o 1024000 -i 1000 -v 100 +dio28 diotest6 -b 8192 -o 1024000 -i 1000 -v 200 + +### Run the tests with more children +dio29 diotest3 -b 65536 -n 100 -i 100 -o 1024000 +dio30 diotest6 -b 65536 -n 100 -i 100 -o 1024000 +# +# RAW DEVICE TEST SECTION +# DEV1 and DEV2 should be exported prior to execution or +# replaced with the actual device ids, i.e. +# dio33 diotest1 -i /dev/sda2 -o /dev/sda3 +# +### Run the tests with raw device +#dio33 diotest1 -i $DEV1 -o $DEV2 +#dio34 diotest2 -f $DEV1 +#dio36 diotest3 -f $DEV1 +#dio37 diotest5 -f $DEV1 +#dio38 diotest6 -f $DEV1 +# +### Run the tests with raw device and larger iterations +#dio39 diotest1 -b 65536 -n 2000 -i $DEV1 -o $DEV2 +#dio40 diotest2 -b 65536 -i 1000 -f $DEV1 +#dio41 diotest3 -b 65536 -i 1000 -f $DEV1 +#dio42 diotest5 -b 65536 -i 1000 -f $DEV1 +#dio43 diotest6 -b 65536 -i 1000 -f $DEV1 +# +## Run the tests with raw device and larger offset - 100 MB +#dio44 diotest2 -b 65536 -i 1000 -o 104857600 -f $DEV1 +#dio45 diotest3 -b 65536 -i 1000 -o 104857600 -f $DEV1 +#dio46 diotest5 -b 65536 -i 1000 -o 104857600 -f $DEV1 +#dio47 diotest6 -b 65536 -i 1000 -o 104857600 -f $DEV1 + diff --git a/ltp/runtest/dma_thread_diotest b/ltp/runtest/dma_thread_diotest new file mode 100644 index 0000000000000000000000000000000000000000..d5234459150ce7a02117159424276cf2651e42cd --- /dev/null +++ b/ltp/runtest/dma_thread_diotest @@ -0,0 +1,7 @@ +dma_thread_diotest1 dma_thread_diotest -a 512 +dma_thread_diotest2 dma_thread_diotest -a 1024 +dma_thread_diotest3 dma_thread_diotest -a 1536 +dma_thread_diotest4 dma_thread_diotest -a 2048 +dma_thread_diotest5 dma_thread_diotest -a 2560 +dma_thread_diotest6 dma_thread_diotest -a 3072 +dma_thread_diotest7 dma_thread_diotest -a 3584 diff --git a/ltp/runtest/fcntl-locktests b/ltp/runtest/fcntl-locktests new file mode 100644 index 0000000000000000000000000000000000000000..d464c13f451dd2c2461dceb4705bdeb958dc5169 --- /dev/null +++ b/ltp/runtest/fcntl-locktests @@ -0,0 +1 @@ +FCNTL_LOCKTESTS locktests -n 100 -f /tmp/fcntl_locktest_testfile diff --git a/ltp/runtest/fs b/ltp/runtest/fs new file mode 100644 index 0000000000000000000000000000000000000000..1d753e0ddfdc0eee077a937cb6901a02a9e4aa48 --- /dev/null +++ b/ltp/runtest/fs @@ -0,0 +1,89 @@ +#DESCRIPTION:Filesystem stress tests +gf01 growfiles -W gf01 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 -f glseek20 -S 2 -d $TMPDIR +gf02 growfiles -W gf02 -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_ -d $TMPDIR +gf03 growfiles -W gf03 -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_ -d $TMPDIR +gf04 growfiles -W gf04 -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_ -d $TMPDIR +gf05 growfiles -W gf05 -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_ -d $TMPDIR +gf06 growfiles -W gf06 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -f g_rand10 -S 2 -d $TMPDIR +gf07 growfiles -W gf07 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p -f g_rand13 -S 2 -d $TMPDIR +gf08 growfiles -W gf08 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -f g_rand11 -S 2 -d $TMPDIR +gf09 growfiles -W gf09 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p -f g_rand12 -S 2 -d $TMPDIR +gf10 growfiles -W gf10 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l -f g_lio14 -S 2 -d $TMPDIR +gf11 growfiles -W gf11 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L -f g_lio15 -S 2 -d $TMPDIR +gf12 mkfifo $TMPDIR/gffifo17; growfiles -b -W gf12 -e 1 -u -i 0 -L 30 $TMPDIR/gffifo17 +gf13 mkfifo $TMPDIR/gffifo18; growfiles -b -W gf13 -e 1 -u -i 0 -L 30 -I r -r 1-4096 $TMPDIR/gffifo18 +gf14 growfiles -W gf14 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 -f glseek19 -S 2 -d $TMPDIR +gf15 growfiles -W gf15 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 -f Lgfile1 -d $TMPDIR +gf16 growfiles -W gf16 -b -e 1 -i 0 -L 120 -u -g 4090 -T 101 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_ -d $TMPDIR +gf17 growfiles -W gf17 -b -e 1 -i 0 -L 120 -u -g 5000 -T 101 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_ -d $TMPDIR +gf18 growfiles -W gf18 -b -e 1 -i 0 -L 120 -w -u -r 10-5000 -I r -l -S 2 -f Lgf04_ -d $TMPDIR +gf19 growfiles -W gf19 -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_ -d $TMPDIR +gf20 growfiles -W gf20 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 -f gfbigio-$$ -d $TMPDIR +gf21 growfiles -W gf21 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 -f gf-bld-$$ -d $TMPDIR +gf22 growfiles -W gf22 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 -f gf-bldf-$$ -d $TMPDIR +gf23 growfiles -W gf23 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 -f gf-inf-$$ -d $TMPDIR +gf24 growfiles -W gf24 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -f gf-jbld-$$ -d $TMPDIR +gf25 growfiles -W gf25 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 -f gf-large-gs-$$ -d $TMPDIR +gf26 growfiles -W gf26 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 -f gfsmallio-$$ -d $TMPDIR +gf27 growfiles -W gf27 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u -f gfsparse-1-$$ -d $TMPDIR +gf28 growfiles -W gf28 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u -f gfsparse-2-$$ -d $TMPDIR +gf29 growfiles -W gf29 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u -f gfsparse-3-$$ -d $TMPDIR +gf30 growfiles -W gf30 -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 -f gf-sync-$$ -d $TMPDIR +rwtest01 export LTPROOT; rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:$TMPDIR/rw-sync-$$ +rwtest02 export LTPROOT; rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:$TMPDIR/rw-buffered-$$ +rwtest03 export LTPROOT; rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:$TMPDIR/mm-buff-$$ +rwtest04 export LTPROOT; rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:$TMPDIR/mm-sync-$$ +rwtest05 export LTPROOT; rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:$TMPDIR/rwtest01%f + +#must be run as root +#iogen01 iogen -i 120s -s read,write 500b:doio.f1.$$ 1000b:doio.f2.$$ | doio -akv -n 2 +iogen01 export LTPROOT; rwtest -N iogen01 -i 120s -s read,write -Da -Dv -n 2 500b:$TMPDIR/doio.f1.$$ 1000b:$TMPDIR/doio.f2.$$ + +fs_inod01 fs_inod $TMPDIR 10 10 10 +linker01 linktest.sh +openfile01 openfile -f10 -t10 +inode01 inode01 +inode02 inode02 +stream01 stream01 +stream02 stream02 +stream03 stream03 +stream04 stream04 +stream05 stream05 +ftest01 ftest01 +ftest02 ftest02 +ftest03 ftest03 +ftest04 ftest04 +ftest05 ftest05 +ftest06 ftest06 +ftest07 ftest07 +ftest08 ftest08 + +lftest01 lftest +writetest01 writetest + +#Also run the fs_di (Data Integrity tests) +fs_di fs_di -d $TMPDIR + +# Read every file in /proc. Not likely to crash, but does enough +# to disturb the kernel. A good kernel latency killer too. +# 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 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 + +#Run the Quota Remount Test introduced in linux-2.6.26 +quota_remount_test01 quota_remount_test01.sh + +isofs isofs.sh + +fs_fill fs_fill + +binfmt_misc01 binfmt_misc01.sh +binfmt_misc02 binfmt_misc02.sh + +squashfs01 squashfs01 diff --git a/ltp/runtest/fs_bind b/ltp/runtest/fs_bind new file mode 100644 index 0000000000000000000000000000000000000000..61b3e76283f32f615404b4c9708e2eae05f5b135 --- /dev/null +++ b/ltp/runtest/fs_bind @@ -0,0 +1,105 @@ +#DESCRIPTION:Bind mounts and shared subtrees + +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/ltp/runtest/fs_perms_simple b/ltp/runtest/fs_perms_simple new file mode 100644 index 0000000000000000000000000000000000000000..b2dc7204ce1bb5965a78f131db978c2c0f63ee5d --- /dev/null +++ b/ltp/runtest/fs_perms_simple @@ -0,0 +1,26 @@ +# +# These tests are setting file permissions/group/uid and are trying to +# open/write/execute the file. +# +# fs_perms file_mode file_uid file_gid test_uid test_gid mode (r|w|x) expected_result + +# We are executing shell script, thuss +# both exec and read right is needed. +fs_perms01 fs_perms 005 99 99 12 100 x 0 +fs_perms02 fs_perms 050 99 99 200 99 x 0 +fs_perms03 fs_perms 500 99 99 99 500 x 0 +fs_perms04 fs_perms 002 99 99 12 100 w 0 +fs_perms05 fs_perms 020 99 99 200 99 w 0 +fs_perms06 fs_perms 200 99 99 99 500 w 0 +fs_perms07 fs_perms 004 99 99 12 100 r 0 +fs_perms08 fs_perms 040 99 99 200 99 r 0 +fs_perms09 fs_perms 400 99 99 99 500 r 0 +fs_perms10 fs_perms 000 99 99 99 99 r 1 +fs_perms11 fs_perms 000 99 99 99 99 w 1 +fs_perms12 fs_perms 000 99 99 99 99 x 1 +fs_perms13 fs_perms 010 99 99 99 500 x 1 +fs_perms14 fs_perms 100 99 99 200 99 x 1 +fs_perms15 fs_perms 020 99 99 99 500 w 1 +fs_perms16 fs_perms 200 99 99 200 99 w 1 +fs_perms17 fs_perms 040 99 99 99 500 r 1 +fs_perms18 fs_perms 400 99 99 200 99 r 1 diff --git a/ltp/runtest/fs_readonly b/ltp/runtest/fs_readonly new file mode 100644 index 0000000000000000000000000000000000000000..dc70d28d8ad3b99d18dac022650b4e455fe0b954 --- /dev/null +++ b/ltp/runtest/fs_readonly @@ -0,0 +1,55 @@ +test_robind01 test_robind.sh -c "growfiles -W gf01 -b -e 1 -u -i 0 -L 5 -w -C 1 -l -I r -T 10 glseek20 glseek20.2" +test_robind02 test_robind.sh -c "growfiles -W gf02 -b -e 1 -L 10 -i 100 -I p -S 2 -u -f gf03_" +test_robind03 test_robind.sh -c "growfiles -W gf03 -b -e 1 -g 1 -i 1 -S 150 -u -f gf05_" +test_robind04 test_robind.sh -c "growfiles -W gf04 -b -e 1 -g 4090 -i 500 -t 39000 -u -f gf06_" +test_robind05 test_robind.sh -c "growfiles -W gf05 -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -u -f gf07_" +test_robind06 test_robind.sh -c "growfiles -W gf06 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 3 -C 1 g_rand10 g_rand10.2" +test_robind07 test_robind.sh -c "growfiles -W gf07 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 3 -C 1 -I p g_rand13 g_rand13.2" +test_robind08 test_robind.sh -c "growfiles -W gf08 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 3 -C 1 g_rand11 g_rand11.2" +test_robind09 test_robind.sh -c "growfiles -W gf09 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 3 -C 1 -I p g_rand12 g_rand12.2" +test_robind10 test_robind.sh -c "growfiles -W gf10 -b -e 1 -u -r 1-5000 -i 0 -L 3 -C 1 -I l g_lio14 g_lio14.2" +test_robind11 test_robind.sh -c "growfiles -W gf11 -b -e 1 -u -r 1-5000 -i 0 -L 3 -C 1 -I L g_lio15 g_lio15.2" +test_robind12 test_robind.sh -c "mkfifo gffifo17; growfiles -b -W gf12 -e 1 -u -i 0 -L 3 gffifo17" +test_robind13 test_robind.sh -c "mkfifo gffifo18; growfiles -b -W gf13 -e 1 -u -i 0 -L 3 -I r -r 1-4096 gffifo18" +test_robind14 test_robind.sh -c "growfiles -W gf14 -b -e 1 -u -i 0 -L 2 -w -l -C 1 -T 10 glseek19 glseek19.2" +test_robind15 test_robind.sh -c "growfiles -W gf15 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 3 Lgfile1" +test_robind16 test_robind.sh -c "growfiles -W gf16 -b -e 1 -i 0 -L 3 -u -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -S 10 -f Lgf02_" +test_robind17 test_robind.sh -c "growfiles -W gf17 -b -e 1 -i 0 -L 3 -u -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -S 10 -f Lgf03_" +test_robind18 test_robind.sh -c "growfiles -W gf18 -b -e 1 -i 0 -L 3 -w -u -r 10-5000 -I r -l -S 2 -f Lgf04_" +test_robind19 test_robind.sh -c "growfiles -W gf19 -b -e 1 -g 5000 -i 500 -t 49900 -T10 -c9 -I p -o O_RDWR,O_CREAT,O_TRUNC -u -f gf08i_" +test_robind20 test_robind.sh -c "growfiles -W gf20 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 gfbigio-$$" +test_robind21 test_robind.sh -c "growfiles -W gf21 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bld-$$" +test_robind22 test_robind.sh -c "growfiles -W gf22 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bldf-$$" +test_robind23 test_robind.sh -c "growfiles -W gf23 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 gf-inf-$$" +test_robind24 test_robind.sh -c "growfiles -W gf24 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 gf-jbld-$$" +test_robind25 test_robind.sh -c "growfiles -W gf25 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 gf-large-gs-$$" +test_robind26 test_robind.sh -c "growfiles -W gf26 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 gfsmallio-$$" +test_robind27 test_robind.sh -c "growfiles -W gf27 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u gfsparse-1-$$" +test_robind28 test_robind.sh -c "growfiles -W gf28 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u gfsparse-2-$$" +test_robind29 test_robind.sh -c "growfiles -W gf29 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u gfsparse-3-$$" +test_robind30 test_robind.sh -c "growfiles -W gf30 -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-$$" +test_robind31 test_robind.sh -c "rwtest -N rwtest01 -c -q -i 60s -f sync 10%25000:rw-sync-$$" +test_robind32 test_robind.sh -c "rwtest -N rwtest02 -c -q -i 60s -f buffered 10%25000:rw-buffered-$$" +test_robind33 test_robind.sh -c "rwtest -N rwtest03 -c -q -i 60s -n 2 -f buffered -s mmread,mmwrite -m random -Dv 10%25000:mm-buff-$$" +test_robind34 test_robind.sh -c "rwtest -N rwtest04 -c -q -i 60s -n 2 -f sync -s mmread,mmwrite -m random -Dv 10%25000:mm-sync-$$" +test_robind35 test_robind.sh -c "rwtest -N rwtest05 -c -q -i 50 -T 64b 500b:rwtest01%f" +test_robind36 test_robind.sh -c "rwtest -N iogen01 -i 120s -s read,write -Da -Dv -n 2 500b:doio.f1.$$ 1000b:doio.f2.$$" +test_robind37 test_robind.sh -c "fs_inod . 10 10 1" +test_robind38 test_robind.sh -c "openfile -f10 -t10" +test_robind39 test_robind.sh -c "inode01" +test_robind40 test_robind.sh -c "inode02" +test_robind41 test_robind.sh -c "stream01" +test_robind42 test_robind.sh -c "stream02" +test_robind43 test_robind.sh -c "stream03" +test_robind44 test_robind.sh -c "stream04" +test_robind45 test_robind.sh -c "stream05" +test_robind46 test_robind.sh -c "ftest01" +test_robind47 test_robind.sh -c "ftest02" +test_robind48 test_robind.sh -c "ftest03" +test_robind49 test_robind.sh -c "ftest04" +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 -n 80" +test_robind55 test_robind.sh -c "writetest" diff --git a/ltp/runtest/hugetlb b/ltp/runtest/hugetlb new file mode 100644 index 0000000000000000000000000000000000000000..0896d3c941f068628f53c31197b293906c4ecba6 --- /dev/null +++ b/ltp/runtest/hugetlb @@ -0,0 +1,59 @@ +hugefallocate01 hugefallocate01 +hugefallocate02 hugefallocate02 + +hugefork01 hugefork01 +hugefork02 hugefork02 + +hugemmap01 hugemmap01 +hugemmap02 hugemmap02 +hugemmap04 hugemmap04 +hugemmap05 hugemmap05 +hugemmap06 hugemmap06 +hugemmap07 hugemmap07 +hugemmap08 hugemmap08 +hugemmap09 hugemmap09 +hugemmap10 hugemmap10 +hugemmap11 hugemmap11 +hugemmap12 hugemmap12 +hugemmap13 hugemmap13 +hugemmap14 hugemmap14 +hugemmap15 hugemmap15 +hugemmap16 hugemmap16 +hugemmap17 hugemmap17 +hugemmap18 hugemmap18 +hugemmap19 hugemmap19 +hugemmap20 hugemmap20 +hugemmap21 hugemmap21 +hugemmap22 hugemmap22 +hugemmap23 hugemmap23 +hugemmap24 hugemmap24 +hugemmap25 hugemmap25 +hugemmap26 hugemmap26 +hugemmap27 hugemmap27 +hugemmap28 hugemmap28 +hugemmap29 hugemmap29 +hugemmap30 hugemmap30 +hugemmap31 hugemmap31 +hugemmap32 hugemmap32 +hugemmap34 hugemmap34 +hugemmap05_1 hugemmap05 -m +hugemmap05_2 hugemmap05 -s +hugemmap05_3 hugemmap05 -s -m + +hugeshmat01 hugeshmat01 -i 5 +hugeshmat02 hugeshmat02 -i 5 +hugeshmat03 hugeshmat03 -i 5 +hugeshmat04 hugeshmat04 -i 5 +hugeshmat05 hugeshmat05 -i 5 + +hugeshmctl01 hugeshmctl01 -i 5 +hugeshmctl02 hugeshmctl02 -i 5 +hugeshmctl03 hugeshmctl03 -i 5 + +hugeshmdt01 hugeshmdt01 -i 5 + +hugeshmget01 hugeshmget01 -i 10 +hugeshmget02 hugeshmget02 -i 10 +hugeshmget03 hugeshmget03 -i 10 +hugeshmget05 hugeshmget05 -i 10 +hugeshmget06 hugeshmget06 -i 10 diff --git a/ltp/runtest/hyperthreading b/ltp/runtest/hyperthreading new file mode 100644 index 0000000000000000000000000000000000000000..8c89cd48e0dbd185e642eed2be74b8023241d763 --- /dev/null +++ b/ltp/runtest/hyperthreading @@ -0,0 +1,4 @@ +#DESCRIPTION:Hyperthreading stress tests +smt_smp_enabled smt_smp_enabled.sh +smt_smp_affinity smt_smp_affinity.sh + diff --git a/ltp/runtest/ima b/ltp/runtest/ima new file mode 100644 index 0000000000000000000000000000000000000000..01942eefa36399cc29663e500593197ead224aeb --- /dev/null +++ b/ltp/runtest/ima @@ -0,0 +1,10 @@ +#DESCRIPTION:Integrity Measurement Architecture (IMA) +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/ltp/runtest/input b/ltp/runtest/input new file mode 100644 index 0000000000000000000000000000000000000000..775338cd10f0afe3c50a603853fdce68472d02ec --- /dev/null +++ b/ltp/runtest/input @@ -0,0 +1,6 @@ +input01 input01 +input02 input02 +input03 input03 +input04 input04 +input05 input05 +input06 input06 diff --git a/ltp/runtest/irq b/ltp/runtest/irq new file mode 100644 index 0000000000000000000000000000000000000000..56d0d23c87b156acab19b901400a8bfb0f469bf3 --- /dev/null +++ b/ltp/runtest/irq @@ -0,0 +1 @@ +irqbalance01 irqbalance01 diff --git a/ltp/runtest/kernel_misc b/ltp/runtest/kernel_misc new file mode 100644 index 0000000000000000000000000000000000000000..78f00d305fea10367fb4fd2845f25dd151a833ea --- /dev/null +++ b/ltp/runtest/kernel_misc @@ -0,0 +1,18 @@ +cn_pec_sh cn_pec.sh +kmsg01 kmsg01 +fw_load fw_load +rtc01 rtc01 +rtc02 rtc02 +block_dev block_dev +tpci tpci +tbio tbio +ltp_acpi ltp_acpi +cpufreq_boost cpufreq_boost +uaccess uaccess +rcu_torture rcu_torture.sh +lock_torture lock_torture.sh +zram01 zram01.sh +zram02 zram02.sh +zram03 zram03 +umip_basic_test umip_basic_test +aslr01 aslr01 diff --git a/ltp/runtest/kvm b/ltp/runtest/kvm new file mode 100644 index 0000000000000000000000000000000000000000..5c285e6565cc0baa7a017a6d25d5dc9f9476de2a --- /dev/null +++ b/ltp/runtest/kvm @@ -0,0 +1,8 @@ +kvm_svm01 kvm_svm01 +kvm_svm02 kvm_svm02 +kvm_svm03 kvm_svm03 +kvm_svm04 kvm_svm04 +kvm_vmx01 kvm_vmx01 +kvm_vmx02 kvm_vmx02 +# Tests below may interfere with bug reproducibility +kvm_pagefault01 kvm_pagefault01 diff --git a/ltp/runtest/ltp-aio-stress b/ltp/runtest/ltp-aio-stress new file mode 100644 index 0000000000000000000000000000000000000000..1de49b40635692bb65504fb14c2091295d52d47c --- /dev/null +++ b/ltp/runtest/ltp-aio-stress @@ -0,0 +1,55 @@ +# ltp A-sync IO Stress IO tests +ADS1000 aio-stress -o2 -r4k -f1 +ADS1001 aio-stress -o2 -r8k -f1 +ADS1002 aio-stress -o2 -r16k -f1 +ADS1003 aio-stress -o2 -r32k -t2 -f2 +ADS1004 aio-stress -o2 -r64k -f2 +ADS1005 aio-stress -o3 -r4k -f2 +ADS1006 aio-stress -o3 -r8k -f2 +ADS1007 aio-stress -o3 -r16k -f2 +ADS1008 aio-stress -o3 -r32k -f4 +ADS1009 aio-stress -o3 -r64k -t4 -f4 +ADS1010 aio-stress -o3 -r128k -t4 -f4 +ADS1011 aio-stress -o3 -r256k -t8 -f8 +ADS1012 aio-stress -o3 -r512k -t8 -f8 +ADS1013 aio-stress -o2 -O -r4k -t8 -f8 +ADS1014 aio-stress -o2 -O -r8k -f2 +ADS1015 aio-stress -o2 -O -r16k -f2 +ADS1016 aio-stress -o2 -O -r32k -t2 -f2 +ADS1017 aio-stress -o2 -O -r64k -t2 -f2 +ADS1018 aio-stress -o3 -O -r4k -t2 -f2 +ADS1019 aio-stress -o3 -O -r8k -t2 -f2 +ADS1020 aio-stress -o3 -O -r16k -t2 -f2 +ADS1021 aio-stress -o3 -O -r32k -t4 -f4 +ADS1022 aio-stress -o3 -O -r64k -t4 -f4 +ADS1023 aio-stress -o3 -O -r128k -t4 -f4 +ADS1024 aio-stress -o3 -O -r256k -t8 -f8 +ADS1025 aio-stress -o3 -O -r512k -t8 -f8 +ADS1026 aio-stress -o0 -r4k -t8 -f8 +ADS1027 aio-stress -o0 -r8k -f1 +ADS1028 aio-stress -o0 -r16k -f1 +ADS1029 aio-stress -o0 -r32k -t2 -f2 +ADS1030 aio-stress -o0 -r64k -t2 -f2 +ADS1031 aio-stress -o1 -r4k -t2 -f1 +ADS1032 aio-stress -o1 -r8k -t2 -f1 +ADS1033 aio-stress -o1 -r16k -t2 -f2 +ADS1034 aio-stress -o1 -r32k -t4 -f4 +ADS1035 aio-stress -o1 -r64k -t4 -f4 +ADS1036 aio-stress -o1 -r128k -t4 -f4 +ADS1037 aio-stress -o1 -r256k -t8 -f8 +ADS1038 aio-stress -o1 -r512k -t8 -f8 +ADS1039 aio-stress -o1 -O -r4k -t8 -f8 +ADS1040 aio-stress -o1 -O -r8k -t2 -f2 +ADS1041 aio-stress -o1 -O -r16k -t2 -f2 +ADS1042 aio-stress -o1 -O -r32k -t2 -f2 +ADS1043 aio-stress -o1 -O -r64k -t2 -f2 +ADS1044 aio-stress -o1 -O -r4k -t4 -f4 +ADS1045 aio-stress -o1 -O -r8k -t4 -f4 +ADS1046 aio-stress -o1 -O -r16k -t4 -f4 +ADS1047 aio-stress -o1 -O -r32k -t8 -f8 +ADS1048 aio-stress -o1 -O -r64k -t8 -f8 +ADS1049 aio-stress -o1 -O -r128k -t8 -f8 +ADS1050 aio-stress -o1 -O -r256k -t2 -f2 +ADS1051 aio-stress -o3 -r8k -t2 -f2 +ADS1052 aio-stress -o3 -r16k -t2 -f2 +ADS1053 aio-stress -o3 -r32k -t4 -f4 diff --git a/ltp/runtest/ltp-aiodio.part1 b/ltp/runtest/ltp-aiodio.part1 new file mode 100644 index 0000000000000000000000000000000000000000..dd597b7de914a865c57ea3dde022767bed3502ab --- /dev/null +++ b/ltp/runtest/ltp-aiodio.part1 @@ -0,0 +1,142 @@ +#DESCRIPTION:ltp A-sync IO and Direct IO tests +# +AD001 aiocp -b 1k -n 1 -f DIRECT +AD002 aiocp -b 1k -n 1 -f SYNC +AD003 aiocp -b 1k -n 2 -f DIRECT +AD004 aiocp -b 1k -n 2 -f SYNC +AD005 aiocp -b 1k -n 4 -f DIRECT +AD006 aiocp -b 1k -n 4 -f SYNC +AD007 aiocp -b 1k -n 8 -f DIRECT +AD008 aiocp -b 1k -n 8 -f SYNC +AD009 aiocp -b 1k -n 16 -f DIRECT +AD010 aiocp -b 1k -n 16 -f SYNC +AD011 aiocp -b 1k -n 32 -f DIRECT +AD012 aiocp -b 1k -n 32 -f SYNC +AD013 aiocp -b 1k -n 64 -f DIRECT +AD014 aiocp -b 1k -n 64 -f SYNC +AD015 aiocp -b 2k -n 1 -f DIRECT +AD016 aiocp -b 2k -n 1 -f SYNC +AD017 aiocp -b 2k -n 2 -f DIRECT +AD018 aiocp -b 2k -n 2 -f SYNC +AD019 aiocp -b 2k -n 4 -f DIRECT +AD020 aiocp -b 2k -n 4 -f SYNC +AD021 aiocp -b 2k -n 8 -f DIRECT +AD022 aiocp -b 2k -n 8 -f SYNC +AD023 aiocp -b 2k -n 16 -f DIRECT +AD024 aiocp -b 2k -n 16 -f SYNC +AD025 aiocp -b 2k -n 32 -f DIRECT +AD026 aiocp -b 2k -n 32 -f SYNC +AD027 aiocp -b 2k -n 64 -f DIRECT +AD028 aiocp -b 2k -n 64 -f SYNC +AD029 aiocp -b 4k -n 1 -f DIRECT +AD030 aiocp -b 4k -n 1 -f SYNC +AD031 aiocp -b 4k -n 2 -f DIRECT +AD032 aiocp -b 4k -n 2 -f SYNC +AD033 aiocp -b 4k -n 4 -f DIRECT +AD034 aiocp -b 4k -n 4 -f SYNC +AD035 aiocp -b 4k -n 8 -f DIRECT +AD036 aiocp -b 4k -n 8 -f SYNC +AD037 aiocp -b 4k -n 16 -f DIRECT +AD038 aiocp -b 4k -n 16 -f SYNC +AD039 aiocp -b 4k -n 32 -f DIRECT +AD040 aiocp -b 4k -n 32 -f SYNC +AD041 aiocp -b 4k -n 64 -f DIRECT +AD042 aiocp -b 4k -n 64 -f SYNC +AD043 aiocp -b 8k -n 1 -f DIRECT +AD044 aiocp -b 8k -n 1 -f SYNC +AD045 aiocp -b 8k -n 2 -f DIRECT +AD046 aiocp -b 8k -n 2 -f SYNC +AD047 aiocp -b 8k -n 4 -f DIRECT +AD048 aiocp -b 8k -n 4 -f SYNC +AD049 aiocp -b 8k -n 8 -f DIRECT +AD050 aiocp -b 8k -n 8 -f SYNC +AD051 aiocp -b 8k -n 16 -f DIRECT +AD052 aiocp -b 8k -n 16 -f SYNC +AD053 aiocp -b 8k -n 32 -f DIRECT +AD054 aiocp -b 8k -n 32 -f SYNC +AD055 aiocp -b 8k -n 64 -f DIRECT +AD056 aiocp -b 8k -n 64 -f SYNC +AD057 aiocp -b 16k -n 1 -f DIRECT +AD058 aiocp -b 16k -n 1 -f SYNC +AD059 aiocp -b 16k -n 2 -f DIRECT +AD060 aiocp -b 16k -n 2 -f SYNC +AD061 aiocp -b 16k -n 4 -f DIRECT +AD062 aiocp -b 16k -n 4 -f SYNC +AD063 aiocp -b 16k -n 8 -f DIRECT +AD064 aiocp -b 16k -n 8 -f SYNC +AD065 aiocp -b 16k -n 16 -f DIRECT +AD066 aiocp -b 16k -n 16 -f SYNC +AD067 aiocp -b 16k -n 32 -f DIRECT +AD068 aiocp -b 16k -n 32 -f SYNC +AD069 aiocp -b 16k -n 64 -f DIRECT +AD070 aiocp -b 16k -n 64 -f SYNC +AD071 aiocp -b 32k -n 1 -f DIRECT +AD072 aiocp -b 32k -n 1 -f SYNC +AD073 aiocp -b 32k -n 2 -f DIRECT +AD074 aiocp -b 32k -n 2 -f SYNC +AD075 aiocp -b 32k -n 4 -f DIRECT +AD076 aiocp -b 32k -n 4 -f SYNC +AD077 aiocp -b 32k -n 8 -f DIRECT +AD078 aiocp -b 32k -n 8 -f SYNC +AD079 aiocp -b 32k -n 16 -f DIRECT +AD080 aiocp -b 32k -n 16 -f SYNC +AD081 aiocp -b 32k -n 32 -f DIRECT +AD082 aiocp -b 32k -n 32 -f SYNC +AD083 aiocp -b 32k -n 64 -f DIRECT +AD084 aiocp -b 32k -n 64 -f SYNC +AD085 aiocp -b 64k -n 1 -f DIRECT +AD086 aiocp -b 64k -n 1 -f SYNC +AD087 aiocp -b 64k -n 2 -f DIRECT +AD088 aiocp -b 64k -n 2 -f SYNC +AD089 aiocp -b 64k -n 4 -f DIRECT +AD090 aiocp -b 64k -n 4 -f SYNC +AD091 aiocp -b 64k -n 8 -f DIRECT +AD092 aiocp -b 64k -n 8 -f SYNC +AD093 aiocp -b 64k -n 16 -f DIRECT +AD094 aiocp -b 64k -n 16 -f SYNC +AD095 aiocp -b 64k -n 32 -f DIRECT +AD096 aiocp -b 64k -n 32 -f SYNC +AD097 aiocp -b 64k -n 64 -f DIRECT +AD098 aiocp -b 64k -n 64 -f SYNC +AD099 aiocp -b 128k -n 1 -f DIRECT +AD100 aiocp -b 128k -n 1 -f SYNC +AD101 aiocp -b 128k -n 2 -f DIRECT +AD102 aiocp -b 128k -n 2 -f SYNC +AD103 aiocp -b 128k -n 4 -f DIRECT +AD104 aiocp -b 128k -n 4 -f SYNC +AD105 aiocp -b 128k -n 8 -f DIRECT +AD106 aiocp -b 128k -n 8 -f SYNC +AD107 aiocp -b 128k -n 16 -f DIRECT +AD108 aiocp -b 128k -n 16 -f SYNC +AD109 aiocp -b 128k -n 32 -f DIRECT +AD110 aiocp -b 128k -n 32 -f SYNC +AD111 aiocp -b 128k -n 64 -f DIRECT +AD112 aiocp -b 128k -n 64 -f SYNC +AD113 aiocp -b 256k -n 1 -f DIRECT +AD114 aiocp -b 256k -n 1 -f SYNC +AD115 aiocp -b 256k -n 2 -f DIRECT +AD116 aiocp -b 256k -n 2 -f SYNC +AD117 aiocp -b 256k -n 4 -f DIRECT +AD118 aiocp -b 256k -n 4 -f SYNC +AD119 aiocp -b 256k -n 8 -f DIRECT +AD120 aiocp -b 256k -n 8 -f SYNC +AD121 aiocp -b 256k -n 16 -f DIRECT +AD122 aiocp -b 256k -n 16 -f SYNC +AD123 aiocp -b 256k -n 32 -f DIRECT +AD124 aiocp -b 256k -n 32 -f SYNC +AD125 aiocp -b 256k -n 64 -f DIRECT +AD126 aiocp -b 256k -n 64 -f SYNC +AD127 aiocp -b 512k -n 1 -f DIRECT +AD128 aiocp -b 512k -n 1 -f SYNC +AD129 aiocp -b 512k -n 2 -f DIRECT +AD130 aiocp -b 512k -n 2 -f SYNC +AD131 aiocp -b 512k -n 4 -f DIRECT +AD132 aiocp -b 512k -n 4 -f SYNC +AD133 aiocp -b 512k -n 8 -f DIRECT +AD134 aiocp -b 512k -n 8 -f SYNC +AD135 aiocp -b 512k -n 16 -f DIRECT +AD136 aiocp -b 512k -n 16 -f SYNC +AD137 aiocp -b 512k -n 32 -f DIRECT +AD138 aiocp -b 512k -n 32 -f SYNC +AD139 aiocp -b 512k -n 64 -f DIRECT +AD140 aiocp -b 512k -n 64 -f SYNC diff --git a/ltp/runtest/ltp-aiodio.part2 b/ltp/runtest/ltp-aiodio.part2 new file mode 100644 index 0000000000000000000000000000000000000000..599c9fd2f53b14b1c29cf558f69e4a92ce0e64ea --- /dev/null +++ b/ltp/runtest/ltp-aiodio.part2 @@ -0,0 +1,83 @@ +ADSP000 aiodio_sparse +ADSP001 aiodio_sparse -s 180k +ADSP002 aiodio_sparse -s 1751k -w 11k +ADSP003 aiodio_sparse -o 9 -s 180k -w 18k +ADSP004 aiodio_sparse -o 2 -w 2k -s 4k -n 2 +ADSP005 aiodio_sparse -o 2 -w 4k -s 8k -n 2 +ADSP006 aiodio_sparse -o 4 -w 8k -s 32k -n 2 +ADSP007 aiodio_sparse -o 4 -w 16k -s 64k -n 2 +ADSP008 aiodio_sparse -o 4 -w 32k -s 128k -n 2 +ADSP009 aiodio_sparse -o 4 -w 64k -s 256k -n 2 +ADSP010 aiodio_sparse -o 4 -w 128k -s 512k -n 2 +ADSP011 aiodio_sparse -o 4 -w 256k -s 1024k -n 2 +ADSP012 aiodio_sparse -o 4 -w 512k -s 2048k -n 2 +ADSP013 aiodio_sparse -o 4 -w 1024k -s 4096k -n 2 +ADSP014 aiodio_sparse -o 4 -w 2048k -s 8192k -n 2 +ADSP015 aiodio_sparse -o 4 -w 4096k -s 16384k -n 2 +ADSP016 aiodio_sparse -o 4 -w 8192k -s 32768k -n 2 +ADSP017 aiodio_sparse -o 4 -w 16384k -s 65536k -n 2 +ADSP018 aiodio_sparse -o 4 -w 16384k -s 65536k -n 4 +ADSP019 aiodio_sparse -o 4 -w 16384k -s 65536k -n 6 +ADSP020 aiodio_sparse -o 4 -w 128k -s 512k -n 6 +ADSP021 aiodio_sparse -o 4 -w 256k -s 1024k -n 6 +ADSP022 aiodio_sparse -o 4 -w 512k -s 2048k -n 6 +ADSP023 aiodio_sparse -o 4 -w 1024k -s 4096k -n 6 +ADSP024 aiodio_sparse -o 4 -w 2048k -s 8192k -n 6 +ADSP025 aiodio_sparse -o 4 -w 4096k -s 16384k -n 6 +ADSP026 aiodio_sparse -o 4 -w 18192k -s 72768k -n 6 +ADSP027 aiodio_sparse -o 4 -w 18192k -s 518192k -n 6 +ADSP028 aiodio_sparse -o 4 -w 65536k -s 262144k -n 6 +ADSP029 aiodio_sparse -o 6 -w 65536k -n 6 +ADSP030 aiodio_sparse -o 8 -w 128k -s 1024k -n 6 +ADSP031 aiodio_sparse -o 16 -w 256k -s 4096k -n 6 +ADSP032 aiodio_sparse -o 32 -w 512k -s 16384k -n 6 +ADSP033 aiodio_sparse -o 64 -w 1024k -s 65536k -n 6 +ADSP034 aiodio_sparse -o 4 -w 4096k -s 16384k -n 32 +ADSP035 aiodio_sparse -o 4 -w 4096k -s 16384k -n 64 +ADSP036 aiodio_sparse -o 4 -w 18192k -s 72768k -n 128 +ADSP037 aiodio_sparse -o 4 -w 18192k -n 512 +ADSP038 aiodio_sparse -o 4 -w 18192k -n 1000 +ADSP039 dio_sparse +ADSP040 dio_sparse -s 180k +ADSP041 dio_sparse -s 1751k -w 11k +ADSP042 dio_sparse -s 180k -w 18k +ADSP043 dio_sparse -w 2k -s 2k -n 2 +ADSP044 dio_sparse -w 4k -s 2k -n 2 +ADSP045 dio_sparse -w 4k -s 4k -n 2 +ADSP046 dio_sparse -w 16k -s 16k -n 2 +ADSP047 dio_sparse -w 32k -s 32k -n 2 +ADSP048 dio_sparse -w 64k -s 64k -n 2 +ADSP049 dio_sparse -w 128k -s 128k -n 2 +ADSP050 dio_sparse -w 256k -s 256k -n 2 +ADSP051 dio_sparse -w 512k -s 512k -n 2 +ADSP052 dio_sparse -w 1024k -s 1024k -n 2 +ADSP053 dio_sparse -w 2048k -s 2048k -n 2 +ADSP054 dio_sparse -w 4096k -s 4096k -n 2 +ADSP055 dio_sparse -w 8192k -s 8192k -n 2 +ADSP056 dio_sparse -w 18192k -s 18192k -n 2 +ADSP057 dio_sparse -w 518192k -s 518192k -n 2 +ADSP058 dio_sparse -w 58192k -s 58192k -n 4 +ADSP059 dio_sparse -w 58192k -s 58192k -n 6 +ADSP060 dio_sparse -w 256k -s 256k -n 6 +ADSP061 dio_sparse -w 512k -s 512k -n 6 +ADSP062 dio_sparse -w 1024k -s 1024k -n 6 +ADSP063 dio_sparse -w 2048k -s 2048k -n 6 +ADSP064 dio_sparse -w 2048k -s 4096k -n 6 +ADSP065 dio_sparse -w 8192k -s 8192k -n 6 +ADSP066 dio_sparse -w 18192k -s 18192k -n 6 +ADSP067 dio_sparse -w 58192k -s 518192k -n 6 +ADSP068 dio_sparse -w 518192k -s 518192k -n 6 +ADSP069 dio_sparse -w 1024k -s 2048k -n 6 +ADSP070 dio_sparse -w 4096k -s 4096k -n 32 +ADSP071 dio_sparse -w 8192k -s 8192k -n 64 +ADSP072 dio_sparse -w 518192k -s 18192k -n 128 +ADSP073 dio_sparse -w 518192k -s 518192k -n 512 +ADSP074 dio_sparse -w 518192k -s 518192k -n 1000 +ADSP075 dio_sparse -w 4k -s 2k -o 2k -n 2 +ADSP076 dio_sparse -w 2k -s 1k -o 1k -n 2 +ADSP077 dio_sparse -w 1k -s 512 -o 512 -n 2 +ADSP078 dio_sparse -w 4k -s 2k -o 3k -n 2 +ADSP079 dio_sparse -w 4k -s 4k -o 4k -n 2 +ADSP080 dio_sparse -w 4k -s 4k -o 6k -n 2 +ADSP081 dio_sparse -w 4k -s 4k -o 8k -n 2 +ADSP082 dio_sparse -w 16k -s 8k -o 8k -n 2 diff --git a/ltp/runtest/ltp-aiodio.part3 b/ltp/runtest/ltp-aiodio.part3 new file mode 100644 index 0000000000000000000000000000000000000000..decf2f6ea17198880f97cdf5367b448cc09152f6 --- /dev/null +++ b/ltp/runtest/ltp-aiodio.part3 @@ -0,0 +1,21 @@ +fsx01 fsx-linux -l 500000 -r 4096 -t 4096 -w 4096 -N 10000 +fsx02 fsx-linux -l 500000 -r 4096 -t 2048 -w 2048 -N 10000 +fsx03 fsx-linux -l 500000 -r 4096 -N 10000 +fsx04 fsx-linux -N 10000 +fsx05 fsx-linux -N 10000 -o 1024 +fsx06 fsx-linux -N 10000 -o 2048 +fsx07 fsx-linux -N 10000 -o 4096 +fsx08 fsx-linux -N 10000 -o 8192 +fsx09 fsx-linux -N 10000 -o 16384 +fsx10 fsx-linux -N 10000 -o 32768 +fsx12 fsx-linux -N 10000 -o 128000 +fsx13 fsx-linux -N 10000 -o 1024 -l 500000 -r 4096 -t 4096 -w 4096 +fsx14 fsx-linux -N 10000 -o 2048 -l 500000 -r 4096 -t 2048 -w 2048 +fsx15 fsx-linux -N 10000 -o 4096 -l 500000 -r 4096 -t 4096 -w 4096 +fsx16 fsx-linux -N 10000 -o 8192 -l 500000 -r 4096 -t 2048 -w 2048 +fsx17 fsx-linux -N 10000 -o 16384 -l 500000 -r 4096 -t 4096 -w 4096 +fsx18 fsx-linux -N 10000 -o 32768 -l 500000 -r 4096 -t 2048 -w 2048 +fsx19 fsx-linux -N 10000 -o 128000 -l 500000 -r 4096 -t 4096 -w 4096 +fsx20 fsx-linux -N 10000 -o 128000 -l 500000 -r 4096 -t 4096 -w 40963 +fsx21 fsx-linux -N 10000 -o 128000 -l 500000 -r 4096 -t 4096 -w 40966 +fsx22 fsx-linux -N 100000 diff --git a/ltp/runtest/ltp-aiodio.part4 b/ltp/runtest/ltp-aiodio.part4 new file mode 100644 index 0000000000000000000000000000000000000000..de00b8a78655c429a223e68f0926c0b6031e7de7 --- /dev/null +++ b/ltp/runtest/ltp-aiodio.part4 @@ -0,0 +1,66 @@ +aio01 aio01 +aio02 aio02 + +#Running dio_sparse & dirty tests +DI000 dirty +DS000 dio_sparse +DI001 dirty +DS001 dio_sparse +DI002 dirty +DS002 dio_sparse +DI003 dirty +DS003 dio_sparse +DI004 dirty +DS004 dio_sparse +DI005 dirty +DS005 dio_sparse +DI006 dirty +DS006 dio_sparse +DI007 dirty +DS007 dio_sparse +DI008 dirty +DS008 dio_sparse +DI009 dirty +DS009 dio_sparse +#iteration on dio_sparse +DIO00 dio_sparse +DIO01 dio_sparse +DIO02 dio_sparse +DIO03 dio_sparse +DIO04 dio_sparse +DIO05 dio_sparse +DIO06 dio_sparse +DIO07 dio_sparse +DIO08 dio_sparse +DIO09 dio_sparse +#Running aiodio_append +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 +ADI002 dio_append +ADI003 dio_append +ADI004 dio_append +ADI005 dio_append +ADI006 dio_append +ADI007 dio_append +ADI008 dio_append +ADI009 dio_append +#Running dio_truncate +DIT000 dio_truncate -n 1 +DIT001 dio_truncate +DIT002 dio_truncate +#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/ltp/runtest/math b/ltp/runtest/math new file mode 100644 index 0000000000000000000000000000000000000000..6915ebe0512ae5627e33feeee268f6d75d4c978b --- /dev/null +++ b/ltp/runtest/math @@ -0,0 +1,15 @@ +#DESCRIPTION:Math library tests - CPU tests +abs01 abs01 + +atof01 atof01 + +float_bessel float_bessel -v +float_exp_log float_exp_log -v +float_iperb float_iperb -v +float_power float_power -v +float_trigo float_trigo -v + +fptest01 fptest01 +fptest02 fptest02 + +nextafter01 nextafter01 diff --git a/ltp/runtest/mm b/ltp/runtest/mm new file mode 100644 index 0000000000000000000000000000000000000000..41d624ad86fc354cc1284bbcee192420a93fa93a --- /dev/null +++ b/ltp/runtest/mm @@ -0,0 +1,100 @@ +#DESCRIPTION:Memory Mgmt tests +mmap21_01 mmap21 -m 10000 +# 40 Mb mmap() test. +# Creates a 10000 page mmap, touches all of the map, sync's it, and +# munmap()s it. +mmap21_02 mmap21 + +mtest01 mtest01 -p80 +mtest01w mtest01 -p80 -w + +#test for race conditions +mtest05 mmstress +mtest06 mmap1 +mtest06_2 mmap2 -a -p +mtest06_3 mmap3 -p +# Remains diabled till the infinite loop problem is solved +#mtest-6_4 shmat1 -x 0.00005 + +mem02 mem02 + +page01 page01 +page02 page02 + +data_space data_space +stack_space stack_space + +shmt02 shmt02 +shmt03 shmt03 +shmt04 shmt04 +shmt05 shmt05 +shmt07 shmt07 +shmt08 shmt08 +shmt09 shmt09 +shmt10 shmt10 + +shm_test01 shm_test -l 10 -t 2 +mallocstress01 mallocstress + +mmapstress01 mmapstress01 +mmapstress02 mmapstress02 +mmapstress03 mmapstress03 +mmapstress04 mmapstress04 +mmapstress05 mmapstress05 +mmapstress06 mmapstress06 20 +mmapstress07 TMPFILE=`mktemp $TMPDIR/example.XXXXXXXXXXXX`; mmapstress07 $TMPFILE +mmapstress08 mmapstress08 +mmapstress09 mmapstress09 -p 20 -t 0.2 +mmapstress10 mmapstress10 -p 20 -t 0.2 + +mmap10 mmap10 +mmap10_1 mmap10 -i 60 + +kallsyms kallsyms + +ksm01 ksm01 +ksm01_1 ksm01 -u 128 +ksm02 ksm02 +ksm02_1 ksm02 -u 128 +ksm03 ksm03 +ksm03_1 ksm03 -u 128 +ksm04 ksm04 +ksm04_1 ksm04 -u 128 +ksm05 ksm05 -I 10 +ksm06 ksm06 +ksm06_1 ksm06 -n 10 +ksm06_2 ksm06 -n 8000 +ksm07 ksm07 + +cpuset01 cpuset01 +cpuset02 cpuset02 + +oom01 oom01 +oom02 oom02 +oom03 oom03 +oom04 oom04 +oom05 oom05 + +swapping01 swapping01 -i 5 + +thp01 thp01 -I 120 +thp02 thp02 +thp03 thp03 +thp04 thp04 + +vma01 vma01 +vma02 vma02 +vma03 vma03 +vma04 vma04 +vma05 vma05.sh + +overcommit_memory01 overcommit_memory +overcommit_memory02 overcommit_memory -R 0 +overcommit_memory03 overcommit_memory -R 30 +overcommit_memory04 overcommit_memory -R 80 +overcommit_memory05 overcommit_memory -R 100 +overcommit_memory06 overcommit_memory -R 200 + +max_map_count max_map_count -i 10 + +min_free_kbytes min_free_kbytes diff --git a/ltp/runtest/net.features b/ltp/runtest/net.features new file mode 100644 index 0000000000000000000000000000000000000000..37c380aaa26fb95b0fead2b9b78f62aff0f82cf0 --- /dev/null +++ b/ltp/runtest/net.features @@ -0,0 +1,91 @@ +# +# Stress tests for various network features +# +bbr01 bbr01.sh +bbr01_ipv6 bbr01.sh -6 + +bbr02 bbr02.sh +bbr02_ipv6 bbr02.sh -6 + +bind_noport01 bind_noport01.sh +bind_noport01_ipv6 bind_noport01.sh -6 + +busy_poll01 busy_poll01.sh +busy_poll01_ipv6 busy_poll01.sh -6 + +busy_poll02 busy_poll02.sh +busy_poll02_ipv6 busy_poll02.sh -6 + +busy_poll03 busy_poll03.sh +busy_poll03_ipv6 busy_poll03.sh -6 + +dccp01 dccp01.sh +dccp01_ipv6 dccp01.sh -6 + +sctp01 sctp01.sh +sctp01_ipv6 sctp01.sh -6 + +tcp_fastopen tcp_fastopen_run.sh +tcp_fastopen6 tcp_fastopen_run.sh -6 + +vxlan01 vxlan01.sh +vxlan02 vxlan02.sh +vxlan02_ipv6 vxlan02.sh -6 + +vxlan_multi_03 vxlan03.sh -d multi +vxlan_uni_03 vxlan03.sh -d uni + +vxlan_ipv6_multi_03 vxlan03.sh -6 -d multi +vxlan_ipv6_uni_03 vxlan03.sh -6 -d uni + +vxlan_uni_04 vxlan04.sh -d uni +vxlan_ipv6_uni_04 vxlan04.sh -6 -d uni + +vlan01 vlan01.sh +vlan02 vlan02.sh +vlan03 vlan03.sh + +macvlan01 macvlan01.sh +macvtap01 macvtap01.sh + +macsec01 macsec01.sh +macsec02 macsec02.sh +macsec03 macsec03.sh + +ipvlan01 ipvlan01.sh + +gre_ipv4_01 gre01.sh +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 + +geneve01 geneve01.sh +geneve01_ipv6 geneve01.sh -6 +geneve02 geneve02.sh +geneve02_ipv6 geneve02.sh -6 + +sit01 sit01.sh + +mpls01 mpls01.sh +mpls02 mpls02.sh +mpls02_ipv6 mpls02.sh -6 +mpls03 mpls03.sh +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/ltp/runtest/net.ipv6 b/ltp/runtest/net.ipv6 new file mode 100644 index 0000000000000000000000000000000000000000..e599978c0137685f6646f16ae73204493d89be4e --- /dev/null +++ b/ltp/runtest/net.ipv6 @@ -0,0 +1,12 @@ +#DESCRIPTION:IPV6 related tests +ping601 ping01.sh -6 +ping602 ping02.sh -6 +sendfile601 sendfile01.sh -6 +tcpdump601 tcpdump01.sh -6 +tracepath601 tracepath01.sh -6 +traceroute601 traceroute01.sh -6 +dhcpd6 dhcpd_tests.sh -6 +dnsmasq6 dnsmasq_tests.sh -6 +ipneigh6_ip ipneigh01.sh -6 -c ip +ip6tables iptables01.sh -6 +nft6 nft01.sh -6 diff --git a/ltp/runtest/net.ipv6_lib b/ltp/runtest/net.ipv6_lib new file mode 100644 index 0000000000000000000000000000000000000000..636232b6e606884f311240c4a248c035348fed7a --- /dev/null +++ b/ltp/runtest/net.ipv6_lib @@ -0,0 +1,7 @@ +#DESCRIPTION:IPV6 related tests +in6_01 in6_01 +in6_02 in6_02 +getaddrinfo_01 getaddrinfo_01 +asapi_01 asapi_01 +asapi_02 asapi_02 +asapi_03 asapi_03 diff --git a/ltp/runtest/net.multicast b/ltp/runtest/net.multicast new file mode 100644 index 0000000000000000000000000000000000000000..14c8e5a125da2ce41bb603fa88207cb4d9b5b0ae --- /dev/null +++ b/ltp/runtest/net.multicast @@ -0,0 +1,8 @@ +#DESCRIPTION:Multicast networking tests +# +# PLEASE READ THE README FILE IN /multicast BEFORE RUNNING THESE. +# +mc_cmds mc_cmds.sh +mc_commo mc_commo.sh +mc_member mc_member.sh +mc_opts mc_opts.sh diff --git a/ltp/runtest/net.nfs b/ltp/runtest/net.nfs new file mode 100644 index 0000000000000000000000000000000000000000..fef993da88175fc2574c1505b567bd1719ea2056 --- /dev/null +++ b/ltp/runtest/net.nfs @@ -0,0 +1,141 @@ +#DESCRIPTION:Network filesystem stress +# +# PLEASE READ THE README FILE network/README.md BEFORE RUNNING THESE. +# +nfs01_v30_ip4u nfs01.sh -v 3 -t udp +nfs01_v30_ip4t nfs01.sh -v 3 -t tcp +nfs01_v40_ip4t nfs01.sh -v 4 -t tcp +nfs01_v41_ip4t nfs01.sh -v 4.1 -t tcp +nfs01_v42_ip4t nfs01.sh -v 4.2 -t tcp +nfs01_v30_ip6u nfs01.sh -6 -v 3 -t udp +nfs01_v30_ip6t nfs01.sh -6 -v 3 -t tcp +nfs01_v40_ip6t nfs01.sh -6 -v 4 -t tcp +nfs01_v41_ip6t nfs01.sh -6 -v 4.1 -t tcp +nfs01_v42_ip6t nfs01.sh -6 -v 4.2 -t tcp + +nfs02_v30_ip4u nfs02.sh -v 3 -t udp +nfs02_v30_ip4t nfs02.sh -v 3 -t tcp +nfs02_v40_ip4t nfs02.sh -v 4 -t tcp +nfs02_v41_ip4t nfs02.sh -v 4.1 -t tcp +nfs02_v42_ip4t nfs02.sh -v 4.2 -t tcp +nfs02_v30_ip6u nfs02.sh -6 -v 3 -t udp +nfs02_v30_ip6t nfs02.sh -6 -v 3 -t tcp +nfs02_v40_ip6t nfs02.sh -6 -v 4 -t tcp +nfs02_v41_ip6t nfs02.sh -6 -v 4.1 -t tcp +nfs02_v42_ip6t nfs02.sh -6 -v 4.2 -t tcp + +nfs03_v30_ip4u nfs03.sh -v 3 -t udp +nfs03_v30_ip4t nfs03.sh -v 3 -t tcp +nfs03_v40_ip4t nfs03.sh -v 4 -t tcp +nfs03_v41_ip4t nfs03.sh -v 4.1 -t tcp +nfs03_v42_ip4t nfs03.sh -v 4.2 -t tcp +nfs03_v30_ip6u nfs03.sh -6 -v 3 -t udp +nfs03_v30_ip6t nfs03.sh -6 -v 3 -t tcp +nfs03_v40_ip6t nfs03.sh -6 -v 4 -t tcp +nfs03_v41_ip6t nfs03.sh -6 -v 4.1 -t tcp +nfs03_v42_ip6t nfs03.sh -6 -v 4.2 -t tcp + +nfs04_v30_ip4u nfs04.sh -v 3 -t udp +nfs04_v30_ip4t nfs04.sh -v 3 -t tcp +nfs04_v40_ip4t nfs04.sh -v 4 -t tcp +nfs04_v41_ip4t nfs04.sh -v 4.1 -t tcp +nfs04_v42_ip4t nfs04.sh -v 4.2 -t tcp +nfs04_v30_ip6u nfs04.sh -6 -v 3 -t udp +nfs04_v30_ip6t nfs04.sh -6 -v 3 -t tcp +nfs04_v40_ip6t nfs04.sh -6 -v 4 -t tcp +nfs04_v41_ip6t nfs04.sh -6 -v 4.1 -t tcp +nfs04_v42_ip6t nfs04.sh -6 -v 4.2 -t tcp + +nfs05_v30_ip4u nfs05.sh -v 3 -t udp +nfs05_v30_ip4t nfs05.sh -v 3 -t tcp +nfs05_v40_ip4t nfs05.sh -v 4 -t tcp +nfs05_v41_ip4t nfs05.sh -v 4.1 -t tcp +nfs05_v42_ip4t nfs05.sh -v 4.2 -t tcp +nfs05_v30_ip6u nfs05.sh -6 -v 3 -t udp +nfs05_v30_ip6t nfs05.sh -6 -v 3 -t tcp +nfs05_v40_ip6t nfs05.sh -6 -v 4 -t tcp +nfs05_v41_ip6t nfs05.sh -6 -v 4.1 -t tcp +nfs05_v42_ip6t nfs05.sh -6 -v 4.2 -t tcp + +nfs06_v30_v40_ip4 nfs06.sh -v "3,3,3,4,4,4" -t "udp,udp,tcp,tcp,tcp,tcp" +nfs06_vall_ip4t nfs06.sh -v "3,4,4.1,4.2,4.2,4.2" -t "tcp,tcp,tcp,tcp,tcp,tcp" +nfs06_v4x_ip6t nfs06.sh -6 -v "4,4.1,4.1,4.2,4.2,4.2" -t "tcp,tcp,tcp,tcp,tcp,tcp" + +nfs07_v30_ip4u nfs07.sh -v 3 -t udp +nfs07_v30_ip4t nfs07.sh -v 3 -t tcp +nfs07_v40_ip4t nfs07.sh -v 4 -t tcp +nfs07_v41_ip4t nfs07.sh -v 4.1 -t tcp +nfs07_v42_ip4t nfs07.sh -v 4.2 -t tcp +nfs07_v30_ip6u nfs07.sh -6 -v 3 -t udp +nfs07_v30_ip6t nfs07.sh -6 -v 3 -t tcp +nfs07_v40_ip6t nfs07.sh -6 -v 4 -t tcp +nfs07_v41_ip6t nfs07.sh -6 -v 4.1 -t tcp +nfs07_v42_ip6t nfs07.sh -6 -v 4.2 -t tcp + +nfs08_v30_ip4u nfs08.sh -v 3 -t udp +nfs08_v30_ip4t nfs08.sh -v 3 -t tcp +nfs08_v40_ip4t nfs08.sh -v 4 -t tcp +nfs08_v41_ip4t nfs08.sh -v 4.1 -t tcp +nfs08_v42_ip4t nfs08.sh -v 4.2 -t tcp +nfs08_v30_ip6u nfs08.sh -6 -v 3 -t udp +nfs08_v30_ip6t nfs08.sh -6 -v 3 -t tcp +nfs08_v40_ip6t nfs08.sh -6 -v 4 -t tcp +nfs08_v41_ip6t nfs08.sh -6 -v 4.1 -t tcp +nfs08_v42_ip6t nfs08.sh -6 -v 4.2 -t tcp + +nfs09_v30_ip4u nfs09.sh -v 3 -t udp +nfs09_v30_ip4t nfs09.sh -v 3 -t tcp +nfs09_v40_ip4t nfs09.sh -v 4 -t tcp +nfs09_v41_ip4t nfs09.sh -v 4.1 -t tcp +nfs09_v42_ip4t nfs09.sh -v 4.2 -t tcp +nfs09_v30_ip6u nfs09.sh -6 -v 3 -t udp +nfs09_v30_ip6t nfs09.sh -6 -v 3 -t tcp +nfs09_v40_ip6t nfs09.sh -6 -v 4 -t tcp +nfs09_v41_ip6t nfs09.sh -6 -v 4.1 -t tcp +nfs09_v42_ip6t nfs09.sh -6 -v 4.2 -t tcp + +nfs10_v30_ip4u nfs10.sh -v 3 -t udp +nfs10_v30_ip4t nfs10.sh -v 3 -t tcp +nfs10_v40_ip4t nfs10.sh -v 4 -t tcp +nfs10_v41_ip4t nfs10.sh -v 4.1 -t tcp +nfs10_v42_ip4t nfs10.sh -v 4.2 -t tcp +nfs10_v30_ip6u nfs10.sh -6 -v 3 -t udp +nfs10_v30_ip6t nfs10.sh -6 -v 3 -t tcp +nfs10_v40_ip6t nfs10.sh -6 -v 4 -t tcp +nfs10_v41_ip6t nfs10.sh -6 -v 4.1 -t tcp +nfs10_v42_ip6t nfs10.sh -6 -v 4.2 -t tcp + +nfslock01_v30_ip4u nfslock01.sh -v 3 -t udp +nfslock01_v30_ip4t nfslock01.sh -v 3 -t tcp +nfslock01_v40_ip4t nfslock01.sh -v 4 -t tcp +nfslock01_v41_ip4t nfslock01.sh -v 4.1 -t tcp +nfslock01_v42_ip4t nfslock01.sh -v 4.2 -t tcp +nfslock01_v30_ip6u nfslock01.sh -6 -v 3 -t udp +nfslock01_v30_ip6t nfslock01.sh -6 -v 3 -t tcp +nfslock01_v40_ip6t nfslock01.sh -6 -v 4 -t tcp +nfslock01_v41_ip6t nfslock01.sh -6 -v 4.1 -t tcp +nfslock01_v42_ip6t nfslock01.sh -6 -v 4.2 -t tcp + +nfsstat01_v30_ip4u nfsstat01.sh -v 3 -t udp +nfsstat01_v30_ip4t nfsstat01.sh -v 3 -t tcp +nfsstat01_v40_ip4t nfsstat01.sh -v 4 -t tcp +nfsstat01_v41_ip4t nfsstat01.sh -v 4.1 -t tcp +nfsstat01_v42_ip4t nfsstat01.sh -v 4.2 -t tcp +nfsstat01_v30_ip6u nfsstat01.sh -6 -v 3 -t udp +nfsstat01_v30_ip6t nfsstat01.sh -6 -v 3 -t tcp +nfsstat01_v40_ip6t nfsstat01.sh -6 -v 4 -t tcp +nfsstat01_v41_ip6t nfsstat01.sh -6 -v 4.1 -t tcp +nfsstat01_v42_ip6t nfsstat01.sh -6 -v 4.2 -t tcp + +nfsstat02 nfsstat02.sh + +fsx_v30_ip4u fsx.sh -v 3 -t udp +fsx_v30_ip4t fsx.sh -v 3 -t tcp +fsx_v40_ip4t fsx.sh -v 4 -t tcp +fsx_v41_ip4t fsx.sh -v 4.1 -t tcp +fsx_v42_ip4t fsx.sh -v 4.2 -t tcp +fsx_v30_ip6u fsx.sh -6 -v 3 -t udp +fsx_v30_ip6t fsx.sh -6 -v 3 -t tcp +fsx_v40_ip6t fsx.sh -6 -v 4 -t tcp +fsx_v41_ip6t fsx.sh -6 -v 4.1 -t tcp +fsx_v42_ip6t fsx.sh -6 -v 4.2 -t tcp diff --git a/ltp/runtest/net.rpc_tests b/ltp/runtest/net.rpc_tests new file mode 100644 index 0000000000000000000000000000000000000000..25d219dce64f6b682f4081cf93d2d18d29ed53dc --- /dev/null +++ b/ltp/runtest/net.rpc_tests @@ -0,0 +1,58 @@ +rpc01 rpc01.sh +rpcinfo rpcinfo01.sh + +rpc_pmap_set rpc_test.sh -c rpc_pmap_set +rpc_pmap_unset rpc_test.sh -c rpc_pmap_unset +rpc_pmap_getport rpc_test.sh -s rpc_svc_1 -c rpc_pmap_getport +rpc_pmap_getmaps rpc_test.sh -s rpc_svc_1 -c rpc_pmap_getmaps +rpc_pmap_rmtcall rpc_test.sh -s rpc_svc_1 -c rpc_pmap_rmtcall +rpc_get_myaddress rpc_test.sh -c rpc_get_myaddress + +rpc_authnone_create rpc_test.sh -c rpc_authnone_create +rpc_authunix_create rpc_test.sh -c rpc_authunix_create +rpc_authunix_create_default rpc_test.sh -c rpc_authunix_create_default +rpc_auth_destroy rpc_test.sh -c rpc_auth_destroy + +rpc_clnt_broadcast rpc_test.sh -s rpc_svc_1 -c rpc_clnt_broadcast + +rpc_svc_destroy rpc_test.sh -c rpc_svc_destroy +rpc_svcfd_create rpc_test.sh -c rpc_svcfd_create +rpc_svctcp_create rpc_test.sh -c rpc_svctcp_create +rpc_svcudp_create rpc_test.sh -c rpc_svcudp_create +rpc_svcraw_create rpc_test.sh -c rpc_svcraw_create +rpc_svcudp_bufcreate rpc_test.sh -c rpc_svcudp_bufcreate +rpc_clnt_destroy rpc_test.sh -s rpc_svc_1 -c rpc_clnt_destroy +rpc_clnt_create rpc_test.sh -s rpc_svc_1 -c rpc_clnt_create +rpc_clntraw_create rpc_test.sh -s rpc_svc_1 -c rpc_clntraw_create +rpc_clnttcp_create rpc_test.sh -s rpc_svc_1 -c rpc_clnttcp_create +rpc_clntudp_create rpc_test.sh -s rpc_svc_1 -c rpc_clntudp_create +rpc_clntudp_bufcreate rpc_test.sh -s rpc_svc_1 -c rpc_clntudp_bufcreate + +rpc_clnt_pcreateerror rpc_test.sh -s rpc_svc_1 -c rpc_clnt_pcreateerror +rpc_clnt_perrno rpc_test.sh -s rpc_svc_1 -c rpc_clnt_perrno +rpc_clnt_perror rpc_test.sh -s rpc_svc_1 -c rpc_clnt_perror +rpc_clnt_spcreateerror rpc_test.sh -s rpc_svc_1 -c rpc_clnt_spcreateerror +rpc_clnt_sperrno rpc_test.sh -s rpc_svc_1 -c rpc_clnt_sperrno +rpc_clnt_sperror rpc_test.sh -s rpc_svc_1 -c rpc_clnt_sperror +rpc_svcerr_noproc rpc_test.sh -s rpc_svc_1 -c rpc_svcerr_noproc +rpc_svcerr_noprog rpc_test.sh -c rpc_svcerr_noprog +rpc_svcerr_progvers rpc_test.sh -s rpc_svc_1 -c rpc_svcerr_progvers +rpc_svcerr_systemerr rpc_test.sh -s rpc_svc_1 -c rpc_svcerr_systemerr +rpc_svcerr_auth rpc_test.sh -s rpc_svc_1 -c rpc_svcerr_auth +rpc_svcerr_weakauth rpc_test.sh -s rpc_svc_1 -c rpc_svcerr_weakauth + +rpc_xprt_register rpc_test.sh -c rpc_xprt_register +rpc_xprt_unregister rpc_test.sh -c rpc_xprt_unregister +rpc_svc_register rpc_test.sh -c rpc_svc_register +rpc_svc_unregister rpc_test.sh -c rpc_svc_unregister +rpc_registerrpc rpc_test.sh -c rpc_registerrpc + +rpc_clnt_call rpc_test.sh -s rpc_svc_1 -c rpc_clnt_call +rpc_callrpc rpc_test.sh -s rpc_svc_1 -c rpc_callrpc +rpc_clnt_freeres rpc_test.sh -s rpc_svc_1 -c rpc_clnt_freeres +rpc_clnt_geterr rpc_test.sh -s rpc_svc_1 -c rpc_clnt_geterr +rpc_clnt_control rpc_test.sh -s rpc_svc_1 -c rpc_clnt_control +rpc_svc_getcaller rpc_test.sh -s rpc_svc_1 -c rpc_svc_getcaller +rpc_svc_freeargs rpc_test.sh -s rpc_svc_1 -c rpc_svc_freeargs +rpc_svc_getargs rpc_test.sh -s rpc_svc_getargs -c rpc_svc_getargs_client +rpc_svc_sendreply rpc_test.sh -s rpc_svc_sendreply -c rpc_svc_sendreply_client diff --git a/ltp/runtest/net.sctp b/ltp/runtest/net.sctp new file mode 100644 index 0000000000000000000000000000000000000000..71cc0d19549f4e7496acca2d8d2e51035bbe75a5 --- /dev/null +++ b/ltp/runtest/net.sctp @@ -0,0 +1,43 @@ +#DESCRIPTION:Stream Control Transmission Protocol (SCTP) Tests +# +test_1_to_1_accept_close test_1_to_1_accept_close +test_1_to_1_addrs test_1_to_1_addrs +test_1_to_1_connect test_1_to_1_connect +test_1_to_1_connectx test_1_to_1_connectx +test_1_to_1_events test_1_to_1_events +test_1_to_1_initmsg_connect test_1_to_1_initmsg_connect +test_1_to_1_nonblock test_1_to_1_nonblock +test_1_to_1_recvfrom test_1_to_1_recvfrom +test_1_to_1_recvmsg test_1_to_1_recvmsg +test_1_to_1_rtoinfo test_1_to_1_rtoinfo +test_1_to_1_send test_1_to_1_send +test_1_to_1_sendmsg test_1_to_1_sendmsg +test_1_to_1_sendto test_1_to_1_sendto +test_1_to_1_shutdown test_1_to_1_shutdown +test_1_to_1_socket_bind_listen test_1_to_1_socket_bind_listen +test_1_to_1_sockopt test_1_to_1_sockopt +test_1_to_1_threads test_1_to_1_threads +test_assoc_abort test_assoc_abort +test_assoc_shutdown test_assoc_shutdown +test_autoclose test_autoclose +test_basic test_basic +test_basic_v6 test_basic_v6 +test_connect test_connect +test_connectx test_connectx +test_fragments test_fragments +test_fragments_v6 test_fragments_v6 +test_getname test_getname +test_getname_v6 test_getname_v6 +test_inaddr_any test_inaddr_any +test_inaddr_any_v6 test_inaddr_any_v6 +test_peeloff test_peeloff +test_peeloff_v6 test_peeloff_v6 +test_recvmsg test_recvmsg +test_sctp_sendrecvmsg test_sctp_sendrecvmsg +test_sctp_sendrecvmsg_v6 test_sctp_sendrecvmsg_v6 +test_sockopt test_sockopt +test_sockopt_v6 test_sockopt_v6 +test_tcp_style test_tcp_style +test_tcp_style_v6 test_tcp_style_v6 +test_timetolive test_timetolive +test_timetolive_v6 test_timetolive_v6 diff --git a/ltp/runtest/net.tcp_cmds b/ltp/runtest/net.tcp_cmds new file mode 100644 index 0000000000000000000000000000000000000000..aba02fb30ac6ba529edcaba4e167fb5f62bec4a2 --- /dev/null +++ b/ltp/runtest/net.tcp_cmds @@ -0,0 +1,20 @@ +#DESCRIPTION:TCP/IP commands tests +# +# PLEASE READ THE README FILE IN /tcp_cmds BEFORE RUNNING THESE. +# +ipneigh01_arp ipneigh01.sh -c arp +ipneigh01_ip ipneigh01.sh -c ip +arping01 arping01.sh +netstat netstat01.sh +ping01 ping01.sh +ping02 ping02.sh +sendfile sendfile01.sh +tc01 tc01.sh +tcpdump tcpdump01.sh +iptables iptables01.sh +nft nft01.sh +dhcpd dhcpd_tests.sh +dnsmasq dnsmasq_tests.sh +iproute ip_tests.sh +tracepath01 tracepath01.sh +traceroute01 traceroute01.sh diff --git a/ltp/runtest/net.tirpc_tests b/ltp/runtest/net.tirpc_tests new file mode 100644 index 0000000000000000000000000000000000000000..8aa69ef4d8ac9200af54063c86b52494c7dc1481 --- /dev/null +++ b/ltp/runtest/net.tirpc_tests @@ -0,0 +1,48 @@ +tirpc_rpcb_getaddr rpc_test.sh -s tirpc_svc_3 -c tirpc_rpcb_getaddr +tirpc_rpcb_getmaps rpc_test.sh -s tirpc_svc_3 -c tirpc_rpcb_getmaps + +tirpc_authnone_create rpc_test.sh -c tirpc_authnone_create +tirpc_authsys_create rpc_test.sh -s tirpc_svc_1 -c tirpc_authsys_create +tirpc_authsys_create_default rpc_test.sh -c tirpc_authsys_create_default + +tirpc_clnt_dg_create rpc_test.sh -s tirpc_svc_5 -c tirpc_clnt_dg_create +tirpc_svc_dg_create rpc_test.sh -c tirpc_svc_dg_create +tirpc_clnt_vc_create rpc_test.sh -s tirpc_svc_5 -c tirpc_clnt_vc_create +tirpc_svc_vc_create rpc_test.sh -c tirpc_svc_vc_create +tirpc_bottomlevel_clnt_call rpc_test.sh -s tirpc_svc_5 -c tirpc_bottomlevel_clnt_call + +tirpc_clnt_pcreateerror rpc_test.sh -s tirpc_svc_11 -c tirpc_clnt_pcreateerror +tirpc_clnt_perrno rpc_test.sh -s tirpc_svc_11 -c tirpc_clnt_perrno +tirpc_clnt_perror rpc_test.sh -s tirpc_svc_11 -c tirpc_clnt_perror +tirpc_svcerr_noproc rpc_test.sh -s tirpc_svc_11 -c tirpc_svcerr_noproc +tirpc_svcerr_noprog rpc_test.sh -s tirpc_svc_11 -c tirpc_svcerr_noprog +tirpc_svcerr_progvers rpc_test.sh -s tirpc_svc_11 -c tirpc_svcerr_progvers +tirpc_svcerr_systemerr rpc_test.sh -s tirpc_svc_11 -c tirpc_svcerr_systemerr +tirpc_svcerr_weakauth rpc_test.sh -s tirpc_svc_11 -c tirpc_svcerr_weakauth + +tirpc_clnt_tli_create rpc_test.sh -s tirpc_svc_4 -c tirpc_clnt_tli_create +tirpc_svc_tli_create rpc_test.sh -c tirpc_svc_tli_create +tirpc_rpcb_set rpc_test.sh -c tirpc_rpcb_set +tirpc_rpcb_unset rpc_test.sh -c tirpc_rpcb_unset +tirpc_rpcb_rmtcall rpc_test.sh -s tirpc_svc_4 -c tirpc_rpcb_rmtcall +tirpc_svc_reg rpc_test.sh -c tirpc_svc_reg +tirpc_svc_unreg rpc_test.sh -c tirpc_svc_unreg +tirpc_expertlevel_clnt_call rpc_test.sh -s tirpc_svc_4 -c tirpc_expertlevel_clnt_call + +tirpc_clnt_tp_create rpc_test.sh -s tirpc_svc_3 -c tirpc_clnt_tp_create +tirpc_clnt_tp_create_timed rpc_test.sh -s tirpc_svc_3 -c tirpc_clnt_tp_create_timed +tirpc_svc_tp_create rpc_test.sh -c tirpc_svc_tp_create +tirpc_interlevel_clnt_call rpc_test.sh -s tirpc_svc_3 -c tirpc_interlevel_clnt_call +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_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 +tirpc_svc_create rpc_test.sh -c tirpc_svc_create +tirpc_toplevel_clnt_call rpc_test.sh -s tirpc_svc_2 -c tirpc_toplevel_clnt_call +tirpc_clnt_destroy rpc_test.sh -s tirpc_svc_2 -c tirpc_clnt_destroy +tirpc_svc_destroy rpc_test.sh -c tirpc_svc_destroy diff --git a/ltp/runtest/net_stress.appl b/ltp/runtest/net_stress.appl new file mode 100644 index 0000000000000000000000000000000000000000..0da12717e4391579dbb59f9fc0e8c06b5f8fc76a --- /dev/null +++ b/ltp/runtest/net_stress.appl @@ -0,0 +1,18 @@ +# +# Stress test for major application protocol (ssh, dns, http, ftp) +# + +ssh4-stress ssh-stress.sh +ssh6-stress ssh-stress.sh -6 + +dns4-stress dns-stress.sh +dns6-stress dns-stress.sh -6 + +http4-stress http-stress.sh +http6-stress http-stress.sh -6 + +ftp4-download-stress ftp-download-stress.sh +ftp6-download-stress ftp-download-stress.sh -6 + +ftp4-upload-stress ftp-upload-stress.sh +ftp6-upload-stress ftp-upload-stress.sh -6 diff --git a/ltp/runtest/net_stress.broken_ip b/ltp/runtest/net_stress.broken_ip new file mode 100644 index 0000000000000000000000000000000000000000..a5536c0c28f773734a01a7a6eedc9109e0cbb5c0 --- /dev/null +++ b/ltp/runtest/net_stress.broken_ip @@ -0,0 +1,17 @@ +# +# Stress test for TCP/IP protocol stack +# + +# Broken IP packet +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.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/ltp/runtest/net_stress.interface b/ltp/runtest/net_stress.interface new file mode 100644 index 0000000000000000000000000000000000000000..106f2f151aecaa9b2d7d505431ce408fc25b527b --- /dev/null +++ b/ltp/runtest/net_stress.interface @@ -0,0 +1,31 @@ +# +# Stress test for interface +# + +if4-addr-change_ifconfig if4-addr-change.sh + +if4-updown_ip if-updown.sh -c ip +if4-updown_ifconfig if-updown.sh -c ifconfig +if4-addr-adddel_ip if-addr-adddel.sh -c ip +if4-addr-adddel_ifconfig if-addr-adddel.sh -c ifconfig +if4-addr-addlarge_ip if-addr-addlarge.sh -c ip +if4-addr-addlarge_ifconfig if-addr-addlarge.sh -c ifconfig +if4-route-adddel_ip if-route-adddel.sh -c ip +if4-route-adddel_route if-route-adddel.sh -c route +if4-route-addlarge_ip if-route-addlarge.sh -c ip +if4-route-addlarge_route if-route-addlarge.sh -c route +if4-mtu-change_ip if-mtu-change.sh -c ip +if4-mtu-change_ifconfig if-mtu-change.sh -c ifconfig + +if6-updown_ip if-updown.sh -6 -c ip +if6-updown_ifconfig if-updown.sh -6 -c ifconfig +if6-addr-adddel_ip if-addr-adddel.sh -6 -c ip +if6-addr-adddel_ifconfig if-addr-adddel.sh -6 -c ifconfig +if6-addr-addlarge_ip if-addr-addlarge.sh -6 -c ip +if6-addr-addlarge_ifconfig if-addr-addlarge.sh -6 -c ifconfig +if6-route-adddel_ip if-route-adddel.sh -6 -c ip +if6-route-adddel_route if-route-adddel.sh -6 -c route +if6-route-addlarge_ip if-route-addlarge.sh -6 -c ip +if6-route-addlarge_route if-route-addlarge.sh -6 -c route +if6-mtu-change_ip if-mtu-change.sh -6 -c ip +if6-mtu-change_ifconfig if-mtu-change.sh -6 -c ifconfig diff --git a/ltp/runtest/net_stress.ipsec_dccp b/ltp/runtest/net_stress.ipsec_dccp new file mode 100644 index 0000000000000000000000000000000000000000..e765d35b5c40e86a3bdfb843cc0f55bca57922dc --- /dev/null +++ b/ltp/runtest/net_stress.ipsec_dccp @@ -0,0 +1,109 @@ +dccp4_ipsec01 dccp_ipsec.sh -s 100:500:1000:R1000 +dccp4_ipsec02 dccp_ipsec.sh -p ah -m transport -s 100:500:1000:R1000 +dccp4_ipsec03 dccp_ipsec.sh -p ah -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec04 dccp_ipsec.sh -p esp -m transport -s 100:500:1000:R1000 +dccp4_ipsec05 dccp_ipsec.sh -p esp -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec06 dccp_ipsec.sh -p comp -m transport -s 100:500:1000:R1000 +dccp4_ipsec07 dccp_ipsec.sh -p comp -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec08 dccp_ipsec.sh -A rfc4106_128 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec09 dccp_ipsec.sh -A rfc4106_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec10 dccp_ipsec.sh -A rfc4106_192 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec11 dccp_ipsec.sh -A rfc4106_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec12 dccp_ipsec.sh -A rfc4106_256 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec13 dccp_ipsec.sh -A rfc4106_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec14 dccp_ipsec.sh -A rfc4309_128 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec15 dccp_ipsec.sh -A rfc4309_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec16 dccp_ipsec.sh -A rfc4309_192 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec17 dccp_ipsec.sh -A rfc4309_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec18 dccp_ipsec.sh -A rfc4309_256 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec19 dccp_ipsec.sh -A rfc4309_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec20 dccp_ipsec.sh -A rfc4543_128 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec21 dccp_ipsec.sh -A rfc4543_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec22 dccp_ipsec.sh -A rfc4543_192 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec23 dccp_ipsec.sh -A rfc4543_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec24 dccp_ipsec.sh -A rfc4543_256 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp4_ipsec25 dccp_ipsec.sh -A rfc4543_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec26 dccp_ipsec.sh -p esp -a sha1 -e cast5 -m transport -s 100:500:1000:R1000 +dccp4_ipsec27 dccp_ipsec.sh -p esp -a sha1 -e cast5 -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec28 dccp_ipsec.sh -p esp -a sha256 -e blowfish -m transport -s 100:500:1000:R1000 +dccp4_ipsec29 dccp_ipsec.sh -p esp -a sha256 -e blowfish -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec30 dccp_ipsec.sh -p esp -a sha384 -e twofish -m transport -s 100:500:1000:R1000 +dccp4_ipsec31 dccp_ipsec.sh -p esp -a sha384 -e twofish -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec32 dccp_ipsec.sh -p esp -a sha512 -e camellia -m transport -s 100:500:1000:R1000 +dccp4_ipsec33 dccp_ipsec.sh -p esp -a sha512 -e camellia -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec34 dccp_ipsec.sh -p esp -a rmd160 -e serpent -m transport -s 100:500:1000:R1000 +dccp4_ipsec35 dccp_ipsec.sh -p esp -a rmd160 -e serpent -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec36 dccp_ipsec.sh -p esp -m beet -s 100:500:1000:R1000 + +dccp6_ipsec01 dccp_ipsec.sh -6 -s 100:500:1000:R1000 +dccp6_ipsec02 dccp_ipsec.sh -6 -p ah -m transport -s 100:500:1000:R1000 +dccp6_ipsec03 dccp_ipsec.sh -6 -p ah -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec04 dccp_ipsec.sh -6 -p esp -m transport -s 100:500:1000:R1000 +dccp6_ipsec05 dccp_ipsec.sh -6 -p esp -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec06 dccp_ipsec.sh -6 -p comp -m transport -s 100:500:1000:R1000 +dccp6_ipsec07 dccp_ipsec.sh -6 -p comp -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec08 dccp_ipsec.sh -6 -A rfc4106_128 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec09 dccp_ipsec.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec10 dccp_ipsec.sh -6 -A rfc4106_192 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec11 dccp_ipsec.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec12 dccp_ipsec.sh -6 -A rfc4106_256 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec13 dccp_ipsec.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec14 dccp_ipsec.sh -6 -A rfc4309_128 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec15 dccp_ipsec.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec16 dccp_ipsec.sh -6 -A rfc4309_192 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec17 dccp_ipsec.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec18 dccp_ipsec.sh -6 -A rfc4309_256 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec19 dccp_ipsec.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec20 dccp_ipsec.sh -6 -A rfc4543_128 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec21 dccp_ipsec.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec22 dccp_ipsec.sh -6 -A rfc4543_192 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec23 dccp_ipsec.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec24 dccp_ipsec.sh -6 -A rfc4543_256 -p esp_aead -m transport -s 100:500:1000:R1000 +dccp6_ipsec25 dccp_ipsec.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec26 dccp_ipsec.sh -6 -p esp -a sha1 -e cast5 -m transport -s 100:500:1000:R1000 +dccp6_ipsec27 dccp_ipsec.sh -6 -p esp -a sha1 -e cast5 -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec28 dccp_ipsec.sh -6 -p esp -a sha256 -e blowfish -m transport -s 100:500:1000:R1000 +dccp6_ipsec29 dccp_ipsec.sh -6 -p esp -a sha256 -e blowfish -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec30 dccp_ipsec.sh -6 -p esp -a sha384 -e twofish -m transport -s 100:500:1000:R1000 +dccp6_ipsec31 dccp_ipsec.sh -6 -p esp -a sha384 -e twofish -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec32 dccp_ipsec.sh -6 -p esp -a sha512 -e camellia -m transport -s 100:500:1000:R1000 +dccp6_ipsec33 dccp_ipsec.sh -6 -p esp -a sha512 -e camellia -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec34 dccp_ipsec.sh -6 -p esp -a rmd160 -e serpent -m transport -s 100:500:1000:R1000 +dccp6_ipsec35 dccp_ipsec.sh -6 -p esp -a rmd160 -e serpent -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec36 dccp_ipsec.sh -6 -p esp -m beet -s 100:500:1000:R1000 + +dccp4_ipsec_vti01 dccp_ipsec_vti.sh -p ah -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti02 dccp_ipsec_vti.sh -p esp -m tunnel -s 100:500:1000:R1000 +# dccp4_ipsec_vti03 dccp_ipsec_vti.sh -p comp -m tunnel -s 100:500:1000 +dccp4_ipsec_vti04 dccp_ipsec_vti.sh -A rfc4106_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti05 dccp_ipsec_vti.sh -A rfc4106_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti06 dccp_ipsec_vti.sh -A rfc4106_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti07 dccp_ipsec_vti.sh -A rfc4309_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti08 dccp_ipsec_vti.sh -A rfc4309_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti09 dccp_ipsec_vti.sh -A rfc4309_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti10 dccp_ipsec_vti.sh -A rfc4543_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti11 dccp_ipsec_vti.sh -A rfc4543_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti12 dccp_ipsec_vti.sh -A rfc4543_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti13 dccp_ipsec_vti.sh -p esp -a sha1 -e cast5 -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti14 dccp_ipsec_vti.sh -p esp -a sha256 -e blowfish -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti15 dccp_ipsec_vti.sh -p esp -a sha384 -e twofish -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti16 dccp_ipsec_vti.sh -p esp -a sha512 -e camellia -m tunnel -s 100:500:1000:R1000 +dccp4_ipsec_vti17 dccp_ipsec_vti.sh -p esp -a rmd160 -e serpent -m tunnel -s 100:500:1000:R1000 + +dccp6_ipsec_vti01 dccp_ipsec_vti.sh -6 -p ah -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti02 dccp_ipsec_vti.sh -6 -p esp -m tunnel -s 100:500:1000:R1000 +# dccp6_ipsec_vti03 dccp_ipsec_vti.sh -6 -p comp -m tunnel -s 100:500:1000 +dccp6_ipsec_vti04 dccp_ipsec_vti.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti05 dccp_ipsec_vti.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti06 dccp_ipsec_vti.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti07 dccp_ipsec_vti.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti08 dccp_ipsec_vti.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti09 dccp_ipsec_vti.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti10 dccp_ipsec_vti.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti11 dccp_ipsec_vti.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti12 dccp_ipsec_vti.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti13 dccp_ipsec_vti.sh -6 -p esp -a sha1 -e cast5 -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti14 dccp_ipsec_vti.sh -6 -p esp -a sha256 -e blowfish -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti15 dccp_ipsec_vti.sh -6 -p esp -a sha384 -e twofish -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti16 dccp_ipsec_vti.sh -6 -p esp -a sha512 -e camellia -m tunnel -s 100:500:1000:R1000 +dccp6_ipsec_vti17 dccp_ipsec_vti.sh -6 -p esp -a rmd160 -e serpent -m tunnel -s 100:500:1000:R1000 diff --git a/ltp/runtest/net_stress.ipsec_icmp b/ltp/runtest/net_stress.ipsec_icmp new file mode 100644 index 0000000000000000000000000000000000000000..58c0924a4f78763aa7e889c8c4685478800db8a6 --- /dev/null +++ b/ltp/runtest/net_stress.ipsec_icmp @@ -0,0 +1,119 @@ +# Stress test for IPsec with ICMP messages +# Max ICMP message size descriptsion, MAX_SIZE is 65535 +# +# IPv4 +# ---- +# MAX = MAX_SIZE - IP(20) - ICMP(8) = 65507 +# +# IPsec [AH]: MAX - AH(24) = 65483 +# IPsec [AH + Tunnel]: MAX - AH(24) - Tunnel(20) = 65463 +# +# ESP Header has pad payload, so the ESP length is variable +# IPsec [ESP]: MAX - ESP(37) = 65470 +# IPsec [ESP + Tunnel]: MAX - ESP(37) - Tunnel(20) = 65450 +# +# IPv6 +# ---- +# MAX = MAX_SIZE - ICMP(8) = 65527 +# +# IPsec [AH]: MAX - AH(24) = 65503 +# +# When receive, we drop the tunnel header first and only leave the inside IPv6 +# Header and ICMP message. That's why we can have so large message size. +# IPsec [AH + Tunnel]: MAX +# IPsec [ESP]: MAX - ESP(37) = 65490 +# IPsec [ESP + Tunnel]: MAX +# +# IPsec compression: same message size but different content will result in different data size +# after compression. So we just use a large enough message size(65000) for testing + +icmp4-uni-basic01 icmp-uni-basic.sh -s 10:100:1000:10000:65507 +icmp4-uni-basic02 icmp-uni-basic.sh -p ah -m transport -s 10:100:1000:10000:65483 +icmp4-uni-basic03 icmp-uni-basic.sh -p ah -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-basic04 icmp-uni-basic.sh -p esp -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic05 icmp-uni-basic.sh -p esp -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic06 icmp-uni-basic.sh -p comp -m transport -s 10:100:1000:10000:65000 +icmp4-uni-basic07 icmp-uni-basic.sh -p comp -m tunnel -s 10:100:1000:10000:65000 +icmp4-uni-basic08 icmp-uni-basic.sh -A rfc4106_128 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic09 icmp-uni-basic.sh -A rfc4106_192 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic10 icmp-uni-basic.sh -A rfc4106_256 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic11 icmp-uni-basic.sh -A rfc4309_128 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic12 icmp-uni-basic.sh -A rfc4309_192 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic13 icmp-uni-basic.sh -A rfc4309_256 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic14 icmp-uni-basic.sh -A rfc4543_128 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic15 icmp-uni-basic.sh -A rfc4543_192 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic16 icmp-uni-basic.sh -A rfc4543_256 -p esp_aead -m transport -s 10:100:1000:10000:65470 +icmp4-uni-basic17 icmp-uni-basic.sh -A rfc4106_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic18 icmp-uni-basic.sh -A rfc4106_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic19 icmp-uni-basic.sh -A rfc4106_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic20 icmp-uni-basic.sh -A rfc4309_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic21 icmp-uni-basic.sh -A rfc4309_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic22 icmp-uni-basic.sh -A rfc4309_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic23 icmp-uni-basic.sh -A rfc4543_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic24 icmp-uni-basic.sh -A rfc4543_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic25 icmp-uni-basic.sh -A rfc4543_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65450 +icmp4-uni-basic26 icmp-uni-basic.sh -p esp -m beet -s 10:100:1000:10000:65470 + +icmp6-uni-basic01 icmp-uni-basic.sh -6 -s 10:100:1000:10000:65527 +icmp6-uni-basic02 icmp-uni-basic.sh -6 -p ah -m transport -s 10:100:1000:10000:65503 +icmp6-uni-basic03 icmp-uni-basic.sh -6 -p ah -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic04 icmp-uni-basic.sh -6 -p esp -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic05 icmp-uni-basic.sh -6 -p esp -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic06 icmp-uni-basic.sh -6 -p comp -m transport -s 10:100:1000:10000:65000 +icmp6-uni-basic07 icmp-uni-basic.sh -6 -p comp -m tunnel -s 10:100:1000:10000:65000 +icmp6-uni-basic08 icmp-uni-basic.sh -6 -A rfc4106_128 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic09 icmp-uni-basic.sh -6 -A rfc4106_192 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic10 icmp-uni-basic.sh -6 -A rfc4106_256 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic11 icmp-uni-basic.sh -6 -A rfc4309_128 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic12 icmp-uni-basic.sh -6 -A rfc4309_192 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic13 icmp-uni-basic.sh -6 -A rfc4309_256 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic14 icmp-uni-basic.sh -6 -A rfc4543_128 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic15 icmp-uni-basic.sh -6 -A rfc4543_192 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic16 icmp-uni-basic.sh -6 -A rfc4543_256 -p esp_aead -m transport -s 10:100:1000:10000:65490 +icmp6-uni-basic17 icmp-uni-basic.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic18 icmp-uni-basic.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic19 icmp-uni-basic.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic20 icmp-uni-basic.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic21 icmp-uni-basic.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic22 icmp-uni-basic.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic23 icmp-uni-basic.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic24 icmp-uni-basic.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic25 icmp-uni-basic.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-basic26 icmp-uni-basic.sh -6 -p esp -m beet -s 10:100:1000:10000:65490 + +icmp4-uni-vti01 icmp-uni-vti.sh -p ah -a sha256 -m tunnel -S fffffffe -k 1 -s 10:100:1000:10000:65463 +icmp4-uni-vti02 icmp-uni-vti.sh -p esp -a sha512 -e des -m tunnel -S fffffffe -k 2 -s 10:100:1000:10000:65450 +icmp4-uni-vti03 icmp-uni-vti.sh -p esp -a rmd160 -e cast5 -m tunnel -S fffffffe -k 0xffffffff -s 10:100:1000:10000:65463 +icmp4-uni-vti04 icmp-uni-vti.sh -p esp -e blowfish -m tunnel -S fffffffe -k 3 -s 10:100:1000:10000:65463 +icmp4-uni-vti05 icmp-uni-vti.sh -p esp -a sha512 -e twofish -m tunnel -S fffffffe -k 0x7fffffff -s 10:100:1000:10000:65463 +icmp4-uni-vti06 icmp-uni-vti.sh -p esp -a sha384 -e camellia -m tunnel -S fffffffe -k 0x80000000 -s 10:100:1000:10000:65463 +icmp4-uni-vti07 icmp-uni-vti.sh -p esp -a sha512 -e serpent -m tunnel -S fffffffe -k 0xffff -s 10:100:1000:10000:65463 +icmp4-uni-vti08 icmp-uni-vti.sh -A rfc4106_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti09 icmp-uni-vti.sh -A rfc4106_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti10 icmp-uni-vti.sh -A rfc4106_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti11 icmp-uni-vti.sh -A rfc4309_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti12 icmp-uni-vti.sh -A rfc4309_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti13 icmp-uni-vti.sh -A rfc4309_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti14 icmp-uni-vti.sh -A rfc4543_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti15 icmp-uni-vti.sh -A rfc4543_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti16 icmp-uni-vti.sh -A rfc4543_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65463 +icmp4-uni-vti17 icmp-uni-vti.sh -p comp -m tunnel -s 1000 + +icmp6-uni-vti01 icmp-uni-vti.sh -6 -p ah -m tunnel -S fffffffe -k 0xffffffff -s 10:100:1000:10000:65527 +icmp6-uni-vti02 icmp-uni-vti.sh -6 -p esp -a sha256 -e des3_ede -m tunnel -S fffffffe -k 0xffffffff -s 10:100:1000:10000:65527 +icmp6-uni-vti03 icmp-uni-vti.sh -6 -p esp -a sha512 -e cast5 -m tunnel -S fffffffe -k 1 -s 10:100:1000:10000:65527 +icmp6-uni-vti04 icmp-uni-vti.sh -6 -p esp -a rmd160 -e blowfish -m tunnel -S fffffffe -k 0x80000000 -s 10:100:1000:10000:65527 +icmp6-uni-vti05 icmp-uni-vti.sh -6 -p esp -e twofish -m tunnel -S fffffffe -k 0xffff -s 10:100:1000:10000:65527 +icmp6-uni-vti06 icmp-uni-vti.sh -6 -p esp -a sha512 -e camellia -m tunnel -S fffffffe -k 0x7fffffff -s 10:100:1000:10000:65527 +icmp6-uni-vti07 icmp-uni-vti.sh -6 -p esp -a sha384 -e serpent -m tunnel -S ffffffff -k 0x11111111 -s 10:100:1000:10000:65527 +icmp6-uni-vti08 icmp-uni-vti.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti09 icmp-uni-vti.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti10 icmp-uni-vti.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti11 icmp-uni-vti.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti12 icmp-uni-vti.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti13 icmp-uni-vti.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti14 icmp-uni-vti.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti15 icmp-uni-vti.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti16 icmp-uni-vti.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 10:100:1000:10000:65527 +icmp6-uni-vti17 icmp-uni-vti.sh -6 -p comp -m tunnel -s 1000 + diff --git a/ltp/runtest/net_stress.ipsec_sctp b/ltp/runtest/net_stress.ipsec_sctp new file mode 100644 index 0000000000000000000000000000000000000000..b86de0c74416c6943c2fc75f1c484ee04c896c5a --- /dev/null +++ b/ltp/runtest/net_stress.ipsec_sctp @@ -0,0 +1,109 @@ +sctp4_ipsec01 sctp_ipsec.sh -s 100:1000:65535:R65535 +sctp4_ipsec02 sctp_ipsec.sh -p ah -m transport -s 100:1000:65535:R65535 +sctp4_ipsec03 sctp_ipsec.sh -p ah -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec04 sctp_ipsec.sh -p esp -m transport -s 100:1000:65535:R65535 +sctp4_ipsec05 sctp_ipsec.sh -p esp -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec06 sctp_ipsec.sh -p comp -m transport -s 100:1000:65535:R65535 +sctp4_ipsec07 sctp_ipsec.sh -p comp -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec08 sctp_ipsec.sh -A rfc4106_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec09 sctp_ipsec.sh -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec10 sctp_ipsec.sh -A rfc4106_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec11 sctp_ipsec.sh -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec12 sctp_ipsec.sh -A rfc4106_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec13 sctp_ipsec.sh -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec14 sctp_ipsec.sh -A rfc4309_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec15 sctp_ipsec.sh -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec16 sctp_ipsec.sh -A rfc4309_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec17 sctp_ipsec.sh -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec18 sctp_ipsec.sh -A rfc4309_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec19 sctp_ipsec.sh -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec20 sctp_ipsec.sh -A rfc4543_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec21 sctp_ipsec.sh -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec22 sctp_ipsec.sh -A rfc4543_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec23 sctp_ipsec.sh -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec24 sctp_ipsec.sh -A rfc4543_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp4_ipsec25 sctp_ipsec.sh -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec26 sctp_ipsec.sh -p esp -a sha1 -e cast5 -m transport -s 100:1000:65535:R65535 +sctp4_ipsec27 sctp_ipsec.sh -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec28 sctp_ipsec.sh -p esp -a sha256 -e blowfish -m transport -s 100:1000:65535:R65535 +sctp4_ipsec29 sctp_ipsec.sh -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec30 sctp_ipsec.sh -p esp -a sha384 -e twofish -m transport -s 100:1000:65535:R65535 +sctp4_ipsec31 sctp_ipsec.sh -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec32 sctp_ipsec.sh -p esp -a sha512 -e camellia -m transport -s 100:1000:65535:R65535 +sctp4_ipsec33 sctp_ipsec.sh -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec34 sctp_ipsec.sh -p esp -a rmd160 -e serpent -m transport -s 100:1000:65535:R65535 +sctp4_ipsec35 sctp_ipsec.sh -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec36 sctp_ipsec.sh -p esp -m beet -s 100:1000:65535:R65535 + +sctp6_ipsec01 sctp_ipsec.sh -6 -s 100:1000:65535:R65535 +sctp6_ipsec02 sctp_ipsec.sh -6 -p ah -m transport -s 100:1000:65535:R65535 +sctp6_ipsec03 sctp_ipsec.sh -6 -p ah -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec04 sctp_ipsec.sh -6 -p esp -m transport -s 100:1000:65535:R65535 +sctp6_ipsec05 sctp_ipsec.sh -6 -p esp -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec06 sctp_ipsec.sh -6 -p comp -m transport -s 100:1000:65535:R65535 +sctp6_ipsec07 sctp_ipsec.sh -6 -p comp -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec08 sctp_ipsec.sh -6 -A rfc4106_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec09 sctp_ipsec.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec10 sctp_ipsec.sh -6 -A rfc4106_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec11 sctp_ipsec.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec12 sctp_ipsec.sh -6 -A rfc4106_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec13 sctp_ipsec.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec14 sctp_ipsec.sh -6 -A rfc4309_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec15 sctp_ipsec.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec16 sctp_ipsec.sh -6 -A rfc4309_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec17 sctp_ipsec.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec18 sctp_ipsec.sh -6 -A rfc4309_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec19 sctp_ipsec.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec20 sctp_ipsec.sh -6 -A rfc4543_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec21 sctp_ipsec.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec22 sctp_ipsec.sh -6 -A rfc4543_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec23 sctp_ipsec.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec24 sctp_ipsec.sh -6 -A rfc4543_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +sctp6_ipsec25 sctp_ipsec.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec26 sctp_ipsec.sh -6 -p esp -a sha1 -e cast5 -m transport -s 100:1000:65535:R65535 +sctp6_ipsec27 sctp_ipsec.sh -6 -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec28 sctp_ipsec.sh -6 -p esp -a sha256 -e blowfish -m transport -s 100:1000:65535:R65535 +sctp6_ipsec29 sctp_ipsec.sh -6 -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec30 sctp_ipsec.sh -6 -p esp -a sha384 -e twofish -m transport -s 100:1000:65535:R65535 +sctp6_ipsec31 sctp_ipsec.sh -6 -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec32 sctp_ipsec.sh -6 -p esp -a sha512 -e camellia -m transport -s 100:1000:65535:R65535 +sctp6_ipsec33 sctp_ipsec.sh -6 -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec34 sctp_ipsec.sh -6 -p esp -a rmd160 -e serpent -m transport -s 100:1000:65535:R65535 +sctp6_ipsec35 sctp_ipsec.sh -6 -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec36 sctp_ipsec.sh -6 -p esp -m beet -s 100:1000:65535:R65535 + +sctp4_ipsec_vti01 sctp_ipsec_vti.sh -p ah -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti02 sctp_ipsec_vti.sh -p esp -m tunnel -s 100:1000:65535:R65535 +# sctp4_ipsec_vti03 sctp_ipsec_vti.sh -p comp -m tunnel -s 100:1000:65535 +sctp4_ipsec_vti04 sctp_ipsec_vti.sh -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti05 sctp_ipsec_vti.sh -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti06 sctp_ipsec_vti.sh -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti07 sctp_ipsec_vti.sh -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti08 sctp_ipsec_vti.sh -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti09 sctp_ipsec_vti.sh -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti10 sctp_ipsec_vti.sh -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti11 sctp_ipsec_vti.sh -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti12 sctp_ipsec_vti.sh -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti13 sctp_ipsec_vti.sh -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti14 sctp_ipsec_vti.sh -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti15 sctp_ipsec_vti.sh -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti16 sctp_ipsec_vti.sh -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65535:R65535 +sctp4_ipsec_vti17 sctp_ipsec_vti.sh -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65535:R65535 + +sctp6_ipsec_vti01 sctp_ipsec_vti.sh -6 -p ah -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti02 sctp_ipsec_vti.sh -6 -p esp -m tunnel -s 100:1000:65535:R65535 +# sctp6_ipsec_vti03 sctp_ipsec_vti.sh -6 -p comp -m tunnel -s 100:1000:65535 +sctp6_ipsec_vti04 sctp_ipsec_vti.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti05 sctp_ipsec_vti.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti06 sctp_ipsec_vti.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti07 sctp_ipsec_vti.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti08 sctp_ipsec_vti.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti09 sctp_ipsec_vti.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti10 sctp_ipsec_vti.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti11 sctp_ipsec_vti.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti12 sctp_ipsec_vti.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti13 sctp_ipsec_vti.sh -6 -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti14 sctp_ipsec_vti.sh -6 -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti15 sctp_ipsec_vti.sh -6 -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti16 sctp_ipsec_vti.sh -6 -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65535:R65535 +sctp6_ipsec_vti17 sctp_ipsec_vti.sh -6 -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65535:R65535 diff --git a/ltp/runtest/net_stress.ipsec_tcp b/ltp/runtest/net_stress.ipsec_tcp new file mode 100644 index 0000000000000000000000000000000000000000..09d238449c9b91be347ad9a07f73267d2203224a --- /dev/null +++ b/ltp/runtest/net_stress.ipsec_tcp @@ -0,0 +1,109 @@ +tcp4_ipsec01 tcp_ipsec.sh -s 100:1000:65535:R65535 +tcp4_ipsec02 tcp_ipsec.sh -p ah -m transport -s 100:1000:65535:R65535 +tcp4_ipsec03 tcp_ipsec.sh -p ah -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec04 tcp_ipsec.sh -p esp -m transport -s 100:1000:65535:R65535 +tcp4_ipsec05 tcp_ipsec.sh -p esp -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec06 tcp_ipsec.sh -p comp -m transport -s 100:1000:65535:R65535 +tcp4_ipsec07 tcp_ipsec.sh -p comp -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec08 tcp_ipsec.sh -A rfc4106_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec09 tcp_ipsec.sh -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec10 tcp_ipsec.sh -A rfc4106_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec11 tcp_ipsec.sh -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec12 tcp_ipsec.sh -A rfc4106_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec13 tcp_ipsec.sh -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec14 tcp_ipsec.sh -A rfc4309_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec15 tcp_ipsec.sh -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec16 tcp_ipsec.sh -A rfc4309_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec17 tcp_ipsec.sh -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec18 tcp_ipsec.sh -A rfc4309_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec19 tcp_ipsec.sh -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec20 tcp_ipsec.sh -A rfc4543_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec21 tcp_ipsec.sh -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec22 tcp_ipsec.sh -A rfc4543_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec23 tcp_ipsec.sh -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec24 tcp_ipsec.sh -A rfc4543_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp4_ipsec25 tcp_ipsec.sh -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec26 tcp_ipsec.sh -p esp -a sha1 -e cast5 -m transport -s 100:1000:65535:R65535 +tcp4_ipsec27 tcp_ipsec.sh -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec28 tcp_ipsec.sh -p esp -a sha256 -e blowfish -m transport -s 100:1000:65535:R65535 +tcp4_ipsec29 tcp_ipsec.sh -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec30 tcp_ipsec.sh -p esp -a sha384 -e twofish -m transport -s 100:1000:65535:R65535 +tcp4_ipsec31 tcp_ipsec.sh -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec32 tcp_ipsec.sh -p esp -a sha512 -e camellia -m transport -s 100:1000:65535:R65535 +tcp4_ipsec33 tcp_ipsec.sh -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec34 tcp_ipsec.sh -p esp -a rmd160 -e serpent -m transport -s 100:1000:65535:R65535 +tcp4_ipsec35 tcp_ipsec.sh -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec36 tcp_ipsec.sh -p esp -m beet -s 100:1000:65535:R65535 + +tcp6_ipsec01 tcp_ipsec.sh -6 -s 100:1000:65535:R65535 +tcp6_ipsec02 tcp_ipsec.sh -6 -p ah -m transport -s 100:1000:65535:R65535 +tcp6_ipsec03 tcp_ipsec.sh -6 -p ah -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec04 tcp_ipsec.sh -6 -p esp -m transport -s 100:1000:65535:R65535 +tcp6_ipsec05 tcp_ipsec.sh -6 -p esp -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec06 tcp_ipsec.sh -6 -p comp -m transport -s 100:1000:65535:R65535 +tcp6_ipsec07 tcp_ipsec.sh -6 -p comp -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec08 tcp_ipsec.sh -6 -A rfc4106_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec09 tcp_ipsec.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec10 tcp_ipsec.sh -6 -A rfc4106_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec11 tcp_ipsec.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec12 tcp_ipsec.sh -6 -A rfc4106_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec13 tcp_ipsec.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec14 tcp_ipsec.sh -6 -A rfc4309_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec15 tcp_ipsec.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec16 tcp_ipsec.sh -6 -A rfc4309_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec17 tcp_ipsec.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec18 tcp_ipsec.sh -6 -A rfc4309_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec19 tcp_ipsec.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec20 tcp_ipsec.sh -6 -A rfc4543_128 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec21 tcp_ipsec.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec22 tcp_ipsec.sh -6 -A rfc4543_192 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec23 tcp_ipsec.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec24 tcp_ipsec.sh -6 -A rfc4543_256 -p esp_aead -m transport -s 100:1000:65535:R65535 +tcp6_ipsec25 tcp_ipsec.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec26 tcp_ipsec.sh -6 -p esp -a sha1 -e cast5 -m transport -s 100:1000:65535:R65535 +tcp6_ipsec27 tcp_ipsec.sh -6 -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec28 tcp_ipsec.sh -6 -p esp -a sha256 -e blowfish -m transport -s 100:1000:65535:R65535 +tcp6_ipsec29 tcp_ipsec.sh -6 -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec30 tcp_ipsec.sh -6 -p esp -a sha384 -e twofish -m transport -s 100:1000:65535:R65535 +tcp6_ipsec31 tcp_ipsec.sh -6 -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec32 tcp_ipsec.sh -6 -p esp -a sha512 -e camellia -m transport -s 100:1000:65535:R65535 +tcp6_ipsec33 tcp_ipsec.sh -6 -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec34 tcp_ipsec.sh -6 -p esp -a rmd160 -e serpent -m transport -s 100:1000:65535:R65535 +tcp6_ipsec35 tcp_ipsec.sh -6 -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec36 tcp_ipsec.sh -6 -p esp -m beet -s 100:1000:65535:R65535 + +tcp4_ipsec_vti01 tcp_ipsec_vti.sh -p ah -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti02 tcp_ipsec_vti.sh -p esp -m tunnel -s 100:1000:65535:R65535 +# tcp4_ipsec_vti03 tcp_ipsec_vti.sh -p comp -m tunnel -s 100:1000:65535 +tcp4_ipsec_vti04 tcp_ipsec_vti.sh -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti05 tcp_ipsec_vti.sh -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti06 tcp_ipsec_vti.sh -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti07 tcp_ipsec_vti.sh -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti08 tcp_ipsec_vti.sh -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti09 tcp_ipsec_vti.sh -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti10 tcp_ipsec_vti.sh -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti11 tcp_ipsec_vti.sh -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti12 tcp_ipsec_vti.sh -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti13 tcp_ipsec_vti.sh -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti14 tcp_ipsec_vti.sh -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti15 tcp_ipsec_vti.sh -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti16 tcp_ipsec_vti.sh -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65535:R65535 +tcp4_ipsec_vti17 tcp_ipsec_vti.sh -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65535:R65535 + +tcp6_ipsec_vti01 tcp_ipsec_vti.sh -6 -p ah -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti02 tcp_ipsec_vti.sh -6 -p esp -m tunnel -s 100:1000:65535:R65535 +# tcp6_ipsec_vti03 tcp_ipsec_vti.sh -6 -p comp -m tunnel -s 100:1000:65535 +tcp6_ipsec_vti04 tcp_ipsec_vti.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti05 tcp_ipsec_vti.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti06 tcp_ipsec_vti.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti07 tcp_ipsec_vti.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti08 tcp_ipsec_vti.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti09 tcp_ipsec_vti.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti10 tcp_ipsec_vti.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti11 tcp_ipsec_vti.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti12 tcp_ipsec_vti.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti13 tcp_ipsec_vti.sh -6 -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti14 tcp_ipsec_vti.sh -6 -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti15 tcp_ipsec_vti.sh -6 -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti16 tcp_ipsec_vti.sh -6 -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65535:R65535 +tcp6_ipsec_vti17 tcp_ipsec_vti.sh -6 -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65535:R65535 diff --git a/ltp/runtest/net_stress.ipsec_udp b/ltp/runtest/net_stress.ipsec_udp new file mode 100644 index 0000000000000000000000000000000000000000..37b449017c9e2e1ce9fef1dc96d6286b2f0f4ef6 --- /dev/null +++ b/ltp/runtest/net_stress.ipsec_udp @@ -0,0 +1,109 @@ +udp4_ipsec01 udp_ipsec.sh -s 100:1000:65507:R65507 +udp4_ipsec02 udp_ipsec.sh -p ah -m transport -s 100:1000:65483:R65483 +udp4_ipsec03 udp_ipsec.sh -p ah -m tunnel -s 100:1000:65463:R65463 +udp4_ipsec04 udp_ipsec.sh -p esp -m transport -s 100:1000:65470:R65470 +udp4_ipsec05 udp_ipsec.sh -p esp -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec06 udp_ipsec.sh -p comp -m transport -s 100:1000:65000:R65000 +udp4_ipsec07 udp_ipsec.sh -p comp -m tunnel -s 100:1000:65000:R65000 +udp4_ipsec08 udp_ipsec.sh -A rfc4106_128 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec09 udp_ipsec.sh -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec10 udp_ipsec.sh -A rfc4106_192 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec11 udp_ipsec.sh -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec12 udp_ipsec.sh -A rfc4106_256 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec13 udp_ipsec.sh -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec14 udp_ipsec.sh -A rfc4309_128 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec15 udp_ipsec.sh -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec16 udp_ipsec.sh -A rfc4309_192 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec17 udp_ipsec.sh -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec18 udp_ipsec.sh -A rfc4309_256 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec19 udp_ipsec.sh -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec20 udp_ipsec.sh -A rfc4543_128 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec21 udp_ipsec.sh -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec22 udp_ipsec.sh -A rfc4543_192 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec23 udp_ipsec.sh -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec24 udp_ipsec.sh -A rfc4543_256 -p esp_aead -m transport -s 100:1000:65470:R65470 +udp4_ipsec25 udp_ipsec.sh -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec26 udp_ipsec.sh -p esp -a sha1 -e cast5 -m transport -s 100:1000:65470:R65470 +udp4_ipsec27 udp_ipsec.sh -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec28 udp_ipsec.sh -p esp -a sha256 -e blowfish -m transport -s 100:1000:65470:R65470 +udp4_ipsec29 udp_ipsec.sh -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65426:R65426 +udp4_ipsec30 udp_ipsec.sh -p esp -a sha384 -e twofish -m transport -s 100:1000:65446:R65446 +udp4_ipsec31 udp_ipsec.sh -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65426:R65426 +udp4_ipsec32 udp_ipsec.sh -p esp -a sha512 -e camellia -m transport -s 100:1000:65446:R65446 +udp4_ipsec33 udp_ipsec.sh -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65426:R65426 +udp4_ipsec34 udp_ipsec.sh -p esp -a rmd160 -e serpent -m transport -s 100:1000:65446:R65446 +udp4_ipsec35 udp_ipsec.sh -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65426:R65426 +udp4_ipsec36 udp_ipsec.sh -p esp -m beet -s 100:1000:65446:R65446 + +udp6_ipsec01 udp_ipsec.sh -6 -s 100:1000:65527:R65527 +udp6_ipsec02 udp_ipsec.sh -6 -p ah -m transport -s 100:1000:65503:R65503 +udp6_ipsec03 udp_ipsec.sh -6 -p ah -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec04 udp_ipsec.sh -6 -p esp -m transport -s 100:1000:65490:R65490 +udp6_ipsec05 udp_ipsec.sh -6 -p esp -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec06 udp_ipsec.sh -6 -p comp -m transport -s 100:1000:65000:R65000 +udp6_ipsec07 udp_ipsec.sh -6 -p comp -m tunnel -s 100:1000:65000:R65000 +udp6_ipsec08 udp_ipsec.sh -6 -A rfc4106_128 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec09 udp_ipsec.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec10 udp_ipsec.sh -6 -A rfc4106_192 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec11 udp_ipsec.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec12 udp_ipsec.sh -6 -A rfc4106_256 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec13 udp_ipsec.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec14 udp_ipsec.sh -6 -A rfc4309_128 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec15 udp_ipsec.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec16 udp_ipsec.sh -6 -A rfc4309_192 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec17 udp_ipsec.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec18 udp_ipsec.sh -6 -A rfc4309_256 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec19 udp_ipsec.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec20 udp_ipsec.sh -6 -A rfc4543_128 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec21 udp_ipsec.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec22 udp_ipsec.sh -6 -A rfc4543_192 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec23 udp_ipsec.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec24 udp_ipsec.sh -6 -A rfc4543_256 -p esp_aead -m transport -s 100:1000:65490:R65490 +udp6_ipsec25 udp_ipsec.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec26 udp_ipsec.sh -6 -p esp -a sha1 -e cast5 -m transport -s 100:1000:65490:R65490 +udp6_ipsec27 udp_ipsec.sh -6 -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec28 udp_ipsec.sh -6 -p esp -a sha256 -e blowfish -m transport -s 100:1000:65490:R65490 +udp6_ipsec29 udp_ipsec.sh -6 -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec30 udp_ipsec.sh -6 -p esp -a sha384 -e twofish -m transport -s 100:1000:65462:R65462 +udp6_ipsec31 udp_ipsec.sh -6 -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec32 udp_ipsec.sh -6 -p esp -a sha512 -e camellia -m transport -s 100:1000:65462:R65462 +udp6_ipsec33 udp_ipsec.sh -6 -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec34 udp_ipsec.sh -6 -p esp -a rmd160 -e serpent -m transport -s 100:1000:65478:R65478 +udp6_ipsec35 udp_ipsec.sh -6 -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec36 udp_ipsec.sh -6 -p esp -m beet -s 100:1000:65478:R65478 + +udp4_ipsec_vti01 udp_ipsec_vti.sh -p ah -m tunnel -s 100:1000:65463:R65463 +udp4_ipsec_vti02 udp_ipsec_vti.sh -p esp -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti03 udp_ipsec_vti.sh -p comp -m tunnel -s 1000 +udp4_ipsec_vti04 udp_ipsec_vti.sh -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti05 udp_ipsec_vti.sh -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti06 udp_ipsec_vti.sh -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti07 udp_ipsec_vti.sh -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti08 udp_ipsec_vti.sh -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti09 udp_ipsec_vti.sh -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti10 udp_ipsec_vti.sh -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti11 udp_ipsec_vti.sh -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti12 udp_ipsec_vti.sh -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti13 udp_ipsec_vti.sh -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65450:R65450 +udp4_ipsec_vti14 udp_ipsec_vti.sh -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65426:R65426 +udp4_ipsec_vti15 udp_ipsec_vti.sh -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65426:R65426 +udp4_ipsec_vti16 udp_ipsec_vti.sh -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65426:R65426 +udp4_ipsec_vti17 udp_ipsec_vti.sh -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65426:R65426 + +udp6_ipsec_vti01 udp_ipsec_vti.sh -6 -p ah -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti02 udp_ipsec_vti.sh -6 -p esp -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti03 udp_ipsec_vti.sh -6 -p comp -m tunnel -s 1000 +udp6_ipsec_vti04 udp_ipsec_vti.sh -6 -A rfc4106_128 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti05 udp_ipsec_vti.sh -6 -A rfc4106_192 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti06 udp_ipsec_vti.sh -6 -A rfc4106_256 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti07 udp_ipsec_vti.sh -6 -A rfc4309_128 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti08 udp_ipsec_vti.sh -6 -A rfc4309_192 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti09 udp_ipsec_vti.sh -6 -A rfc4309_256 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti10 udp_ipsec_vti.sh -6 -A rfc4543_128 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti11 udp_ipsec_vti.sh -6 -A rfc4543_192 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti12 udp_ipsec_vti.sh -6 -A rfc4543_256 -p esp_aead -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti13 udp_ipsec_vti.sh -6 -p esp -a sha1 -e cast5 -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti14 udp_ipsec_vti.sh -6 -p esp -a sha256 -e blowfish -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti15 udp_ipsec_vti.sh -6 -p esp -a sha384 -e twofish -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti16 udp_ipsec_vti.sh -6 -p esp -a sha512 -e camellia -m tunnel -s 100:1000:65527:R65527 +udp6_ipsec_vti17 udp_ipsec_vti.sh -6 -p esp -a rmd160 -e serpent -m tunnel -s 100:1000:65527:R65527 diff --git a/ltp/runtest/net_stress.multicast b/ltp/runtest/net_stress.multicast new file mode 100644 index 0000000000000000000000000000000000000000..08b1770fb174d3db006464251426e58751b088cb --- /dev/null +++ b/ltp/runtest/net_stress.multicast @@ -0,0 +1,29 @@ +# +# Stress test for TCP/IP protocol stack (Multicast) +# + +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.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/ltp/runtest/net_stress.route b/ltp/runtest/net_stress.route new file mode 100644 index 0000000000000000000000000000000000000000..5590ef0231d6f24fd324012e821d78bde2583901 --- /dev/null +++ b/ltp/runtest/net_stress.route @@ -0,0 +1,16 @@ +# Stress test for routing table +route4-change-dst route-change-dst.sh +route4-change-gw route-change-gw.sh +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 route-redirect.sh + +route6-change-dst route-change-dst.sh -6 +route6-change-gw route-change-gw.sh -6 +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 route-redirect.sh -6 diff --git a/ltp/runtest/nptl b/ltp/runtest/nptl new file mode 100644 index 0000000000000000000000000000000000000000..45e546caf1da4a483fc7a8a0be6a72ecb827a560 --- /dev/null +++ b/ltp/runtest/nptl @@ -0,0 +1,3 @@ +#DESCRIPTION:Native POSIX Thread Library (NPTL) Tests +nptl01 nptl01 + diff --git a/ltp/runtest/numa b/ltp/runtest/numa new file mode 100644 index 0000000000000000000000000000000000000000..3b9a9a7c5bb6c38962dbfd3b4ff70c6f0fc03307 --- /dev/null +++ b/ltp/runtest/numa @@ -0,0 +1,23 @@ +migrate_pages01 migrate_pages01 +migrate_pages02 migrate_pages02 +migrate_pages03 migrate_pages03 + +move_pages01 move_pages01 +move_pages02 move_pages02 +move_pages03 move_pages03 +move_pages04 move_pages04 +move_pages05 move_pages05 +move_pages06 move_pages06 +move_pages07 move_pages07 +move_pages09 move_pages09 +move_pages10 move_pages10 +move_pages11 move_pages11 +move_pages12 move_pages12 + +numa_testcases numa01.sh + +set_mempolicy01 set_mempolicy01 +set_mempolicy02 set_mempolicy02 +set_mempolicy03 set_mempolicy03 +set_mempolicy04 set_mempolicy04 +set_mempolicy05 set_mempolicy05 diff --git a/ltp/runtest/power_management_tests b/ltp/runtest/power_management_tests new file mode 100644 index 0000000000000000000000000000000000000000..884e615cd8ebcd61edc114d867957d8d258a743d --- /dev/null +++ b/ltp/runtest/power_management_tests @@ -0,0 +1,7 @@ +#POWER_MANAGEMENT +runpwtests01 runpwtests01.sh +runpwtests02 runpwtests02.sh +runpwtests03 runpwtests03.sh +runpwtests04 runpwtests04.sh +#runpwtests05 runpwtests05.sh +runpwtests06 runpwtests06.sh diff --git a/ltp/runtest/power_management_tests_exclusive b/ltp/runtest/power_management_tests_exclusive new file mode 100644 index 0000000000000000000000000000000000000000..0eb01224764165167e16562f94200250cf08f74c --- /dev/null +++ b/ltp/runtest/power_management_tests_exclusive @@ -0,0 +1,6 @@ +#POWER_MANAGEMENT exclusive +runpwtests_exclusive01 runpwtests_exclusive01.sh +runpwtests_exclusive02 runpwtests_exclusive02.sh +runpwtests_exclusive03 runpwtests_exclusive03.sh +runpwtests_exclusive04 runpwtests_exclusive04.sh +runpwtests_exclusive05 runpwtests_exclusive05.sh diff --git a/ltp/runtest/pty b/ltp/runtest/pty new file mode 100644 index 0000000000000000000000000000000000000000..4b1abe7a602a14456877f3bc42f2275a3be0f8f0 --- /dev/null +++ b/ltp/runtest/pty @@ -0,0 +1,18 @@ +#DESCRIPTION:Terminal type stress +pty01 pty01 +pty02 pty02 +pty03 pty03 +pty04 pty04 +pty05 pty05 +pty06 pty06 +pty07 pty07 +pty08 pty08 +pty09 pty09 +ptem01 ptem01 +ptem02 ptem02 +ptem03 ptem03 +ptem04 ptem04 +ptem05 ptem05 +ptem06 ptem06 +hangup01 hangup01 + diff --git a/ltp/runtest/s390x_tests b/ltp/runtest/s390x_tests new file mode 100644 index 0000000000000000000000000000000000000000..0c2bf05a5b5dcf72315c61af4e71775bfb99aed1 --- /dev/null +++ b/ltp/runtest/s390x_tests @@ -0,0 +1,2 @@ +# Those tests are designed to be executed in s390x environment (zVM or LPAR) +vmcp vmcp_m.sh diff --git a/ltp/runtest/sched b/ltp/runtest/sched new file mode 100644 index 0000000000000000000000000000000000000000..ecedd1a92bf39790247f030e59c26a9442eaefef --- /dev/null +++ b/ltp/runtest/sched @@ -0,0 +1,22 @@ +#DESCRIPTION:Scheduler Stress Tests +pth_str01 pth_str01 +pth_str02 pth_str02 -n1000 +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 +starvation starvation + +proc_sched_rt01 proc_sched_rt01 + +sched_cli_serv run_sched_cliserv.sh +# Run this stress test for 2 minutes +sched_stress sched_stress.sh + +autogroup01 autogroup01 + +sched_football sched_football diff --git a/ltp/runtest/scsi_debug.part1 b/ltp/runtest/scsi_debug.part1 new file mode 100644 index 0000000000000000000000000000000000000000..ce147028852f8f42b877063e1bc9ab9ac4f65f5e --- /dev/null +++ b/ltp/runtest/scsi_debug.part1 @@ -0,0 +1,145 @@ +#DESCRIPTION:scsi_debug filesystem tests +# Check the Reiserfs filesystem +gf201 growfiles -W gf201 -d /test/growfiles/reiser -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 glseek20 glseek20.2 +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_ +gf206 growfiles -W gf206 -d /test/growfiles/reiser -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand10 g_rand10.2 +gf207 growfiles -W gf207 -d /test/growfiles/reiser -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p g_rand13 g_rand13.2 +gf208 growfiles -W gf208 -d /test/growfiles/reiser -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 g_rand11 g_rand11.2 +gf209 growfiles -W gf209 -d /test/growfiles/reiser -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p g_rand12 g_rand12.2 +gf210 growfiles -W gf210 -d /test/growfiles/reiser -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l g_lio14 g_lio14.2 +gf211 growfiles -W gf211 -d /test/growfiles/reiser -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L g_lio15 g_lio15.2 +gf212 mkfifo gffifo17; growfiles -W gf212 -d /test/growfiles/reiser -b -e 1 -u -i 0 -L 30 gffifo17 +gf213 mkfifo gffifo18; growfiles -W gf213 -d /test/growfiles/reiser -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 gffifo18 +gf214 growfiles -W gf214 -d /test/growfiles/reiser -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 glseek19 glseek19.2 +gf215 growfiles -W gf215 -d /test/growfiles/reiser -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 Lgfile1 +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_ +gf220 growfiles -W gf220 -d /test/growfiles/reiser -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 gfbigio-$$ +gf221 growfiles -W gf221 -d /test/growfiles/reiser -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bld-$$ +gf222 growfiles -W gf222 -d /test/growfiles/reiser -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bldf-$$ +gf223 growfiles -W gf223 -d /test/growfiles/reiser -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 gf-inf-$$ +gf224 growfiles -W gf224 -d /test/growfiles/reiser -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 gf-jbld-$$ +gf225 growfiles -W gf225 -d /test/growfiles/reiser -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 gf-large-gs-$$ +gf226 growfiles -W gf226 -d /test/growfiles/reiser -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 gfsmallio-$$ +gf227 growfiles -W gf227 -d /test/growfiles/reiser -b -D 0 -w -g 8b -C 1 -b -i 1000 -u gfsparse-1-$$ +gf228 growfiles -W gf228 -d /test/growfiles/reiser -b -D 0 -w -g 16b -C 1 -b -i 1000 -u gfsparse-2-$$ +gf229 growfiles -W gf229 -d /test/growfiles/reiser -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u gfsparse-3-$$ +gf230 growfiles -W gf230 -d /test/growfiles/reiser -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/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 +gf301 growfiles -W gf301 -d /test/growfiles/ext2 -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 glseek20 glseek20.2 +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_ +gf306 growfiles -W gf306 -d /test/growfiles/ext2 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand10 g_rand10.2 +gf307 growfiles -W gf307 -d /test/growfiles/ext2 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p g_rand13 g_rand13.2 +gf308 growfiles -W gf308 -d /test/growfiles/ext2 -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 g_rand11 g_rand11.2 +gf309 growfiles -W gf309 -d /test/growfiles/ext2 -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p g_rand12 g_rand12.2 +gf310 growfiles -W gf310 -d /test/growfiles/ext2 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l g_lio14 g_lio14.2 +gf311 growfiles -W gf311 -d /test/growfiles/ext2 -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L g_lio15 g_lio15.2 +gf312 mkfifo gffifo17; growfiles -W gf312 -d /test/growfiles/ext2 -b -e 1 -u -i 0 -L 30 gffifo17 +gf313 mkfifo gffifo18; growfiles -W gf313 -d /test/growfiles/ext2 -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 gffifo18 +gf314 growfiles -W gf314 -d /test/growfiles/ext2 -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 glseek19 glseek19.2 +gf315 growfiles -W gf315 -d /test/growfiles/ext2 -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 Lgfile1 +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_ +gf320 growfiles -W gf320 -d /test/growfiles/ext2 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 gfbigio-$$ +gf321 growfiles -W gf321 -d /test/growfiles/ext2 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bld-$$ +gf322 growfiles -W gf322 -d /test/growfiles/ext2 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bldf-$$ +gf323 growfiles -W gf323 -d /test/growfiles/ext2 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 gf-inf-$$ +gf324 growfiles -W gf324 -d /test/growfiles/ext2 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 gf-jbld-$$ +gf325 growfiles -W gf325 -d /test/growfiles/ext2 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 gf-large-gs-$$ +gf326 growfiles -W gf326 -d /test/growfiles/ext2 -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 gfsmallio-$$ +gf327 growfiles -W gf327 -d /test/growfiles/ext2 -b -D 0 -w -g 8b -C 1 -b -i 1000 -u gfsparse-1-$$ +gf328 growfiles -W gf328 -d /test/growfiles/ext2 -b -D 0 -w -g 16b -C 1 -b -i 1000 -u gfsparse-2-$$ +gf329 growfiles -W gf329 -d /test/growfiles/ext2 -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u gfsparse-3-$$ +gf330 growfiles -W gf330 -d /test/growfiles/ext2 -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/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 the EXT3 filesystem +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 +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_ +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 +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 +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 +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_ +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 MSDOS filesystem +gf101 growfiles -W gf101 -d /test/growfiles/msdos -b -e 1 -u -i 0 -L 20 -w -C 1 -l -I r -T 10 glseek20 glseek20.2 +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_ +gf106 growfiles -W gf106 -d /test/growfiles/msdos -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand10 g_rand10.2 +gf107 growfiles -W gf107 -d /test/growfiles/msdos -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 -I p g_rand13 g_rand13.2 +gf108 growfiles -W gf108 -d /test/growfiles/msdos -b -e 1 -u -r 1-5000 -R 0--2 -i 0 -L 30 -C 1 g_rand11 g_rand11.2 +gf109 growfiles -W gf109 -d /test/growfiles/msdos -b -e 1 -u -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 -I p g_rand12 g_rand12.2 +gf110 growfiles -W gf110 -d /test/growfiles/msdos -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I l g_lio14 g_lio14.2 +gf111 growfiles -W gf111 -d /test/growfiles/msdos -b -e 1 -u -r 1-5000 -i 0 -L 30 -C 1 -I L g_lio15 g_lio15.2 +gf112 mkfifo gffifo17; growfiles -W gf112 -d /test/growfiles/msdos -b -e 1 -u -i 0 -L 30 gffifo17 +gf113 mkfifo gffifo18; growfiles -W gf113 -d /test/growfiles/msdos -b -e 1 -u -i 0 -L 30 -I r -r 1-4096 gffifo18 +gf114 growfiles -W gf114 -d /test/growfiles/msdos -b -e 1 -u -i 0 -L 20 -w -l -C 1 -T 10 glseek19 glseek19.2 +gf115 growfiles -W gf115 -d /test/growfiles/msdos -b -e 1 -u -r 1-49600 -I r -u -i 0 -L 120 Lgfile1 +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_ +gf120 growfiles -W gf120 -d /test/growfiles/msdos -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1-256000:512 -R 512-256000 -T 4 gfbigio-$$ +gf121 growfiles -W gf121 -d /test/growfiles/msdos -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bld-$$ +gf122 growfiles -W gf122 -d /test/growfiles/msdos -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 -T 10 -t 20480 gf-bldf-$$ +gf123 growfiles -W gf123 -d /test/growfiles/msdos -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 512-64000:1024 -R 1-384000 -T 4 gf-inf-$$ +gf124 growfiles -W gf124 -d /test/growfiles/msdos -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -g 20480 gf-jbld-$$ +gf125 growfiles -W gf125 -d /test/growfiles/msdos -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 1024000-2048000:2048 -R 4095-2048000 -T 1 gf-large-gs-$$ +gf126 growfiles -W gf126 -d /test/growfiles/msdos -D 0 -b -i 0 -L 60 -u -B 1000b -e 1 -r 128-32768:128 -R 512-64000 -T 4 gfsmallio-$$ +gf127 growfiles -W gf127 -d /test/growfiles/msdos -b -D 0 -w -g 8b -C 1 -b -i 1000 -u gfsparse-1-$$ +gf128 growfiles -W gf128 -d /test/growfiles/msdos -b -D 0 -w -g 16b -C 1 -b -i 1000 -u gfsparse-2-$$ +gf129 growfiles -W gf129 -d /test/growfiles/msdos -b -D 0 -r 1-4096 -R 0-33554432 -i 0 -L 60 -C 1 -u gfsparse-3-$$ +gf130 growfiles -W gf130 -d /test/growfiles/msdos -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/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 diff --git a/ltp/runtest/smack b/ltp/runtest/smack new file mode 100644 index 0000000000000000000000000000000000000000..0e80048337089696949fbd2d9ef6932bfdb4dace --- /dev/null +++ b/ltp/runtest/smack @@ -0,0 +1,10 @@ +smack_set_ambient smack_set_ambient.sh +smack_set_current smack_set_current.sh +smack_set_doi smack_set_doi.sh +smack_set_netlabel smack_set_netlabel.sh +smack_set_socket_labels smack_set_socket_labels +smack_set_cipso smack_set_cipso.sh +smack_set_direct smack_set_direct.sh +smack_set_load smack_set_load.sh +smack_set_onlycap smack_set_onlycap.sh +smack_file_access smack_file_access.sh diff --git a/ltp/runtest/smoketest b/ltp/runtest/smoketest new file mode 100644 index 0000000000000000000000000000000000000000..538ee06f1b1c1d2e9620c35e5008047d23e03e00 --- /dev/null +++ b/ltp/runtest/smoketest @@ -0,0 +1,15 @@ +# 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 +stat04 stat04 +splice02 splice02 -s 20 +df01_sh df01.sh +shell_test01 echo "SUCCESS" | shell_pipe01.sh +ping602 ping02.sh -6 +macsec02 macsec02.sh diff --git a/ltp/runtest/staging b/ltp/runtest/staging new file mode 100644 index 0000000000000000000000000000000000000000..ef1cdea150d88632c45004e394938260e21c889f --- /dev/null +++ b/ltp/runtest/staging @@ -0,0 +1 @@ +# Tests for features that are not yet in the stable kernel ABI diff --git a/ltp/runtest/syscalls b/ltp/runtest/syscalls new file mode 100644 index 0000000000000000000000000000000000000000..e738c332bf973840e6cc0bde489882eb65018991 --- /dev/null +++ b/ltp/runtest/syscalls @@ -0,0 +1,1875 @@ +#DESCRIPTION:Kernel system calls +abort01 abort01 + +accept01 accept01 +accept02 accept02 +accept03 accept03 + +accept4_01 accept4_01 + +access01 access01 +access02 access02 +access03 access03 +access04 access04 + +acct01 acct01 +acct02 acct02 + +add_key01 add_key01 +add_key02 add_key02 +add_key03 add_key03 +add_key04 add_key04 +add_key05 add_key05 + +adjtimex01 adjtimex01 +adjtimex02 adjtimex02 +adjtimex03 adjtimex03 + +alarm02 alarm02 +alarm03 alarm03 +alarm05 alarm05 +alarm06 alarm06 +alarm07 alarm07 + +arch_prctl01 arch_prctl01 + +bind01 bind01 +bind02 bind02 +bind03 bind03 +bind04 bind04 +bind05 bind05 +bind06 bind06 + +bpf_map01 bpf_map01 +bpf_prog01 bpf_prog01 +bpf_prog02 bpf_prog02 +bpf_prog03 bpf_prog03 +bpf_prog04 bpf_prog04 +bpf_prog05 bpf_prog05 +bpf_prog06 bpf_prog06 +bpf_prog07 bpf_prog07 + +brk01 brk01 +brk02 brk02 + +capget01 capget01 +capget02 capget02 + +capset01 capset01 +capset02 capset02 +capset03 capset03 +capset04 capset04 + +cacheflush01 cacheflush01 + +cachestat01 cachestat01 +cachestat02 cachestat02 +cachestat03 cachestat03 +cachestat04 cachestat04 + +chdir01 chdir01 +chdir04 chdir04 + +chmod01 chmod01 +chmod03 chmod03 +chmod05 chmod05 +chmod06 chmod06 +chmod07 chmod07 +chmod08 chmod08 +chmod09 chmod09 + +chown01 chown01 +chown01_16 chown01_16 +chown02 chown02 +chown02_16 chown02_16 +chown03 chown03 +chown03_16 chown03_16 +chown04 chown04 +chown04_16 chown04_16 +chown05 chown05 +chown05_16 chown05_16 + +chroot01 chroot01 +chroot02 chroot02 +chroot03 chroot03 +chroot04 chroot04 + +clock_adjtime01 clock_adjtime01 +clock_adjtime02 clock_adjtime02 + +clock_getres01 clock_getres01 +clock_nanosleep01 clock_nanosleep01 +clock_nanosleep02 clock_nanosleep02 +clock_nanosleep03 clock_nanosleep03 +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 +clone03 clone03 +clone04 clone04 +clone05 clone05 +clone06 clone06 +clone07 clone07 +clone08 clone08 +clone09 clone09 + +clone301 clone301 +clone302 clone302 +clone303 clone303 + +close01 close01 +close02 close02 + +close_range01 close_range01 +close_range02 close_range02 + +confstr01 confstr01 + +connect01 connect01 +connect02 connect02 + +creat01 creat01 +creat03 creat03 +creat04 creat04 +creat05 creat05 +creat06 creat06 +creat07 creat07 +creat08 creat08 +creat09 creat09 + +delete_module01 delete_module01 +delete_module02 delete_module02 +delete_module03 delete_module03 + +dup01 dup01 +dup02 dup02 +dup03 dup03 +dup04 dup04 +dup05 dup05 +dup06 dup06 +dup07 dup07 + +dup201 dup201 +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_wait05 epoll_wait05 +epoll_wait06 epoll_wait06 +epoll_wait07 epoll_wait07 +epoll_pwait01 epoll_pwait01 +epoll_pwait02 epoll_pwait02 +epoll_pwait03 epoll_pwait03 +epoll_pwait04 epoll_pwait04 +epoll_pwait05 epoll_pwait05 +epoll_pwait06 epoll_pwait06 + +eventfd01 eventfd01 +eventfd02 eventfd02 +eventfd03 eventfd03 +eventfd04 eventfd04 +eventfd05 eventfd05 +eventfd06 eventfd06 + +eventfd2_01 eventfd2_01 +eventfd2_02 eventfd2_02 +eventfd2_03 eventfd2_03 + +execl01 execl01 +execle01 execle01 +execlp01 execlp01 + +execv01 execv01 +execve01 execve01 +execve02 execve02 +execve03 execve03 +execve04 execve04 +execve05 execve05 -i 5 -n 32 +execve06 execve06 +execvp01 execvp01 +execveat01 execveat01 +execveat02 execveat02 +execveat03 execveat03 + +exit01 exit01 +exit02 exit02 + +exit_group01 exit_group01 + +#faccessat test cases +faccessat01 faccessat01 +faccessat02 faccessat02 + +#faccessat2 test cases +faccessat201 faccessat201 +faccessat202 faccessat202 + +#fallocate test cases +fallocate01 fallocate01 +fallocate02 fallocate02 +fallocate03 fallocate03 +fallocate04 fallocate04 +fallocate05 fallocate05 +fallocate06 fallocate06 + +fsetxattr01 fsetxattr01 +fsetxattr02 fsetxattr02 + +#posix_fadvise test cases +posix_fadvise01 posix_fadvise01 +posix_fadvise01_64 posix_fadvise01_64 +posix_fadvise02 posix_fadvise02 +posix_fadvise02_64 posix_fadvise02_64 +posix_fadvise03 posix_fadvise03 +posix_fadvise03_64 posix_fadvise03_64 +posix_fadvise04 posix_fadvise04 +posix_fadvise04_64 posix_fadvise04_64 + +fchdir01 fchdir01 +fchdir02 fchdir02 +fchdir03 fchdir03 + +fchmod01 fchmod01 +fchmod02 fchmod02 +fchmod03 fchmod03 +fchmod04 fchmod04 +fchmod05 fchmod05 +fchmod06 fchmod06 + +#fchmodat test cases +fchmodat01 fchmodat01 +fchmodat02 fchmodat02 + +fchmodat2_01 fchmodat2_01 +fchmodat2_02 fchmodat2_02 + +fchown01 fchown01 +fchown01_16 fchown01_16 +fchown02 fchown02 +fchown02_16 fchown02_16 +fchown03 fchown03 +fchown03_16 fchown03_16 +fchown04 fchown04 +fchown04_16 fchown04_16 +fchown05 fchown05 +fchown05_16 fchown05_16 + +#fchownat test case +fchownat01 fchownat01 +fchownat02 fchownat02 +fchownat03 fchownat03 + +fcntl01 fcntl01 +fcntl01_64 fcntl01_64 +fcntl02 fcntl02 +fcntl02_64 fcntl02_64 +fcntl03 fcntl03 +fcntl03_64 fcntl03_64 +fcntl04 fcntl04 +fcntl04_64 fcntl04_64 +fcntl05 fcntl05 +fcntl05_64 fcntl05_64 +fcntl07 fcntl07 +fcntl07_64 fcntl07_64 +fcntl08 fcntl08 +fcntl08_64 fcntl08_64 +fcntl09 fcntl09 +fcntl09_64 fcntl09_64 +fcntl10 fcntl10 +fcntl10_64 fcntl10_64 +fcntl11 fcntl11 +fcntl11_64 fcntl11_64 +fcntl12 fcntl12 +fcntl12_64 fcntl12_64 +fcntl13 fcntl13 +fcntl13_64 fcntl13_64 +fcntl14 fcntl14 +fcntl14_64 fcntl14_64 +fcntl15 fcntl15 +fcntl15_64 fcntl15_64 +fcntl16 fcntl16 +fcntl16_64 fcntl16_64 +fcntl17 fcntl17 +fcntl17_64 fcntl17_64 +fcntl18 fcntl18 +fcntl18_64 fcntl18_64 +fcntl19 fcntl19 +fcntl19_64 fcntl19_64 +fcntl20 fcntl20 +fcntl20_64 fcntl20_64 +fcntl21 fcntl21 +fcntl21_64 fcntl21_64 +fcntl22 fcntl22 +fcntl22_64 fcntl22_64 +fcntl23 fcntl23 +fcntl23_64 fcntl23_64 +fcntl24 fcntl24 +fcntl24_64 fcntl24_64 +fcntl25 fcntl25 +fcntl25_64 fcntl25_64 +fcntl26 fcntl26 +fcntl26_64 fcntl26_64 +fcntl27 fcntl27 +fcntl27_64 fcntl27_64 +fcntl29 fcntl29 +fcntl29_64 fcntl29_64 +fcntl30 fcntl30 +fcntl30_64 fcntl30_64 +fcntl31 fcntl31 +fcntl31_64 fcntl31_64 +fcntl32 fcntl32 +fcntl32_64 fcntl32_64 +fcntl33 fcntl33 +fcntl33_64 fcntl33_64 +fcntl34 fcntl34 +fcntl34_64 fcntl34_64 +fcntl35 fcntl35 +fcntl35_64 fcntl35_64 +fcntl36 fcntl36 +fcntl36_64 fcntl36_64 +fcntl37 fcntl37 +fcntl37_64 fcntl37_64 +fcntl38 fcntl38 +fcntl38_64 fcntl38_64 +fcntl39 fcntl39 +fcntl39_64 fcntl39_64 +fcntl40 fcntl40 +fcntl40_64 fcntl40_64 + +fdatasync01 fdatasync01 +fdatasync02 fdatasync02 +fdatasync03 fdatasync03 + +fgetxattr01 fgetxattr01 +fgetxattr02 fgetxattr02 +fgetxattr03 fgetxattr03 + +finit_module01 finit_module01 +finit_module02 finit_module02 + +flistxattr01 flistxattr01 +flistxattr02 flistxattr02 +flistxattr03 flistxattr03 + +flock01 flock01 +flock02 flock02 +flock03 flock03 +flock04 flock04 +flock06 flock06 +flock07 flock07 + +fmtmsg01 fmtmsg01 + +fork01 fork01 +fork03 fork03 +fork04 fork04 +fork05 fork05 +fork06 fork_procs -n 1000 +fork07 fork07 +fork08 fork08 +fork09 fork09 +fork10 fork10 +fork11 fork_procs -n 100 +fork13 fork13 +fork14 fork14 + +fpathconf01 fpathconf01 + +fremovexattr01 fremovexattr01 +fremovexattr02 fremovexattr02 + +fsconfig01 fsconfig01 +fsconfig02 fsconfig02 +fsconfig03 fsconfig03 + +fsmount01 fsmount01 +fsmount02 fsmount02 + +fsopen01 fsopen01 +fsopen02 fsopen02 + +fspick01 fspick01 +fspick02 fspick02 + +fstat02 fstat02 +fstat02_64 fstat02_64 +fstat03 fstat03 +fstat03_64 fstat03_64 + +#fstatat64/newfstatat test cases +fstatat01 fstatat01 + +fstatfs01 fstatfs01 +fstatfs01_64 fstatfs01_64 +fstatfs02 fstatfs02 +fstatfs02_64 fstatfs02_64 + +fsync01 fsync01 +fsync02 fsync02 +fsync03 fsync03 +fsync04 fsync04 + +ftruncate01 ftruncate01 +ftruncate01_64 ftruncate01_64 +ftruncate03 ftruncate03 +ftruncate03_64 ftruncate03_64 +ftruncate04 ftruncate04 +ftruncate04_64 ftruncate04_64 + +#futimesat test cases +futimesat01 futimesat01 + +getcontext01 getcontext01 + +getcpu01 getcpu01 +getcpu02 getcpu02 + +getcwd01 getcwd01 +getcwd02 getcwd02 +getcwd03 getcwd03 +getcwd04 getcwd04 + +getdents01 getdents01 +getdents02 getdents02 + +getdomainname01 getdomainname01 + +getegid01 getegid01 +getegid01_16 getegid01_16 +getegid02 getegid02 +getegid02_16 getegid02_16 + +geteuid01 geteuid01 +geteuid01_16 geteuid01_16 +geteuid02 geteuid02 +geteuid02_16 geteuid02_16 + +getgid01 getgid01 +getgid01_16 getgid01_16 +getgid03 getgid03 +getgid03_16 getgid03_16 + +getgroups01 getgroups01 +getgroups01_16 getgroups01_16 +getgroups03 getgroups03 +getgroups03_16 getgroups03_16 + +gethostbyname_r01 gethostbyname_r01 + +gethostid01 gethostid01 + +gethostname01 gethostname01 +gethostname02 gethostname02 + +getitimer01 getitimer01 +getitimer02 getitimer02 + +getpagesize01 getpagesize01 + +getpeername01 getpeername01 + +getpgid01 getpgid01 +getpgid02 getpgid02 + +getpgrp01 getpgrp01 + +getpid01 getpid01 +getpid02 getpid02 + +getppid01 getppid01 +getppid02 getppid02 + +getpriority01 getpriority01 +getpriority02 getpriority02 + +getrandom01 getrandom01 +getrandom02 getrandom02 +getrandom03 getrandom03 +getrandom04 getrandom04 +getrandom05 getrandom05 + +getresgid01 getresgid01 +getresgid01_16 getresgid01_16 +getresgid02 getresgid02 +getresgid02_16 getresgid02_16 +getresgid03 getresgid03 +getresgid03_16 getresgid03_16 + +getresuid01 getresuid01 +getresuid01_16 getresuid01_16 +getresuid02 getresuid02 +getresuid02_16 getresuid02_16 +getresuid03 getresuid03 +getresuid03_16 getresuid03_16 + +getrlimit01 getrlimit01 +getrlimit02 getrlimit02 +getrlimit03 getrlimit03 + +get_mempolicy01 get_mempolicy01 +get_mempolicy02 get_mempolicy02 +get_robust_list01 get_robust_list01 + +getrusage01 getrusage01 +getrusage02 getrusage02 +getrusage03 getrusage03 +getrusage04 getrusage04 + +getsid01 getsid01 +getsid02 getsid02 + +getsockname01 getsockname01 + +getsockopt01 getsockopt01 +getsockopt02 getsockopt02 + +gettid01 gettid01 +gettid02 gettid02 + +gettimeofday01 gettimeofday01 +gettimeofday02 gettimeofday02 + +getuid01 getuid01 +getuid01_16 getuid01_16 +getuid03 getuid03 +getuid03_16 getuid03_16 + +getxattr01 getxattr01 +getxattr02 getxattr02 +getxattr03 getxattr03 +getxattr04 getxattr04 +getxattr05 getxattr05 + +init_module01 init_module01 +init_module02 init_module02 + +#Needs tty device. +#ioctl02 ioctl02 -d /dev/tty0 + +# Introducing ioctl tests for all /dev/tty* devices +ioctl01 ioctl01 +ioctl02 test_ioctl +ioctl03 ioctl03 +ioctl04 ioctl04 +ioctl05 ioctl05 +ioctl06 ioctl06 +ioctl07 ioctl07 +ioctl08 ioctl08 +ioctl09 ioctl09 +ioctl10 ioctl10 + +ioctl_loop01 ioctl_loop01 +ioctl_loop02 ioctl_loop02 +ioctl_loop03 ioctl_loop03 +ioctl_loop04 ioctl_loop04 +ioctl_loop05 ioctl_loop05 +ioctl_loop06 ioctl_loop06 +ioctl_loop07 ioctl_loop07 + +ioctl_ns01 ioctl_ns01 +ioctl_ns02 ioctl_ns02 +ioctl_ns03 ioctl_ns03 +ioctl_ns04 ioctl_ns04 +ioctl_ns05 ioctl_ns05 +ioctl_ns06 ioctl_ns06 +ioctl_ns07 ioctl_ns07 + +ioctl_sg01 ioctl_sg01 + +ioctl_ficlone01 ioctl_ficlone01 +ioctl_ficlone02 ioctl_ficlone02 +ioctl_ficlone03 ioctl_ficlone03 +ioctl_ficlonerange01 ioctl_ficlonerange01 +ioctl_ficlonerange02 ioctl_ficlonerange02 +ioctl_fiemap01 ioctl_fiemap01 + +inotify_init1_01 inotify_init1_01 +inotify_init1_02 inotify_init1_02 + +inotify01 inotify01 +inotify02 inotify02 +inotify03 inotify03 +inotify04 inotify04 +inotify05 inotify05 +inotify06 inotify06 +inotify07 inotify07 +inotify08 inotify08 +inotify09 inotify09 +inotify10 inotify10 +inotify11 inotify11 +inotify12 inotify12 + +fanotify01 fanotify01 +fanotify02 fanotify02 +fanotify03 fanotify03 +fanotify04 fanotify04 +fanotify05 fanotify05 +fanotify06 fanotify06 +fanotify07 fanotify07 +fanotify08 fanotify08 +fanotify09 fanotify09 +fanotify10 fanotify10 +fanotify11 fanotify11 +fanotify12 fanotify12 +fanotify13 fanotify13 +fanotify14 fanotify14 +fanotify15 fanotify15 +fanotify16 fanotify16 +fanotify17 fanotify17 +fanotify18 fanotify18 +fanotify19 fanotify19 +fanotify20 fanotify20 +fanotify21 fanotify21 +fanotify22 fanotify22 +fanotify23 fanotify23 +fanotify24 fanotify24 + +ioperm01 ioperm01 +ioperm02 ioperm02 + +iopl01 iopl01 +iopl02 iopl02 + +ioprio_get01 ioprio_get01 +ioprio_set01 ioprio_set01 +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 +keyctl03 keyctl03 +keyctl04 keyctl04 +keyctl05 keyctl05 +keyctl06 keyctl06 +keyctl07 keyctl07 +keyctl08 keyctl08 +keyctl09 keyctl09 + +kcmp01 kcmp01 +kcmp02 kcmp02 +kcmp03 kcmp03 + +kill02 kill02 +kill03 kill03 +kill05 kill05 +kill06 kill06 +kill08 kill08 +kill10 kill10 +kill11 kill11 +kill12 kill12 +kill13 kill13 + +landlock01 landlock01 +landlock02 landlock02 +landlock03 landlock03 +landlock04 landlock04 +landlock05 landlock05 +landlock06 landlock06 +landlock07 landlock07 +landlock08 landlock08 +landlock09 landlock09 +landlock10 landlock10 + +lchown01 lchown01 +lchown01_16 lchown01_16 +lchown02 lchown02 +lchown03 lchown03 +lchown02_16 lchown02_16 +lchown03_16 lchown03_16 + +lgetxattr01 lgetxattr01 +lgetxattr02 lgetxattr02 + +link02 link02 +link04 link04 +link05 link05 +link08 link08 + +#linkat test cases +linkat01 linkat01 +linkat02 linkat02 + +listen01 listen01 + +listmount01 listmount01 +listmount02 listmount02 +listmount03 listmount03 +listmount04 listmount04 + +listxattr01 listxattr01 +listxattr02 listxattr02 +listxattr03 listxattr03 + +llistxattr01 llistxattr01 +llistxattr02 llistxattr02 +llistxattr03 llistxattr03 + +llseek01 llseek01 +llseek02 llseek02 +llseek03 llseek03 + +lremovexattr01 lremovexattr01 + +lseek01 lseek01 +lseek02 lseek02 +lseek07 lseek07 +lseek11 lseek11 + +lsm_get_self_attr01 lsm_get_self_attr01 +lsm_get_self_attr02 lsm_get_self_attr02 +lsm_get_self_attr03 lsm_get_self_attr03 +lsm_list_modules01 lsm_list_modules01 +lsm_list_modules02 lsm_list_modules02 +lsm_set_self_attr01 lsm_set_self_attr01 + +lstat01 lstat01 +lstat01_64 lstat01_64 +lstat02 lstat02 +lstat02_64 lstat02_64 +lstat03 lstat03 +lstat03_64 lstat03_64 + +mallinfo02 mallinfo02 + +mallinfo2_01 mallinfo2_01 + +mallopt01 mallopt01 + +mbind01 mbind01 +mbind02 mbind02 +mbind03 mbind03 +mbind04 mbind04 + +memset01 memset01 +memcmp01 memcmp01 +memcpy01 memcpy01 + +migrate_pages01 migrate_pages01 +migrate_pages02 migrate_pages02 +migrate_pages03 migrate_pages03 + +mlockall01 mlockall01 +mlockall02 mlockall02 +mlockall03 mlockall03 + +mkdir02 mkdir02 +mkdir03 mkdir03 +mkdir04 mkdir04 +mkdir05 mkdir05 +mkdir09 mkdir09 + +#mkdirat test cases +mkdirat01 mkdirat01 +mkdirat02 mkdirat02 + +mknod01 mknod01 +mknod02 mknod02 +mknod03 mknod03 +mknod04 mknod04 +mknod05 mknod05 +mknod06 mknod06 +mknod07 mknod07 +mknod08 mknod08 +mknod09 mknod09 + +#mknodat test cases +mknodat01 mknodat01 +mknodat02 mknodat02 + +mlock01 mlock01 +mlock02 mlock02 +mlock03 mlock03 -i 20 +mlock04 mlock04 +mlock05 mlock05 + +mlock201 mlock201 +mlock202 mlock202 +mlock203 mlock203 + +mmap01 mmap01 +mmap02 mmap02 +mmap03 mmap03 +mmap04 mmap04 +mmap05 mmap05 +mmap06 mmap06 +mmap08 mmap08 +mmap09 mmap09 +mmap12 mmap12 +mmap13 mmap13 +mmap14 mmap14 +# test is broken, mask it for now. +#mmap11 mmap11 -i 30000 +mmap15 mmap15 +mmap16 mmap16 +mmap17 mmap17 +mmap18 mmap18 +mmap19 mmap19 +mmap20 mmap20 +mmap21_01 mmap21 -m 1 +mmap21_02 mmap21 +mmap22 mmap22 + +modify_ldt01 modify_ldt01 +modify_ldt02 modify_ldt02 + +mount01 mount01 +mount02 mount02 +mount03 mount03 +mount04 mount04 +mount05 mount05 +mount06 mount06 +mount07 mount07 + +mount_setattr01 mount_setattr01 + +move_mount01 move_mount01 +move_mount02 move_mount02 +move_mount03 move_mount03 + +move_pages01 move_pages01 +move_pages02 move_pages02 +move_pages03 move_pages03 +move_pages04 move_pages04 +move_pages05 move_pages05 +move_pages06 move_pages06 +move_pages07 move_pages07 +move_pages09 move_pages09 +move_pages10 move_pages10 +move_pages11 move_pages11 +move_pages12 move_pages12 + +mprotect01 mprotect01 +mprotect02 mprotect02 +mprotect03 mprotect03 +mprotect04 mprotect04 +mprotect05 mprotect05 + +pkey01 pkey01 + +mq_notify01 mq_notify01 +mq_notify02 mq_notify02 +mq_notify03 mq_notify03 +mq_open01 mq_open01 +mq_timedreceive01 mq_timedreceive01 +mq_timedsend01 mq_timedsend01 +mq_unlink01 mq_unlink01 + +mremap01 mremap01 +mremap02 mremap02 +mremap03 mremap03 +mremap04 mremap04 +mremap05 mremap05 +mremap06 mremap06 + +mseal01 mseal01 +mseal02 mseal02 + +msgctl01 msgctl01 +msgctl02 msgctl02 +msgctl03 msgctl03 +msgctl04 msgctl04 +msgctl05 msgctl05 +msgctl06 msgctl06 +msgctl12 msgctl12 + +msgstress01 msgstress01 + +msgget01 msgget01 +msgget02 msgget02 +msgget03 msgget03 +msgget04 msgget04 +msgget05 msgget05 + +msgrcv01 msgrcv01 +msgrcv02 msgrcv02 +msgrcv03 msgrcv03 +msgrcv05 msgrcv05 +msgrcv06 msgrcv06 +msgrcv07 msgrcv07 +msgrcv08 msgrcv08 + +msgsnd01 msgsnd01 +msgsnd02 msgsnd02 +msgsnd05 msgsnd05 +msgsnd06 msgsnd06 + +msync01 msync01 +msync02 msync02 +msync03 msync03 +msync04 msync04 + +munlock01 munlock01 +munlock02 munlock02 + +munlockall01 munlockall01 + +munmap01 munmap01 +munmap03 munmap03 +munmap04 munmap04 + +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 + +nice01 nice01 +nice02 nice02 +nice03 nice03 +nice04 nice04 +nice05 nice05 + +open01 open01 +open02 open02 +open03 open03 +open04 open04 +open06 open06 +open07 open07 +open08 open08 +open09 open09 +open10 open10 +open11 open11 +open12 open12 +open13 open13 +open14 open14 +open15 open15 + +openat01 openat01 +openat02 openat02 +openat03 openat03 +openat04 openat04 + +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 +madvise03 madvise03 +madvise05 madvise05 +madvise06 madvise06 +madvise07 madvise07 +madvise08 madvise08 +madvise09 madvise09 +madvise10 madvise10 +madvise11 madvise11 +madvise12 madvise12 + +newuname01 newuname01 + +pathconf01 pathconf01 +pathconf02 pathconf02 + +pause01 pause01 +pause02 pause02 + +personality01 personality01 +personality02 personality02 + +pidfd_getfd01 pidfd_getfd01 +pidfd_getfd02 pidfd_getfd02 + +pidfd_open01 pidfd_open01 +pidfd_open02 pidfd_open02 +pidfd_open03 pidfd_open03 +pidfd_open04 pidfd_open04 + +pidfd_send_signal01 pidfd_send_signal01 +pidfd_send_signal02 pidfd_send_signal02 +pidfd_send_signal03 pidfd_send_signal03 + +pipe01 pipe01 +pipe02 pipe02 +pipe03 pipe03 +pipe04 pipe04 +pipe05 pipe05 +pipe06 pipe06 +pipe07 pipe07 +pipe08 pipe08 +pipe09 pipe09 +pipe10 pipe10 +pipe11 pipe11 +pipe12 pipe12 +pipe13 pipe13 +pipe14 pipe14 +pipe15 pipe15 + +pipe2_01 pipe2_01 +pipe2_02 pipe2_02 +pipe2_04 pipe2_04 + +# Interprocess communication stress tests +pipeio_1 pipeio -T pipeio_1 -c 5 -s 4090 -i 100 -b -f x80 +pipeio_2 pipeio -T pipeio_2 -c 5 -s 4090 -i 100 -f x80 +pipeio_3 pipeio -T pipeio_3 -c 5 -s 4090 -i 100 -u -b -f x80 +pipeio_4 pipeio -T pipeio_4 -c 5 -s 4090 -i 100 -u -f x80 +pipeio_5 pipeio -T pipeio_5 -c 5 -s 5000 -i 10 -b -f x80 +pipeio_6 pipeio -T pipeio_6 -c 5 -s 5000 -i 10 -b -u -f x80 +pipeio_7 pipeio -T pipeio_7 -c 5 -s 5000 -i 10 -f x80 +pipeio_8 pipeio -T pipeio_8 -c 5 -s 5000 -i 10 -u -f x80 + +pivot_root01 pivot_root01 + +poll01 poll01 +poll02 poll02 + +ppoll01 ppoll01 + +prctl01 prctl01 +prctl02 prctl02 +prctl03 prctl03 +prctl05 prctl05 +prctl06 prctl06 +prctl07 prctl07 +prctl08 prctl08 +prctl09 prctl09 +prctl10 prctl10 + +pread01 pread01 +pread01_64 pread01_64 +pread02 pread02 +pread02_64 pread02_64 + +preadv01 preadv01 +preadv01_64 preadv01_64 +preadv02 preadv02 +preadv02_64 preadv02_64 +preadv03 preadv03 +preadv03_64 preadv03_64 + +preadv201 preadv201 +preadv201_64 preadv201_64 +preadv202 preadv202 +preadv202_64 preadv202_64 +preadv203 preadv203 +preadv203_64 preadv203_64 + +profil01 profil01 + +process_vm_readv01 process_vm01 -r +process_vm_readv02 process_vm_readv02 +process_vm_readv03 process_vm_readv03 +process_vm_writev01 process_vm01 +process_vm_writev02 process_vm_writev02 + +process_madvise01 process_madvise01 + +prot_hsymlinks prot_hsymlinks +dirtyc0w dirtyc0w +dirtyc0w_shmem dirtyc0w_shmem +dirtypipe dirtypipe + +pselect01 pselect01 +pselect01_64 pselect01_64 +pselect02 pselect02 +pselect02_64 pselect02_64 +pselect03 pselect03 +pselect03_64 pselect03_64 + +ptrace01 ptrace01 +ptrace02 ptrace02 +ptrace03 ptrace03 +ptrace04 ptrace04 +ptrace05 ptrace05 +ptrace06 ptrace06 +ptrace07 ptrace07 +ptrace08 ptrace08 +ptrace09 ptrace09 +ptrace10 ptrace10 +ptrace11 ptrace11 + +pwrite01 pwrite01 +pwrite02 pwrite02 +pwrite03 pwrite03 +pwrite04 pwrite04 + +pwrite01_64 pwrite01_64 +pwrite02_64 pwrite02_64 +pwrite03_64 pwrite03_64 +pwrite04_64 pwrite04_64 + +pwritev01 pwritev01 +pwritev01_64 pwritev01_64 +pwritev02 pwritev02 +pwritev02_64 pwritev02_64 +pwritev03 pwritev03 +pwritev03_64 pwritev03_64 + +pwritev201 pwritev201 +pwritev201_64 pwritev201_64 +pwritev202 pwritev202 +pwritev202_64 pwritev202_64 + +quotactl01 quotactl01 +quotactl02 quotactl02 +quotactl03 quotactl03 +quotactl04 quotactl04 +quotactl05 quotactl05 +quotactl06 quotactl06 +quotactl07 quotactl07 +quotactl08 quotactl08 +quotactl09 quotactl09 + +read01 read01 +read02 read02 +read03 read03 +read04 read04 + +readahead01 readahead01 +readahead02 readahead02 + +readdir01 readdir01 +readdir21 readdir21 + +readlink01 readlink01 +readlink03 readlink03 + +#readlinkat test cases +readlinkat01 readlinkat01 +readlinkat02 readlinkat02 + +readv01 readv01 +readv02 readv02 + +realpath01 realpath01 + +reboot01 reboot01 +reboot02 reboot02 + +recv01 recv01 + +recvfrom01 recvfrom01 + +recvmsg01 recvmsg01 +recvmsg02 recvmsg02 +recvmsg03 recvmsg03 + +recvmmsg01 recvmmsg01 + +remap_file_pages01 remap_file_pages01 +remap_file_pages02 remap_file_pages02 + +removexattr01 removexattr01 +removexattr02 removexattr02 + +rename01 rename01 +rename03 rename03 +rename04 rename04 +rename05 rename05 +rename06 rename06 +rename07 rename07 +rename08 rename08 +rename09 rename09 +rename10 rename10 +rename11 rename11 +rename12 rename12 +rename13 rename13 +rename14 rename14 +rename15 rename15 + +#renameat test cases +renameat01 renameat01 + +renameat201 renameat201 +renameat202 renameat202 -i 10 + +request_key01 request_key01 +request_key02 request_key02 +request_key03 request_key03 +request_key04 request_key04 +request_key05 request_key05 +request_key06 request_key06 + +rmdir01 rmdir01 +rmdir02 rmdir02 +rmdir03 rmdir03 + +rt_sigaction01 rt_sigaction01 +rt_sigaction02 rt_sigaction02 +rt_sigaction03 rt_sigaction03 +rt_sigprocmask01 rt_sigprocmask01 +rt_sigprocmask02 rt_sigprocmask02 +rt_sigqueueinfo01 rt_sigqueueinfo01 +rt_sigqueueinfo02 rt_sigqueueinfo02 +rt_sigsuspend01 rt_sigsuspend01 +rt_sigtimedwait01 rt_sigtimedwait01 +rt_tgsigqueueinfo01 rt_tgsigqueueinfo01 + +sbrk01 sbrk01 +sbrk02 sbrk02 +sbrk03 sbrk03 + +sched_get_priority_max01 sched_get_priority_max01 +sched_get_priority_max02 sched_get_priority_max02 + +sched_get_priority_min01 sched_get_priority_min01 +sched_get_priority_min02 sched_get_priority_min02 + +sched_getparam01 sched_getparam01 +sched_getparam03 sched_getparam03 + +sched_rr_get_interval01 sched_rr_get_interval01 +sched_rr_get_interval02 sched_rr_get_interval02 +sched_rr_get_interval03 sched_rr_get_interval03 + +sched_setparam01 sched_setparam01 +sched_setparam02 sched_setparam02 +sched_setparam03 sched_setparam03 +sched_setparam04 sched_setparam04 +sched_setparam05 sched_setparam05 + +sched_getscheduler01 sched_getscheduler01 +sched_getscheduler02 sched_getscheduler02 + +sched_setscheduler01 sched_setscheduler01 +sched_setscheduler02 sched_setscheduler02 +sched_setscheduler03 sched_setscheduler03 +sched_setscheduler04 sched_setscheduler04 + +sched_yield01 sched_yield01 + +sched_setaffinity01 sched_setaffinity01 +sched_getaffinity01 sched_getaffinity01 + +sched_setattr01 sched_setattr01 +sched_getattr01 sched_getattr01 +sched_getattr02 sched_getattr02 + +seccomp01 seccomp01 + +select01 select01 +select02 select02 +select03 select03 +select04 select04 + +semctl01 semctl01 +semctl02 semctl02 +semctl03 semctl03 +semctl04 semctl04 +semctl05 semctl05 +semctl06 semctl06 +semctl07 semctl07 +semctl08 semctl08 +semctl09 semctl09 + +semget01 semget01 +semget02 semget02 +semget05 semget05 + +semop01 semop01 +semop02 semop02 +semop03 semop03 +semop04 semop04 +semop05 semop05 + +send01 send01 +send02 send02 + +sendfile02 sendfile02 +sendfile02_64 sendfile02_64 +sendfile03 sendfile03 +sendfile03_64 sendfile03_64 +sendfile04 sendfile04 +sendfile04_64 sendfile04_64 +sendfile05 sendfile05 +sendfile05_64 sendfile05_64 +sendfile06 sendfile06 +sendfile06_64 sendfile06_64 +sendfile07 sendfile07 +sendfile07_64 sendfile07_64 +sendfile08 sendfile08 +sendfile08_64 sendfile08_64 +sendfile09 sendfile09 +sendfile09_64 sendfile09_64 + + +sendmsg01 sendmsg01 +sendmsg02 sendmsg02 +sendmsg03 sendmsg03 + +sendmmsg01 sendmmsg01 +sendmmsg02 sendmmsg02 + +sendto01 sendto01 +sendto02 sendto02 +sendto03 sendto03 + +set_mempolicy01 set_mempolicy01 +set_mempolicy02 set_mempolicy02 +set_mempolicy03 set_mempolicy03 +set_mempolicy04 set_mempolicy04 + +set_robust_list01 set_robust_list01 +set_thread_area01 set_thread_area01 +set_thread_area02 set_thread_area02 +set_tid_address01 set_tid_address01 + +setdomainname01 setdomainname01 +setdomainname02 setdomainname02 +setdomainname03 setdomainname03 + +setfsgid01 setfsgid01 +setfsgid01_16 setfsgid01_16 +setfsgid02 setfsgid02 +setfsgid02_16 setfsgid02_16 +setfsgid03 setfsgid03 +setfsgid03_16 setfsgid03_16 + +setfsuid01 setfsuid01 +setfsuid01_16 setfsuid01_16 +setfsuid02 setfsuid02 +setfsuid02_16 setfsuid02_16 +setfsuid03 setfsuid03 +setfsuid03_16 setfsuid03_16 +setfsuid04 setfsuid04 +setfsuid04_16 setfsuid04_16 + +setgid01 setgid01 +setgid01_16 setgid01_16 +setgid02 setgid02 +setgid02_16 setgid02_16 +setgid03 setgid03 +setgid03_16 setgid03_16 + +setegid01 setegid01 +setegid02 setegid02 + +sgetmask01 sgetmask01 + +setgroups01 setgroups01 +setgroups01_16 setgroups01_16 +setgroups02 setgroups02 +setgroups02_16 setgroups02_16 +setgroups03 setgroups03 +setgroups03_16 setgroups03_16 + +sethostname01 sethostname01 +sethostname02 sethostname02 +sethostname03 sethostname03 + +setitimer01 setitimer01 +setitimer02 setitimer02 + +setns01 setns01 +setns02 setns02 + +setpgid01 setpgid01 +setpgid02 setpgid02 +setpgid03 setpgid03 + +setpgrp01 setpgrp01 +setpgrp02 setpgrp02 + +setpriority01 setpriority01 +setpriority02 setpriority02 + +setregid01 setregid01 +setregid01_16 setregid01_16 +setregid02 setregid02 +setregid02_16 setregid02_16 +setregid03 setregid03 +setregid03_16 setregid03_16 +setregid04 setregid04 +setregid04_16 setregid04_16 + +setresgid01 setresgid01 +setresgid01_16 setresgid01_16 +setresgid02 setresgid02 +setresgid02_16 setresgid02_16 +setresgid03 setresgid03 +setresgid03_16 setresgid03_16 +setresgid04 setresgid04 +setresgid04_16 setresgid04_16 + +setresuid01 setresuid01 +setresuid01_16 setresuid01_16 +setresuid02 setresuid02 +setresuid02_16 setresuid02_16 +setresuid03 setresuid03 +setresuid03_16 setresuid03_16 +setresuid04 setresuid04 +setresuid04_16 setresuid04_16 +setresuid05 setresuid05 +setresuid05_16 setresuid05_16 + +setreuid01 setreuid01 +setreuid01_16 setreuid01_16 +setreuid02 setreuid02 +setreuid02_16 setreuid02_16 +setreuid03 setreuid03 +setreuid03_16 setreuid03_16 +setreuid04 setreuid04 +setreuid04_16 setreuid04_16 +setreuid05 setreuid05 +setreuid05_16 setreuid05_16 +setreuid06 setreuid06 +setreuid06_16 setreuid06_16 +setreuid07 setreuid07 +setreuid07_16 setreuid07_16 + +setrlimit01 setrlimit01 +setrlimit02 setrlimit02 +setrlimit03 setrlimit03 +setrlimit04 setrlimit04 +setrlimit05 setrlimit05 +setrlimit06 setrlimit06 + +setsid01 setsid01 + +setsockopt01 setsockopt01 +setsockopt02 setsockopt02 +setsockopt03 setsockopt03 +setsockopt04 setsockopt04 +setsockopt05 setsockopt05 +setsockopt06 setsockopt06 +setsockopt07 setsockopt07 +setsockopt08 setsockopt08 +setsockopt09 setsockopt09 +setsockopt10 setsockopt10 + +settimeofday01 settimeofday01 +settimeofday02 settimeofday02 + +setuid01 setuid01 +setuid01_16 setuid01_16 +setuid03 setuid03 +setuid03_16 setuid03_16 +setuid04 setuid04 +setuid04_16 setuid04_16 + +setxattr01 setxattr01 +setxattr02 setxattr02 +setxattr03 setxattr03 + +shmat01 shmat01 +shmat02 shmat02 +shmat03 shmat03 +shmat04 shmat04 + +shmctl01 shmctl01 +shmctl02 shmctl02 +shmctl03 shmctl03 +shmctl04 shmctl04 +shmctl05 shmctl05 +shmctl06 shmctl06 +shmctl07 shmctl07 +shmctl08 shmctl08 + +shmdt01 shmdt01 +shmdt02 shmdt02 + +shmget02 shmget02 +shmget03 shmget03 +shmget04 shmget04 +shmget05 shmget05 +shmget06 shmget06 + +shutdown01 shutdown01 +shutdown02 shutdown02 + +sigaction01 sigaction01 +sigaction02 sigaction02 + +sigaltstack01 sigaltstack01 +sigaltstack02 sigaltstack02 + + +sighold02 sighold02 + +signal01 signal01 +signal02 signal02 +signal03 signal03 +signal04 signal04 +signal05 signal05 +signal06 signal06 + +signalfd01 signalfd01 +signalfd02 signalfd02 + +signalfd4_01 signalfd4_01 +signalfd4_02 signalfd4_02 + +sigpending02 sigpending02 + +sigprocmask01 sigprocmask01 + +sigrelse01 sigrelse01 + +sigsuspend01 sigsuspend01 +sigsuspend02 sigsuspend02 + +sigtimedwait01 sigtimedwait01 + +sigwait01 sigwait01 +sigwaitinfo01 sigwaitinfo01 + +socket01 socket01 +socket02 socket02 + +socketcall01 socketcall01 +socketcall02 socketcall02 +socketcall03 socketcall03 + +socketpair01 socketpair01 +socketpair02 socketpair02 + +sockioctl01 sockioctl01 + +splice01 splice01 +splice02 splice02 +splice03 splice03 +splice04 splice04 +splice05 splice05 +splice06 splice06 +splice07 splice07 +splice08 splice08 +splice09 splice09 + +tee01 tee01 +tee02 tee02 + +ssetmask01 ssetmask01 + +stat01 stat01 +stat01_64 stat01_64 +stat02 stat02 +stat02_64 stat02_64 +stat03 stat03 +stat03_64 stat03_64 +stat04 stat04 +stat04_64 stat04_64 + +statmount01 statmount01 +statmount02 statmount02 +statmount03 statmount03 +statmount04 statmount04 +statmount05 statmount05 +statmount06 statmount06 +statmount07 statmount07 +statmount08 statmount08 + +statfs01 statfs01 +statfs01_64 statfs01_64 +statfs02 statfs02 +statfs02_64 statfs02_64 +statfs03 statfs03 +statfs03_64 statfs03_64 + +statvfs01 statvfs01 +statvfs02 statvfs02 + +stime01 stime01 +stime02 stime02 + +string01 string01 + +swapoff01 swapoff01 +swapoff02 swapoff02 + +swapon01 swapon01 +swapon02 swapon02 +swapon03 swapon03 + +#Exclusive syscall() for POWER6 machines only +switch01 endian_switch01 + +symlink02 symlink02 +symlink03 symlink03 +symlink04 symlink04 + +#symlinkat test cases +symlinkat01 symlinkat01 + +sync01 sync01 + +syncfs01 syncfs01 + +#testcases for sync_file_range +sync_file_range01 sync_file_range01 +sync_file_range02 sync_file_range02 + +syscall01 syscall01 + +sysconf01 sysconf01 + +sysctl01 sysctl01 +sysctl03 sysctl03 +sysctl04 sysctl04 + +sysfs01 sysfs01 +sysfs02 sysfs02 +sysfs03 sysfs03 +sysfs04 sysfs04 +sysfs05 sysfs05 + +sysinfo01 sysinfo01 +sysinfo02 sysinfo02 +sysinfo03 sysinfo03 + +syslog11 syslog11 +syslog12 syslog12 + +tgkill01 tgkill01 +tgkill02 tgkill02 +tgkill03 tgkill03 + +time01 time01 + +times01 times01 +times03 times03 + +# New syscall support from 2.6.25 kernel onwards + +timerfd01 timerfd01 +timerfd02 timerfd02 +timerfd04 timerfd04 +timerfd_create01 timerfd_create01 +timerfd_gettime01 timerfd_gettime01 +timerfd_settime01 timerfd_settime01 +timerfd_settime02 timerfd_settime02 + +timer_create01 timer_create01 +timer_create02 timer_create02 +timer_create03 timer_create03 + +timer_delete01 timer_delete01 +timer_delete02 timer_delete02 + +timer_getoverrun01 timer_getoverrun01 +timer_gettime01 timer_gettime01 + +timer_settime01 timer_settime01 +timer_settime02 timer_settime02 +timer_settime03 timer_settime03 + +tkill01 tkill01 +tkill02 tkill02 + +truncate02 truncate02 +truncate02_64 truncate02_64 +truncate03 truncate03 +truncate03_64 truncate03_64 + +# This syscall is obsolete. The latest glibc does not even +# include the ulimit.h file anymore. The test will fail +# because the error handling has been simplified. +# +ulimit01 ulimit01 + +umask01 umask01 + +uname01 uname01 +uname02 uname02 +uname04 uname04 + +unlink05 unlink05 +unlink07 unlink07 +unlink08 unlink08 +unlink09 unlink09 +unlink10 unlink10 + +#unlinkat test cases +unlinkat01 unlinkat01 + +unshare01 unshare01 +unshare02 unshare02 +unshare03 unshare03 +unshare04 unshare04 +unshare05 unshare05 + +# +# These tests require an unmounted block device +# to run correctly. Please see individual test +# code for more information. +# +umount01 umount01 +umount02 umount02 +umount03 umount03 + +umount2_01 umount2_01 +umount2_02 umount2_02 + +userfaultfd01 userfaultfd01 + +ustat01 ustat01 +ustat02 ustat02 + +utime01 utime01 +utime02 utime02 +utime03 utime03 +utime04 utime04 +utime05 utime05 +utime06 utime06 +utime07 utime07 + +utimes01 utimes01 + +# Introduced from Kernel 2.6.22 onwards +utimensat01 utimensat01 + +vfork01 vfork01 +vfork02 vfork02 + +vhangup01 vhangup01 +vhangup02 vhangup02 + +#vmsplice test cases +vmsplice01 vmsplice01 +vmsplice02 vmsplice02 +vmsplice03 vmsplice03 +vmsplice04 vmsplice04 + +wait01 wait01 +wait02 wait02 + +wait401 wait401 +wait402 wait402 +wait403 wait403 + +waitpid01 waitpid01 +waitpid03 waitpid03 +waitpid04 waitpid04 +waitpid06 waitpid06 +waitpid07 waitpid07 +waitpid08 waitpid08 +waitpid09 waitpid09 +waitpid10 waitpid10 +waitpid11 waitpid11 +waitpid12 waitpid12 +waitpid13 waitpid13 + +waitid01 waitid01 +waitid02 waitid02 +waitid03 waitid03 +waitid04 waitid04 +waitid05 waitid05 +waitid06 waitid06 +waitid07 waitid07 +waitid08 waitid08 +waitid09 waitid09 +waitid10 waitid10 +waitid11 waitid11 + +write01 write01 +write02 write02 +write03 write03 +write04 write04 +write05 write05 +write06 write06 + +writev01 writev01 +writev02 writev02 +writev03 writev03 +writev05 writev05 +writev06 writev06 +writev07 writev07 + +perf_event_open01 perf_event_open01 +perf_event_open02 perf_event_open02 + +futex_cmp_requeue01 futex_cmp_requeue01 +futex_cmp_requeue02 futex_cmp_requeue02 +futex_wait01 futex_wait01 +futex_wait02 futex_wait02 +futex_wait03 futex_wait03 +futex_wait04 futex_wait04 +futex_wait05 futex_wait05 +futex_waitv01 futex_waitv01 +futex_waitv02 futex_waitv02 +futex_waitv03 futex_waitv03 +futex_wake01 futex_wake01 +futex_wake02 futex_wake02 +futex_wake03 futex_wake03 +futex_wake04 futex_wake04 +futex_wait_bitset01 futex_wait_bitset01 + +memfd_create01 memfd_create01 +memfd_create02 memfd_create02 +memfd_create03 memfd_create03 +memfd_create04 memfd_create04 + +copy_file_range01 copy_file_range01 +copy_file_range02 copy_file_range02 +copy_file_range03 copy_file_range03 + +statx01 statx01 +statx02 statx02 +statx03 statx03 +statx04 statx04 +statx05 statx05 +statx06 statx06 +statx07 statx07 +statx08 statx08 +statx09 statx09 +statx10 statx10 +statx11 statx11 +statx12 statx12 + +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/ltp/runtest/syscalls-ipc b/ltp/runtest/syscalls-ipc new file mode 100644 index 0000000000000000000000000000000000000000..8960c487ca652a11be548a03b31836da6fd444b7 --- /dev/null +++ b/ltp/runtest/syscalls-ipc @@ -0,0 +1,68 @@ +msgctl01 msgctl01 +msgctl02 msgctl02 +msgctl03 msgctl03 +msgctl04 msgctl04 +msgctl05 msgctl05 +msgctl06 msgctl06 +msgctl12 msgctl12 + +msgstress01 msgstress01 + +msgget01 msgget01 +msgget02 msgget02 +msgget03 msgget03 +msgget04 msgget04 +msgget05 msgget05 + +msgrcv01 msgrcv01 +msgrcv02 msgrcv02 +msgrcv03 msgrcv03 +msgrcv05 msgrcv05 +msgrcv06 msgrcv06 +msgrcv07 msgrcv07 +msgrcv08 msgrcv08 + +msgsnd01 msgsnd01 +msgsnd02 msgsnd02 +msgsnd05 msgsnd05 +msgsnd06 msgsnd06 + +semctl01 semctl01 +semctl02 semctl02 +semctl03 semctl03 +semctl04 semctl04 +semctl05 semctl05 +semctl06 semctl06 +semctl07 semctl07 +semctl08 semctl08 +semctl09 semctl09 + +semget01 semget01 +semget02 semget02 +semget05 semget05 + +semop01 semop01 +semop02 semop02 +semop03 semop03 + +shmat01 shmat01 +shmat02 shmat02 +shmat04 shmat04 + +shmctl01 shmctl01 +shmctl02 shmctl02 +shmctl03 shmctl03 +shmctl04 shmctl04 +shmctl05 shmctl05 +shmctl06 shmctl06 +shmctl07 shmctl07 +shmctl08 shmctl08 + +shmdt01 shmdt01 +shmdt02 shmdt02 + +shmget02 shmget02 +shmget03 shmget03 +shmget04 shmget04 +shmget05 shmget05 +shmget06 shmget06 diff --git a/ltp/runtest/tpm_tools b/ltp/runtest/tpm_tools new file mode 100644 index 0000000000000000000000000000000000000000..1cceac7ef6eb9be37d219a72910e7ae0cc272a02 --- /dev/null +++ b/ltp/runtest/tpm_tools @@ -0,0 +1,13 @@ +#DESCRIPTION:TPM Management Tools +tpm01 tpm_selftest_tests.sh +tpm02 tpm_version_tests.sh +tpm03 tpm_getpubek_tests.sh +tpm04 tpm_takeownership_tests.sh +tpm05 tpm_restrictpubek_tests.sh +tpm06 tpm_changeauth_tests.sh +tpmtoken01 tpmtoken_init_tests.sh +tpmtoken02 tpmtoken_setpasswd_tests.sh +tpmtoken03 tpmtoken_import_tests.sh +tpmtoken04 tpmtoken_protect_tests.sh +tpmtoken05 tpmtoken_objects_tests.sh +tpm07 tpm_clear_tests.sh diff --git a/ltp/runtest/tracing b/ltp/runtest/tracing new file mode 100644 index 0000000000000000000000000000000000000000..d2700ca57669faec8bd71b77097994c7e1cb6b18 --- /dev/null +++ b/ltp/runtest/tracing @@ -0,0 +1,10 @@ +#DESCRIPTION:Tracing testing +ftrace_regression01 ftrace_regression01.sh +ftrace_regression02 ftrace_regression02.sh +ftrace-stress-test ftrace_stress_test.sh 90 +dynamic_debug01 dynamic_debug01.sh +pt_full_trace_basic pt_test +pt_snapshot_trace_basic pt_test -m +pt_ex_user pt_test -e user +pt_ex_kernel pt_test -e kernel +pt_disable_branch pt_test -b diff --git a/ltp/runtest/uevent b/ltp/runtest/uevent new file mode 100644 index 0000000000000000000000000000000000000000..0b59c87233eeed90e52ab0b360dc2b03434cd25b --- /dev/null +++ b/ltp/runtest/uevent @@ -0,0 +1,3 @@ +uevent01 uevent01 +uevent02 uevent02 +uevent03 uevent03 diff --git a/ltp/runtest/watchqueue b/ltp/runtest/watchqueue new file mode 100644 index 0000000000000000000000000000000000000000..bd6b0a4230720d892c7a05a770fdf297faf48d3e --- /dev/null +++ b/ltp/runtest/watchqueue @@ -0,0 +1,9 @@ +wqueue01 wqueue01 +wqueue02 wqueue02 +wqueue03 wqueue03 +wqueue04 wqueue04 +wqueue05 wqueue05 +wqueue06 wqueue06 +wqueue07 wqueue07 +wqueue08 wqueue08 +wqueue09 wqueue09 diff --git a/ltp/scenario_groups/Makefile b/ltp/scenario_groups/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fcbc9270829e2e496ef8bcc0fb69e558a0bb81ed --- /dev/null +++ b/ltp/scenario_groups/Makefile @@ -0,0 +1,38 @@ +# +# scenario-groups Makefile. +# +# Copyright (C) 2010, Linux Test Project. +# +# 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, November 2010 +# + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk + +INSTALL_DIR := scenario_groups + +# Don't copy over the Makefile +UNWANTED_FILES := Makefile + +INSTALL_MODE := 00644 + +INSTALL_TARGETS := $(filter-out $(UNWANTED_FILES),$(notdir $(patsubst $(abs_srcdir)/%,%,$(sort $(wildcard $(abs_srcdir)/*))))) + +MAKE_TARGETS := + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/scenario_groups/default b/ltp/scenario_groups/default new file mode 100644 index 0000000000000000000000000000000000000000..0e76b2bee11c937e878ddf77c94f695129d98dbf --- /dev/null +++ b/ltp/scenario_groups/default @@ -0,0 +1,28 @@ +syscalls +fs +fs_perms_simple +dio +mm +ipc +irq +sched +math +nptl +pty +containers +fs_bind +controllers +fcntl-locktests +power_management_tests +hugetlb +commands +hyperthreading +can +cpuhotplug +net.ipv6_lib +input +cve +crypto +kernel_misc +uevent +watchqueue diff --git a/ltp/scenario_groups/network b/ltp/scenario_groups/network new file mode 100644 index 0000000000000000000000000000000000000000..974b9fc58317912d194334af28278fa9a22eef65 --- /dev/null +++ b/ltp/scenario_groups/network @@ -0,0 +1,20 @@ +can +net.features +net.ipv6 +net.ipv6_lib +net.tcp_cmds +net.multicast +net.nfs +net.rpc_tests +net.tirpc_tests +net.sctp +net_stress.appl +net_stress.broken_ip +net_stress.interface +net_stress.ipsec_dccp +net_stress.ipsec_icmp +net_stress.ipsec_sctp +net_stress.ipsec_tcp +net_stress.ipsec_udp +net_stress.multicast +net_stress.route diff --git a/ltp/scripts/calctimeouts.py b/ltp/scripts/calctimeouts.py new file mode 100755 index 0000000000000000000000000000000000000000..18886704ff7819d5180dc320cf3af25ed73c866c --- /dev/null +++ b/ltp/scripts/calctimeouts.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2025 Cyril Hrubis +# Copyright (c) 2025 Andrea Cervesato +""" +This script parses JSON results from kirk and LTP metadata in order to +calculate timeouts for tests based on the results file. +It can also patch tests automatically and replace the calculated timeout. +""" + +import re +import os +import json +import argparse + +# The test runtime is multiplied by this to get a timeout +TIMEOUT_MUL = 1.2 + + +def _sed(fname, expr, replace): + """ + Pythonic version of sed command. + """ + content = [] + matcher = re.compile(expr) + + with open(fname, 'r', encoding="utf-8") as data: + for line in data: + match = matcher.search(line) + if not match: + content.append(line) + else: + content.append(replace) + + with open(fname, 'w', encoding="utf-8") as data: + data.writelines(content) + + +def _patch(ltp_dir, fname, new_timeout, override): + """ + If `override` is True, it patches a test file, searching for timeout and + replacing it with `new_timeout`. + """ + orig_timeout = None + file_path = os.path.join(ltp_dir, fname) + + with open(file_path, 'r', encoding="utf-8") as c_source: + matcher = re.compile(r'\s*.timeout\s*=\s*(\d+).') + for line in c_source: + match = matcher.search(line) + if not match: + continue + + timeout = match.group(1) + orig_timeout = int(timeout) + + if orig_timeout: + if orig_timeout < new_timeout or override: + print(f"CHANGE {fname} timeout {orig_timeout} -> {new_timeout}") + _sed(file_path, r".timeout = [0-9]*,\n", + f"\t.timeout = {new_timeout},\n") + else: + print(f"KEEP {fname} timeout {orig_timeout} (new {new_timeout})") + else: + print(f"ADD {fname} timeout {new_timeout}") + _sed(file_path, + "static struct tst_test test = {", + "static struct tst_test test = {\n" + f"\t.timeout = {new_timeout},\n") + + +def _patch_all(ltp_dir, timeouts, override): + """ + Patch all tests. + """ + for timeout in timeouts: + if timeout['path']: + _patch(ltp_dir, timeout['path'], timeout['timeout'], override) + + +def _print_table(timeouts): + """ + Print the timeouts table. + """ + timeouts.sort(key=lambda x: x['timeout'], reverse=True) + + total = 0 + + print("Old library tests\n-----------------\n") + for timeout in timeouts: + if not timeout['newlib']: + print(f"{timeout['name']:30s} {timeout['timeout']}") + total += 1 + + print(f"\n\t{total} tests in total") + + total = 0 + + print("\nNew library tests\n-----------------\n") + for timeout in timeouts: + if timeout['newlib']: + print(f"{timeout['name']:30s} {timeout['timeout']}") + total += 1 + + print(f"\n\t{total} tests in total") + + +def _parse_data(ltp_dir, results_path): + """ + Parse results data and metadata, then it generates timeouts data. + """ + timeouts = [] + results = None + metadata = None + + with open(results_path, 'r', encoding="utf-8") as file: + results = json.load(file) + + metadata_path = os.path.join(ltp_dir, 'metadata', 'ltp.json') + with open(metadata_path, 'r', encoding="utf-8") as file: + metadata = json.load(file) + + for test in results['results']: + name = test['test_fqn'] + duration = test['test']['duration'] + + # if test runs for all_filesystems, normalize runtime to one filesystem + filesystems = max(1, test['test']['log'].count('TINFO: Formatting /')) + + # check if test is new library test + test_is_newlib = name in metadata['tests'] + + # store test file path + path = None + if test_is_newlib: + path = metadata['tests'][name]['fname'] + + test_has_runtime = False + if test_is_newlib: + # filter out tests with runtime + test_has_runtime = 'runtime' in metadata['tests'][name] + + # timer tests define runtime dynamically in timer library + test_has_runtime = 'sample' in metadata['tests'][name] + + # select tests that does not have runtime and which are executed + # for a long time + if not test_has_runtime and duration >= 0.5: + data = {} + data["name"] = name + data["timeout"] = int(TIMEOUT_MUL * duration/filesystems + 0.5) + data["newlib"] = test_is_newlib + data["path"] = path + + timeouts.append(data) + + return timeouts + + +def _file_exists(filepath): + """ + Check if the given file path exists. + """ + if not os.path.isfile(filepath): + raise argparse.ArgumentTypeError( + f"The file '{filepath}' does not exist.") + return filepath + + +def _dir_exists(dirpath): + """ + Check if the given directory path exists. + """ + if not os.path.isdir(dirpath): + raise argparse.ArgumentTypeError( + f"The directory '{dirpath}' does not exist.") + return dirpath + + +def run(): + """ + Entry point of the script. + """ + parser = argparse.ArgumentParser( + description="Script to calculate LTP tests timeouts") + + parser.add_argument( + '-l', + '--ltp-dir', + type=_dir_exists, + help='LTP source code directory', + default='..') + + parser.add_argument( + '-r', + '--results', + type=_file_exists, + required=True, + help='kirk results.json file location') + + parser.add_argument( + '-o', + '--override', + default=False, + action='store_true', + help='Always override test timeouts') + + parser.add_argument( + '-p', + '--patch', + default=False, + action='store_true', + help='Patch tests with updated timeout') + + parser.add_argument( + '-t', + '--print-table', + default=True, + action='store_true', + help='Print table with suggested timeouts') + + args = parser.parse_args() + + timeouts = _parse_data(args.ltp_dir, args.results) + + if args.print_table: + _print_table(timeouts) + + if args.patch: + _patch_all(args.ltp_dir, timeouts, args.override) + + +if __name__ == "__main__": + run() diff --git a/ltp/scripts/checkbashisms.pl b/ltp/scripts/checkbashisms.pl new file mode 100755 index 0000000000000000000000000000000000000000..ba417c9934737d4d36986f9a0ebf4dcfa32b53f7 --- /dev/null +++ b/ltp/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 +
+ +

v4l-test: Test environment for Video For Linux Two (V4L2) API

+

+Download v4l-test +or visit v4l-test project page at +sourceforge.net . +

+ +

What is this?

+

+v4l-test is a test environment for V4L2 drivers. The V4L2 drivers +are running under Linux in kernel space. This test environment is +running in userspace and tries what normal video application would do. +It also tries some things which are supposed to test the error handling +mechanisms of a V4L2 driver. These are the "invalid test cases". +

+

+The V4L2 API only covers webcams and analog tuner cards. The digital +broadcast is out of the scope of V4L2 API so it is also out of the +scope of this test environment. See +Linux DVB API +for digital broadcast and +Chapter 6.3 Relation of V4L2 to other Linux +multimedia APIs in V4L2 specification. +

+ +

How to build?

+

+To build the test environment you will need a C compiler, "make" and +the CUnit development files installed. Just type "make" and the test +environment is ready. +

+ +

How to run?

+

+You need to have a video device (i.e. webcam, tuner card, etc.) +connected to your system and available under /dev/video0. If you don't +have any hardware device available, you can still test the "Virtual +Video Driver". To compile this you need to compile your kernel with +CONFIG_VIDEO_VIVI=m under: +

+
+  -> Device Drivers
+    -> Multimedia devices
+      -> Video For Linux
+        -> Video capture adapters
+          -> Virtual Video Driver
+
+

+At this point you can execute v4l-test. +

+ +

Video for Linux Two Specification

+

+The V4L2 API specification +revision 0.24 is the base for this test environment. The most recent +version can be found at +http://v4l2spec.bytesex.org/spec/ . +

+ +

Code Coverage

+

+The code coverage shows which lines of the code were executed and how +many times. The measurement results gives you a feedback about the +quality of the test cases. You can measure the code coverage of a +kernel module with the +gocv and +lcov softwares. +

+ +

Current status

+

+Currently all test are running and evaluated automatically. This might +change in future if we want to test for example plugging and unplugging +a USB video device or ask the user if a received picture make sense or +not. +

+

+The following tables give an overview about the current state of +implemented test cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
V4L API elementCovered?Note
V4L2 close()yesAll
V4L2 ioctl()yesAll
ioctl VIDIOC_CROPCAPyes, only when STREAM_OFFOpt.
ioctl VIDIOC_DBG_G_REGISTERnoExp.
ioctl VIDIOC_DBG_S_REGISTERnoExp.
ioctl VIDIOC_ENCODER_CMDnoExp.
ioctl VIDIOC_TRY_ENCODER_CMDnoExp.
ioctl VIDIOC_ENUMAUDIOyes, only when STREAM_OFFEnum.
ioctl VIDIOC_ENUMAUDOUTyes, only when STREAM_OFFEnum.
ioctl VIDIOC_ENUM_FMTyes, only when STREAM_OFFEnum.
ioctl VIDIOC_ENUM_FRAMESIZESyes, only when STREAM_OFFExp. Enum.
ioctl VIDIOC_ENUM_FRAMEINTERVALSnoExp. Enum.
ioctl VIDIOC_ENUMINPUTyes, only when STREAM_OFFEnum.
ioctl VIDIOC_ENUMOUTPUTyes, only when STREAM_OFFEnum.
ioctl VIDIOC_ENUMSTDyes, only when STREAM_OFFEnum.
ioctl VIDIOC_G_AUDIOyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_AUDIOyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_AUDOUTyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_AUDOUTyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_CHIP_IDENTnoExp.
ioctl VIDIOC_G_CROPyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_CROPyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_CTRLyes, only when STREAM_OFF
ioctl VIDIOC_S_CTRLyes, only when STREAM_OFF
ioctl VIDIOC_G_ENC_INDEXnoExp.
ioctl VIDIOC_G_EXT_CTRLSyes, only when STREAM_OFF, currently only zero and one itemOpt.
ioctl VIDIOC_S_EXT_CTRLSyes, only when STREAM_OFF, only with zero itemOpt.
ioctl VIDIOC_TRY_EXT_CTRLSyes, only when STREAM_OFF, only with zero itemOpt.
ioctl VIDIOC_G_FBUFnoOpt.
ioctl VIDIOC_S_FBUFnoOpt.
ioctl VIDIOC_G_FMTyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_FMTyes, only when STREAM_OFFOpt.
ioctl VIDIOC_TRY_FMTnoOpt.
ioctl VIDIOC_G_FREQUENCYyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_FREQUENCYyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_INPUTyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_INPUTyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_JPEGCOMPyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_JPEGCOMPnoOpt.
ioctl VIDIOC_G_MODULATORyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_MODULATORnoOpt.
ioctl VIDIOC_G_OUTPUTyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_OUTPUTyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_PARMyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_PARMnoOpt.
ioctl VIDIOC_G_PRIORITYyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_PRIORITYyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_SLICED_VBI_CAPyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_STDyes, only when STREAM_OFFOpt.
ioctl VIDIOC_S_STDyes, only when STREAM_OFFOpt.
ioctl VIDIOC_G_TUNERyes, only when STREAM_OFF
ioctl VIDIOC_S_TUNERyes, only when STREAM_OFF
ioctl VIDIOC_LOG_STATUSyes, only when STREAM_OFFOpt.
ioctl VIDIOC_OVERLAYnoOpt.
ioctl VIDIOC_QBUFnoOpt.
ioctl VIDIOC_DQBUFnoOpt.
ioctl VIDIOC_QUERYBUFyes, only when STREAM_OFFOpt.
ioctl VIDIOC_QUERYCAPyes, only when STREAM_OFFAll
ioctl VIDIOC_QUERYCTRLyes, only private and user controls; + only user controls with V4L2_CTRL_FLAG_NEXT_CTRLEnum.
ioctl VIDIOC_QUERYMENUyes, only when STREAM_OFFEnum.
ioctl VIDIOC_QUERYSTDyes, only when STREAM_OFFOpt.
ioctl VIDIOC_REQBUFSyes, only when STREAM_OFFOpt.
ioctl VIDIOC_STREAMONnoOpt.
ioctl VIDIOC_STREAMOFFnoOpt.
V4L2 mmap()noOpt.
V4L2 munmap()noOpt.
V4L2 open()yes, partlyAll
V4L2 poll()noOpt.
V4L2 read()noOpt.
V4L2 select()noOpt.
V4L2 write()noOpt.
+ +

+All: all drivers should support
+Opt.: optional
+Enum.: enumeration, will return EINVAL for the first unknown entry
+Exp.: experimental, may change in future +

+ +

The following actions are not part of the V4L2 API but they might have +influence on the V4L2 API functions:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionCovered?
Load kernel moduleno
Unload kernel moduleno
USB connect event (in case of USB webcams)no
USB disconnect event (in case of USB webcams)no
Suspendno
Resumeno
Check for memory leak (e.g. analyze /proc/slab_allocators)no
Opening /dev/video0 multiple timesno
Using /dev/video0 from a multi-threaded or multi-process environment paralellno
+ + +

Similar projects

+

+There migth be similar projects which also tries to test the V4L2 API. +So far I could find the following: +

+ +

+Please let me know if this list misses other V4L or V4L2 test project. +

+

+The following documents and articles are useful if you are dealing with V4L2: +

+ +

+For USB or V4L loopback testing: +

+ +

+And what else can we read if we are looking for webcam test ideas: +

+ + +

Feedbacks

+

Any feedbacks, comments, ideas, etc. are welcome at the author's email address. +You can find the email address in the source package in the README file.

+
+

Last changed: +Thu Jul 23 06:47:49 CEST 2009 +

+

+ Valid HTML 4.01 Strict + SourceForge.net Logo +

+ + + diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/results.html b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/results.html new file mode 100644 index 0000000000000000000000000000000000000000..a5c1c05466b3de1d4dc2e7d37ac15b549806c318 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/results.html @@ -0,0 +1,124 @@ + + + + + v4l-test: Resutls + + +

+Home +
+

+
+ +

v4l-test: Results

+

+The following list collects the problems which were found by using the v4l-test +project or during developing it. +

+ + + +

In the out-of-tree em28xx-new driver +the following problems were identified with the help of v4l-test:

+ + + +
+

Last changed: +Wed Jul 8 08:38:00 CEST 2009 +

+

+ Valid HTML 4.01 Strict + SourceForge.net Logo +

+ + + diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16506.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16506.htm new file mode 100644 index 0000000000000000000000000000000000000000..da9e33f13f494febb5290f04d3ce1ff09d402bd5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16506.htm @@ -0,0 +1,2189 @@ + +Video For Linux Two Header File
Video for Linux Two API Specification: Revision 0.24
PrevNext

Appendix A. Video For Linux Two Header File

/*
+ *  Video for Linux Two header file
+ *
+ *  Copyright (C) 1999-2007 the contributors
+ *
+ *  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.
+ *
+ *  Alternatively you can redistribute this file under the terms of the
+ *  BSD license as stated below:
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *  3. The names of its contributors may not be used to endorse or promote
+ *     products derived from this software without specific prior written
+ *     permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *      Header file for v4l or V4L2 drivers and applications
+ * with public API.
+ * All kernel-specific stuff were moved to media/v4l2-dev.h, so
+ * no #if __KERNEL tests are allowed here
+ *
+ *      See http://linuxtv.org for more info
+ *
+ *      Author: Bill Dirks <bill@thedirks.org>
+ *              Justin Schoeman
+ *              Hans Verkuil <hverkuil@xs4all.nl>
+ *              et al.
+ */
+#ifndef __LINUX_VIDEODEV2_H
+#define __LINUX_VIDEODEV2_H
+#ifdef __KERNEL__
+#include <linux/time.h>     /* need struct timeval */
+#include <linux/compiler.h> /* need __user */
+#else
+#define __user
+#include <sys/time.h>
+#endif
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/*
+ * Common stuff for both V4L1 and V4L2
+ * Moved from videodev.h
+ */
+#define VIDEO_MAX_FRAME               32
+
+#define VID_TYPE_CAPTURE        1       /* Can capture */
+#define VID_TYPE_TUNER          2       /* Can tune */
+#define VID_TYPE_TELETEXT       4       /* Does teletext */
+#define VID_TYPE_OVERLAY        8       /* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY      16      /* Overlay by chromakey */
+#define VID_TYPE_CLIPPING       32      /* Can clip */
+#define VID_TYPE_FRAMERAM       64      /* Uses the frame buffer memory */
+#define VID_TYPE_SCALES         128     /* Scalable */
+#define VID_TYPE_MONOCHROME     256     /* Monochrome only */
+#define VID_TYPE_SUBCAPTURE     512     /* Can capture subareas of the image */
+#define VID_TYPE_MPEG_DECODER   1024    /* Can decode MPEG streams */
+#define VID_TYPE_MPEG_ENCODER   2048    /* Can encode MPEG streams */
+#define VID_TYPE_MJPEG_DECODER  4096    /* Can decode MJPEG streams */
+#define VID_TYPE_MJPEG_ENCODER  8192    /* Can encode MJPEG streams */
+
+/*
+ *      M I S C E L L A N E O U S
+ */
+
+/*  Four-character-code (FOURCC) */
+#define v4l2_fourcc(a,b,c,d)\
+        (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
+
+/*
+ *      E N U M S
+ */
+enum v4l2_field {
+        V4L2_FIELD_ANY           = 0, /* driver can choose from none,
+                                         top, bottom, interlaced
+                                         depending on whatever it thinks
+                                         is approximate ... */
+        V4L2_FIELD_NONE          = 1, /* this device has no fields ... */
+        V4L2_FIELD_TOP           = 2, /* top field only */
+        V4L2_FIELD_BOTTOM        = 3, /* bottom field only */
+        V4L2_FIELD_INTERLACED    = 4, /* both fields interlaced */
+        V4L2_FIELD_SEQ_TB        = 5, /* both fields sequential into one
+                                         buffer, top-bottom order */
+        V4L2_FIELD_SEQ_BT        = 6, /* same as above + bottom-top order */
+        V4L2_FIELD_ALTERNATE     = 7, /* both fields alternating into
+                                         separate buffers */
+        V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field
+                                         first and the top field is
+                                         transmitted first */
+        V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field
+                                         first and the bottom field is
+                                         transmitted first */
+};
+#define V4L2_FIELD_HAS_TOP(field)       \
+        ((field) == V4L2_FIELD_TOP      ||\
+         (field) == V4L2_FIELD_INTERLACED ||\
+         (field) == V4L2_FIELD_INTERLACED_TB ||\
+         (field) == V4L2_FIELD_INTERLACED_BT ||\
+         (field) == V4L2_FIELD_SEQ_TB   ||\
+         (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTTOM(field)    \
+        ((field) == V4L2_FIELD_BOTTOM   ||\
+         (field) == V4L2_FIELD_INTERLACED ||\
+         (field) == V4L2_FIELD_INTERLACED_TB ||\
+         (field) == V4L2_FIELD_INTERLACED_BT ||\
+         (field) == V4L2_FIELD_SEQ_TB   ||\
+         (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTH(field)      \
+        ((field) == V4L2_FIELD_INTERLACED ||\
+         (field) == V4L2_FIELD_INTERLACED_TB ||\
+         (field) == V4L2_FIELD_INTERLACED_BT ||\
+         (field) == V4L2_FIELD_SEQ_TB ||\
+         (field) == V4L2_FIELD_SEQ_BT)
+
+enum v4l2_buf_type {
+        V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,
+        V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2,
+        V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3,
+        V4L2_BUF_TYPE_VBI_CAPTURE          = 4,
+        V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
+        V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
+        V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
+#if 1 /*KEEP*/
+        /* Experimental */
+        V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
+#endif
+        V4L2_BUF_TYPE_PRIVATE              = 0x80,
+};
+
+enum v4l2_ctrl_type {
+        V4L2_CTRL_TYPE_INTEGER       = 1,
+        V4L2_CTRL_TYPE_BOOLEAN       = 2,
+        V4L2_CTRL_TYPE_MENU          = 3,
+        V4L2_CTRL_TYPE_BUTTON        = 4,
+        V4L2_CTRL_TYPE_INTEGER64     = 5,
+        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
+};
+
+enum v4l2_tuner_type {
+        V4L2_TUNER_RADIO             = 1,
+        V4L2_TUNER_ANALOG_TV         = 2,
+        V4L2_TUNER_DIGITAL_TV        = 3,
+};
+
+enum v4l2_memory {
+        V4L2_MEMORY_MMAP             = 1,
+        V4L2_MEMORY_USERPTR          = 2,
+        V4L2_MEMORY_OVERLAY          = 3,
+};
+
+/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
+enum v4l2_colorspace {
+        /* ITU-R 601 -- broadcast NTSC/PAL */
+        V4L2_COLORSPACE_SMPTE170M     = 1,
+
+        /* 1125-Line (US) HDTV */
+        V4L2_COLORSPACE_SMPTE240M     = 2,
+
+        /* HD and modern captures. */
+        V4L2_COLORSPACE_REC709        = 3,
+
+        /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
+        V4L2_COLORSPACE_BT878         = 4,
+
+        /* These should be useful.  Assume 601 extents. */
+        V4L2_COLORSPACE_470_SYSTEM_M  = 5,
+        V4L2_COLORSPACE_470_SYSTEM_BG = 6,
+
+        /* I know there will be cameras that send this.  So, this is
+         * unspecified chromaticities and full 0-255 on each of the
+         * Y'CbCr components
+         */
+        V4L2_COLORSPACE_JPEG          = 7,
+
+        /* For RGB colourspaces, this is probably a good start. */
+        V4L2_COLORSPACE_SRGB          = 8,
+};
+
+enum v4l2_priority {
+        V4L2_PRIORITY_UNSET       = 0,  /* not initialized */
+        V4L2_PRIORITY_BACKGROUND  = 1,
+        V4L2_PRIORITY_INTERACTIVE = 2,
+        V4L2_PRIORITY_RECORD      = 3,
+        V4L2_PRIORITY_DEFAULT     = V4L2_PRIORITY_INTERACTIVE,
+};
+
+struct v4l2_rect {
+        __s32   left;
+        __s32   top;
+        __s32   width;
+        __s32   height;
+};
+
+struct v4l2_fract {
+        __u32   numerator;
+        __u32   denominator;
+};
+
+/*
+ *      D R I V E R   C A P A B I L I T I E S
+ */
+struct v4l2_capability
+{
+        __u8    driver[16];     /* i.e.ie; "bttv" */
+        __u8    card[32];       /* i.e.ie; "Hauppauge WinTV" */
+        __u8    bus_info[32];   /* "PCI:" + pci_name(pci_dev) */
+        __u32   version;        /* should use KERNEL_VERSION() */
+        __u32   capabilities;   /* Device capabilities */
+        __u32   reserved[4];
+};
+
+/* Values for 'capabilities' field */
+#define V4L2_CAP_VIDEO_CAPTURE          0x00000001  /* Is a video capture device */
+#define V4L2_CAP_VIDEO_OUTPUT           0x00000002  /* Is a video output device */
+#define V4L2_CAP_VIDEO_OVERLAY          0x00000004  /* Can do video overlay */
+#define V4L2_CAP_VBI_CAPTURE            0x00000010  /* Is a raw VBI capture device */
+#define V4L2_CAP_VBI_OUTPUT             0x00000020  /* Is a raw VBI output device */
+#define V4L2_CAP_SLICED_VBI_CAPTURE     0x00000040  /* Is a sliced VBI capture device */
+#define V4L2_CAP_SLICED_VBI_OUTPUT      0x00000080  /* Is a sliced VBI output device */
+#define V4L2_CAP_RDS_CAPTURE            0x00000100  /* RDS data capture */
+#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY   0x00000200  /* Can do video output overlay */
+
+#define V4L2_CAP_TUNER                  0x00010000  /* has a tuner */
+#define V4L2_CAP_AUDIO                  0x00020000  /* has audio support */
+#define V4L2_CAP_RADIO                  0x00040000  /* is a radio device */
+
+#define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
+#define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
+#define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
+
+/*
+ *      V I D E O   I M A G E   F O R M A T
+ */
+struct v4l2_pix_format
+{
+        __u32                   width;
+        __u32                   height;
+        __u32                   pixelformat;
+        enum v4l2_field         field;
+        __u32                   bytesperline;   /* for padding, zero if unused */
+        __u32                   sizeimage;
+        enum v4l2_colorspace    colorspace;
+        __u32                   priv;           /* private data, depends on pixelformat */
+};
+
+/*      Pixel format         FOURCC                        depth  Description  */
+#define V4L2_PIX_FMT_RGB332  v4l2_fourcc('R','G','B','1') /*  8  RGB-3-3-2     */
+#define V4L2_PIX_FMT_RGB444  v4l2_fourcc('R','4','4','4') /* 16  xxxxrrrr ggggbbbb */
+#define V4L2_PIX_FMT_RGB555  v4l2_fourcc('R','G','B','O') /* 16  RGB-5-5-5     */
+#define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R','G','B','P') /* 16  RGB-5-6-5     */
+#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16  RGB-5-5-5 BE  */
+#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16  RGB-5-6-5 BE  */
+#define V4L2_PIX_FMT_BGR24   v4l2_fourcc('B','G','R','3') /* 24  BGR-8-8-8     */
+#define V4L2_PIX_FMT_RGB24   v4l2_fourcc('R','G','B','3') /* 24  RGB-8-8-8     */
+#define V4L2_PIX_FMT_BGR32   v4l2_fourcc('B','G','R','4') /* 32  BGR-8-8-8-8   */
+#define V4L2_PIX_FMT_RGB32   v4l2_fourcc('R','G','B','4') /* 32  RGB-8-8-8-8   */
+#define V4L2_PIX_FMT_GREY    v4l2_fourcc('G','R','E','Y') /*  8  Greyscale     */
+#define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y','1','6',' ') /* 16  Greyscale     */
+#define V4L2_PIX_FMT_PAL8    v4l2_fourcc('P','A','L','8') /*  8  8-bit palette */
+#define V4L2_PIX_FMT_YVU410  v4l2_fourcc('Y','V','U','9') /*  9  YVU 4:1:0     */
+#define V4L2_PIX_FMT_YVU420  v4l2_fourcc('Y','V','1','2') /* 12  YVU 4:2:0     */
+#define V4L2_PIX_FMT_YUYV    v4l2_fourcc('Y','U','Y','V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_UYVY    v4l2_fourcc('U','Y','V','Y') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16  YVU422 planar */
+#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16  YVU411 planar */
+#define V4L2_PIX_FMT_Y41P    v4l2_fourcc('Y','4','1','P') /* 12  YUV 4:1:1     */
+#define V4L2_PIX_FMT_YUV444  v4l2_fourcc('Y','4','4','4') /* 16  xxxxyyyy uuuuvvvv */
+#define V4L2_PIX_FMT_YUV555  v4l2_fourcc('Y','U','V','O') /* 16  YUV-5-5-5     */
+#define V4L2_PIX_FMT_YUV565  v4l2_fourcc('Y','U','V','P') /* 16  YUV-5-6-5     */
+#define V4L2_PIX_FMT_YUV32   v4l2_fourcc('Y','U','V','4') /* 32  YUV-8-8-8-8   */
+
+/* two planes -- one Y, one Cr + Cb interleaved  */
+#define V4L2_PIX_FMT_NV12    v4l2_fourcc('N','V','1','2') /* 12  Y/CbCr 4:2:0  */
+#define V4L2_PIX_FMT_NV21    v4l2_fourcc('N','V','2','1') /* 12  Y/CrCb 4:2:0  */
+
+/*  The following formats are not defined in the V4L2 specification */
+#define V4L2_PIX_FMT_YUV410  v4l2_fourcc('Y','U','V','9') /*  9  YUV 4:1:0     */
+#define V4L2_PIX_FMT_YUV420  v4l2_fourcc('Y','U','1','2') /* 12  YUV 4:2:0     */
+#define V4L2_PIX_FMT_YYUV    v4l2_fourcc('Y','Y','U','V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_HI240   v4l2_fourcc('H','I','2','4') /*  8  8-bit color   */
+#define V4L2_PIX_FMT_HM12    v4l2_fourcc('H','M','1','2') /*  8  YUV 4:2:0 16x16 macroblocks */
+
+/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
+#define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B','A','8','1') /*  8  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B','Y','R','2') /* 16  BGBG.. GRGR.. */
+
+/* compressed formats */
+#define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M','J','P','G') /* Motion-JPEG   */
+#define V4L2_PIX_FMT_JPEG     v4l2_fourcc('J','P','E','G') /* JFIF JPEG     */
+#define V4L2_PIX_FMT_DV       v4l2_fourcc('d','v','s','d') /* 1394          */
+#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M','P','E','G') /* MPEG-1/2/4    */
+
+/*  Vendor-specific formats   */
+#define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
+#define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S','9','1','0') /* SN9C10x compression */
+#define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P','W','C','1') /* pwc older webcam */
+#define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
+#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') /* ET61X251 compression */
+
+/*
+ *      F O R M A T   E N U M E R A T I O N
+ */
+struct v4l2_fmtdesc
+{
+        __u32               index;             /* Format number      */
+        enum v4l2_buf_type  type;              /* buffer type        */
+        __u32               flags;
+        __u8                description[32];   /* Description string */
+        __u32               pixelformat;       /* Format fourcc      */
+        __u32               reserved[4];
+};
+
+#define V4L2_FMT_FLAG_COMPRESSED 0x0001
+
+#if 1 /*KEEP*/
+        /* Experimental Frame Size and frame rate enumeration */
+/*
+ *      F R A M E   S I Z E   E N U M E R A T I O N
+ */
+enum v4l2_frmsizetypes
+{
+        V4L2_FRMSIZE_TYPE_DISCRETE      = 1,
+        V4L2_FRMSIZE_TYPE_CONTINUOUS    = 2,
+        V4L2_FRMSIZE_TYPE_STEPWISE      = 3,
+};
+
+struct v4l2_frmsize_discrete
+{
+        __u32                   width;          /* Frame width [pixel] */
+        __u32                   height;         /* Frame height [pixel] */
+};
+
+struct v4l2_frmsize_stepwise
+{
+        __u32                   min_width;      /* Minimum frame width [pixel] */
+        __u32                   max_width;      /* Maximum frame width [pixel] */
+        __u32                   step_width;     /* Frame width step size [pixel] */
+        __u32                   min_height;     /* Minimum frame height [pixel] */
+        __u32                   max_height;     /* Maximum frame height [pixel] */
+        __u32                   step_height;    /* Frame height step size [pixel] */
+};
+
+struct v4l2_frmsizeenum
+{
+        __u32                   index;          /* Frame size number */
+        __u32                   pixel_format;   /* Pixel format */
+        __u32                   type;           /* Frame size type the device supports. */
+
+        union {                                 /* Frame size */
+                struct v4l2_frmsize_discrete    discrete;
+                struct v4l2_frmsize_stepwise    stepwise;
+        };
+
+        __u32   reserved[2];                    /* Reserved space for future use */
+};
+
+/*
+ *      F R A M E   R A T E   E N U M E R A T I O N
+ */
+enum v4l2_frmivaltypes
+{
+        V4L2_FRMIVAL_TYPE_DISCRETE      = 1,
+        V4L2_FRMIVAL_TYPE_CONTINUOUS    = 2,
+        V4L2_FRMIVAL_TYPE_STEPWISE      = 3,
+};
+
+struct v4l2_frmival_stepwise
+{
+        struct v4l2_fract       min;            /* Minimum frame interval [s] */
+        struct v4l2_fract       max;            /* Maximum frame interval [s] */
+        struct v4l2_fract       step;           /* Frame interval step size [s] */
+};
+
+struct v4l2_frmivalenum
+{
+        __u32                   index;          /* Frame format index */
+        __u32                   pixel_format;   /* Pixel format */
+        __u32                   width;          /* Frame width */
+        __u32                   height;         /* Frame height */
+        __u32                   type;           /* Frame interval type the device supports. */
+
+        union {                                 /* Frame interval */
+                struct v4l2_fract               discrete;
+                struct v4l2_frmival_stepwise    stepwise;
+        };
+
+        __u32   reserved[2];                    /* Reserved space for future use */
+};
+#endif
+
+/*
+ *      T I M E C O D E
+ */
+struct v4l2_timecode
+{
+        __u32   type;
+        __u32   flags;
+        __u8    frames;
+        __u8    seconds;
+        __u8    minutes;
+        __u8    hours;
+        __u8    userbits[4];
+};
+
+/*  Type  */
+#define V4L2_TC_TYPE_24FPS              1
+#define V4L2_TC_TYPE_25FPS              2
+#define V4L2_TC_TYPE_30FPS              3
+#define V4L2_TC_TYPE_50FPS              4
+#define V4L2_TC_TYPE_60FPS              5
+
+/*  Flags  */
+#define V4L2_TC_FLAG_DROPFRAME          0x0001 /* "drop-frame" mode */
+#define V4L2_TC_FLAG_COLORFRAME         0x0002
+#define V4L2_TC_USERBITS_field          0x000C
+#define V4L2_TC_USERBITS_USERDEFINED    0x0000
+#define V4L2_TC_USERBITS_8BITCHARS      0x0008
+/* The above is based on SMPTE timecodes */
+
+struct v4l2_jpegcompression
+{
+        int quality;
+
+        int  APPn;              /* Number of APP segment to be written,
+                                 * must be 0..15 */
+        int  APP_len;           /* Length of data in JPEG APPn segment */
+        char APP_data[60];      /* Data in the JPEG APPn segment. */
+
+        int  COM_len;           /* Length of data in JPEG COM segment */
+        char COM_data[60];      /* Data in JPEG COM segment */
+
+        __u32 jpeg_markers;     /* Which markers should go into the JPEG
+                                 * output. Unless you exactly know what
+                                 * you do, leave them untouched.
+                                 * Inluding less markers will make the
+                                 * resulting code smaller, but there will
+                                 * be fewer aplications which can read it.
+                                 * The presence of the APP and COM marker
+                                 * is influenced by APP_len and COM_len
+                                 * ONLY, not by this property! */
+
+#define V4L2_JPEG_MARKER_DHT (1<<3)    /* Define Huffman Tables */
+#define V4L2_JPEG_MARKER_DQT (1<<4)    /* Define Quantization Tables */
+#define V4L2_JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
+#define V4L2_JPEG_MARKER_COM (1<<6)    /* Comment segment */
+#define V4L2_JPEG_MARKER_APP (1<<7)    /* App segment, driver will
+                                        * allways use APP0 */
+};
+
+/*
+ *      M E M O R Y - M A P P I N G   B U F F E R S
+ */
+struct v4l2_requestbuffers
+{
+        __u32                   count;
+        enum v4l2_buf_type      type;
+        enum v4l2_memory        memory;
+        __u32                   reserved[2];
+};
+
+struct v4l2_buffer
+{
+        __u32                   index;
+        enum v4l2_buf_type      type;
+        __u32                   bytesused;
+        __u32                   flags;
+        enum v4l2_field         field;
+        struct timeval          timestamp;
+        struct v4l2_timecode    timecode;
+        __u32                   sequence;
+
+        /* memory location */
+        enum v4l2_memory        memory;
+        union {
+                __u32           offset;
+                unsigned long   userptr;
+        } m;
+        __u32                   length;
+        __u32                   input;
+        __u32                   reserved;
+};
+
+/*  Flags for 'flags' field */
+#define V4L2_BUF_FLAG_MAPPED    0x0001  /* Buffer is mapped (flag) */
+#define V4L2_BUF_FLAG_QUEUED    0x0002  /* Buffer is queued for processing */
+#define V4L2_BUF_FLAG_DONE      0x0004  /* Buffer is ready */
+#define V4L2_BUF_FLAG_KEYFRAME  0x0008  /* Image is a keyframe (I-frame) */
+#define V4L2_BUF_FLAG_PFRAME    0x0010  /* Image is a P-frame */
+#define V4L2_BUF_FLAG_BFRAME    0x0020  /* Image is a B-frame */
+#define V4L2_BUF_FLAG_TIMECODE  0x0100  /* timecode field is valid */
+#define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
+
+/*
+ *      O V E R L A Y   P R E V I E W
+ */
+struct v4l2_framebuffer
+{
+        __u32                   capability;
+        __u32                   flags;
+/* FIXME: in theory we should pass something like PCI device + memory
+ * region + offset instead of some physical address */
+        void*                   base;
+        struct v4l2_pix_format  fmt;
+};
+/*  Flags for the 'capability' field. Read only */
+#define V4L2_FBUF_CAP_EXTERNOVERLAY     0x0001
+#define V4L2_FBUF_CAP_CHROMAKEY         0x0002
+#define V4L2_FBUF_CAP_LIST_CLIPPING     0x0004
+#define V4L2_FBUF_CAP_BITMAP_CLIPPING   0x0008
+#define V4L2_FBUF_CAP_LOCAL_ALPHA       0x0010
+#define V4L2_FBUF_CAP_GLOBAL_ALPHA      0x0020
+#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA   0x0040
+/*  Flags for the 'flags' field. */
+#define V4L2_FBUF_FLAG_PRIMARY          0x0001
+#define V4L2_FBUF_FLAG_OVERLAY          0x0002
+#define V4L2_FBUF_FLAG_CHROMAKEY        0x0004
+#define V4L2_FBUF_FLAG_LOCAL_ALPHA      0x0008
+#define V4L2_FBUF_FLAG_GLOBAL_ALPHA     0x0010
+#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA  0x0020
+
+struct v4l2_clip
+{
+        struct v4l2_rect        c;
+        struct v4l2_clip        __user *next;
+};
+
+struct v4l2_window
+{
+        struct v4l2_rect        w;
+        enum v4l2_field         field;
+        __u32                   chromakey;
+        struct v4l2_clip        __user *clips;
+        __u32                   clipcount;
+        void                    __user *bitmap;
+        __u8                    global_alpha;
+};
+
+/*
+ *      C A P T U R E   P A R A M E T E R S
+ */
+struct v4l2_captureparm
+{
+        __u32              capability;    /*  Supported modes */
+        __u32              capturemode;   /*  Current mode */
+        struct v4l2_fract  timeperframe;  /*  Time per frame in .1us units */
+        __u32              extendedmode;  /*  Driver-specific extensions */
+        __u32              readbuffers;   /*  # of buffers for read */
+        __u32              reserved[4];
+};
+
+/*  Flags for 'capability' and 'capturemode' fields */
+#define V4L2_MODE_HIGHQUALITY   0x0001  /*  High quality imaging mode */
+#define V4L2_CAP_TIMEPERFRAME   0x1000  /*  timeperframe field is supported */
+
+struct v4l2_outputparm
+{
+        __u32              capability;   /*  Supported modes */
+        __u32              outputmode;   /*  Current mode */
+        struct v4l2_fract  timeperframe; /*  Time per frame in seconds */
+        __u32              extendedmode; /*  Driver-specific extensions */
+        __u32              writebuffers; /*  # of buffers for write */
+        __u32              reserved[4];
+};
+
+/*
+ *      I N P U T   I M A G E   C R O P P I N G
+ */
+struct v4l2_cropcap {
+        enum v4l2_buf_type      type;
+        struct v4l2_rect        bounds;
+        struct v4l2_rect        defrect;
+        struct v4l2_fract       pixelaspect;
+};
+
+struct v4l2_crop {
+        enum v4l2_buf_type      type;
+        struct v4l2_rect        c;
+};
+
+/*
+ *      A N A L O G   V I D E O   S T A N D A R D
+ */
+
+typedef __u64 v4l2_std_id;
+
+/* one bit for each */
+#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
+#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
+#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
+#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
+#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
+#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
+#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
+#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
+
+#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
+#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
+#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
+#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
+
+#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
+#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
+#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
+#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
+
+#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
+#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
+#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
+#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
+#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
+#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
+#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
+#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
+
+/* ATSC/HDTV */
+#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
+#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
+
+/* FIXME:
+   Although std_id is 64 bits, there is an issue on PPC32 architecture that
+   makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding
+   this value to 32 bits.
+   As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide),
+   it should work fine. However, if needed to add more than two standards,
+   v4l2-common.c should be fixed.
+ */
+
+/* some merged standards */
+#define V4L2_STD_MN     (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
+#define V4L2_STD_B      (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
+#define V4L2_STD_GH     (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
+#define V4L2_STD_DK     (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
+
+/* some common needed stuff */
+#define V4L2_STD_PAL_BG         (V4L2_STD_PAL_B         |\
+                                 V4L2_STD_PAL_B1        |\
+                                 V4L2_STD_PAL_G)
+#define V4L2_STD_PAL_DK         (V4L2_STD_PAL_D         |\
+                                 V4L2_STD_PAL_D1        |\
+                                 V4L2_STD_PAL_K)
+#define V4L2_STD_PAL            (V4L2_STD_PAL_BG        |\
+                                 V4L2_STD_PAL_DK        |\
+                                 V4L2_STD_PAL_H         |\
+                                 V4L2_STD_PAL_I)
+#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M        |\
+                                 V4L2_STD_NTSC_M_JP     |\
+                                 V4L2_STD_NTSC_M_KR)
+#define V4L2_STD_SECAM_DK       (V4L2_STD_SECAM_D       |\
+                                 V4L2_STD_SECAM_K       |\
+                                 V4L2_STD_SECAM_K1)
+#define V4L2_STD_SECAM          (V4L2_STD_SECAM_B       |\
+                                 V4L2_STD_SECAM_G       |\
+                                 V4L2_STD_SECAM_H       |\
+                                 V4L2_STD_SECAM_DK      |\
+                                 V4L2_STD_SECAM_L       |\
+                                 V4L2_STD_SECAM_LC)
+
+#define V4L2_STD_525_60         (V4L2_STD_PAL_M         |\
+                                 V4L2_STD_PAL_60        |\
+                                 V4L2_STD_NTSC          |\
+                                 V4L2_STD_NTSC_443)
+#define V4L2_STD_625_50         (V4L2_STD_PAL           |\
+                                 V4L2_STD_PAL_N         |\
+                                 V4L2_STD_PAL_Nc        |\
+                                 V4L2_STD_SECAM)
+#define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
+                                 V4L2_STD_ATSC_16_VSB)
+
+#define V4L2_STD_UNKNOWN        0
+#define V4L2_STD_ALL            (V4L2_STD_525_60        |\
+                                 V4L2_STD_625_50)
+
+struct v4l2_standard
+{
+        __u32                index;
+        v4l2_std_id          id;
+        __u8                 name[24];
+        struct v4l2_fract    frameperiod; /* Frames, not fields */
+        __u32                framelines;
+        __u32                reserved[4];
+};
+
+/*
+ *      V I D E O   I N P U T S
+ */
+struct v4l2_input
+{
+        __u32        index;             /*  Which input */
+        __u8         name[32];          /*  Label */
+        __u32        type;              /*  Type of input */
+        __u32        audioset;          /*  Associated audios (bitfield) */
+        __u32        tuner;             /*  Associated tuner */
+        v4l2_std_id  std;
+        __u32        status;
+        __u32        reserved[4];
+};
+
+/*  Values for the 'type' field */
+#define V4L2_INPUT_TYPE_TUNER           1
+#define V4L2_INPUT_TYPE_CAMERA          2
+
+/* field 'status' - general */
+#define V4L2_IN_ST_NO_POWER    0x00000001  /* Attached device is off */
+#define V4L2_IN_ST_NO_SIGNAL   0x00000002
+#define V4L2_IN_ST_NO_COLOR    0x00000004
+
+/* field 'status' - analog */
+#define V4L2_IN_ST_NO_H_LOCK   0x00000100  /* No horizontal sync lock */
+#define V4L2_IN_ST_COLOR_KILL  0x00000200  /* Color killer is active */
+
+/* field 'status' - digital */
+#define V4L2_IN_ST_NO_SYNC     0x00010000  /* No synchronization lock */
+#define V4L2_IN_ST_NO_EQU      0x00020000  /* No equalizer lock */
+#define V4L2_IN_ST_NO_CARRIER  0x00040000  /* Carrier recovery failed */
+
+/* field 'status' - VCR and set-top box */
+#define V4L2_IN_ST_MACROVISION 0x01000000  /* Macrovision detected */
+#define V4L2_IN_ST_NO_ACCESS   0x02000000  /* Conditional access denied */
+#define V4L2_IN_ST_VTR         0x04000000  /* VTR time constant */
+
+/*
+ *      V I D E O   O U T P U T S
+ */
+struct v4l2_output
+{
+        __u32        index;             /*  Which output */
+        __u8         name[32];          /*  Label */
+        __u32        type;              /*  Type of output */
+        __u32        audioset;          /*  Associated audios (bitfield) */
+        __u32        modulator;         /*  Associated modulator */
+        v4l2_std_id  std;
+        __u32        reserved[4];
+};
+/*  Values for the 'type' field */
+#define V4L2_OUTPUT_TYPE_MODULATOR              1
+#define V4L2_OUTPUT_TYPE_ANALOG                 2
+#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY       3
+
+/*
+ *      C O N T R O L S
+ */
+struct v4l2_control
+{
+        __u32                id;
+        __s32                value;
+};
+
+struct v4l2_ext_control
+{
+        __u32 id;
+        __u32 reserved2[2];
+        union {
+                __s32 value;
+                __s64 value64;
+                void *reserved;
+        };
+} __attribute__ ((packed));
+
+struct v4l2_ext_controls
+{
+        __u32 ctrl_class;
+        __u32 count;
+        __u32 error_idx;
+        __u32 reserved[2];
+        struct v4l2_ext_control *controls;
+};
+
+/*  Values for ctrl_class field */
+#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */
+#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */
+#define V4L2_CTRL_CLASS_CAMERA 0x009a0000       /* Camera class controls */
+
+#define V4L2_CTRL_ID_MASK         (0x0fffffff)
+#define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
+#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+
+/*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
+struct v4l2_queryctrl
+{
+        __u32                id;
+        enum v4l2_ctrl_type  type;
+        __u8                 name[32];  /* Whatever */
+        __s32                minimum;   /* Note signedness */
+        __s32                maximum;
+        __s32                step;
+        __s32                default_value;
+        __u32                flags;
+        __u32                reserved[2];
+};
+
+/*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
+struct v4l2_querymenu
+{
+        __u32           id;
+        __u32           index;
+        __u8            name[32];       /* Whatever */
+        __u32           reserved;
+};
+
+/*  Control flags  */
+#define V4L2_CTRL_FLAG_DISABLED         0x0001
+#define V4L2_CTRL_FLAG_GRABBED          0x0002
+#define V4L2_CTRL_FLAG_READ_ONLY        0x0004
+#define V4L2_CTRL_FLAG_UPDATE           0x0008
+#define V4L2_CTRL_FLAG_INACTIVE         0x0010
+#define V4L2_CTRL_FLAG_SLIDER           0x0020
+
+/*  Query flag, to be ORed with the control ID */
+#define V4L2_CTRL_FLAG_NEXT_CTRL        0x80000000
+
+/*  User-class control IDs defined by V4L2 */
+#define V4L2_CID_BASE                   (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_USER_BASE              V4L2_CID_BASE
+/*  IDs reserved for driver specific controls */
+#define V4L2_CID_PRIVATE_BASE           0x08000000
+
+#define V4L2_CID_USER_CLASS             (V4L2_CTRL_CLASS_USER | 1)
+#define V4L2_CID_BRIGHTNESS             (V4L2_CID_BASE+0)
+#define V4L2_CID_CONTRAST               (V4L2_CID_BASE+1)
+#define V4L2_CID_SATURATION             (V4L2_CID_BASE+2)
+#define V4L2_CID_HUE                    (V4L2_CID_BASE+3)
+#define V4L2_CID_AUDIO_VOLUME           (V4L2_CID_BASE+5)
+#define V4L2_CID_AUDIO_BALANCE          (V4L2_CID_BASE+6)
+#define V4L2_CID_AUDIO_BASS             (V4L2_CID_BASE+7)
+#define V4L2_CID_AUDIO_TREBLE           (V4L2_CID_BASE+8)
+#define V4L2_CID_AUDIO_MUTE             (V4L2_CID_BASE+9)
+#define V4L2_CID_AUDIO_LOUDNESS         (V4L2_CID_BASE+10)
+#define V4L2_CID_BLACK_LEVEL            (V4L2_CID_BASE+11) /* Deprecated */
+#define V4L2_CID_AUTO_WHITE_BALANCE     (V4L2_CID_BASE+12)
+#define V4L2_CID_DO_WHITE_BALANCE       (V4L2_CID_BASE+13)
+#define V4L2_CID_RED_BALANCE            (V4L2_CID_BASE+14)
+#define V4L2_CID_BLUE_BALANCE           (V4L2_CID_BASE+15)
+#define V4L2_CID_GAMMA                  (V4L2_CID_BASE+16)
+#define V4L2_CID_WHITENESS              (V4L2_CID_GAMMA) /* Deprecated */
+#define V4L2_CID_EXPOSURE               (V4L2_CID_BASE+17)
+#define V4L2_CID_AUTOGAIN               (V4L2_CID_BASE+18)
+#define V4L2_CID_GAIN                   (V4L2_CID_BASE+19)
+#define V4L2_CID_HFLIP                  (V4L2_CID_BASE+20)
+#define V4L2_CID_VFLIP                  (V4L2_CID_BASE+21)
+
+/* Deprecated, use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */
+#define V4L2_CID_HCENTER_DEPRECATED     (V4L2_CID_BASE+22)
+#define V4L2_CID_VCENTER_DEPRECATED     (V4L2_CID_BASE+23)
+
+#define V4L2_CID_POWER_LINE_FREQUENCY   (V4L2_CID_BASE+24)
+enum v4l2_power_line_frequency {
+        V4L2_CID_POWER_LINE_FREQUENCY_DISABLED  = 0,
+        V4L2_CID_POWER_LINE_FREQUENCY_50HZ      = 1,
+        V4L2_CID_POWER_LINE_FREQUENCY_60HZ      = 2,
+};
+#define V4L2_CID_HUE_AUTO                       (V4L2_CID_BASE+25)
+#define V4L2_CID_WHITE_BALANCE_TEMPERATURE      (V4L2_CID_BASE+26)
+#define V4L2_CID_SHARPNESS                      (V4L2_CID_BASE+27)
+#define V4L2_CID_BACKLIGHT_COMPENSATION         (V4L2_CID_BASE+28)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+29) /* last CID + 1 */
+
+/*  MPEG-class control IDs defined by V4L2 */
+#define V4L2_CID_MPEG_BASE                      (V4L2_CTRL_CLASS_MPEG | 0x900)
+#define V4L2_CID_MPEG_CLASS                     (V4L2_CTRL_CLASS_MPEG | 1)
+
+/*  MPEG streams */
+#define V4L2_CID_MPEG_STREAM_TYPE               (V4L2_CID_MPEG_BASE+0)
+enum v4l2_mpeg_stream_type {
+        V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
+        V4L2_MPEG_STREAM_TYPE_MPEG2_TS   = 1, /* MPEG-2 transport stream */
+        V4L2_MPEG_STREAM_TYPE_MPEG1_SS   = 2, /* MPEG-1 system stream */
+        V4L2_MPEG_STREAM_TYPE_MPEG2_DVD  = 3, /* MPEG-2 DVD-compatible stream */
+        V4L2_MPEG_STREAM_TYPE_MPEG1_VCD  = 4, /* MPEG-1 VCD-compatible stream */
+        V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
+};
+#define V4L2_CID_MPEG_STREAM_PID_PMT            (V4L2_CID_MPEG_BASE+1)
+#define V4L2_CID_MPEG_STREAM_PID_AUDIO          (V4L2_CID_MPEG_BASE+2)
+#define V4L2_CID_MPEG_STREAM_PID_VIDEO          (V4L2_CID_MPEG_BASE+3)
+#define V4L2_CID_MPEG_STREAM_PID_PCR            (V4L2_CID_MPEG_BASE+4)
+#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO       (V4L2_CID_MPEG_BASE+5)
+#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO       (V4L2_CID_MPEG_BASE+6)
+#define V4L2_CID_MPEG_STREAM_VBI_FMT            (V4L2_CID_MPEG_BASE+7)
+enum v4l2_mpeg_stream_vbi_fmt {
+        V4L2_MPEG_STREAM_VBI_FMT_NONE = 0,  /* No VBI in the MPEG stream */
+        V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1,  /* VBI in private packets, IVTV format */
+};
+
+/*  MPEG audio */
+#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ       (V4L2_CID_MPEG_BASE+100)
+enum v4l2_mpeg_audio_sampling_freq {
+        V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
+        V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
+        V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_ENCODING            (V4L2_CID_MPEG_BASE+101)
+enum v4l2_mpeg_audio_encoding {
+        V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
+        V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
+        V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_L1_BITRATE          (V4L2_CID_MPEG_BASE+102)
+enum v4l2_mpeg_audio_l1_bitrate {
+        V4L2_MPEG_AUDIO_L1_BITRATE_32K  = 0,
+        V4L2_MPEG_AUDIO_L1_BITRATE_64K  = 1,
+        V4L2_MPEG_AUDIO_L1_BITRATE_96K  = 2,
+        V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
+        V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
+        V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
+        V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
+        V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
+        V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
+        V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
+        V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
+        V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
+        V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
+        V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L2_BITRATE          (V4L2_CID_MPEG_BASE+103)
+enum v4l2_mpeg_audio_l2_bitrate {
+        V4L2_MPEG_AUDIO_L2_BITRATE_32K  = 0,
+        V4L2_MPEG_AUDIO_L2_BITRATE_48K  = 1,
+        V4L2_MPEG_AUDIO_L2_BITRATE_56K  = 2,
+        V4L2_MPEG_AUDIO_L2_BITRATE_64K  = 3,
+        V4L2_MPEG_AUDIO_L2_BITRATE_80K  = 4,
+        V4L2_MPEG_AUDIO_L2_BITRATE_96K  = 5,
+        V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
+        V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
+        V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
+        V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
+        V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
+        V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
+        V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
+        V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L3_BITRATE          (V4L2_CID_MPEG_BASE+104)
+enum v4l2_mpeg_audio_l3_bitrate {
+        V4L2_MPEG_AUDIO_L3_BITRATE_32K  = 0,
+        V4L2_MPEG_AUDIO_L3_BITRATE_40K  = 1,
+        V4L2_MPEG_AUDIO_L3_BITRATE_48K  = 2,
+        V4L2_MPEG_AUDIO_L3_BITRATE_56K  = 3,
+        V4L2_MPEG_AUDIO_L3_BITRATE_64K  = 4,
+        V4L2_MPEG_AUDIO_L3_BITRATE_80K  = 5,
+        V4L2_MPEG_AUDIO_L3_BITRATE_96K  = 6,
+        V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
+        V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
+        V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
+        V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
+        V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
+        V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
+        V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE                (V4L2_CID_MPEG_BASE+105)
+enum v4l2_mpeg_audio_mode {
+        V4L2_MPEG_AUDIO_MODE_STEREO       = 0,
+        V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
+        V4L2_MPEG_AUDIO_MODE_DUAL         = 2,
+        V4L2_MPEG_AUDIO_MODE_MONO         = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION      (V4L2_CID_MPEG_BASE+106)
+enum  v4l2_mpeg_audio_mode_extension {
+        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4  = 0,
+        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8  = 1,
+        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
+        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_EMPHASIS            (V4L2_CID_MPEG_BASE+107)
+enum v4l2_mpeg_audio_emphasis {
+        V4L2_MPEG_AUDIO_EMPHASIS_NONE         = 0,
+        V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
+        V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17    = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_CRC                 (V4L2_CID_MPEG_BASE+108)
+enum v4l2_mpeg_audio_crc {
+        V4L2_MPEG_AUDIO_CRC_NONE  = 0,
+        V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
+};
+#define V4L2_CID_MPEG_AUDIO_MUTE                (V4L2_CID_MPEG_BASE+109)
+
+/*  MPEG video */
+#define V4L2_CID_MPEG_VIDEO_ENCODING            (V4L2_CID_MPEG_BASE+200)
+enum v4l2_mpeg_video_encoding {
+        V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0,
+        V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_ASPECT              (V4L2_CID_MPEG_BASE+201)
+enum v4l2_mpeg_video_aspect {
+        V4L2_MPEG_VIDEO_ASPECT_1x1     = 0,
+        V4L2_MPEG_VIDEO_ASPECT_4x3     = 1,
+        V4L2_MPEG_VIDEO_ASPECT_16x9    = 2,
+        V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
+};
+#define V4L2_CID_MPEG_VIDEO_B_FRAMES            (V4L2_CID_MPEG_BASE+202)
+#define V4L2_CID_MPEG_VIDEO_GOP_SIZE            (V4L2_CID_MPEG_BASE+203)
+#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE         (V4L2_CID_MPEG_BASE+204)
+#define V4L2_CID_MPEG_VIDEO_PULLDOWN            (V4L2_CID_MPEG_BASE+205)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE        (V4L2_CID_MPEG_BASE+206)
+enum v4l2_mpeg_video_bitrate_mode {
+        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
+        V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_BITRATE             (V4L2_CID_MPEG_BASE+207)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK        (V4L2_CID_MPEG_BASE+208)
+#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
+#define V4L2_CID_MPEG_VIDEO_MUTE                (V4L2_CID_MPEG_BASE+210)
+#define V4L2_CID_MPEG_VIDEO_MUTE_YUV            (V4L2_CID_MPEG_BASE+211)
+
+/*  MPEG-class control IDs specific to the CX2584x driver as defined by V4L2 */
+#define V4L2_CID_MPEG_CX2341X_BASE                              (V4L2_CTRL_CLASS_MPEG | 0x1000)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE         (V4L2_CID_MPEG_CX2341X_BASE+0)
+enum v4l2_mpeg_cx2341x_video_spatial_filter_mode {
+        V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
+        V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER              (V4L2_CID_MPEG_CX2341X_BASE+1)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE    (V4L2_CID_MPEG_CX2341X_BASE+2)
+enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type {
+        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF                  = 0,
+        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR               = 1,
+        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT              = 2,
+        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE      = 3,
+        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE  (V4L2_CID_MPEG_CX2341X_BASE+3)
+enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type {
+        V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF    = 0,
+        V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE        (V4L2_CID_MPEG_CX2341X_BASE+4)
+enum v4l2_mpeg_cx2341x_video_temporal_filter_mode {
+        V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
+        V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER             (V4L2_CID_MPEG_CX2341X_BASE+5)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE          (V4L2_CID_MPEG_CX2341X_BASE+6)
+enum v4l2_mpeg_cx2341x_video_median_filter_type {
+        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF      = 0,
+        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR      = 1,
+        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT     = 2,
+        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
+        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG     = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM   (V4L2_CID_MPEG_CX2341X_BASE+7)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP      (V4L2_CID_MPEG_CX2341X_BASE+8)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP    (V4L2_CID_MPEG_CX2341X_BASE+10)
+#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS         (V4L2_CID_MPEG_CX2341X_BASE+11)
+
+/*  Camera class control IDs */
+#define V4L2_CID_CAMERA_CLASS_BASE      (V4L2_CTRL_CLASS_CAMERA | 0x900)
+#define V4L2_CID_CAMERA_CLASS           (V4L2_CTRL_CLASS_CAMERA | 1)
+
+#define V4L2_CID_EXPOSURE_AUTO                  (V4L2_CID_CAMERA_CLASS_BASE+1)
+enum v4l2_exposure_auto_type {
+        V4L2_EXPOSURE_AUTO = 0,
+        V4L2_EXPOSURE_MANUAL = 1,
+        V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,
+        V4L2_EXPOSURE_APERTURE_PRIORITY = 3
+};
+#define V4L2_CID_EXPOSURE_ABSOLUTE              (V4L2_CID_CAMERA_CLASS_BASE+2)
+#define V4L2_CID_EXPOSURE_AUTO_PRIORITY         (V4L2_CID_CAMERA_CLASS_BASE+3)
+
+#define V4L2_CID_PAN_RELATIVE                   (V4L2_CID_CAMERA_CLASS_BASE+4)
+#define V4L2_CID_TILT_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+5)
+#define V4L2_CID_PAN_RESET                      (V4L2_CID_CAMERA_CLASS_BASE+6)
+#define V4L2_CID_TILT_RESET                     (V4L2_CID_CAMERA_CLASS_BASE+7)
+
+#define V4L2_CID_PAN_ABSOLUTE                   (V4L2_CID_CAMERA_CLASS_BASE+8)
+#define V4L2_CID_TILT_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+9)
+
+#define V4L2_CID_FOCUS_ABSOLUTE                 (V4L2_CID_CAMERA_CLASS_BASE+10)
+#define V4L2_CID_FOCUS_RELATIVE                 (V4L2_CID_CAMERA_CLASS_BASE+11)
+#define V4L2_CID_FOCUS_AUTO                     (V4L2_CID_CAMERA_CLASS_BASE+12)
+
+/*
+ *      T U N I N G
+ */
+struct v4l2_tuner
+{
+        __u32                   index;
+        __u8                    name[32];
+        enum v4l2_tuner_type    type;
+        __u32                   capability;
+        __u32                   rangelow;
+        __u32                   rangehigh;
+        __u32                   rxsubchans;
+        __u32                   audmode;
+        __s32                   signal;
+        __s32                   afc;
+        __u32                   reserved[4];
+};
+
+struct v4l2_modulator
+{
+        __u32                   index;
+        __u8                    name[32];
+        __u32                   capability;
+        __u32                   rangelow;
+        __u32                   rangehigh;
+        __u32                   txsubchans;
+        __u32                   reserved[4];
+};
+
+/*  Flags for the 'capability' field */
+#define V4L2_TUNER_CAP_LOW              0x0001
+#define V4L2_TUNER_CAP_NORM             0x0002
+#define V4L2_TUNER_CAP_STEREO           0x0010
+#define V4L2_TUNER_CAP_LANG2            0x0020
+#define V4L2_TUNER_CAP_SAP              0x0020
+#define V4L2_TUNER_CAP_LANG1            0x0040
+
+/*  Flags for the 'rxsubchans' field */
+#define V4L2_TUNER_SUB_MONO             0x0001
+#define V4L2_TUNER_SUB_STEREO           0x0002
+#define V4L2_TUNER_SUB_LANG2            0x0004
+#define V4L2_TUNER_SUB_SAP              0x0004
+#define V4L2_TUNER_SUB_LANG1            0x0008
+
+/*  Values for the 'audmode' field */
+#define V4L2_TUNER_MODE_MONO            0x0000
+#define V4L2_TUNER_MODE_STEREO          0x0001
+#define V4L2_TUNER_MODE_LANG2           0x0002
+#define V4L2_TUNER_MODE_SAP             0x0002
+#define V4L2_TUNER_MODE_LANG1           0x0003
+#define V4L2_TUNER_MODE_LANG1_LANG2     0x0004
+
+struct v4l2_frequency
+{
+        __u32                 tuner;
+        enum v4l2_tuner_type  type;
+        __u32                 frequency;
+        __u32                 reserved[8];
+};
+
+/*
+ *      A U D I O
+ */
+struct v4l2_audio
+{
+        __u32   index;
+        __u8    name[32];
+        __u32   capability;
+        __u32   mode;
+        __u32   reserved[2];
+};
+
+/*  Flags for the 'capability' field */
+#define V4L2_AUDCAP_STEREO              0x00001
+#define V4L2_AUDCAP_AVL                 0x00002
+
+/*  Flags for the 'mode' field */
+#define V4L2_AUDMODE_AVL                0x00001
+
+struct v4l2_audioout
+{
+        __u32   index;
+        __u8    name[32];
+        __u32   capability;
+        __u32   mode;
+        __u32   reserved[2];
+};
+
+/*
+ *      M P E G   S E R V I C E S
+ *
+ *      NOTE: EXPERIMENTAL API
+ */
+#if 1 /*KEEP*/
+#define V4L2_ENC_IDX_FRAME_I    (0)
+#define V4L2_ENC_IDX_FRAME_P    (1)
+#define V4L2_ENC_IDX_FRAME_B    (2)
+#define V4L2_ENC_IDX_FRAME_MASK (0xf)
+
+struct v4l2_enc_idx_entry {
+        __u64 offset;
+        __u64 pts;
+        __u32 length;
+        __u32 flags;
+        __u32 reserved[2];
+};
+
+#define V4L2_ENC_IDX_ENTRIES (64)
+struct v4l2_enc_idx {
+        __u32 entries;
+        __u32 entries_cap;
+        __u32 reserved[4];
+        struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES];
+};
+
+
+#define V4L2_ENC_CMD_START      (0)
+#define V4L2_ENC_CMD_STOP       (1)
+#define V4L2_ENC_CMD_PAUSE      (2)
+#define V4L2_ENC_CMD_RESUME     (3)
+
+/* Flags for V4L2_ENC_CMD_STOP */
+#define V4L2_ENC_CMD_STOP_AT_GOP_END    (1 << 0)
+
+struct v4l2_encoder_cmd {
+        __u32 cmd;
+        __u32 flags;
+        union {
+                struct {
+                        __u32 data[8];
+                } raw;
+        };
+};
+
+#endif
+
+
+/*
+ *      D A T A   S E R V I C E S   ( V B I )
+ *
+ *      Data services API by Michael Schimek
+ */
+
+/* Raw VBI */
+struct v4l2_vbi_format
+{
+        __u32   sampling_rate;          /* in 1 Hz */
+        __u32   offset;
+        __u32   samples_per_line;
+        __u32   sample_format;          /* V4L2_PIX_FMT_* */
+        __s32   start[2];
+        __u32   count[2];
+        __u32   flags;                  /* V4L2_VBI_* */
+        __u32   reserved[2];            /* must be zero */
+};
+
+/*  VBI flags  */
+#define V4L2_VBI_UNSYNC         (1<< 0)
+#define V4L2_VBI_INTERLACED     (1<< 1)
+
+/* Sliced VBI
+ *
+ *    This implements is a proposal V4L2 API to allow SLICED VBI
+ * required for some hardware encoders. It should change without
+ * notice in the definitive implementation.
+ */
+
+struct v4l2_sliced_vbi_format
+{
+        __u16   service_set;
+        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+                                 (equals frame lines 313-336 for 625 line video
+                                  standards, 263-286 for 525 line standards) */
+        __u16   service_lines[2][24];
+        __u32   io_size;
+        __u32   reserved[2];            /* must be zero */
+};
+
+/* Teletext World System Teletext
+   (WST), defined on ITU-R BT.653-2 */
+#define V4L2_SLICED_TELETEXT_B          (0x0001)
+/* Video Program System, defined on ETS 300 231*/
+#define V4L2_SLICED_VPS                 (0x0400)
+/* Closed Caption, defined on EIA-608 */
+#define V4L2_SLICED_CAPTION_525         (0x1000)
+/* Wide Screen System, defined on ITU-R BT1119.1 */
+#define V4L2_SLICED_WSS_625             (0x4000)
+
+#define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
+#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
+
+struct v4l2_sliced_vbi_cap
+{
+        __u16   service_set;
+        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+                                 (equals frame lines 313-336 for 625 line video
+                                  standards, 263-286 for 525 line standards) */
+        __u16   service_lines[2][24];
+        enum v4l2_buf_type type;
+        __u32   reserved[3];    /* must be 0 */
+};
+
+struct v4l2_sliced_vbi_data
+{
+        __u32   id;
+        __u32   field;          /* 0: first field, 1: second field */
+        __u32   line;           /* 1-23 */
+        __u32   reserved;       /* must be 0 */
+        __u8    data[48];
+};
+
+/*
+ *      A G G R E G A T E   S T R U C T U R E S
+ */
+
+/*      Stream data format
+ */
+struct v4l2_format
+{
+        enum v4l2_buf_type type;
+        union
+        {
+                struct v4l2_pix_format          pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE
+                struct v4l2_window              win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY
+                struct v4l2_vbi_format          vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE
+                struct v4l2_sliced_vbi_format   sliced;  // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
+                __u8    raw_data[200];                   // user-defined
+        } fmt;
+};
+
+
+/*      Stream type-dependent parameters
+ */
+struct v4l2_streamparm
+{
+        enum v4l2_buf_type type;
+        union
+        {
+                struct v4l2_captureparm capture;
+                struct v4l2_outputparm  output;
+                __u8    raw_data[200];  /* user-defined */
+        } parm;
+};
+
+/*
+ *      A D V A N C E D   D E B U G G I N G
+ *
+ *      NOTE: EXPERIMENTAL API
+ */
+
+/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
+
+#define V4L2_CHIP_MATCH_HOST       0  /* Match against chip ID on host (0 for the host) */
+#define V4L2_CHIP_MATCH_I2C_DRIVER 1  /* Match against I2C driver ID */
+#define V4L2_CHIP_MATCH_I2C_ADDR   2  /* Match against I2C 7-bit address */
+
+struct v4l2_register {
+        __u32 match_type; /* Match type */
+        __u32 match_chip; /* Match this chip, meaning determined by match_type */
+        __u64 reg;
+        __u64 val;
+};
+
+/* VIDIOC_G_CHIP_IDENT */
+struct v4l2_chip_ident {
+        __u32 match_type;  /* Match type */
+        __u32 match_chip;  /* Match this chip, meaning determined by match_type */
+        __u32 ident;       /* chip identifier as specified in <media/v4l2-chip-ident.h> */
+        __u32 revision;    /* chip revision, chip specific */
+};
+
+/*
+ *      I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
+ *
+ */
+#define VIDIOC_QUERYCAP         _IOR  ('V',  0, struct v4l2_capability)
+#define VIDIOC_RESERVED         _IO   ('V',  1)
+#define VIDIOC_ENUM_FMT         _IOWR ('V',  2, struct v4l2_fmtdesc)
+#define VIDIOC_G_FMT            _IOWR ('V',  4, struct v4l2_format)
+#define VIDIOC_S_FMT            _IOWR ('V',  5, struct v4l2_format)
+#define VIDIOC_REQBUFS          _IOWR ('V',  8, struct v4l2_requestbuffers)
+#define VIDIOC_QUERYBUF         _IOWR ('V',  9, struct v4l2_buffer)
+#define VIDIOC_G_FBUF           _IOR  ('V', 10, struct v4l2_framebuffer)
+#define VIDIOC_S_FBUF           _IOW  ('V', 11, struct v4l2_framebuffer)
+#define VIDIOC_OVERLAY          _IOW  ('V', 14, int)
+#define VIDIOC_QBUF             _IOWR ('V', 15, struct v4l2_buffer)
+#define VIDIOC_DQBUF            _IOWR ('V', 17, struct v4l2_buffer)
+#define VIDIOC_STREAMON         _IOW  ('V', 18, int)
+#define VIDIOC_STREAMOFF        _IOW  ('V', 19, int)
+#define VIDIOC_G_PARM           _IOWR ('V', 21, struct v4l2_streamparm)
+#define VIDIOC_S_PARM           _IOWR ('V', 22, struct v4l2_streamparm)
+#define VIDIOC_G_STD            _IOR  ('V', 23, v4l2_std_id)
+#define VIDIOC_S_STD            _IOW  ('V', 24, v4l2_std_id)
+#define VIDIOC_ENUMSTD          _IOWR ('V', 25, struct v4l2_standard)
+#define VIDIOC_ENUMINPUT        _IOWR ('V', 26, struct v4l2_input)
+#define VIDIOC_G_CTRL           _IOWR ('V', 27, struct v4l2_control)
+#define VIDIOC_S_CTRL           _IOWR ('V', 28, struct v4l2_control)
+#define VIDIOC_G_TUNER          _IOWR ('V', 29, struct v4l2_tuner)
+#define VIDIOC_S_TUNER          _IOW  ('V', 30, struct v4l2_tuner)
+#define VIDIOC_G_AUDIO          _IOR  ('V', 33, struct v4l2_audio)
+#define VIDIOC_S_AUDIO          _IOW  ('V', 34, struct v4l2_audio)
+#define VIDIOC_QUERYCTRL        _IOWR ('V', 36, struct v4l2_queryctrl)
+#define VIDIOC_QUERYMENU        _IOWR ('V', 37, struct v4l2_querymenu)
+#define VIDIOC_G_INPUT          _IOR  ('V', 38, int)
+#define VIDIOC_S_INPUT          _IOWR ('V', 39, int)
+#define VIDIOC_G_OUTPUT         _IOR  ('V', 46, int)
+#define VIDIOC_S_OUTPUT         _IOWR ('V', 47, int)
+#define VIDIOC_ENUMOUTPUT       _IOWR ('V', 48, struct v4l2_output)
+#define VIDIOC_G_AUDOUT         _IOR  ('V', 49, struct v4l2_audioout)
+#define VIDIOC_S_AUDOUT         _IOW  ('V', 50, struct v4l2_audioout)
+#define VIDIOC_G_MODULATOR      _IOWR ('V', 54, struct v4l2_modulator)
+#define VIDIOC_S_MODULATOR      _IOW  ('V', 55, struct v4l2_modulator)
+#define VIDIOC_G_FREQUENCY      _IOWR ('V', 56, struct v4l2_frequency)
+#define VIDIOC_S_FREQUENCY      _IOW  ('V', 57, struct v4l2_frequency)
+#define VIDIOC_CROPCAP          _IOWR ('V', 58, struct v4l2_cropcap)
+#define VIDIOC_G_CROP           _IOWR ('V', 59, struct v4l2_crop)
+#define VIDIOC_S_CROP           _IOW  ('V', 60, struct v4l2_crop)
+#define VIDIOC_G_JPEGCOMP       _IOR  ('V', 61, struct v4l2_jpegcompression)
+#define VIDIOC_S_JPEGCOMP       _IOW  ('V', 62, struct v4l2_jpegcompression)
+#define VIDIOC_QUERYSTD         _IOR  ('V', 63, v4l2_std_id)
+#define VIDIOC_TRY_FMT          _IOWR ('V', 64, struct v4l2_format)
+#define VIDIOC_ENUMAUDIO        _IOWR ('V', 65, struct v4l2_audio)
+#define VIDIOC_ENUMAUDOUT       _IOWR ('V', 66, struct v4l2_audioout)
+#define VIDIOC_G_PRIORITY       _IOR  ('V', 67, enum v4l2_priority)
+#define VIDIOC_S_PRIORITY       _IOW  ('V', 68, enum v4l2_priority)
+#define VIDIOC_G_SLICED_VBI_CAP _IOWR ('V', 69, struct v4l2_sliced_vbi_cap)
+#define VIDIOC_LOG_STATUS       _IO   ('V', 70)
+#define VIDIOC_G_EXT_CTRLS      _IOWR ('V', 71, struct v4l2_ext_controls)
+#define VIDIOC_S_EXT_CTRLS      _IOWR ('V', 72, struct v4l2_ext_controls)
+#define VIDIOC_TRY_EXT_CTRLS    _IOWR ('V', 73, struct v4l2_ext_controls)
+#if 1 /*KEEP*/
+#define VIDIOC_ENUM_FRAMESIZES  _IOWR ('V', 74, struct v4l2_frmsizeenum)
+#define VIDIOC_ENUM_FRAMEINTERVALS      _IOWR ('V', 75, struct v4l2_frmivalenum)
+#define VIDIOC_G_ENC_INDEX      _IOR  ('V', 76, struct v4l2_enc_idx)
+#define VIDIOC_ENCODER_CMD      _IOWR ('V', 77, struct v4l2_encoder_cmd)
+#define VIDIOC_TRY_ENCODER_CMD  _IOWR ('V', 78, struct v4l2_encoder_cmd)
+
+/* Experimental, only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
+#define VIDIOC_DBG_S_REGISTER   _IOW  ('V', 79, struct v4l2_register)
+#define VIDIOC_DBG_G_REGISTER   _IOWR ('V', 80, struct v4l2_register)
+
+#define VIDIOC_G_CHIP_IDENT     _IOWR ('V', 81, struct v4l2_chip_ident)
+#endif
+
+#ifdef __OLD_VIDIOC_
+/* for compatibility, will go away some day */
+#define VIDIOC_OVERLAY_OLD      _IOWR ('V', 14, int)
+#define VIDIOC_S_PARM_OLD       _IOW  ('V', 22, struct v4l2_streamparm)
+#define VIDIOC_S_CTRL_OLD       _IOW  ('V', 28, struct v4l2_control)
+#define VIDIOC_G_AUDIO_OLD      _IOWR ('V', 33, struct v4l2_audio)
+#define VIDIOC_G_AUDOUT_OLD     _IOWR ('V', 49, struct v4l2_audioout)
+#define VIDIOC_CROPCAP_OLD      _IOR  ('V', 58, struct v4l2_cropcap)
+#endif
+
+#define BASE_VIDIOC_PRIVATE     192             /* 192-255 are private */
+
+#endif /* __LINUX_VIDEODEV2_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */

PrevHomeNext
Obsolete API Elements Video Capture Example
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16706.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16706.htm new file mode 100644 index 0000000000000000000000000000000000000000..b65471d11065a9fe8d0e18e5a2b9c150e41511fc --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16706.htm @@ -0,0 +1,849 @@ + +Video Capture Example
Video for Linux Two API Specification: Revision 0.24
PrevNext

Appendix B. Video Capture Example

/*
+ *  V4L2 video capture example
+ *
+ *  This program can be used and distributed without restrictions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <getopt.h>             /* getopt_long() */
+
+#include <fcntl.h>              /* low-level i/o */
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>          /* for videodev2.h */
+
+#include <linux/videodev2.h>
+
+#define CLEAR(x) memset (&(x), 0, sizeof (x))
+
+typedef enum {
+        IO_METHOD_READ,
+        IO_METHOD_MMAP,
+        IO_METHOD_USERPTR,
+} io_method;
+
+struct buffer {
+        void *                  start;
+        size_t                  length;
+};
+
+static char *           dev_name        = NULL;
+static io_method        io              = IO_METHOD_MMAP;
+static int              fd              = -1;
+struct buffer *         buffers         = NULL;
+static unsigned int     n_buffers       = 0;
+
+static void
+errno_exit                      (const char *           s)
+{
+        fprintf (stderr, "%s error %d, %s\n",
+                 s, errno, strerror (errno));
+
+        exit (EXIT_FAILURE);
+}
+
+static int
+xioctl                          (int                    fd,
+                                 int                    request,
+                                 void *                 arg)
+{
+        int r;
+
+        do r = ioctl (fd, request, arg);
+        while (-1 == r && EINTR == errno);
+
+        return r;
+}
+
+static void
+process_image                   (const void *           p)
+{
+        fputc ('.', stdout);
+        fflush (stdout);
+}
+
+static int
+read_frame                      (void)
+{
+        struct v4l2_buffer buf;
+        unsigned int i;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                if (-1 == read (fd, buffers[0].start, buffers[0].length)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit ("read");
+                        }
+                }
+
+                process_image (buffers[0].start);
+
+                break;
+
+        case IO_METHOD_MMAP:
+                CLEAR (buf);
+
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_MMAP;
+
+                if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit ("VIDIOC_DQBUF");
+                        }
+                }
+
+                assert (buf.index < n_buffers);
+
+                process_image (buffers[buf.index].start);
+
+                if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                        errno_exit ("VIDIOC_QBUF");
+
+                break;
+
+        case IO_METHOD_USERPTR:
+                CLEAR (buf);
+
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_USERPTR;
+
+                if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit ("VIDIOC_DQBUF");
+                        }
+                }
+
+                for (i = 0; i < n_buffers; ++i)
+                        if (buf.m.userptr == (unsigned long) buffers[i].start
+                            && buf.length == buffers[i].length)
+                                break;
+
+                assert (i < n_buffers);
+
+                process_image ((void *) buf.m.userptr);
+
+                if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                        errno_exit ("VIDIOC_QBUF");
+
+                break;
+        }
+
+        return 1;
+}
+
+static void
+mainloop                        (void)
+{
+        unsigned int count;
+
+        count = 100;
+
+        while (count-- > 0) {
+                for (;;) {
+                        fd_set fds;
+                        struct timeval tv;
+                        int r;
+
+                        FD_ZERO (&fds);
+                        FD_SET (fd, &fds);
+
+                        /* Timeout. */
+                        tv.tv_sec = 2;
+                        tv.tv_usec = 0;
+
+                        r = select (fd + 1, &fds, NULL, NULL, &tv);
+
+                        if (-1 == r) {
+                                if (EINTR == errno)
+                                        continue;
+
+                                errno_exit ("select");
+                        }
+
+                        if (0 == r) {
+                                fprintf (stderr, "select timeout\n");
+                                exit (EXIT_FAILURE);
+                        }
+
+                        if (read_frame ())
+                                break;
+
+                        /* EAGAIN - continue select loop. */
+                }
+        }
+}
+
+static void
+stop_capturing                  (void)
+{
+        enum v4l2_buf_type type;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                /* Nothing to do. */
+                break;
+
+        case IO_METHOD_MMAP:
+        case IO_METHOD_USERPTR:
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
+                        errno_exit ("VIDIOC_STREAMOFF");
+
+                break;
+        }
+}
+
+static void
+start_capturing                 (void)
+{
+        unsigned int i;
+        enum v4l2_buf_type type;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                /* Nothing to do. */
+                break;
+
+        case IO_METHOD_MMAP:
+                for (i = 0; i < n_buffers; ++i) {
+                        struct v4l2_buffer buf;
+
+                        CLEAR (buf);
+
+                        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                        buf.memory      = V4L2_MEMORY_MMAP;
+                        buf.index       = i;
+
+                        if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                                errno_exit ("VIDIOC_QBUF");
+                }
+
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
+                        errno_exit ("VIDIOC_STREAMON");
+
+                break;
+
+        case IO_METHOD_USERPTR:
+                for (i = 0; i < n_buffers; ++i) {
+                        struct v4l2_buffer buf;
+
+                        CLEAR (buf);
+
+                        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                        buf.memory      = V4L2_MEMORY_USERPTR;
+                        buf.index       = i;
+                        buf.m.userptr   = (unsigned long) buffers[i].start;
+                        buf.length      = buffers[i].length;
+
+                        if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                                errno_exit ("VIDIOC_QBUF");
+                }
+
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
+                        errno_exit ("VIDIOC_STREAMON");
+
+                break;
+        }
+}
+
+static void
+uninit_device                   (void)
+{
+        unsigned int i;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                free (buffers[0].start);
+                break;
+
+        case IO_METHOD_MMAP:
+                for (i = 0; i < n_buffers; ++i)
+                        if (-1 == munmap (buffers[i].start, buffers[i].length))
+                                errno_exit ("munmap");
+                break;
+
+        case IO_METHOD_USERPTR:
+                for (i = 0; i < n_buffers; ++i)
+                        free (buffers[i].start);
+                break;
+        }
+
+        free (buffers);
+}
+
+static void
+init_read                       (unsigned int           buffer_size)
+{
+        buffers = calloc (1, sizeof (*buffers));
+
+        if (!buffers) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+
+        buffers[0].length = buffer_size;
+        buffers[0].start = malloc (buffer_size);
+
+        if (!buffers[0].start) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+}
+
+static void
+init_mmap                       (void)
+{
+        struct v4l2_requestbuffers req;
+
+        CLEAR (req);
+
+        req.count               = 4;
+        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory              = V4L2_MEMORY_MMAP;
+
+        if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s does not support "
+                                 "memory mapping\n", dev_name);
+                        exit (EXIT_FAILURE);
+                } else {
+                        errno_exit ("VIDIOC_REQBUFS");
+                }
+        }
+
+        if (req.count < 2) {
+                fprintf (stderr, "Insufficient buffer memory on %s\n",
+                         dev_name);
+                exit (EXIT_FAILURE);
+        }
+
+        buffers = calloc (req.count, sizeof (*buffers));
+
+        if (!buffers) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+
+        for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
+                struct v4l2_buffer buf;
+
+                CLEAR (buf);
+
+                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory      = V4L2_MEMORY_MMAP;
+                buf.index       = n_buffers;
+
+                if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
+                        errno_exit ("VIDIOC_QUERYBUF");
+
+                buffers[n_buffers].length = buf.length;
+                buffers[n_buffers].start =
+                        mmap (NULL /* start anywhere */,
+                              buf.length,
+                              PROT_READ | PROT_WRITE /* required */,
+                              MAP_SHARED /* recommended */,
+                              fd, buf.m.offset);
+
+                if (MAP_FAILED == buffers[n_buffers].start)
+                        errno_exit ("mmap");
+        }
+}
+
+static void
+init_userp                      (unsigned int           buffer_size)
+{
+        struct v4l2_requestbuffers req;
+        unsigned int page_size;
+
+        page_size = getpagesize ();
+        buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
+
+        CLEAR (req);
+
+        req.count               = 4;
+        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory              = V4L2_MEMORY_USERPTR;
+
+        if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s does not support "
+                                 "user pointer i/o\n", dev_name);
+                        exit (EXIT_FAILURE);
+                } else {
+                        errno_exit ("VIDIOC_REQBUFS");
+                }
+        }
+
+        buffers = calloc (4, sizeof (*buffers));
+
+        if (!buffers) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+
+        for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
+                buffers[n_buffers].length = buffer_size;
+                buffers[n_buffers].start = memalign (/* boundary */ page_size,
+                                                     buffer_size);
+
+                if (!buffers[n_buffers].start) {
+                        fprintf (stderr, "Out of memory\n");
+                        exit (EXIT_FAILURE);
+                }
+        }
+}
+
+static void
+init_device                     (void)
+{
+        struct v4l2_capability cap;
+        struct v4l2_cropcap cropcap;
+        struct v4l2_crop crop;
+        struct v4l2_format fmt;
+        unsigned int min;
+
+        if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s is no V4L2 device\n",
+                                 dev_name);
+                        exit (EXIT_FAILURE);
+                } else {
+                        errno_exit ("VIDIOC_QUERYCAP");
+                }
+        }
+
+        if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
+                fprintf (stderr, "%s is no video capture device\n",
+                         dev_name);
+                exit (EXIT_FAILURE);
+        }
+
+        switch (io) {
+        case IO_METHOD_READ:
+                if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
+                        fprintf (stderr, "%s does not support read i/o\n",
+                                 dev_name);
+                        exit (EXIT_FAILURE);
+                }
+
+                break;
+
+        case IO_METHOD_MMAP:
+        case IO_METHOD_USERPTR:
+                if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
+                        fprintf (stderr, "%s does not support streaming i/o\n",
+                                 dev_name);
+                        exit (EXIT_FAILURE);
+                }
+
+                break;
+        }
+
+
+        /* Select video input, video standard and tune here. */
+
+
+        CLEAR (cropcap);
+
+        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+        if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
+                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                crop.c = cropcap.defrect; /* reset to default */
+
+                if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
+                        switch (errno) {
+                        case EINVAL:
+                                /* Cropping not supported. */
+                                break;
+                        default:
+                                /* Errors ignored. */
+                                break;
+                        }
+                }
+        } else {
+                /* Errors ignored. */
+        }
+
+
+        CLEAR (fmt);
+
+        fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        fmt.fmt.pix.width       = 640;
+        fmt.fmt.pix.height      = 480;
+        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
+
+        if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
+                errno_exit ("VIDIOC_S_FMT");
+
+        /* Note VIDIOC_S_FMT may change width and height. */
+
+        /* Buggy driver paranoia. */
+        min = fmt.fmt.pix.width * 2;
+        if (fmt.fmt.pix.bytesperline < min)
+                fmt.fmt.pix.bytesperline = min;
+        min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
+        if (fmt.fmt.pix.sizeimage < min)
+                fmt.fmt.pix.sizeimage = min;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                init_read (fmt.fmt.pix.sizeimage);
+                break;
+
+        case IO_METHOD_MMAP:
+                init_mmap ();
+                break;
+
+        case IO_METHOD_USERPTR:
+                init_userp (fmt.fmt.pix.sizeimage);
+                break;
+        }
+}
+
+static void
+close_device                    (void)
+{
+        if (-1 == close (fd))
+                errno_exit ("close");
+
+        fd = -1;
+}
+
+static void
+open_device                     (void)
+{
+        struct stat st;
+
+        if (-1 == stat (dev_name, &st)) {
+                fprintf (stderr, "Cannot identify '%s': %d, %s\n",
+                         dev_name, errno, strerror (errno));
+                exit (EXIT_FAILURE);
+        }
+
+        if (!S_ISCHR (st.st_mode)) {
+                fprintf (stderr, "%s is no device\n", dev_name);
+                exit (EXIT_FAILURE);
+        }
+
+        fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
+
+        if (-1 == fd) {
+                fprintf (stderr, "Cannot open '%s': %d, %s\n",
+                         dev_name, errno, strerror (errno));
+                exit (EXIT_FAILURE);
+        }
+}
+
+static void
+usage                           (FILE *                 fp,
+                                 int                    argc,
+                                 char **                argv)
+{
+        fprintf (fp,
+                 "Usage: %s [options]\n\n"
+                 "Options:\n"
+                 "-d | --device name   Video device name [/dev/video]\n"
+                 "-h | --help          Print this message\n"
+                 "-m | --mmap          Use memory mapped buffers\n"
+                 "-r | --read          Use read() calls\n"
+                 "-u | --userp         Use application allocated buffers\n"
+                 "",
+                 argv[0]);
+}
+
+static const char short_options [] = "d:hmru";
+
+static const struct option
+long_options [] = {
+        { "device",     required_argument,      NULL,           'd' },
+        { "help",       no_argument,            NULL,           'h' },
+        { "mmap",       no_argument,            NULL,           'm' },
+        { "read",       no_argument,            NULL,           'r' },
+        { "userp",      no_argument,            NULL,           'u' },
+        { 0, 0, 0, 0 }
+};
+
+int
+main                            (int                    argc,
+                                 char **                argv)
+{
+        dev_name = "/dev/video";
+
+        for (;;) {
+                int index;
+                int c;
+
+                c = getopt_long (argc, argv,
+                                 short_options, long_options,
+                                 &index);
+
+                if (-1 == c)
+                        break;
+
+                switch (c) {
+                case 0: /* getopt_long() flag */
+                        break;
+
+                case 'd':
+                        dev_name = optarg;
+                        break;
+
+                case 'h':
+                        usage (stdout, argc, argv);
+                        exit (EXIT_SUCCESS);
+
+                case 'm':
+                        io = IO_METHOD_MMAP;
+                        break;
+
+                case 'r':
+                        io = IO_METHOD_READ;
+                        break;
+
+                case 'u':
+                        io = IO_METHOD_USERPTR;
+                        break;
+
+                default:
+                        usage (stderr, argc, argv);
+                        exit (EXIT_FAILURE);
+                }
+        }
+
+        open_device ();
+
+        init_device ();
+
+        start_capturing ();
+
+        mainloop ();
+
+        stop_capturing ();
+
+        uninit_device ();
+
+        close_device ();
+
+        exit (EXIT_SUCCESS);
+
+        return 0;
+}

PrevHomeNext
Video For Linux Two Header File GNU Free Documentation License
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16721.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16721.htm new file mode 100644 index 0000000000000000000000000000000000000000..7495e598440942f6a128e1febc5391ce390739fb --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/a16721.htm @@ -0,0 +1,246 @@ + +GNU Free Documentation License
Video for Linux Two API Specification: Revision 0.24
PrevNext

Appendix C. GNU Free Documentation License

C.1. 0. PREAMBLE

The purpose of this License is to make a manual, textbook, or + other written document "free" in the sense of + freedom: to assure everyone the effective freedom to copy and + redistribute it, with or without modifying it, either + commercially or noncommercially. Secondarily, this License + preserves for the author and publisher a way to get credit for + their work, while not being considered responsible for + modifications made by others. +

This License is a kind of "copyleft", which means + that derivative works of the document must themselves be free in + the same sense. It complements the GNU General Public License, + which is a copyleft license designed for free software. +

We have designed this License in order to use it for manuals for + free software, because free software needs free documentation: a + free program should come with manuals providing the same + freedoms that the software does. But this License is not limited + to software manuals; it can be used for any textual work, + regardless of subject matter or whether it is published as a + printed book. We recommend this License principally for works + whose purpose is instruction or reference. +


PrevHomeNext
Video Capture Example 1. APPLICABILITY AND DEFINITIONS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/b17127.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/b17127.htm new file mode 100644 index 0000000000000000000000000000000000000000..a0f6e0f9d1bc095ade26efb4a36cd0752764d8d6 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/b17127.htm @@ -0,0 +1,493 @@ + +References
Video for Linux Two API Specification: Revision 0.24
Prev 

References

[EIA 608-B] Electronic Industries Alliance (http://www.eia.org), EIA 608-B "Recommended Practice for Line 21 Data +Service".

[EN 300 294] European Telecommunication Standards Institute +(http://www.etsi.org), EN 300 294 "625-line television Wide Screen Signalling +(WSS)".

[ETS 300 231] European Telecommunication Standards Institute +(http://www.etsi.org), ETS 300 231 "Specification of the domestic video +Programme Delivery Control system (PDC)".

[ETS 300 706] European Telecommunication Standards Institute +(http://www.etsi.org), ETS 300 706 "Enhanced Teletext specification".

[ISO 13818-1] International Telecommunication Union (http://www.itu.ch), International +Organisation for Standardisation (http://www.iso.ch), ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information +technology — Generic coding of moving pictures and associated +audio information: Systems".

[ISO 13818-2] International Telecommunication Union (http://www.itu.ch), International +Organisation for Standardisation (http://www.iso.ch), ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information +technology — Generic coding of moving pictures and associated +audio information: Video".

[ITU BT.470] International Telecommunication Union (http://www.itu.ch), ITU-R Recommendation BT.470-6 "Conventional Television +Systems".

[ITU BT.601] International Telecommunication Union (http://www.itu.ch), ITU-R Recommendation BT.601-5 "Studio Encoding Parameters +of Digital Television for Standard 4:3 and Wide-Screen 16:9 Aspect +Ratios".

[ITU BT.653] International Telecommunication Union (http://www.itu.ch), ITU-R Recommendation BT.653-3 "Teletext systems".

[ITU BT.709] International Telecommunication Union (http://www.itu.ch), ITU-R Recommendation BT.709-5 "Parameter values for the +HDTV standards for production and international programme +exchange".

[ITU BT.1119] International Telecommunication Union (http://www.itu.ch), ITU-R Recommendation BT.1119 "625-line +television Wide Screen Signalling (WSS)".

[JFIF] Independent JPEG Group (http://www.ijg.org), JPEG File Interchange Format: Version 1.02.

[SMPTE 12M] Society of Motion Picture and Television Engineers +(http://www.smpte.org), SMPTE 12M-1999 "Television, Audio and Film - Time and +Control Code".

[SMPTE 170M] Society of Motion Picture and Television Engineers +(http://www.smpte.org), SMPTE 170M-1999 "Television - Composite Analog Video +Signal - NTSC for Studio Applications".

[SMPTE 240M] Society of Motion Picture and Television Engineers +(http://www.smpte.org), SMPTE 240M-1999 "Television - Signal Parameters - +1125-Line High-Definition Production".

[V4L] Alan Cox, Video4Linux API Specification.

This file is part of the Linux kernel sources under +Documentation/video4linux.

[V4LPROG] Alan Cox, Video4Linux Programming (a.k.a. The Video4Linux +Book), 2000.

About V4L driver programming. This +book is part of the Linux kernel DocBook documentation, for example at +http://kernelnewbies.org/documents/. SGML sources are included +in the kernel sources.


PrevHome 
List of Types  
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/book1.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/book1.htm new file mode 100644 index 0000000000000000000000000000000000000000..c317d6ff148ad6e82240fa2c78f0dad1741cceae --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/book1.htm @@ -0,0 +1,1650 @@ + +Video for Linux Two API Specification

Video for Linux Two API Specification

Revision 0.24

Michael H Schimek

            <mschimek@gmx.at>
+          

Bill Dirks

Hans Verkuil

Martin Rubli

Copyright © 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin +Rubli

This document is copyrighted © 1999-2008 by Bill +Dirks, Michael H. Schimek, Hans Verkuil and Martin Rubli.

Permission is granted to copy, distribute and/or modify +this document under the terms of the GNU Free Documentation License, +Version 1.1 or any later version published by the Free Software +Foundation; with no Invariant Sections, with no Front-Cover Texts, and +with no Back-Cover Texts. A copy of the license is included in the +appendix entitled "GNU Free Documentation License".

Programming examples can be used and distributed without +restrictions.


Table of Contents
Introduction
1. Common API Elements
1.1. Opening and Closing Devices
1.1.1. Device Naming
1.1.2. Related Devices
1.1.3. Multiple Opens
1.1.4. Shared Data Streams
1.1.5. Functions
1.2. Querying Capabilities
1.3. Application Priority
1.4. Video Inputs and Outputs
1.5. Audio Inputs and Outputs
1.6. Tuners and Modulators
1.6.1. Tuners
1.6.2. Modulators
1.6.3. Radio Frequency
1.6.4. Satellite Receivers
1.7. Video Standards
1.8. User Controls
1.9. Extended Controls
1.9.1. Introduction
1.9.2. The Extended Control API
1.9.3. Enumerating Extended Controls
1.9.4. Creating Control Panels
1.9.5. MPEG Control Reference
1.9.6. Camera Control Reference
1.10. Data Formats
1.10.1. Data Format Negotiation
1.10.2. Image Format Enumeration
1.11. Image Cropping, Insertion and Scaling
1.11.1. Cropping Structures
1.11.2. Scaling Adjustments
1.11.3. Examples
1.12. Streaming Parameters
2. Image Formats
2.1. Standard Image Formats
2.2. Colorspaces
2.3. Indexed Format
2.4. RGB Formats
Packed RGB formats -- Packed RGB formats
V4L2_PIX_FMT_SBGGR8 ('BA81') -- Bayer RGB format
V4L2_PIX_FMT_SBGGR16 ('BA82') -- Bayer RGB format
2.5. YUV Formats
Packed YUV formats -- Packed YUV formats
V4L2_PIX_FMT_GREY ('GREY') -- Grey-scale image
V4L2_PIX_FMT_Y16 ('Y16 ') -- Grey-scale image
V4L2_PIX_FMT_YUYV ('YUYV') -- Packed format with ½ horizontal chroma +resolution, also known as YUV 4:2:2
V4L2_PIX_FMT_UYVY ('UYVY') -- Variation of +V4L2_PIX_FMT_YUYV with different order of samples +in memory
V4L2_PIX_FMT_Y41P ('Y41P') -- Format with ¼ horizontal chroma +resolution, also known as YUV 4:1:1
V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12') -- Planar formats with ½ horizontal and +vertical chroma resolution, also known as YUV 4:2:0
V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9') -- Planar formats with ¼ horizontal and +vertical chroma resolution, also known as YUV 4:1:0
V4L2_PIX_FMT_YUV422P ('422P') -- Format with ½ horizontal chroma resolution, +also known as YUV 4:2:2. Planar layout as opposed to +V4L2_PIX_FMT_YUYV
V4L2_PIX_FMT_YUV411P ('411P') -- Format with ¼ horizontal chroma resolution, +also known as YUV 4:1:1. Planar layout as opposed to +V4L2_PIX_FMT_Y41P
V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21') -- Formats with ½ horizontal and vertical +chroma resolution, also known as YUV 4:2:0. One luminance and one +chrominance plane with alternating chroma samples as opposed to +V4L2_PIX_FMT_YVU420
2.6. Compressed Formats
2.7. Reserved Format Identifiers
3. Input/Output
3.1. Read/Write
3.2. Streaming I/O (Memory Mapping)
3.3. Streaming I/O (User Pointers)
3.4. Asynchronous I/O
3.5. Buffers
3.5.1. Timecodes
3.6. Field Order
4. Interfaces
4.1. Video Capture Interface
4.1.1. Querying Capabilities
4.1.2. Supplemental Functions
4.1.3. Image Format Negotiation
4.1.4. Reading Images
4.2. Video Overlay Interface
4.2.1. Querying Capabilities
4.2.2. Supplemental Functions
4.2.3. Setup
4.2.4. Overlay Window
4.2.5. Enabling Overlay
4.3. Video Output Interface
4.3.1. Querying Capabilities
4.3.2. Supplemental Functions
4.3.3. Image Format Negotiation
4.3.4. Writing Images
4.4. Video Output Overlay Interface
4.4.1. Querying Capabilities
4.4.2. Framebuffer
4.4.3. Overlay Window and Scaling
4.4.4. Enabling Overlay
4.5. Codec Interface
4.6. Effect Devices Interface
4.7. Raw VBI Data Interface
4.7.1. Querying Capabilities
4.7.2. Supplemental Functions
4.7.3. Raw VBI Format Negotiation
4.7.4. Reading and writing VBI images
4.8. Sliced VBI Data Interface
4.8.1. Querying Capabilities
4.8.2. Supplemental Functions
4.8.3. Sliced VBI Format Negotiation
4.8.4. Reading and writing sliced VBI data
4.9. Teletext Interface
4.10. Radio Interface
4.10.1. Querying Capabilities
4.10.2. Supplemental Functions
4.10.3. Programming
4.11. RDS Interface
I. Function Reference
V4L2 close() -- Close a V4L2 device
V4L2 ioctl() -- Program a V4L2 device
ioctl VIDIOC_CROPCAP -- Information about the video cropping and scaling abilities
ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER -- Read or write hardware registers
ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD -- Execute an encoder command
ioctl VIDIOC_ENUMAUDIO -- Enumerate audio inputs
ioctl VIDIOC_ENUMAUDOUT -- Enumerate audio outputs
ioctl VIDIOC_ENUM_FMT -- Enumerate image formats
ioctl VIDIOC_ENUM_FRAMESIZES -- Enumerate frame sizes
ioctl VIDIOC_ENUM_FRAMEINTERVALS -- Enumerate frame intervals
ioctl VIDIOC_ENUMINPUT -- Enumerate video inputs
ioctl VIDIOC_ENUMOUTPUT -- Enumerate video outputs
ioctl VIDIOC_ENUMSTD -- Enumerate supported video standards
ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO -- Query or select the current audio input and its +attributes
ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT -- Query or select the current audio output
ioctl VIDIOC_G_CHIP_IDENT -- Identify the chips on a TV card
ioctl VIDIOC_G_CROP, VIDIOC_S_CROP -- Get or set the current cropping rectangle
ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL -- Get or set the value of a control
ioctl VIDIOC_G_ENC_INDEX -- Get meta data about a compressed video stream
ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, +VIDIOC_TRY_EXT_CTRLS -- Get or set the value of several controls, try control +values
ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF -- Get or set frame buffer overlay parameters
ioctl VIDIOC_G_FMT, VIDIOC_S_FMT, +VIDIOC_TRY_FMT -- Get or set the data format, try a format
ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY -- Get or set tuner or modulator radio +frequency
ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT -- Query or select the current video input
ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP -- 
ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR -- Get or set modulator attributes
ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT -- Query or select the current video output
ioctl VIDIOC_G_PARM, VIDIOC_S_PARM -- Get or set streaming parameters
ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY -- Query or request the access priority associated with a +file descriptor
ioctl VIDIOC_G_SLICED_VBI_CAP -- Query sliced VBI capabilities
ioctl VIDIOC_G_STD, VIDIOC_S_STD -- Query or select the video standard of the current input
ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER -- Get or set tuner attributes
ioctl VIDIOC_LOG_STATUS -- Log driver status information
ioctl VIDIOC_OVERLAY -- Start or stop video overlay
ioctl VIDIOC_QBUF, VIDIOC_DQBUF -- Exchange a buffer with the driver
ioctl VIDIOC_QUERYBUF -- Query the status of a buffer
ioctl VIDIOC_QUERYCAP -- Query device capabilities
ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU -- Enumerate controls and menu control items
ioctl VIDIOC_QUERYSTD -- Sense the video standard received by the current +input
ioctl VIDIOC_REQBUFS -- Initiate Memory Mapping or User Pointer I/O
ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF -- Start or stop streaming I/O
V4L2 mmap() -- Map device memory into application address space
V4L2 munmap() -- Unmap device memory
V4L2 open() -- Open a V4L2 device
V4L2 poll() -- Wait for some event on a file descriptor
V4L2 read() -- Read from a V4L2 device
V4L2 select() -- Synchronous I/O multiplexing
V4L2 write() -- Write to a V4L2 device
5. V4L2 Driver Programming
6. Changes
6.1. Differences between V4L and V4L2
6.1.1. Opening and Closing Devices
6.1.2. Querying Capabilities
6.1.3. Video Sources
6.1.4. Tuning
6.1.5. Image Properties
6.1.6. Audio
6.1.7. Frame Buffer Overlay
6.1.8. Cropping
6.1.9. Reading Images, Memory Mapping
6.1.10. Reading Raw VBI Data
6.1.11. Miscellaneous
6.2. Changes of the V4L2 API
6.2.1. Early Versions
6.2.2. V4L2 Version 0.16 1999-01-31
6.2.3. V4L2 Version 0.18 1999-03-16
6.2.4. V4L2 Version 0.19 1999-06-05
6.2.5. V4L2 Version 0.20 (1999-09-10)
6.2.6. V4L2 Version 0.20 incremental changes
6.2.7. V4L2 Version 0.20 2000-11-23
6.2.8. V4L2 Version 0.20 2002-07-25
6.2.9. V4L2 in Linux 2.5.46, 2002-10
6.2.10. V4L2 2003-06-19
6.2.11. V4L2 2003-11-05
6.2.12. V4L2 in Linux 2.6.6, 2004-05-09
6.2.13. V4L2 in Linux 2.6.8
6.2.14. V4L2 spec erratum 2004-08-01
6.2.15. V4L2 in Linux 2.6.14
6.2.16. V4L2 in Linux 2.6.15
6.2.17. V4L2 spec erratum 2005-11-27
6.2.18. V4L2 spec erratum 2006-01-10
6.2.19. V4L2 spec erratum 2006-02-03
6.2.20. V4L2 spec erratum 2006-02-04
6.2.21. V4L2 in Linux 2.6.17
6.2.22. V4L2 spec erratum 2006-09-23 (Draft 0.15)
6.2.23. V4L2 in Linux 2.6.18
6.2.24. V4L2 in Linux 2.6.19
6.2.25. V4L2 spec erratum 2006-10-12 (Draft 0.17)
6.2.26. V4L2 in Linux 2.6.21
6.2.27. V4L2 in Linux 2.6.22
6.2.28. V4L2 in Linux 2.6.24
6.2.29. V4L2 in Linux 2.6.25
6.3. Relation of V4L2 to other Linux multimedia APIs
6.3.1. X Video Extension
6.3.2. Digital Video
6.3.3. Audio Interfaces
6.4. Experimental API Elements
6.5. Obsolete API Elements
A. Video For Linux Two Header File
B. Video Capture Example
C. GNU Free Documentation License
C.1. 0. PREAMBLE
C.2. 1. APPLICABILITY AND DEFINITIONS
C.3. 2. VERBATIM COPYING
C.4. 3. COPYING IN QUANTITY
C.5. 4. MODIFICATIONS
C.6. 5. COMBINING DOCUMENTS
C.7. 6. COLLECTIONS OF DOCUMENTS
C.8. 7. AGGREGATION WITH INDEPENDENT WORKS
C.9. 8. TRANSLATION
C.10. 9. TERMINATION
C.11. 10. FUTURE REVISIONS OF THIS LICENSE
C.12. Addendum
List of Types
References
List of Examples
1-1. Information about the current video input
1-2. Switching to the first video input
1-3. Information about the current audio input
1-4. Switching to the first audio input
1-5. Information about the current video standard
1-6. Listing the video standards supported by the current +input
1-7. Selecting a new video standard
1-8. Enumerating all controls
1-9. Changing controls
1-10. Resetting the cropping parameters
1-11. Simple downscaling
1-12. Selecting an output area
1-13. Current scaling factor and pixel aspect
2-1. ITU-R Rec. BT.601 color conversion
2-1. V4L2_PIX_FMT_BGR24 4 × 4 pixel +image
2-1. V4L2_PIX_FMT_SBGGR8 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_SBGGR16 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_GREY 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_Y16 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_YUYV 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_UYVY 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_Y41P 8 × 4 +pixel image
2-1. V4L2_PIX_FMT_YVU420 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_YVU410 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_YUV422P 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_YUV411P 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_NV12 4 × 4 +pixel image
3-1. Mapping buffers
3-2. Initiating streaming I/O with user pointers
4-1. Finding a framebuffer device for OSD

  Next
  Introduction
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c14592.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c14592.htm new file mode 100644 index 0000000000000000000000000000000000000000..41b2e2265fa471ef2b08b0b38ab15fec532c1574 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c14592.htm @@ -0,0 +1,138 @@ + +V4L2 Driver Programming
Video for Linux Two API Specification: Revision 0.24
PrevNext

Chapter 5. V4L2 Driver Programming

to do


PrevHomeNext
V4L2 write() Changes
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c14595.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c14595.htm new file mode 100644 index 0000000000000000000000000000000000000000..290c2cfe013ce4fd59e9b25037fee4c73bf5bae0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c14595.htm @@ -0,0 +1,2903 @@ + +Changes
Video for Linux Two API Specification: Revision 0.24
PrevNext

Chapter 6. Changes

The following chapters document the evolution of the V4L2 API, +errata or extensions. They are also intended to help application and +driver writers to port or update their code.

6.1. Differences between V4L and V4L2

The Video For Linux API was first introduced in Linux 2.1 to +unify and replace various TV and radio device related interfaces, +developed independently by driver writers in prior years. Starting +with Linux 2.5 the much improved V4L2 API replaces the V4L API, +although existing drivers will continue to support V4L applications in +the future, either directly or through the V4L2 compatibility layer in +the videodev kernel module translating ioctls on +the fly. For a transition period not all drivers will support the V4L2 +API.

6.1.1. Opening and Closing Devices

For compatibility reasons the character device file names +recommended for V4L2 video capture, overlay, radio, teletext and raw +vbi capture devices did not change from those used by V4L. They are +listed in Chapter 4 and below in Table 6-1.

The V4L videodev module automatically +assigns minor numbers to drivers in load order, depending on the +registered device type. We recommend that V4L2 drivers by default +register devices with the same numbers, but the system administrator +can assign arbitrary minor numbers using driver module options. The +major device number remains 81.

Table 6-1. V4L Device Types, Names and Numbers

Device TypeFile NameMinor Numbers
Video capture and overlay

/dev/video and +/dev/bttv0a, +/dev/video0 to +/dev/video63

0-63
Radio receiver

/dev/radiob, /dev/radio0 to +/dev/radio63

64-127
Teletext decoder

/dev/vtx, +/dev/vtx0 to +/dev/vtx31

192-223
Raw VBI capture

/dev/vbi, +/dev/vbi0 to +/dev/vbi31

224-255
Notes:
a. According to +Documentation/devices.txt these should be symbolic links to +/dev/video0. Note the original bttv interface is +not compatible with V4L or V4L2.
b. According to +Documentation/devices.txt a symbolic link to +/dev/radio0.

V4L prohibits (or used to prohibit) multiple opens of a +device file. V4L2 drivers may support multiple +opens, see Section 1.1 for details and consequences.

V4L drivers respond to V4L2 ioctls with an EINVAL error code. The +compatibility layer in the V4L2 videodev module +can translate V4L ioctl requests to their V4L2 counterpart, however a +V4L2 driver usually needs more preparation to become fully V4L +compatible. This is covered in more detail in Chapter 5.

6.1.2. Querying Capabilities

The V4L VIDIOCGCAP ioctl is +equivalent to V4L2's VIDIOC_QUERYCAP.

The name field in struct +video_capability became +card in struct v4l2_capability, +type was replaced by +capabilities. Note V4L2 does not +distinguish between device types like this, better think of basic +video input, video output and radio devices supporting a set of +related functions like video capturing, video overlay and VBI +capturing. See Section 1.1 for an +introduction.

struct +video_capability +typestruct v4l2_capability +capabilities flagsPurpose
VID_TYPE_CAPTUREV4L2_CAP_VIDEO_CAPTUREThe video +capture interface is supported.
VID_TYPE_TUNERV4L2_CAP_TUNERThe device has a tuner or +modulator.
VID_TYPE_TELETEXTV4L2_CAP_VBI_CAPTUREThe raw VBI +capture interface is supported.
VID_TYPE_OVERLAYV4L2_CAP_VIDEO_OVERLAYThe video +overlay interface is supported.
VID_TYPE_CHROMAKEYV4L2_FBUF_CAP_CHROMAKEY in +field capability of +struct v4l2_framebufferWhether chromakey overlay is supported. For +more information on overlay see +Section 4.2.
VID_TYPE_CLIPPINGV4L2_FBUF_CAP_LIST_CLIPPING +and V4L2_FBUF_CAP_BITMAP_CLIPPING in field +capability of struct v4l2_framebufferWhether clipping the overlaid image is +supported, see Section 4.2.
VID_TYPE_FRAMERAMV4L2_FBUF_CAP_EXTERNOVERLAY +not set in field +capability of struct v4l2_framebufferWhether overlay overwrites frame buffer memory, +see Section 4.2.
VID_TYPE_SCALES-This flag indicates if the hardware can scale +images. The V4L2 API implies the scale factor by setting the cropping +dimensions and image size with the VIDIOC_S_CROP and VIDIOC_S_FMT +ioctl, respectively. The driver returns the closest sizes possible. +For more information on cropping and scaling see Section 1.11.
VID_TYPE_MONOCHROME-Applications can enumerate the supported image +formats with the VIDIOC_ENUM_FMT ioctl to determine if the device +supports grey scale capturing only. For more information on image +formats see Chapter 2.
VID_TYPE_SUBCAPTURE-Applications can call the VIDIOC_G_CROP ioctl +to determine if the device supports capturing a subsection of the full +picture ("cropping" in V4L2). If not, the ioctl returns the EINVAL error code. +For more information on cropping and scaling see Section 1.11.
VID_TYPE_MPEG_DECODER-Applications can enumerate the supported image +formats with the VIDIOC_ENUM_FMT ioctl to determine if the device +supports MPEG streams.
VID_TYPE_MPEG_ENCODER-See above.
VID_TYPE_MJPEG_DECODER-See above.
VID_TYPE_MJPEG_ENCODER-See above.

The audios field was replaced +by capabilities flag +V4L2_CAP_AUDIO, indicating +if the device has any audio inputs or outputs. To +determine their number applications can enumerate audio inputs with +the VIDIOC_G_AUDIO ioctl. The audio ioctls are described in Section 1.5.

The maxwidth, +maxheight, +minwidth and +minheight fields were removed. Calling the +VIDIOC_S_FMT or VIDIOC_TRY_FMT ioctl with the desired dimensions +returns the closest size possible, taking into account the current +video standard, cropping and scaling limitations.

6.1.3. Video Sources

V4L provides the VIDIOCGCHAN and +VIDIOCSCHAN ioctl using struct +video_channel to enumerate +the video inputs of a V4L device. The equivalent V4L2 ioctls +are VIDIOC_ENUMINPUT, VIDIOC_G_INPUT and VIDIOC_S_INPUT +using struct v4l2_input as discussed in Section 1.4.

The channel field counting +inputs was renamed to index, the video +input types were renamed as follows:

struct video_channel +typestruct v4l2_input +type
VIDEO_TYPE_TVV4L2_INPUT_TYPE_TUNER
VIDEO_TYPE_CAMERAV4L2_INPUT_TYPE_CAMERA

Unlike the tuners field +expressing the number of tuners of this input, V4L2 assumes each video +input is connected to at most one tuner. However a tuner can have more +than one input, i. e. RF connectors, and a device can have multiple +tuners. The index number of the tuner associated with the input, if +any, is stored in field tuner of +struct v4l2_input. Enumeration of tuners is discussed in Section 1.6.

The redundant VIDEO_VC_TUNER flag was +dropped. Video inputs associated with a tuner are of type +V4L2_INPUT_TYPE_TUNER. The +VIDEO_VC_AUDIO flag was replaced by the +audioset field. V4L2 considers devices with +up to 32 audio inputs. Each set bit in the +audioset field represents one audio input +this video input combines with. For information about audio inputs and +how to switch between them see Section 1.5.

The norm field describing the +supported video standards was replaced by +std. The V4L specification mentions a flag +VIDEO_VC_NORM indicating whether the standard can +be changed. This flag was a later addition together with the +norm field and has been removed in the +meantime. V4L2 has a similar, albeit more comprehensive approach +to video standards, see Section 1.7 for more +information.

6.1.4. Tuning

The V4L VIDIOCGTUNER and +VIDIOCSTUNER ioctl and struct +video_tuner can be used to enumerate the +tuners of a V4L TV or radio device. The equivalent V4L2 ioctls are +VIDIOC_G_TUNER and VIDIOC_S_TUNER using struct v4l2_tuner. Tuners are +covered in Section 1.6.

The tuner field counting tuners +was renamed to index. The fields +name, rangelow +and rangehigh remained unchanged.

The VIDEO_TUNER_PAL, +VIDEO_TUNER_NTSC and +VIDEO_TUNER_SECAM flags indicating the supported +video standards were dropped. This information is now contained in the +associated struct v4l2_input. No replacement exists for the +VIDEO_TUNER_NORM flag indicating whether the +video standard can be switched. The mode +field to select a different video standard was replaced by a whole new +set of ioctls and structures described in Section 1.7. +Due to its ubiquity it should be mentioned the BTTV driver supports +several standards in addition to the regular +VIDEO_MODE_PAL (0), +VIDEO_MODE_NTSC, +VIDEO_MODE_SECAM and +VIDEO_MODE_AUTO (3). Namely N/PAL Argentina, +M/PAL, N/PAL, and NTSC Japan with numbers 3-6 (sic).

The VIDEO_TUNER_STEREO_ON flag +indicating stereo reception became +V4L2_TUNER_SUB_STEREO in field +rxsubchans. This field also permits the +detection of monaural and bilingual audio, see the definition of +struct v4l2_tuner for details. Presently no replacement exists for the +VIDEO_TUNER_RDS_ON and +VIDEO_TUNER_MBS_ON flags.

The VIDEO_TUNER_LOW flag was renamed +to V4L2_TUNER_CAP_LOW in the struct v4l2_tuner +capability field.

The VIDIOCGFREQ and +VIDIOCSFREQ ioctl to change the tuner frequency +where renamed to VIDIOC_G_FREQUENCY and VIDIOC_S_FREQUENCY. They +take a pointer to a struct v4l2_frequency instead of an unsigned long +integer.

6.1.5. Image Properties

V4L2 has no equivalent of the +VIDIOCGPICT and VIDIOCSPICT +ioctl and struct video_picture. The following +fields where replaced by V4L2 controls accessible with the +VIDIOC_QUERYCTRL, VIDIOC_G_CTRL and VIDIOC_S_CTRL ioctls:

struct video_pictureV4L2 Control ID
brightnessV4L2_CID_BRIGHTNESS
hueV4L2_CID_HUE
colourV4L2_CID_SATURATION
contrastV4L2_CID_CONTRAST
whitenessV4L2_CID_WHITENESS

The V4L picture controls are assumed to range from 0 to +65535 with no particular reset value. The V4L2 API permits arbitrary +limits and defaults which can be queried with the VIDIOC_QUERYCTRL +ioctl. For general information about controls see Section 1.8.

The depth (average number of +bits per pixel) of a video image is implied by the selected image +format. V4L2 does not explicitely provide such information assuming +applications recognizing the format are aware of the image depth and +others need not know. The palette field +moved into the struct v4l2_pix_format:

struct video_picture +palettestruct v4l2_pix_format +pixfmt
VIDEO_PALETTE_GREY

V4L2_PIX_FMT_GREY

VIDEO_PALETTE_HI240

V4L2_PIX_FMT_HI240a

VIDEO_PALETTE_RGB565

V4L2_PIX_FMT_RGB565

VIDEO_PALETTE_RGB555

V4L2_PIX_FMT_RGB555

VIDEO_PALETTE_RGB24

V4L2_PIX_FMT_BGR24

VIDEO_PALETTE_RGB32

V4L2_PIX_FMT_BGR32b

VIDEO_PALETTE_YUV422

V4L2_PIX_FMT_YUYV

VIDEO_PALETTE_YUYVc

V4L2_PIX_FMT_YUYV

VIDEO_PALETTE_UYVY

V4L2_PIX_FMT_UYVY

VIDEO_PALETTE_YUV420None
VIDEO_PALETTE_YUV411

V4L2_PIX_FMT_Y41Pd

VIDEO_PALETTE_RAW

Nonee

VIDEO_PALETTE_YUV422P

V4L2_PIX_FMT_YUV422P

VIDEO_PALETTE_YUV411P

V4L2_PIX_FMT_YUV411Pf

VIDEO_PALETTE_YUV420P

V4L2_PIX_FMT_YVU420

VIDEO_PALETTE_YUV410P

V4L2_PIX_FMT_YVU410

Notes:
a. This is a custom format used by the BTTV +driver, not one of the V4L2 standard formats.
b. Presumably all V4L RGB formats are +little-endian, although some drivers might interpret them according to machine endianess. V4L2 defines little-endian, big-endian and red/blue +swapped variants. For details see Section 2.4.
c. VIDEO_PALETTE_YUV422 +and VIDEO_PALETTE_YUYV are the same formats. Some +V4L drivers respond to one, some to the other.
d. Not to be confused with +V4L2_PIX_FMT_YUV411P, which is a planar +format.
e. V4L explains this +as: "RAW capture (BT848)"
f. Not to be confused with +V4L2_PIX_FMT_Y41P, which is a packed +format.

V4L2 image formats are defined in Chapter 2. The image format can be selected with the +VIDIOC_S_FMT ioctl.

6.1.6. Audio

The VIDIOCGAUDIO and +VIDIOCSAUDIO ioctl and struct +video_audio are used to enumerate the +audio inputs of a V4L device. The equivalent V4L2 ioctls are +VIDIOC_G_AUDIO and VIDIOC_S_AUDIO using struct v4l2_audio as +discussed in Section 1.5.

The audio "channel number" +field counting audio inputs was renamed to +index.

On VIDIOCSAUDIO the +mode field selects one +of the VIDEO_SOUND_MONO, +VIDEO_SOUND_STEREO, +VIDEO_SOUND_LANG1 or +VIDEO_SOUND_LANG2 audio demodulation modes. When +the current audio standard is BTSC +VIDEO_SOUND_LANG2 refers to SAP and +VIDEO_SOUND_LANG1 is meaningless. Also +undocumented in the V4L specification, there is no way to query the +selected mode. On VIDIOCGAUDIO the driver returns +the actually received audio programmes in this +field. In the V4L2 API this information is stored in the struct v4l2_tuner +rxsubchans and +audmode fields, respectively. See Section 1.6 for more information on tuners. Related to audio +modes struct v4l2_audio also reports if this is a mono or stereo +input, regardless if the source is a tuner.

The following fields where replaced by V4L2 controls +accessible with the VIDIOC_QUERYCTRL, VIDIOC_G_CTRL and +VIDIOC_S_CTRL ioctls:

struct +video_audioV4L2 Control ID
volumeV4L2_CID_AUDIO_VOLUME
bassV4L2_CID_AUDIO_BASS
trebleV4L2_CID_AUDIO_TREBLE
balanceV4L2_CID_AUDIO_BALANCE

To determine which of these controls are supported by a +driver V4L provides the flags +VIDEO_AUDIO_VOLUME, +VIDEO_AUDIO_BASS, +VIDEO_AUDIO_TREBLE and +VIDEO_AUDIO_BALANCE. In the V4L2 API the +VIDIOC_QUERYCTRL ioctl reports if the respective control is +supported. Accordingly the VIDEO_AUDIO_MUTABLE +and VIDEO_AUDIO_MUTE flags where replaced by the +boolean V4L2_CID_AUDIO_MUTE control.

All V4L2 controls have a step +attribute replacing the struct video_audio +step field. The V4L audio controls are +assumed to range from 0 to 65535 with no particular reset value. The +V4L2 API permits arbitrary limits and defaults which can be queried +with the VIDIOC_QUERYCTRL ioctl. For general information about +controls see Section 1.8.

6.1.7. Frame Buffer Overlay

The V4L2 ioctls equivalent to +VIDIOCGFBUF and VIDIOCSFBUF +are VIDIOC_G_FBUF and VIDIOC_S_FBUF. The +base field of struct +video_buffer remained unchanged, except V4L2 +defines a flag to indicate non-destructive overlays instead of a +NULL pointer. All other fields moved into the +struct v4l2_pix_format fmt substructure of +struct v4l2_framebuffer. The depth field was +replaced by pixelformat. See Section 2.4 for a list of RGB formats and their +respective color depths.

Instead of the special ioctls +VIDIOCGWIN and VIDIOCSWIN +V4L2 uses the general-purpose data format negotiation ioctls +VIDIOC_G_FMT and VIDIOC_S_FMT. They take a pointer to a +struct v4l2_format as argument. Here the win +member of the fmt union is used, a +struct v4l2_window.

The x, +y, width and +height fields of struct +video_window moved into struct v4l2_rect +substructure w of struct +v4l2_window. The +chromakey, +clips, and +clipcount fields remained unchanged. Struct +video_clip was renamed to struct v4l2_clip, also +containing a struct v4l2_rect, but the +semantics are still the same.

The VIDEO_WINDOW_INTERLACE flag was +dropped. Instead applications must set the +field field to +V4L2_FIELD_ANY or +V4L2_FIELD_INTERLACED. The +VIDEO_WINDOW_CHROMAKEY flag moved into +struct v4l2_framebuffer, under the new name +V4L2_FBUF_FLAG_CHROMAKEY.

In V4L, storing a bitmap pointer in +clips and setting +clipcount to +VIDEO_CLIP_BITMAP (-1) requests bitmap +clipping, using a fixed size bitmap of 1024 × 625 bits. Struct +v4l2_window has a separate +bitmap pointer field for this purpose and +the bitmap size is determined by w.width and +w.height.

The VIDIOCCAPTURE ioctl to enable or +disable overlay was renamed to VIDIOC_OVERLAY.

6.1.8. Cropping

To capture only a subsection of the full picture V4L +defines the VIDIOCGCAPTURE and +VIDIOCSCAPTURE ioctls using struct +video_capture. The equivalent V4L2 ioctls are +VIDIOC_G_CROP and VIDIOC_S_CROP using struct v4l2_crop, and the related +VIDIOC_CROPCAP ioctl. This is a rather complex matter, see +Section 1.11 for details.

The x, +y, width and +height fields moved into struct v4l2_rect +substructure c of struct +v4l2_crop. The +decimation field was dropped. In the V4L2 +API the scaling factor is implied by the size of the cropping +rectangle and the size of the captured or overlaid image.

The VIDEO_CAPTURE_ODD +and VIDEO_CAPTURE_EVEN flags to capture only the +odd or even field, respectively, were replaced by +V4L2_FIELD_TOP and +V4L2_FIELD_BOTTOM in the field named +field of struct v4l2_pix_format and +struct v4l2_window. These structures are used to select a capture or +overlay format with the VIDIOC_S_FMT ioctl.

6.1.9. Reading Images, Memory Mapping

6.1.9.1. Capturing using the read method

There is no essential difference between reading images +from a V4L or V4L2 device using the read() function, however V4L2 +drivers are not required to support this I/O method. Applications can +determine if the function is available with the VIDIOC_QUERYCAP +ioctl. All V4L2 devices exchanging data with applications must support +the select() and poll() functions.

To select an image format and size, V4L provides the +VIDIOCSPICT and VIDIOCSWIN +ioctls. V4L2 uses the general-purpose data format negotiation ioctls +VIDIOC_G_FMT and VIDIOC_S_FMT. They take a pointer to a +struct v4l2_format as argument, here the struct v4l2_pix_format named +pix of its fmt +union is used.

For more information about the V4L2 read interface see +Section 3.1.

6.1.9.2. Capturing using memory mapping

Applications can read from V4L devices by mapping +buffers in device memory, or more often just buffers allocated in +DMA-able system memory, into their address space. This avoids the data +copying overhead of the read method. V4L2 supports memory mapping as +well, with a few differences.

V4LV4L2
 The image format must be selected before +buffers are allocated, with the VIDIOC_S_FMT ioctl. When no format +is selected the driver may use the last, possibly by another +application requested format.

Applications cannot change the number of +buffers. The it is built into the driver, unless it has a module +option to change the number when the driver module is +loaded.

The VIDIOC_REQBUFS ioctl allocates the +desired number of buffers, this is a required step in the initialization +sequence.

Drivers map all buffers as one contiguous +range of memory. The VIDIOCGMBUF ioctl is +available to query the number of buffers, the offset of each buffer +from the start of the virtual file, and the overall amount of memory +used, which can be used as arguments for the mmap() +function.

Buffers are individually mapped. The +offset and size of each buffer can be determined with the +VIDIOC_QUERYBUF ioctl.

The VIDIOCMCAPTURE +ioctl prepares a buffer for capturing. It also determines the image +format for this buffer. The ioctl returns immediately, eventually with +an EAGAIN error code if no video signal had been detected. When the driver +supports more than one buffer applications can call the ioctl multiple +times and thus have multiple outstanding capture +requests.

The VIDIOCSYNC ioctl +suspends execution until a particular buffer has been +filled.

Drivers maintain an incoming and outgoing +queue. VIDIOC_QBUF enqueues any empty buffer into the incoming +queue. Filled buffers are dequeued from the outgoing queue with the +VIDIOC_DQBUF ioctl. To wait until filled buffers become available this +function, select() or poll() can be used. The +VIDIOC_STREAMON ioctl must be called once after enqueuing one or +more buffers to start capturing. Its counterpart +VIDIOC_STREAMOFF stops capturing and dequeues all buffers from both +queues. Applications can query the signal status, if known, with the +VIDIOC_ENUMINPUT ioctl.

For a more in-depth discussion of memory mapping and +examples, see Section 3.2.

6.1.10. Reading Raw VBI Data

Originally the V4L API did not specify a raw VBI capture +interface, only the device file /dev/vbi was +reserved for this purpose. The only driver supporting this interface +was the BTTV driver, de-facto defining the V4L VBI interface. Reading +from the device yields a raw VBI image with the following +parameters:

struct v4l2_vbi_formatV4L, BTTV driver
sampling_rate28636363 Hz NTSC (or any other 525-line +standard); 35468950 Hz PAL and SECAM (625-line standards)
offset?
samples_per_line2048
sample_formatV4L2_PIX_FMT_GREY. The last four bytes (a +machine endianess integer) contain a frame counter.
start[]10, 273 NTSC; 22, 335 PAL and SECAM
count[]

16, 16a

flags0
Notes:
a. Old driver +versions used different values, eventually the custom +BTTV_VBISIZE ioctl was added to query the +correct values.

Undocumented in the V4L specification, in Linux 2.3 the +VIDIOCGVBIFMT and +VIDIOCSVBIFMT ioctls using struct +vbi_format were added to determine the VBI +image parameters. These ioctls are only partially compatible with the +V4L2 VBI interface specified in Section 4.7.

An offset field does not +exist, sample_format is supposed to be +VIDEO_PALETTE_RAW, equivalent to +V4L2_PIX_FMT_GREY. The remaining fields are +probably equivalent to struct v4l2_vbi_format.

Apparently only the Zoran (ZR 36120) driver implements +these ioctls. The semantics differ from those specified for V4L2 in two +ways. The parameters are reset on open() and +VIDIOCSVBIFMT always returns an EINVAL error code if the +parameters are invalid.

6.1.11. Miscellaneous

V4L2 has no equivalent of the +VIDIOCGUNIT ioctl. Applications can find the VBI +device associated with a video capture device (or vice versa) by +reopening the device and requesting VBI data. For details see +Section 1.1.

No replacement exists for VIDIOCKEY, +and the V4L functions for microcode programming. A new interface for +MPEG compression and playback devices is documented in Section 1.9.


PrevHomeNext
V4L2 Driver Programming Changes of the V4L2 API
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c174.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c174.htm new file mode 100644 index 0000000000000000000000000000000000000000..550cf39303fa1b4cca67d26edfff4506c98e2988 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c174.htm @@ -0,0 +1,776 @@ + +Common API Elements
Video for Linux Two API Specification: Revision 0.24
PrevNext

Chapter 1. Common API Elements

Programming a V4L2 device consists of these +steps:

  • Opening the device

  • Changing device properties, selecting a video and audio +input, video standard, picture brightness a. o.

  • Negotiating a data format

  • Negotiating an input/output method

  • The actual input/output loop

  • Closing the device

In practice most steps are optional and can be executed out of +order. It depends on the V4L2 device type, you can read about the +details in Chapter 4. In this chapter we will discuss +the basic concepts applicable to all devices.

1.1. Opening and Closing Devices

1.1.1. Device Naming

V4L2 drivers are implemented as kernel modules, loaded +manually by the system administrator or automatically when a device is +first opened. The driver modules plug into the "videodev" kernel +module. It provides helper functions and a common application +interface specified in this document.

Each driver thus loaded registers one or more device nodes +with major number 81 and a minor number between 0 and 255. Assigning +minor numbers to V4L2 devices is entirely up to the system administrator, +this is primarily intended to solve conflicts between devices.[1] The module options to select minor numbers are named +after the device special file with a "_nr" suffix. For example "video_nr" +for /dev/video video capture devices. The number is +an offset to the base minor number associated with the device type. +[2] When the driver supports multiple devices of the same +type more than one minor number can be assigned, separated by commas: +

> insmod mydriver.o video_nr=0,1 radio_nr=0,1

In /etc/modules.conf this may be +written as:

alias char-major-81-0 mydriver
+alias char-major-81-1 mydriver
+alias char-major-81-64 mydriver              
+options mydriver video_nr=0,1 radio_nr=0,1   
+          
When an application attempts to open a device +special file with major number 81 and minor number 0, 1, or 64, load +"mydriver" (and the "videodev" module it depends upon).
Register the first two video capture devices with +minor number 0 and 1 (base number is 0), the first two radio device +with minor number 64 and 65 (base 64).

When no minor number is given as module +option the driver supplies a default. Chapter 4 +recommends the base minor numbers to be used for the various device +types. Obviously minor numbers must be unique. When the number is +already in use the offending device will not be +registered.

By convention system administrators create various +character device special files with these major and minor numbers in +the /dev directory. The names recomended for the +different V4L2 device types are listed in Chapter 4.

The creation of character special files (with +mknod) is a privileged operation and +devices cannot be opened by major and minor number. That means +applications cannot reliable scan for loaded or +installed drivers. The user must enter a device name, or the +application can try the conventional device names.

Under the device filesystem (devfs) the minor number +options are ignored. V4L2 drivers (or by proxy the "videodev" module) +automatically create the required device files in the +/dev/v4l directory using the conventional device +names above.

1.1.2. Related Devices

Devices can support several related functions. For example +video capturing, video overlay and VBI capturing are related because +these functions share, amongst other, the same video input and tuner +frequency. V4L and earlier versions of V4L2 used the same device name +and minor number for video capturing and overlay, but different ones +for VBI. Experience showed this approach has several problems[3], and to make things worse the V4L videodev module +used to prohibit multiple opens of a device.

As a remedy the present version of the V4L2 API relaxed the +concept of device types with specific names and minor numbers. For +compatibility with old applications drivers must still register different +minor numbers to assign a default function to the device. But if related +functions are supported by the driver they must be available under all +registered minor numbers. The desired function can be selected after +opening the device as described in Chapter 4.

Imagine a driver supporting video capturing, video +overlay, raw VBI capturing, and FM radio reception. It registers three +devices with minor number 0, 64 and 224 (this numbering scheme is +inherited from the V4L API). Regardless if +/dev/video (81, 0) or +/dev/vbi (81, 224) is opened the application can +select any one of the video capturing, overlay or VBI capturing +functions. Without programming (e. g. reading from the device +with dd or cat) +/dev/video captures video images, while +/dev/vbi captures raw VBI data. +/dev/radio (81, 64) is invariable a radio device, +unrelated to the video functions. Being unrelated does not imply the +devices can be used at the same time, however. The open() +function may very well return an EBUSY error code.

Besides video input or output the hardware may also +support audio sampling or playback. If so, these functions are +implemented as OSS or ALSA PCM devices and eventually OSS or ALSA +audio mixer. The V4L2 API makes no provisions yet to find these +related devices. If you have an idea please write to the Video4Linux +mailing list: https://listman.redhat.com/mailman/listinfo/video4linux-list.

1.1.3. Multiple Opens

In general, V4L2 devices can be opened more than once. +When this is supported by the driver, users can for example start a +"panel" application to change controls like brightness or audio +volume, while another application captures video and audio. In other words, panel +applications are comparable to an OSS or ALSA audio mixer application. +When a device supports multiple functions like capturing and overlay +simultaneously, multiple opens allow concurrent +use of the device by forked processes or specialized applications.

Multiple opens are optional, although drivers should +permit at least concurrent accesses without data exchange, i. e. panel +applications. This implies open() can return an EBUSY error code when the +device is already in use, as well as ioctl() functions initiating +data exchange (namely the VIDIOC_S_FMT ioctl), and the read() +and write() functions.

Mere opening a V4L2 device does not grant exclusive +access.[4] Initiating data exchange however assigns the right +to read or write the requested type of data, and to change related +properties, to this file descriptor. Applications can request +additional access privileges using the priority mechanism described in +Section 1.3.

1.1.4. Shared Data Streams

V4L2 drivers should not support multiple applications +reading or writing the same data stream on a device by copying +buffers, time multiplexing or similar means. This is better handled by +a proxy application in user space. When the driver supports stream +sharing anyway it must be implemented transparently. The V4L2 API does +not specify how conflicts are solved.

1.1.5. Functions

To open and close V4L2 devices applications use the +open() and close() function, respectively. Devices are +programmed using the ioctl() function as explained in the +following sections.

Notes

[1]

Access permissions are associated with character +device special files, hence we must ensure device numbers cannot +change with the module load order. To this end minor numbers are no +longer automatically assigned by the "videodev" module as in V4L but +requested by the driver. The defaults will suffice for most people +unless two drivers compete for the same minor numbers.

[2]

In earlier versions of the V4L2 API the module options +where named after the device special file with a "unit_" prefix, expressing +the minor number itself, not an offset. Rationale for this change is unknown. +Lastly the naming and semantics are just a convention among driver writers, +the point to note is that minor numbers are not supposed to be hardcoded +into drivers.

[3]

Given a device file name one cannot reliable find +related devices. For once names are arbitrary and in a system with +multiple devices, where only some support VBI capturing, a +/dev/video2 is not necessarily related to +/dev/vbi2. The V4L +VIDIOCGUNIT ioctl would require a search for a +device file with a particular major and minor number.

[4]

Drivers could recognize the +O_EXCL open flag. Presently this is not required, +so applications cannot know if it really works.


PrevHomeNext
Introduction Querying Capabilities
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c2030.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c2030.htm new file mode 100644 index 0000000000000000000000000000000000000000..5996ae45de48216285686758295f3c9118a89c36 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c2030.htm @@ -0,0 +1,488 @@ + +Image Formats
Video for Linux Two API Specification: Revision 0.24
PrevNext

Chapter 2. Image Formats

The V4L2 API was primarily designed for devices exchanging +image data with applications. The +v4l2_pix_format structure defines the format +and layout of an image in memory. Image formats are negotiated with +the VIDIOC_S_FMT ioctl. (The explanations here focus on video +capturing and output, for overlay frame buffer formats see also +VIDIOC_G_FBUF.)

Table 2-1. struct v4l2_pix_format

__u32widthImage width in pixels.
__u32heightImage height in pixels.
Applications set these fields to +request an image size, drivers return the closest possible values. In +case of planar formats the width and +height applies to the largest plane. To +avoid ambiguities drivers must return values rounded up to a multiple +of the scale factor of any smaller planes. For example when the image +format is YUV 4:2:0, width and +height must be multiples of two.
__u32pixelformatThe pixel format or type of compression, set by the +application. This is a little endian four character code. V4L2 defines +standard RGB formats in Table 2-1, YUV formats in Section 2.5, and reserved codes in Table 2-8
enum v4l2_fieldfieldVideo images are typically interlaced. Applications +can request to capture or output only the top or bottom field, or both +fields interlaced or sequentially stored in one buffer or alternating +in separate buffers. Drivers return the actual field order selected. +For details see Section 3.6.
__u32bytesperlineDistance in bytes between the leftmost pixels in two +adjacent lines.

Both applications and drivers +can set this field to request padding bytes at the end of each line. +Drivers however may ignore the value requested by the application, +returning width times bytes per pixel or a +larger value required by the hardware. That implies applications can +just set this field to zero to get a reasonable +default.

Video hardware may access padding bytes, +therefore they must reside in accessible memory. Consider cases where +padding bytes after the last line of an image cross a system page +boundary. Input devices may write padding bytes, the value is +undefined. Output devices ignore the contents of padding +bytes.

When the image format is planar the +bytesperline value applies to the largest +plane and is divided by the same factor as the +width field for any smaller planes. For +example the Cb and Cr planes of a YUV 4:2:0 image have half as many +padding bytes following each line as the Y plane. To avoid ambiguities +drivers must return a bytesperline value +rounded up to a multiple of the scale factor.

__u32sizeimageSize in bytes of the buffer to hold a complete image, +set by the driver. Usually this is +bytesperline times +height. When the image consists of variable +length compressed data this is the maximum number of bytes required to +hold an image.
enum v4l2_colorspacecolorspaceThis information supplements the +pixelformat and must be set by the driver, +see Section 2.2.
__u32privReserved for custom (driver defined) additional +information about formats. When not used drivers and applications must +set this field to zero.

2.1. Standard Image Formats

In order to exchange images between drivers and +applications, it is necessary to have standard image data formats +which both sides will interpret the same way. V4L2 includes several +such formats, and this section is intended to be an unambiguous +specification of the standard image data formats in V4L2.

V4L2 drivers are not limited to these formats, however. +Driver-specific formats are possible. In that case the application may +depend on a codec to convert images to one of the standard formats +when needed. But the data can still be stored and retrieved in the +proprietary format. For example, a device may support a proprietary +compressed format. Applications can still capture and save the data in +the compressed format, saving much disk space, and later use a codec +to convert the images to the X Windows screen format when the video is +to be displayed.

Even so, ultimately, some standard formats are needed, so +the V4L2 specification would not be complete without well-defined +standard formats.

The V4L2 standard formats are mainly uncompressed formats. The +pixels are always arranged in memory from left to right, and from top +to bottom. The first byte of data in the image buffer is always for +the leftmost pixel of the topmost row. Following that is the pixel +immediately to its right, and so on until the end of the top row of +pixels. Following the rightmost pixel of the row there may be zero or +more bytes of padding to guarantee that each row of pixel data has a +certain alignment. Following the pad bytes, if any, is data for the +leftmost pixel of the second row from the top, and so on. The last row +has just as many pad bytes after it as the other rows.

In V4L2 each format has an identifier which looks like +PIX_FMT_XXX, defined in the videodev.h header file. These identifiers +represent four character codes +which are also listed below, however they are not the same as those +used in the Windows world.


PrevHomeNext
Streaming Parameters Colorspaces
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c5742.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c5742.htm new file mode 100644 index 0000000000000000000000000000000000000000..e428158d531ba38e6a59d30c9d68769db40fd4a3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c5742.htm @@ -0,0 +1,414 @@ + +Input/Output
Video for Linux Two API Specification: Revision 0.24
PrevNext

Chapter 3. Input/Output

The V4L2 API defines several different methods to read from or +write to a device. All drivers exchanging data with applications must +support at least one of them.

The classic I/O method using the read() +and write() function is automatically selected +after opening a V4L2 device. When the driver does not support this +method attempts to read or write will fail at any time.

Other methods must be negotiated. To select the streaming I/O +method with memory mapped or user buffers applications call the +VIDIOC_REQBUFS ioctl. The asynchronous I/O method is not defined +yet.

Video overlay can be considered another I/O method, although +the application does not directly receive the image data. It is +selected by initiating video overlay with the VIDIOC_S_FMT ioctl. +For more information see Section 4.2.

Generally exactly one I/O method, including overlay, is +associated with each file descriptor. The only exceptions are +applications not exchanging data with a driver ("panel applications", +see Section 1.1) and drivers permitting simultaneous video capturing +and overlay using the same file descriptor, for compatibility with V4L +and earlier versions of V4L2.

VIDIOC_S_FMT and +VIDIOC_REQBUFS would permit this to some degree, +but for simplicity drivers need not support switching the I/O method +(after first switching away from read/write) other than by closing +and reopening the device.

The following sections describe the various I/O methods in +more detail.

3.1. Read/Write

Input and output devices support the +read() and write() function, +respectively, when the V4L2_CAP_READWRITE flag in +the capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl is set.

Drivers may need the CPU to copy the data, but they may also +support DMA to or from user memory, so this I/O method is not +necessarily less efficient than other methods merely exchanging buffer +pointers. It is considered inferior though because no meta-information +like frame counters or timestamps are passed. This information is +necessary to recognize frame dropping and to synchronize with other +data streams. However this is also the simplest I/O method, requiring +little or no setup to exchange data. It permits command line stunts +like this (the vidctrl tool is +fictitious):

> vidctrl /dev/video --input=0 --format=YUYV --size=352x288
+> dd if=/dev/video of=myimage.422 bs=202752 count=1

To read from the device applications use the +read() function, to write the write() function. +Drivers must implement one I/O method if they +exchange data with applications, but it need not be this.[1] When reading or writing is supported, the driver +must also support the select() and poll() +function.[2]

Notes

[1]

It would be desirable if applications could depend on +drivers supporting all I/O interfaces, but as much as the complex +memory mapping I/O can be inadequate for some devices we have no +reason to require this interface, which is most useful for simple +applications capturing still images.

[2]

At the driver level select() and +poll() are the same, and +select() is too important to be optional.


PrevHomeNext
Reserved Format Identifiers Streaming I/O (Memory Mapping)
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c6488.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c6488.htm new file mode 100644 index 0000000000000000000000000000000000000000..dc2a5b721cd44e60cb39a27bc176bfaea7beefc2 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/c6488.htm @@ -0,0 +1,501 @@ + +Interfaces
Video for Linux Two API Specification: Revision 0.24
PrevNext

Chapter 4. Interfaces

4.1. Video Capture Interface

Video capture devices sample an analog video signal and store +the digitized images in memory. Today nearly all devices can capture +at full 25 or 30 frames/second. With this interface applications can +control the capture process and move images from the driver into user +space.

Conventionally V4L2 video capture devices are accessed through +character device special files named /dev/video +and /dev/video0 to +/dev/video63 with major number 81 and minor +numbers 0 to 63. /dev/video is typically a +symbolic link to the preferred video device. Note the same device +files are used for video output devices.

4.1.1. Querying Capabilities

Devices supporting the video capture interface set the +V4L2_CAP_VIDEO_CAPTURE flag in the +capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl. As secondary device functions +they may also support the video overlay +(V4L2_CAP_VIDEO_OVERLAY) and the raw VBI capture +(V4L2_CAP_VBI_CAPTURE) interface. At least one of +the read/write or streaming I/O methods must be supported. Tuners and +audio inputs are optional.

4.1.2. Supplemental Functions

Video capture devices shall support audio input, tuner, controls, +cropping and scaling and streaming parameter ioctls as needed. +The video input and video standard ioctls must be supported by +all video capture devices.

4.1.3. Image Format Negotiation

The result of a capture operation is determined by +cropping and image format parameters. The former select an area of the +video picture to capture, the latter how images are stored in memory, +i. e. in RGB or YUV format, the number of bits per pixel or width and +height. Together they also define how images are scaled in the +process.

As usual these parameters are not reset +at open() time to permit Unix tool chains, programming a device +and then reading from it as if it was a plain file. Well written V4L2 +applications ensure they really get what they want, including cropping +and scaling.

Cropping initialization at minimum requires to reset the +parameters to defaults. An example is given in Section 1.11.

To query the current image format applications set the +type field of a struct v4l2_format to +V4L2_BUF_TYPE_VIDEO_CAPTURE and call the +VIDIOC_G_FMT ioctl with a pointer to this structure. Drivers fill +the struct v4l2_pix_format pix member of the +fmt union.

To request different parameters applications set the +type field of a struct v4l2_format as above and +initialize all fields of the struct v4l2_pix_format +vbi member of the +fmt union, or better just modify the +results of VIDIOC_G_FMT, and call the +VIDIOC_S_FMT ioctl with a pointer to this structure. Drivers may +adjust the parameters and finally return the actual parameters as +VIDIOC_G_FMT does.

Like VIDIOC_S_FMT the +VIDIOC_TRY_FMT ioctl can be used to learn about hardware limitations +without disabling I/O or possibly time consuming hardware +preparations.

The contents of struct v4l2_pix_format are discussed in Chapter 2. See also the specification of the +VIDIOC_G_FMT, VIDIOC_S_FMT +and VIDIOC_TRY_FMT ioctls for details. Video +capture devices must implement both the +VIDIOC_G_FMT and +VIDIOC_S_FMT ioctl, even if +VIDIOC_S_FMT ignores all requests and always +returns default parameters as VIDIOC_G_FMT does. +VIDIOC_TRY_FMT is optional.

4.1.4. Reading Images

A video capture device may support the read() function and/or streaming (memory mapping or user pointer) I/O. See Chapter 3 for details.


PrevHomeNext
Field Order Video Overlay Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/capture-example.html b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/capture-example.html new file mode 100644 index 0000000000000000000000000000000000000000..b65471d11065a9fe8d0e18e5a2b9c150e41511fc --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/capture-example.html @@ -0,0 +1,849 @@ + +Video Capture Example
Video for Linux Two API Specification: Revision 0.24
PrevNext

Appendix B. Video Capture Example

/*
+ *  V4L2 video capture example
+ *
+ *  This program can be used and distributed without restrictions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <getopt.h>             /* getopt_long() */
+
+#include <fcntl.h>              /* low-level i/o */
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>          /* for videodev2.h */
+
+#include <linux/videodev2.h>
+
+#define CLEAR(x) memset (&(x), 0, sizeof (x))
+
+typedef enum {
+        IO_METHOD_READ,
+        IO_METHOD_MMAP,
+        IO_METHOD_USERPTR,
+} io_method;
+
+struct buffer {
+        void *                  start;
+        size_t                  length;
+};
+
+static char *           dev_name        = NULL;
+static io_method        io              = IO_METHOD_MMAP;
+static int              fd              = -1;
+struct buffer *         buffers         = NULL;
+static unsigned int     n_buffers       = 0;
+
+static void
+errno_exit                      (const char *           s)
+{
+        fprintf (stderr, "%s error %d, %s\n",
+                 s, errno, strerror (errno));
+
+        exit (EXIT_FAILURE);
+}
+
+static int
+xioctl                          (int                    fd,
+                                 int                    request,
+                                 void *                 arg)
+{
+        int r;
+
+        do r = ioctl (fd, request, arg);
+        while (-1 == r && EINTR == errno);
+
+        return r;
+}
+
+static void
+process_image                   (const void *           p)
+{
+        fputc ('.', stdout);
+        fflush (stdout);
+}
+
+static int
+read_frame                      (void)
+{
+        struct v4l2_buffer buf;
+        unsigned int i;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                if (-1 == read (fd, buffers[0].start, buffers[0].length)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit ("read");
+                        }
+                }
+
+                process_image (buffers[0].start);
+
+                break;
+
+        case IO_METHOD_MMAP:
+                CLEAR (buf);
+
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_MMAP;
+
+                if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit ("VIDIOC_DQBUF");
+                        }
+                }
+
+                assert (buf.index < n_buffers);
+
+                process_image (buffers[buf.index].start);
+
+                if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                        errno_exit ("VIDIOC_QBUF");
+
+                break;
+
+        case IO_METHOD_USERPTR:
+                CLEAR (buf);
+
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_USERPTR;
+
+                if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit ("VIDIOC_DQBUF");
+                        }
+                }
+
+                for (i = 0; i < n_buffers; ++i)
+                        if (buf.m.userptr == (unsigned long) buffers[i].start
+                            && buf.length == buffers[i].length)
+                                break;
+
+                assert (i < n_buffers);
+
+                process_image ((void *) buf.m.userptr);
+
+                if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                        errno_exit ("VIDIOC_QBUF");
+
+                break;
+        }
+
+        return 1;
+}
+
+static void
+mainloop                        (void)
+{
+        unsigned int count;
+
+        count = 100;
+
+        while (count-- > 0) {
+                for (;;) {
+                        fd_set fds;
+                        struct timeval tv;
+                        int r;
+
+                        FD_ZERO (&fds);
+                        FD_SET (fd, &fds);
+
+                        /* Timeout. */
+                        tv.tv_sec = 2;
+                        tv.tv_usec = 0;
+
+                        r = select (fd + 1, &fds, NULL, NULL, &tv);
+
+                        if (-1 == r) {
+                                if (EINTR == errno)
+                                        continue;
+
+                                errno_exit ("select");
+                        }
+
+                        if (0 == r) {
+                                fprintf (stderr, "select timeout\n");
+                                exit (EXIT_FAILURE);
+                        }
+
+                        if (read_frame ())
+                                break;
+
+                        /* EAGAIN - continue select loop. */
+                }
+        }
+}
+
+static void
+stop_capturing                  (void)
+{
+        enum v4l2_buf_type type;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                /* Nothing to do. */
+                break;
+
+        case IO_METHOD_MMAP:
+        case IO_METHOD_USERPTR:
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
+                        errno_exit ("VIDIOC_STREAMOFF");
+
+                break;
+        }
+}
+
+static void
+start_capturing                 (void)
+{
+        unsigned int i;
+        enum v4l2_buf_type type;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                /* Nothing to do. */
+                break;
+
+        case IO_METHOD_MMAP:
+                for (i = 0; i < n_buffers; ++i) {
+                        struct v4l2_buffer buf;
+
+                        CLEAR (buf);
+
+                        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                        buf.memory      = V4L2_MEMORY_MMAP;
+                        buf.index       = i;
+
+                        if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                                errno_exit ("VIDIOC_QBUF");
+                }
+
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
+                        errno_exit ("VIDIOC_STREAMON");
+
+                break;
+
+        case IO_METHOD_USERPTR:
+                for (i = 0; i < n_buffers; ++i) {
+                        struct v4l2_buffer buf;
+
+                        CLEAR (buf);
+
+                        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                        buf.memory      = V4L2_MEMORY_USERPTR;
+                        buf.index       = i;
+                        buf.m.userptr   = (unsigned long) buffers[i].start;
+                        buf.length      = buffers[i].length;
+
+                        if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                                errno_exit ("VIDIOC_QBUF");
+                }
+
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
+                        errno_exit ("VIDIOC_STREAMON");
+
+                break;
+        }
+}
+
+static void
+uninit_device                   (void)
+{
+        unsigned int i;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                free (buffers[0].start);
+                break;
+
+        case IO_METHOD_MMAP:
+                for (i = 0; i < n_buffers; ++i)
+                        if (-1 == munmap (buffers[i].start, buffers[i].length))
+                                errno_exit ("munmap");
+                break;
+
+        case IO_METHOD_USERPTR:
+                for (i = 0; i < n_buffers; ++i)
+                        free (buffers[i].start);
+                break;
+        }
+
+        free (buffers);
+}
+
+static void
+init_read                       (unsigned int           buffer_size)
+{
+        buffers = calloc (1, sizeof (*buffers));
+
+        if (!buffers) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+
+        buffers[0].length = buffer_size;
+        buffers[0].start = malloc (buffer_size);
+
+        if (!buffers[0].start) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+}
+
+static void
+init_mmap                       (void)
+{
+        struct v4l2_requestbuffers req;
+
+        CLEAR (req);
+
+        req.count               = 4;
+        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory              = V4L2_MEMORY_MMAP;
+
+        if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s does not support "
+                                 "memory mapping\n", dev_name);
+                        exit (EXIT_FAILURE);
+                } else {
+                        errno_exit ("VIDIOC_REQBUFS");
+                }
+        }
+
+        if (req.count < 2) {
+                fprintf (stderr, "Insufficient buffer memory on %s\n",
+                         dev_name);
+                exit (EXIT_FAILURE);
+        }
+
+        buffers = calloc (req.count, sizeof (*buffers));
+
+        if (!buffers) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+
+        for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
+                struct v4l2_buffer buf;
+
+                CLEAR (buf);
+
+                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory      = V4L2_MEMORY_MMAP;
+                buf.index       = n_buffers;
+
+                if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
+                        errno_exit ("VIDIOC_QUERYBUF");
+
+                buffers[n_buffers].length = buf.length;
+                buffers[n_buffers].start =
+                        mmap (NULL /* start anywhere */,
+                              buf.length,
+                              PROT_READ | PROT_WRITE /* required */,
+                              MAP_SHARED /* recommended */,
+                              fd, buf.m.offset);
+
+                if (MAP_FAILED == buffers[n_buffers].start)
+                        errno_exit ("mmap");
+        }
+}
+
+static void
+init_userp                      (unsigned int           buffer_size)
+{
+        struct v4l2_requestbuffers req;
+        unsigned int page_size;
+
+        page_size = getpagesize ();
+        buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
+
+        CLEAR (req);
+
+        req.count               = 4;
+        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory              = V4L2_MEMORY_USERPTR;
+
+        if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s does not support "
+                                 "user pointer i/o\n", dev_name);
+                        exit (EXIT_FAILURE);
+                } else {
+                        errno_exit ("VIDIOC_REQBUFS");
+                }
+        }
+
+        buffers = calloc (4, sizeof (*buffers));
+
+        if (!buffers) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+
+        for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
+                buffers[n_buffers].length = buffer_size;
+                buffers[n_buffers].start = memalign (/* boundary */ page_size,
+                                                     buffer_size);
+
+                if (!buffers[n_buffers].start) {
+                        fprintf (stderr, "Out of memory\n");
+                        exit (EXIT_FAILURE);
+                }
+        }
+}
+
+static void
+init_device                     (void)
+{
+        struct v4l2_capability cap;
+        struct v4l2_cropcap cropcap;
+        struct v4l2_crop crop;
+        struct v4l2_format fmt;
+        unsigned int min;
+
+        if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s is no V4L2 device\n",
+                                 dev_name);
+                        exit (EXIT_FAILURE);
+                } else {
+                        errno_exit ("VIDIOC_QUERYCAP");
+                }
+        }
+
+        if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
+                fprintf (stderr, "%s is no video capture device\n",
+                         dev_name);
+                exit (EXIT_FAILURE);
+        }
+
+        switch (io) {
+        case IO_METHOD_READ:
+                if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
+                        fprintf (stderr, "%s does not support read i/o\n",
+                                 dev_name);
+                        exit (EXIT_FAILURE);
+                }
+
+                break;
+
+        case IO_METHOD_MMAP:
+        case IO_METHOD_USERPTR:
+                if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
+                        fprintf (stderr, "%s does not support streaming i/o\n",
+                                 dev_name);
+                        exit (EXIT_FAILURE);
+                }
+
+                break;
+        }
+
+
+        /* Select video input, video standard and tune here. */
+
+
+        CLEAR (cropcap);
+
+        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+        if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
+                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                crop.c = cropcap.defrect; /* reset to default */
+
+                if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
+                        switch (errno) {
+                        case EINVAL:
+                                /* Cropping not supported. */
+                                break;
+                        default:
+                                /* Errors ignored. */
+                                break;
+                        }
+                }
+        } else {
+                /* Errors ignored. */
+        }
+
+
+        CLEAR (fmt);
+
+        fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        fmt.fmt.pix.width       = 640;
+        fmt.fmt.pix.height      = 480;
+        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
+
+        if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
+                errno_exit ("VIDIOC_S_FMT");
+
+        /* Note VIDIOC_S_FMT may change width and height. */
+
+        /* Buggy driver paranoia. */
+        min = fmt.fmt.pix.width * 2;
+        if (fmt.fmt.pix.bytesperline < min)
+                fmt.fmt.pix.bytesperline = min;
+        min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
+        if (fmt.fmt.pix.sizeimage < min)
+                fmt.fmt.pix.sizeimage = min;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                init_read (fmt.fmt.pix.sizeimage);
+                break;
+
+        case IO_METHOD_MMAP:
+                init_mmap ();
+                break;
+
+        case IO_METHOD_USERPTR:
+                init_userp (fmt.fmt.pix.sizeimage);
+                break;
+        }
+}
+
+static void
+close_device                    (void)
+{
+        if (-1 == close (fd))
+                errno_exit ("close");
+
+        fd = -1;
+}
+
+static void
+open_device                     (void)
+{
+        struct stat st;
+
+        if (-1 == stat (dev_name, &st)) {
+                fprintf (stderr, "Cannot identify '%s': %d, %s\n",
+                         dev_name, errno, strerror (errno));
+                exit (EXIT_FAILURE);
+        }
+
+        if (!S_ISCHR (st.st_mode)) {
+                fprintf (stderr, "%s is no device\n", dev_name);
+                exit (EXIT_FAILURE);
+        }
+
+        fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
+
+        if (-1 == fd) {
+                fprintf (stderr, "Cannot open '%s': %d, %s\n",
+                         dev_name, errno, strerror (errno));
+                exit (EXIT_FAILURE);
+        }
+}
+
+static void
+usage                           (FILE *                 fp,
+                                 int                    argc,
+                                 char **                argv)
+{
+        fprintf (fp,
+                 "Usage: %s [options]\n\n"
+                 "Options:\n"
+                 "-d | --device name   Video device name [/dev/video]\n"
+                 "-h | --help          Print this message\n"
+                 "-m | --mmap          Use memory mapped buffers\n"
+                 "-r | --read          Use read() calls\n"
+                 "-u | --userp         Use application allocated buffers\n"
+                 "",
+                 argv[0]);
+}
+
+static const char short_options [] = "d:hmru";
+
+static const struct option
+long_options [] = {
+        { "device",     required_argument,      NULL,           'd' },
+        { "help",       no_argument,            NULL,           'h' },
+        { "mmap",       no_argument,            NULL,           'm' },
+        { "read",       no_argument,            NULL,           'r' },
+        { "userp",      no_argument,            NULL,           'u' },
+        { 0, 0, 0, 0 }
+};
+
+int
+main                            (int                    argc,
+                                 char **                argv)
+{
+        dev_name = "/dev/video";
+
+        for (;;) {
+                int index;
+                int c;
+
+                c = getopt_long (argc, argv,
+                                 short_options, long_options,
+                                 &index);
+
+                if (-1 == c)
+                        break;
+
+                switch (c) {
+                case 0: /* getopt_long() flag */
+                        break;
+
+                case 'd':
+                        dev_name = optarg;
+                        break;
+
+                case 'h':
+                        usage (stdout, argc, argv);
+                        exit (EXIT_SUCCESS);
+
+                case 'm':
+                        io = IO_METHOD_MMAP;
+                        break;
+
+                case 'r':
+                        io = IO_METHOD_READ;
+                        break;
+
+                case 'u':
+                        io = IO_METHOD_USERPTR;
+                        break;
+
+                default:
+                        usage (stderr, argc, argv);
+                        exit (EXIT_FAILURE);
+                }
+        }
+
+        open_device ();
+
+        init_device ();
+
+        start_capturing ();
+
+        mainloop ();
+
+        stop_capturing ();
+
+        uninit_device ();
+
+        close_device ();
+
+        exit (EXIT_SUCCESS);
+
+        return 0;
+}

PrevHomeNext
Video For Linux Two Header File GNU Free Documentation License
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/f163.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/f163.htm new file mode 100644 index 0000000000000000000000000000000000000000..74e7e3b25eb5a49502866197b3f969dd4b41d68d --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/f163.htm @@ -0,0 +1,176 @@ + +Introduction
Video for Linux Two API Specification: Revision 0.24
PrevNext

Introduction

Video For Linux Two is the second version of the Video For +Linux API, a kernel interface for analog radio and video capture and +output drivers.

Early drivers used ad-hoc interfaces. These were replaced in +Linux 2.2 by Alan Cox' V4L API, based on the interface of the bttv +driver. In 1999 Bill Dirks started the development of V4L2 to fix some +shortcomings of V4L and to support a wider range of devices. The API +was revised again in 2002 prior to its inclusion in Linux 2.5/2.6, and +work continues on improvements and additions while maintaining +compatibility with existing drivers and applications. In 2006/2007 +efforts began on FreeBSD drivers with a V4L2 interface.

This book documents the V4L2 API. Intended audience are +driver and application writers.

If you have questions or ideas regarding the API, please +write to the Video4Linux mailing list: https://listman.redhat.com/mailman/listinfo/video4linux-list. For inquiries about +the V4L2 specification contact the maintainer mschimek@gmx.at.

The latest version of this document and the DocBook SGML +sources are hosted at http://v4l2spec.bytesex.org, +and http://linuxtv.org/downloads/video4linux/API/V4L2_API.


PrevHomeNext
Video for Linux Two API Specification Common API Elements
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/i16960.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/i16960.htm new file mode 100644 index 0000000000000000000000000000000000000000..6ae39541e7906d1e6585463c3fbd58c22ba57087 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/i16960.htm @@ -0,0 +1,413 @@ + +List of Types
Video for Linux Two API Specification: Revision 0.24
PrevNext

List of Types

v4l2_std_id
enum v4l2_buf_type
enum v4l2_colorspace
enum v4l2_ctrl_type
enum v4l2_field
enum v4l2_frmivaltypes
enum v4l2_frmsizetypes
enum v4l2_memory
enum v4l2_priority
enum v4l2_tuner_type
struct v4l2_audio
struct v4l2_audioout
struct v4l2_buffer
struct v4l2_capability
struct v4l2_captureparm
struct v4l2_chip_ident
struct v4l2_clip
struct v4l2_control
struct v4l2_crop
struct v4l2_cropcap
struct v4l2_enc_idx
struct v4l2_enc_idx_entry
struct v4l2_encoder_cmd
struct v4l2_ext_control
struct v4l2_ext_controls
struct v4l2_fmtdesc
struct v4l2_format
struct v4l2_fract
struct v4l2_framebuffer
struct v4l2_frequency
struct v4l2_frmival_stepwise
struct v4l2_frmivalenum
struct v4l2_frmsize_discrete
struct v4l2_frmsize_stepwise
struct v4l2_frmsizeenum
struct v4l2_input
struct v4l2_jpegcompression
struct v4l2_modulator
struct v4l2_output
struct v4l2_outputparm
struct v4l2_pix_format
struct v4l2_queryctrl
struct v4l2_querymenu
struct v4l2_rect
struct v4l2_register
struct v4l2_requestbuffers
struct v4l2_sliced_vbi_cap
struct v4l2_sliced_vbi_data
struct v4l2_sliced_vbi_format
struct v4l2_standard
struct v4l2_streamparm
struct v4l2_timecode
struct v4l2_tuner
struct v4l2_vbi_format
struct v4l2_window

PrevHomeNext
Addendum References
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/index.html b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/index.html new file mode 100644 index 0000000000000000000000000000000000000000..c317d6ff148ad6e82240fa2c78f0dad1741cceae --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/index.html @@ -0,0 +1,1650 @@ + +Video for Linux Two API Specification

Video for Linux Two API Specification

Revision 0.24

Michael H Schimek

            <mschimek@gmx.at>
+          

Bill Dirks

Hans Verkuil

Martin Rubli

Copyright © 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin +Rubli

This document is copyrighted © 1999-2008 by Bill +Dirks, Michael H. Schimek, Hans Verkuil and Martin Rubli.

Permission is granted to copy, distribute and/or modify +this document under the terms of the GNU Free Documentation License, +Version 1.1 or any later version published by the Free Software +Foundation; with no Invariant Sections, with no Front-Cover Texts, and +with no Back-Cover Texts. A copy of the license is included in the +appendix entitled "GNU Free Documentation License".

Programming examples can be used and distributed without +restrictions.


Table of Contents
Introduction
1. Common API Elements
1.1. Opening and Closing Devices
1.1.1. Device Naming
1.1.2. Related Devices
1.1.3. Multiple Opens
1.1.4. Shared Data Streams
1.1.5. Functions
1.2. Querying Capabilities
1.3. Application Priority
1.4. Video Inputs and Outputs
1.5. Audio Inputs and Outputs
1.6. Tuners and Modulators
1.6.1. Tuners
1.6.2. Modulators
1.6.3. Radio Frequency
1.6.4. Satellite Receivers
1.7. Video Standards
1.8. User Controls
1.9. Extended Controls
1.9.1. Introduction
1.9.2. The Extended Control API
1.9.3. Enumerating Extended Controls
1.9.4. Creating Control Panels
1.9.5. MPEG Control Reference
1.9.6. Camera Control Reference
1.10. Data Formats
1.10.1. Data Format Negotiation
1.10.2. Image Format Enumeration
1.11. Image Cropping, Insertion and Scaling
1.11.1. Cropping Structures
1.11.2. Scaling Adjustments
1.11.3. Examples
1.12. Streaming Parameters
2. Image Formats
2.1. Standard Image Formats
2.2. Colorspaces
2.3. Indexed Format
2.4. RGB Formats
Packed RGB formats -- Packed RGB formats
V4L2_PIX_FMT_SBGGR8 ('BA81') -- Bayer RGB format
V4L2_PIX_FMT_SBGGR16 ('BA82') -- Bayer RGB format
2.5. YUV Formats
Packed YUV formats -- Packed YUV formats
V4L2_PIX_FMT_GREY ('GREY') -- Grey-scale image
V4L2_PIX_FMT_Y16 ('Y16 ') -- Grey-scale image
V4L2_PIX_FMT_YUYV ('YUYV') -- Packed format with ½ horizontal chroma +resolution, also known as YUV 4:2:2
V4L2_PIX_FMT_UYVY ('UYVY') -- Variation of +V4L2_PIX_FMT_YUYV with different order of samples +in memory
V4L2_PIX_FMT_Y41P ('Y41P') -- Format with ¼ horizontal chroma +resolution, also known as YUV 4:1:1
V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12') -- Planar formats with ½ horizontal and +vertical chroma resolution, also known as YUV 4:2:0
V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9') -- Planar formats with ¼ horizontal and +vertical chroma resolution, also known as YUV 4:1:0
V4L2_PIX_FMT_YUV422P ('422P') -- Format with ½ horizontal chroma resolution, +also known as YUV 4:2:2. Planar layout as opposed to +V4L2_PIX_FMT_YUYV
V4L2_PIX_FMT_YUV411P ('411P') -- Format with ¼ horizontal chroma resolution, +also known as YUV 4:1:1. Planar layout as opposed to +V4L2_PIX_FMT_Y41P
V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21') -- Formats with ½ horizontal and vertical +chroma resolution, also known as YUV 4:2:0. One luminance and one +chrominance plane with alternating chroma samples as opposed to +V4L2_PIX_FMT_YVU420
2.6. Compressed Formats
2.7. Reserved Format Identifiers
3. Input/Output
3.1. Read/Write
3.2. Streaming I/O (Memory Mapping)
3.3. Streaming I/O (User Pointers)
3.4. Asynchronous I/O
3.5. Buffers
3.5.1. Timecodes
3.6. Field Order
4. Interfaces
4.1. Video Capture Interface
4.1.1. Querying Capabilities
4.1.2. Supplemental Functions
4.1.3. Image Format Negotiation
4.1.4. Reading Images
4.2. Video Overlay Interface
4.2.1. Querying Capabilities
4.2.2. Supplemental Functions
4.2.3. Setup
4.2.4. Overlay Window
4.2.5. Enabling Overlay
4.3. Video Output Interface
4.3.1. Querying Capabilities
4.3.2. Supplemental Functions
4.3.3. Image Format Negotiation
4.3.4. Writing Images
4.4. Video Output Overlay Interface
4.4.1. Querying Capabilities
4.4.2. Framebuffer
4.4.3. Overlay Window and Scaling
4.4.4. Enabling Overlay
4.5. Codec Interface
4.6. Effect Devices Interface
4.7. Raw VBI Data Interface
4.7.1. Querying Capabilities
4.7.2. Supplemental Functions
4.7.3. Raw VBI Format Negotiation
4.7.4. Reading and writing VBI images
4.8. Sliced VBI Data Interface
4.8.1. Querying Capabilities
4.8.2. Supplemental Functions
4.8.3. Sliced VBI Format Negotiation
4.8.4. Reading and writing sliced VBI data
4.9. Teletext Interface
4.10. Radio Interface
4.10.1. Querying Capabilities
4.10.2. Supplemental Functions
4.10.3. Programming
4.11. RDS Interface
I. Function Reference
V4L2 close() -- Close a V4L2 device
V4L2 ioctl() -- Program a V4L2 device
ioctl VIDIOC_CROPCAP -- Information about the video cropping and scaling abilities
ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER -- Read or write hardware registers
ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD -- Execute an encoder command
ioctl VIDIOC_ENUMAUDIO -- Enumerate audio inputs
ioctl VIDIOC_ENUMAUDOUT -- Enumerate audio outputs
ioctl VIDIOC_ENUM_FMT -- Enumerate image formats
ioctl VIDIOC_ENUM_FRAMESIZES -- Enumerate frame sizes
ioctl VIDIOC_ENUM_FRAMEINTERVALS -- Enumerate frame intervals
ioctl VIDIOC_ENUMINPUT -- Enumerate video inputs
ioctl VIDIOC_ENUMOUTPUT -- Enumerate video outputs
ioctl VIDIOC_ENUMSTD -- Enumerate supported video standards
ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO -- Query or select the current audio input and its +attributes
ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT -- Query or select the current audio output
ioctl VIDIOC_G_CHIP_IDENT -- Identify the chips on a TV card
ioctl VIDIOC_G_CROP, VIDIOC_S_CROP -- Get or set the current cropping rectangle
ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL -- Get or set the value of a control
ioctl VIDIOC_G_ENC_INDEX -- Get meta data about a compressed video stream
ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, +VIDIOC_TRY_EXT_CTRLS -- Get or set the value of several controls, try control +values
ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF -- Get or set frame buffer overlay parameters
ioctl VIDIOC_G_FMT, VIDIOC_S_FMT, +VIDIOC_TRY_FMT -- Get or set the data format, try a format
ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY -- Get or set tuner or modulator radio +frequency
ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT -- Query or select the current video input
ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP -- 
ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR -- Get or set modulator attributes
ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT -- Query or select the current video output
ioctl VIDIOC_G_PARM, VIDIOC_S_PARM -- Get or set streaming parameters
ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY -- Query or request the access priority associated with a +file descriptor
ioctl VIDIOC_G_SLICED_VBI_CAP -- Query sliced VBI capabilities
ioctl VIDIOC_G_STD, VIDIOC_S_STD -- Query or select the video standard of the current input
ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER -- Get or set tuner attributes
ioctl VIDIOC_LOG_STATUS -- Log driver status information
ioctl VIDIOC_OVERLAY -- Start or stop video overlay
ioctl VIDIOC_QBUF, VIDIOC_DQBUF -- Exchange a buffer with the driver
ioctl VIDIOC_QUERYBUF -- Query the status of a buffer
ioctl VIDIOC_QUERYCAP -- Query device capabilities
ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU -- Enumerate controls and menu control items
ioctl VIDIOC_QUERYSTD -- Sense the video standard received by the current +input
ioctl VIDIOC_REQBUFS -- Initiate Memory Mapping or User Pointer I/O
ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF -- Start or stop streaming I/O
V4L2 mmap() -- Map device memory into application address space
V4L2 munmap() -- Unmap device memory
V4L2 open() -- Open a V4L2 device
V4L2 poll() -- Wait for some event on a file descriptor
V4L2 read() -- Read from a V4L2 device
V4L2 select() -- Synchronous I/O multiplexing
V4L2 write() -- Write to a V4L2 device
5. V4L2 Driver Programming
6. Changes
6.1. Differences between V4L and V4L2
6.1.1. Opening and Closing Devices
6.1.2. Querying Capabilities
6.1.3. Video Sources
6.1.4. Tuning
6.1.5. Image Properties
6.1.6. Audio
6.1.7. Frame Buffer Overlay
6.1.8. Cropping
6.1.9. Reading Images, Memory Mapping
6.1.10. Reading Raw VBI Data
6.1.11. Miscellaneous
6.2. Changes of the V4L2 API
6.2.1. Early Versions
6.2.2. V4L2 Version 0.16 1999-01-31
6.2.3. V4L2 Version 0.18 1999-03-16
6.2.4. V4L2 Version 0.19 1999-06-05
6.2.5. V4L2 Version 0.20 (1999-09-10)
6.2.6. V4L2 Version 0.20 incremental changes
6.2.7. V4L2 Version 0.20 2000-11-23
6.2.8. V4L2 Version 0.20 2002-07-25
6.2.9. V4L2 in Linux 2.5.46, 2002-10
6.2.10. V4L2 2003-06-19
6.2.11. V4L2 2003-11-05
6.2.12. V4L2 in Linux 2.6.6, 2004-05-09
6.2.13. V4L2 in Linux 2.6.8
6.2.14. V4L2 spec erratum 2004-08-01
6.2.15. V4L2 in Linux 2.6.14
6.2.16. V4L2 in Linux 2.6.15
6.2.17. V4L2 spec erratum 2005-11-27
6.2.18. V4L2 spec erratum 2006-01-10
6.2.19. V4L2 spec erratum 2006-02-03
6.2.20. V4L2 spec erratum 2006-02-04
6.2.21. V4L2 in Linux 2.6.17
6.2.22. V4L2 spec erratum 2006-09-23 (Draft 0.15)
6.2.23. V4L2 in Linux 2.6.18
6.2.24. V4L2 in Linux 2.6.19
6.2.25. V4L2 spec erratum 2006-10-12 (Draft 0.17)
6.2.26. V4L2 in Linux 2.6.21
6.2.27. V4L2 in Linux 2.6.22
6.2.28. V4L2 in Linux 2.6.24
6.2.29. V4L2 in Linux 2.6.25
6.3. Relation of V4L2 to other Linux multimedia APIs
6.3.1. X Video Extension
6.3.2. Digital Video
6.3.3. Audio Interfaces
6.4. Experimental API Elements
6.5. Obsolete API Elements
A. Video For Linux Two Header File
B. Video Capture Example
C. GNU Free Documentation License
C.1. 0. PREAMBLE
C.2. 1. APPLICABILITY AND DEFINITIONS
C.3. 2. VERBATIM COPYING
C.4. 3. COPYING IN QUANTITY
C.5. 4. MODIFICATIONS
C.6. 5. COMBINING DOCUMENTS
C.7. 6. COLLECTIONS OF DOCUMENTS
C.8. 7. AGGREGATION WITH INDEPENDENT WORKS
C.9. 8. TRANSLATION
C.10. 9. TERMINATION
C.11. 10. FUTURE REVISIONS OF THIS LICENSE
C.12. Addendum
List of Types
References
List of Examples
1-1. Information about the current video input
1-2. Switching to the first video input
1-3. Information about the current audio input
1-4. Switching to the first audio input
1-5. Information about the current video standard
1-6. Listing the video standards supported by the current +input
1-7. Selecting a new video standard
1-8. Enumerating all controls
1-9. Changing controls
1-10. Resetting the cropping parameters
1-11. Simple downscaling
1-12. Selecting an output area
1-13. Current scaling factor and pixel aspect
2-1. ITU-R Rec. BT.601 color conversion
2-1. V4L2_PIX_FMT_BGR24 4 × 4 pixel +image
2-1. V4L2_PIX_FMT_SBGGR8 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_SBGGR16 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_GREY 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_Y16 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_YUYV 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_UYVY 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_Y41P 8 × 4 +pixel image
2-1. V4L2_PIX_FMT_YVU420 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_YVU410 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_YUV422P 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_YUV411P 4 × 4 +pixel image
2-1. V4L2_PIX_FMT_NV12 4 × 4 +pixel image
3-1. Mapping buffers
3-2. Initiating streaming I/O with user pointers
4-1. Finding a framebuffer device for OSD

  Next
  Introduction
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10104.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10104.htm new file mode 100644 index 0000000000000000000000000000000000000000..fa79b6eee83dd4dab4ea30fc834c212a03dd35a5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10104.htm @@ -0,0 +1,424 @@ + +ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL

Name

VIDIOC_G_CTRL, VIDIOC_S_CTRL -- Get or set the value of a control

Synopsis

int ioctl(int fd, int request, struct v4l2_control +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_CTRL, VIDIOC_S_CTRL

argp

Description

To get the current value of a control applications +initialize the id field of a struct +v4l2_control and call the +VIDIOC_G_CTRL ioctl with a pointer to this +structure. To change the value of a control applications initialize +the id and value +fields of a struct v4l2_control and call the +VIDIOC_S_CTRL ioctl.

When the id is invalid drivers +return an EINVAL error code. When the value is out +of bounds drivers can choose to take the closest valid value or return +an ERANGE error code, whatever seems more appropriate. However, +VIDIOC_S_CTRL is a write-only ioctl, it does not +return the actual new value.

These ioctls work only with user controls. For other +control classes the VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS or +VIDIOC_TRY_EXT_CTRLS must be used.

Table 1. struct v4l2_control

__u32idIdentifies the control, set by the +application.
__s32valueNew value or current value.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_control id is +invalid.

ERANGE

The struct v4l2_control value +is out of bounds.

EBUSY

The control is temporarily not changeable, possibly +because another applications took over control of the device function +this control belongs to.


PrevHomeNext
ioctl VIDIOC_G_CROP, VIDIOC_S_CROPUpioctl VIDIOC_G_ENC_INDEX
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10211.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10211.htm new file mode 100644 index 0000000000000000000000000000000000000000..7b6b274c061855bc44eebd6d8c46e30b00d9a6eb --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10211.htm @@ -0,0 +1,625 @@ + +ioctl VIDIOC_G_ENC_INDEX
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_ENC_INDEX

Name

VIDIOC_G_ENC_INDEX -- Get meta data about a compressed video stream

Synopsis

int ioctl(int fd, int request, struct v4l2_enc_idx *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_ENC_INDEX

argp

Description

Experimental: This is an experimental +interface and may change in the future.

The VIDIOC_G_ENC_INDEX ioctl provides +meta data about a compressed video stream the same or another +application currently reads from the driver, which is useful for +random access into the stream without decoding it.

To read the data applications must call +VIDIOC_G_ENC_INDEX with a pointer to a +struct v4l2_enc_idx. On success the driver fills the +entry array, stores the number of elements +written in the entries field, and +initializes the entries_cap field.

Each element of the entry array +contains meta data about one picture. A +VIDIOC_G_ENC_INDEX call reads up to +V4L2_ENC_IDX_ENTRIES entries from a driver +buffer, which can hold up to entries_cap +entries. This number can be lower or higher than +V4L2_ENC_IDX_ENTRIES, but not zero. When the +application fails to read the meta data in time the oldest entries +will be lost. When the buffer is empty or no capturing/encoding is in +progress, entries will be zero.

Currently this ioctl is only defined for MPEG-2 program +streams and video elementary streams.

Table 1. struct v4l2_enc_idx

__u32entriesThe number of entries the driver stored in the +entry array.
__u32entries_capThe number of entries the driver can +buffer. Must be greater than zero.
__u32reserved[4]Reserved for future extensions. +Drivers must set the array to zero.
struct v4l2_enc_idx_entryentry[V4L2_ENC_IDX_ENTRIES]Meta data about a compressed video stream. Each +element of the array corresponds to one picture, sorted in ascending +order by their offset.

Table 2. struct v4l2_enc_idx_entry

__u64offsetThe offset in bytes from the beginning of the +compressed video stream to the beginning of this picture, that is a +PES packet header as defined in ISO 13818-1 or a picture +header as defined in ISO 13818-2. When +the encoder is stopped, the driver resets the offset to zero.
__u64ptsThe 33 bit Presentation Time +Stamp of this picture as defined in ISO 13818-1.
__u32lengthThe length of this picture in bytes.
__u32flagsFlags containing the coding type of this picture, see Table 3.
__u32reserved[2]Reserved for future extensions. +Drivers must set the array to zero.

Table 3. Index Entry Flags

V4L2_ENC_IDX_FRAME_I0x00This is an Intra-coded picture.
V4L2_ENC_IDX_FRAME_P0x01This is a Predictive-coded picture.
V4L2_ENC_IDX_FRAME_B0x02This is a Bidirectionally predictive-coded +picture.
V4L2_ENC_IDX_FRAME_MASK0x0FAND the flags field with +this mask to obtain the picture coding type.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The driver does not support this ioctl.


PrevHomeNext
ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRLUpioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, +VIDIOC_TRY_EXT_CTRLS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10386.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10386.htm new file mode 100644 index 0000000000000000000000000000000000000000..67fd64c73de61b4c1076961c3192af81c84b606a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10386.htm @@ -0,0 +1,720 @@ + +ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, +VIDIOC_TRY_EXT_CTRLS
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, +VIDIOC_TRY_EXT_CTRLS

Name

VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, VIDIOC_TRY_EXT_CTRLS -- Get or set the value of several controls, try control +values

Synopsis

int ioctl(int fd, int request, struct v4l2_ext_controls +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, +VIDIOC_TRY_EXT_CTRLS

argp

Description

These ioctls allow the caller to get or set multiple +controls atomically. Control IDs are grouped into control classes (see +Table 3) and all controls in the control array +must belong to the same control class.

Applications must always fill in the +count, +ctrl_class, +controls and +reserved fields of struct v4l2_ext_controls, and +initialize the struct v4l2_ext_control array pointed to by the +controls fields.

To get the current value of a set of controls applications +initialize the id field of each +struct v4l2_ext_control and call the +VIDIOC_G_EXT_CTRLS ioctl.

To change the value of a set of controls applications +initialize the id and +value fields of a struct v4l2_ext_control and +call the VIDIOC_S_EXT_CTRLS ioctl. The controls +will only be set if all control values are +valid.

To check if the a set of controls have correct values +applications initialize the id and +value fields of a struct v4l2_ext_control and +call the VIDIOC_TRY_EXT_CTRLS ioctl. It is up to +the driver whether wrong values are automatically adjusted to a valid +value or if an error is returned.

When the id or +ctrl_class is invalid drivers return an +EINVAL error code. When the value is out of bounds drivers can choose to take +the closest valid value or return an ERANGE error code, whatever seems more +appropriate. In the first case the new value is set in +struct v4l2_ext_control.

The driver will only set/get these controls if all control +values are correct. This prevents the situation where only some of the +controls were set/get. Only low-level errors (e. g. a failed i2c +command) can still cause this situation.

Table 1. struct v4l2_ext_control

__u32id Identifies the control, set by the +application.
__u32reserved2[2] Reserved for future extensions. Drivers and +applications must set the array to zero.
union(anonymous)  
 __s32valueNew value or current value.
 __s64value64New value or current value.
 void *reservedReserved for future pointer-type controls. Currently unused.

Table 2. struct v4l2_ext_controls

__u32ctrl_classThe control class to which all controls belong, see +Table 3.
__u32countThe number of controls in the controls array. May +also be zero.
__u32error_idxSet by the driver in case of an error. It is the +index of the control causing the error or equal to 'count' when the +error is not associated with a particular control. Undefined when the +ioctl returns 0 (success).
__u32reserved[2]Reserved for future extensions. Drivers and +applications must set the array to zero.
struct v4l2_ext_control *controlsPointer to an array of +count v4l2_ext_control structures. Ignored +if count equals zero.

Table 3. Control classes

V4L2_CTRL_CLASS_USER0x980000The class containing user controls. These controls +are described in Section 1.8. All controls that can be set +using the VIDIOC_S_CTRL and VIDIOC_G_CTRL ioctl belong to this +class.
V4L2_CTRL_CLASS_MPEG0x990000The class containing MPEG compression controls. +These controls are described in section Section 1.9.5.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_ext_control id +is invalid or the struct v4l2_ext_controls +ctrl_class is invalid. This error code is +also returned by the VIDIOC_S_EXT_CTRLS and +VIDIOC_TRY_EXT_CTRLS ioctls if two or more +control values are in conflict.

ERANGE

The struct v4l2_ext_control value +is out of bounds.

EBUSY

The control is temporarily not changeable, possibly +because another applications took over control of the device function +this control belongs to.


PrevHomeNext
ioctl VIDIOC_G_ENC_INDEXUpioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10595.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10595.htm new file mode 100644 index 0000000000000000000000000000000000000000..f552f7558811807fc8480f93d883a826cb657d87 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10595.htm @@ -0,0 +1,1154 @@ + +ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF

Name

VIDIOC_G_FBUF, VIDIOC_S_FBUF -- Get or set frame buffer overlay parameters

Synopsis

int ioctl(int fd, int request, struct v4l2_framebuffer *argp);

int ioctl(int fd, int request, const struct v4l2_framebuffer *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_FBUF, VIDIOC_S_FBUF

argp

Description

Applications can use the VIDIOC_G_FBUF and +VIDIOC_S_FBUF ioctl to get and set the +framebuffer parameters for a Video +Overlay or Video Output Overlay +(OSD). The type of overlay is implied by the device type (capture or +output device) and can be determined with the VIDIOC_QUERYCAP ioctl. +One /dev/videoN device must not support both +kinds of overlay.

The V4L2 API distinguishes destructive and non-destructive +overlays. A destructive overlay copies captured video images into the +video memory of a graphics card. A non-destructive overlay blends +video images into a VGA signal or graphics into a video signal. +Video Output Overlays are always +non-destructive.

To get the current parameters applications call the +VIDIOC_G_FBUF ioctl with a pointer to a +v4l2_framebuffer structure. The driver fills +all fields of the structure or returns an EINVAL error code when overlays are +not supported.

To set the parameters for a Video Output +Overlay, applications must initialize the +flags field of a struct +v4l2_framebuffer. Since the framebuffer is +implemented on the TV card all other parameters are determined by the +driver. When an application calls VIDIOC_S_FBUF +with a pointer to this structure, the driver prepares for the overlay +and returns the framebuffer parameters as +VIDIOC_G_FBUF does, or it returns an error +code.

To set the parameters for a non-destructive +Video Overlay, applications must initialize the +flags field, the +fmt substructure, and call +VIDIOC_S_FBUF. Again the driver prepares for the +overlay and returns the framebuffer parameters as +VIDIOC_G_FBUF does, or it returns an error +code.

For a destructive Video Overlay +applications must additionally provide a +base address. Setting up a DMA to a +random memory location can jeopardize the system security, its +stability or even damage the hardware, therefore only the superuser +can set the parameters for a destructive video overlay.

Table 1. struct v4l2_framebuffer

__u32capability Overlay capability flags set by the driver, see +Table 2.
__u32flags Overlay control flags set by application and +driver, see Table 3
void *base 

Physical base address of the framebuffer, +that is the address of the pixel in the top left corner of the +framebuffer.a

This field is irrelevant to +non-destructive Video Overlays. For +destructive Video Overlays applications must +provide a base address. The driver may accept only base addresses +which are a multiple of two, four or eight bytes. For +Video Output Overlays the driver must return +a valid base address, so applications can find the corresponding Linux +framebuffer device (see Section 4.4).

struct v4l2_pix_formatfmt Layout of the frame buffer. The +v4l2_pix_format structure is defined in Chapter 2, for clarification the fields and acceptable values + are listed below:
 __u32widthWidth of the frame buffer in pixels.
 __u32heightHeight of the frame buffer in pixels.
 __u32pixelformat

The pixel format of the +framebuffer.

For non-destructive Video +Overlays this field only defines a format for the +struct v4l2_window chromakey +field.

For destructive Video +Overlays applications must initialize this field. For +Video Output Overlays the driver must return +a valid format.

Usually this is an RGB format (for example +V4L2_PIX_FMT_RGB565) +but YUV formats (only packed YUV formats when chroma keying is used, +not including V4L2_PIX_FMT_YUYV and +V4L2_PIX_FMT_UYVY) and the +V4L2_PIX_FMT_PAL8 format are also permitted. The +behavior of the driver when an application requests a compressed +format is undefined. See Chapter 2 for information on +pixel formats.

 enum v4l2_fieldfieldDrivers and applications shall ignore this field. +If applicable, the field order is selected with the VIDIOC_S_FMT +ioctl, using the field field of +struct v4l2_window.
 __u32bytesperlineDistance in bytes between the leftmost pixels in +two adjacent lines.

This field is irrelevant to +non-destructive Video +Overlays.

For destructive Video +Overlays both applications and drivers can set this field +to request padding bytes at the end of each line. Drivers however may +ignore the requested value, returning width +times bytes-per-pixel or a larger value required by the hardware. That +implies applications can just set this field to zero to get a +reasonable default.

For Video Output +Overlays the driver must return a valid +value.

Video hardware may access padding bytes, therefore +they must reside in accessible memory. Consider for example the case +where padding bytes after the last line of an image cross a system +page boundary. Capture devices may write padding bytes, the value is +undefined. Output devices ignore the contents of padding +bytes.

When the image format is planar the +bytesperline value applies to the largest +plane and is divided by the same factor as the +width field for any smaller planes. For +example the Cb and Cr planes of a YUV 4:2:0 image have half as many +padding bytes following each line as the Y plane. To avoid ambiguities +drivers must return a bytesperline value +rounded up to a multiple of the scale factor.

 __u32sizeimage

This field is irrelevant to +non-destructive Video Overlays. For +destructive Video Overlays applications must +initialize this field. For Video Output +Overlays the driver must return a valid +format.

Together with base it +defines the framebuffer memory accessible by the +driver.

 enum v4l2_colorspacecolorspaceThis information supplements the +pixelformat and must be set by the driver, +see Section 2.2.
 __u32privReserved for additional information about custom +(driver defined) formats. When not used drivers and applications must +set this field to zero.
Notes:
a. A physical base address may not suit all +platforms. GK notes in theory we should pass something like PCI device ++ memory region + offset instead. If you encounter problems please +discuss on the Video4Linux mailing list: +https://listman.redhat.com/mailman/listinfo/video4linux-list.

Table 2. Frame Buffer Capability Flags

V4L2_FBUF_CAP_EXTERNOVERLAY0x0001The device is capable of non-destructive overlays. +When the driver clears this flag, only destructive overlays are +supported. There are no drivers yet which support both destructive and +non-destructive overlays.
V4L2_FBUF_CAP_CHROMAKEY0x0002The device supports clipping by chroma-keying the +images. That is, image pixels replace pixels in the VGA or video +signal only where the latter assume a certain color. Chroma-keying +makes no sense for destructive overlays.
V4L2_FBUF_CAP_LIST_CLIPPING0x0004The device supports clipping using a list of clip +rectangles.
V4L2_FBUF_CAP_BITMAP_CLIPPING0x0008The device supports clipping using a bit mask.
V4L2_FBUF_CAP_LOCAL_ALPHA0x0010The device supports clipping/blending using the +alpha channel of the framebuffer or VGA signal. Alpha blending makes +no sense for destructive overlays.
V4L2_FBUF_CAP_GLOBAL_ALPHA0x0020The device supports alpha blending using a global +alpha value. Alpha blending makes no sense for destructive overlays.
V4L2_FBUF_CAP_LOCAL_INV_ALPHA0x0040The device supports clipping/blending using the +inverted alpha channel of the framebuffer or VGA signal. Alpha +blending makes no sense for destructive overlays.

Table 3. Frame Buffer Flags

V4L2_FBUF_FLAG_PRIMARY0x0001The framebuffer is the primary graphics surface. +In other words, the overlay is destructive. [?]
V4L2_FBUF_FLAG_OVERLAY0x0002The frame buffer is an overlay surface the same +size as the capture. [?]
The purpose of +V4L2_FBUF_FLAG_PRIMARY and +V4L2_FBUF_FLAG_OVERLAY was never quite clear. +Most drivers seem to ignore these flags. For compatibility with the +bttv driver applications should set the +V4L2_FBUF_FLAG_OVERLAY flag.
V4L2_FBUF_FLAG_CHROMAKEY0x0004Use chroma-keying. The chroma-key color is +determined by the chromakey field of +struct v4l2_window and negotiated with the VIDIOC_S_FMT ioctl, see Section 4.2 +and + Section 4.4.
There are no flags to enable +clipping using a list of clip rectangles or a bitmap. These methods +are negotiated with the VIDIOC_S_FMT ioctl, see Section 4.2 and Section 4.4.
V4L2_FBUF_FLAG_LOCAL_ALPHA0x0008Use the alpha channel of the framebuffer to clip or +blend framebuffer pixels with video images. The blend +function is: output = framebuffer pixel * alpha + video pixel * (1 - +alpha). The actual alpha depth depends on the framebuffer pixel +format.
V4L2_FBUF_FLAG_GLOBAL_ALPHA0x0010Use a global alpha value to blend the framebuffer +with video images. The blend function is: output = (framebuffer pixel +* alpha + video pixel * (255 - alpha)) / 255. The alpha value is +determined by the global_alpha field of +struct v4l2_window and negotiated with the VIDIOC_S_FMT ioctl, see Section 4.2 +and Section 4.4.
V4L2_FBUF_FLAG_LOCAL_INV_ALPHA0x0020Like +V4L2_FBUF_FLAG_LOCAL_ALPHA, use the alpha channel +of the framebuffer to clip or blend framebuffer pixels with video +images, but with an inverted alpha value. The blend function is: +output = framebuffer pixel * (1 - alpha) + video pixel * alpha. The +actual alpha depth depends on the framebuffer pixel format.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EPERM

VIDIOC_S_FBUF can only be called +by a privileged user to negotiate the parameters for a destructive +overlay.

EBUSY

The framebuffer parameters cannot be changed at this +time because overlay is already enabled, or capturing is enabled +and the hardware cannot capture and overlay simultaneously.

EINVAL

The ioctl is not supported or the +VIDIOC_S_FBUF parameters are unsuitable.


PrevHomeNext
ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, +VIDIOC_TRY_EXT_CTRLSUpioctl VIDIOC_G_FMT, VIDIOC_S_FMT, +VIDIOC_TRY_FMT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10944.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10944.htm new file mode 100644 index 0000000000000000000000000000000000000000..6bb94e7fb06fdc7c9570377a4a7d2c29e62f9d34 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r10944.htm @@ -0,0 +1,575 @@ + +ioctl VIDIOC_G_FMT, VIDIOC_S_FMT, +VIDIOC_TRY_FMT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_FMT, VIDIOC_S_FMT, +VIDIOC_TRY_FMT

Name

VIDIOC_G_FMT, VIDIOC_S_FMT, VIDIOC_TRY_FMT -- Get or set the data format, try a format

Synopsis

int ioctl(int fd, int request, struct v4l2_format +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_FMT, VIDIOC_S_FMT, VIDIOC_TRY_FMT

argp

Description

These ioctls are used to negotiate the format of data +(typically image format) exchanged between driver and +application.

To query the current parameters applications set the +type field of a struct +v4l2_format to the respective buffer (stream) +type. For example video capture devices use +V4L2_BUF_TYPE_VIDEO_CAPTURE. When the application +calls the VIDIOC_G_FMT ioctl with a pointer to +this structure the driver fills the respective member of the +fmt union. In case of video capture devices +that is the struct v4l2_pix_format pix member. +When the requested buffer type is not supported drivers return an +EINVAL error code.

To change the current format parameters applications +initialize the type field and all +fields of the respective fmt +union member. For details see the documentation of the various devices +types in Chapter 4. Good practice is to query the +current parameters first, and to +modify only those parameters not suitable for the application. When +the application calls the VIDIOC_S_FMT ioctl +with a pointer to a v4l2_format structure +the driver checks +and adjusts the parameters against hardware abilities. Drivers +should not return an error code unless the input is ambiguous, this is +a mechanism to fathom device capabilities and to approach parameters +acceptable for both the application and driver. On success the driver +may program the hardware, allocate resources and generally prepare for +data exchange. +Finally the VIDIOC_S_FMT ioctl returns the +current format parameters as VIDIOC_G_FMT does. +Very simple, inflexible devices may even ignore all input and always +return the default parameters. However all V4L2 devices exchanging +data with the application must implement the +VIDIOC_G_FMT and +VIDIOC_S_FMT ioctl. When the requested buffer +type is not supported drivers return an EINVAL error code on a +VIDIOC_S_FMT attempt. When I/O is already in +progress or the resource is not available for other reasons drivers +return the EBUSY error code.

The VIDIOC_TRY_FMT ioctl is equivalent +to VIDIOC_S_FMT with one exception: it does not +change driver state. It can also be called at any time, never +returning EBUSY. This function is provided to +negotiate parameters, to learn about hardware limitations, without +disabling I/O or possibly time consuming hardware preparations. +Although strongly recommended drivers are not required to implement +this ioctl.

Table 1. struct v4l2_format

enum v4l2_buf_typetype Type of the data stream, see Table 3-2.
unionfmt  
 struct v4l2_pix_formatpixDefinition of an image format, see Chapter 2, used by video capture and output +devices.
 struct v4l2_windowwinDefinition of an overlaid image, see Section 4.2, used by video overlay devices.
 struct v4l2_vbi_formatvbiRaw VBI capture or output parameters. This is +discussed in more detail in Section 4.7. Used by raw VBI +capture and output devices.
 struct v4l2_sliced_vbi_formatslicedSliced VBI capture or output parameters. See +Section 4.8 for details. Used by sliced VBI +capture and output devices.
 __u8raw_data[200]Place holder for future extensions and custom +(driver defined) formats with type +V4L2_BUF_TYPE_PRIVATE and higher.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EBUSY

The data format cannot be changed at this +time, for example because I/O is already in progress.

EINVAL

The struct v4l2_format type +field is invalid, the requested buffer type not supported, or +VIDIOC_TRY_FMT was called and is not +supported with this buffer type.


PrevHomeNext
ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUFUpioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11094.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11094.htm new file mode 100644 index 0000000000000000000000000000000000000000..ef403ea1093dee72d19003a48dc18c7779161b50 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11094.htm @@ -0,0 +1,477 @@ + +ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY

Name

VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY -- Get or set tuner or modulator radio +frequency

Synopsis

int ioctl(int fd, int request, struct v4l2_frequency +*argp);

int ioctl(int fd, int request, const struct v4l2_frequency +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY

argp

Description

To get the current tuner or modulator radio frequency +applications set the tuner field of a +struct v4l2_frequency to the respective tuner or modulator number (only +input devices have tuners, only output devices have modulators), zero +out the reserved array and +call the VIDIOC_G_FREQUENCY ioctl with a pointer +to this structure. The driver stores the current frequency in the +frequency field.

To change the current tuner or modulator radio frequency +applications initialize the tuner, +type and +frequency fields, and the +reserved array of a struct v4l2_frequency and +call the VIDIOC_S_FREQUENCY ioctl with a pointer +to this structure. When the requested frequency is not possible the +driver assumes the closest possible value. However +VIDIOC_S_FREQUENCY is a write-only ioctl, it does +not return the actual new frequency.

Table 1. struct v4l2_frequency

__u32tunerThe tuner or modulator index number. This is the +same value as in the struct v4l2_input tuner +field and the struct v4l2_tuner index field, or +the struct v4l2_output modulator field and the +struct v4l2_modulator index field.
enum v4l2_tuner_typetypeThe tuner type. This is the same value as in the +struct v4l2_tuner type field. The field is not +applicable to modulators, i. e. ignored by drivers.
__u32frequencyTuning frequency in units of 62.5 kHz, or if the +struct v4l2_tuner or struct v4l2_modulator capabilities flag +V4L2_TUNER_CAP_LOW is set, in units of 62.5 +Hz.
__u32reserved[8];Reserved for future extensions. Drivers and + applications must set the array to zero.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The tuner index is out of +bounds or the value in the type field is +wrong.


PrevHomeNext
ioctl VIDIOC_G_FMT, VIDIOC_S_FMT, +VIDIOC_TRY_FMTUpioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11217.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11217.htm new file mode 100644 index 0000000000000000000000000000000000000000..0143a1e3e5561d268c2a228b9dad3a062bff7d38 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11217.htm @@ -0,0 +1,315 @@ + +ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT

Name

VIDIOC_G_INPUT, VIDIOC_S_INPUT -- Query or select the current video input

Synopsis

int ioctl(int fd, int request, int *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_INPUT, VIDIOC_S_INPUT

argp

Description

To query the current video input applications call the +VIDIOC_G_INPUT ioctl with a pointer to an integer +where the driver stores the number of the input, as in the +struct v4l2_input index field. This ioctl will +fail only when there are no video inputs, returning +EINVAL.

To select a video input applications store the number of the +desired input in an integer and call the +VIDIOC_S_INPUT ioctl with a pointer to this +integer. Side effects are possible. For example inputs may support +different video standards, so the driver may implicitly switch the +current standard. It is good practice to select an input before +querying or negotiating any other parameters.

Information about video inputs is available using the +VIDIOC_ENUMINPUT ioctl.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The number of the video input is out of bounds, or +there are no video inputs at all and this ioctl is not +supported.

EBUSY

I/O is in progress, the input cannot be +switched.


PrevHomeNext
ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCYUpioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11285.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11285.htm new file mode 100644 index 0000000000000000000000000000000000000000..6e5c1167c310ae16e21efacc1e2e1e7f7a5f1107 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11285.htm @@ -0,0 +1,485 @@ + +ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP

Name

VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP -- 

Synopsis

int ioctl(int fd, int request, v4l2_jpegcompression *argp);

int ioctl(int fd, int request, const v4l2_jpegcompression *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP

argp

Description

[to do]

Ronald Bultje elaborates:

APP is some application-specific information. The +application can set it itself, and it'll be stored in the JPEG-encoded +fields (eg; interlacing information for in an AVI or so). COM is the +same, but it's comments, like 'encoded by me' or so.

jpeg_markers describes whether the huffman tables, +quantization tables and the restart interval information (all +JPEG-specific stuff) should be stored in the JPEG-encoded fields. +These define how the JPEG field is encoded. If you omit them, +applications assume you've used standard encoding. You usually do want +to add them.

Table 1. struct v4l2_jpegcompression

intquality 
intAPPn 
intAPP_len 
charAPP_data[60] 
intCOM_len 
charCOM_data[60] 
__u32jpeg_markersSee Table 2.

Table 2. JPEG Markers Flags

V4L2_JPEG_MARKER_DHT(1<<3)Define Huffman Tables
V4L2_JPEG_MARKER_DQT(1<<4)Define Quantization Tables
V4L2_JPEG_MARKER_DRI(1<<5)Define Restart Interval
V4L2_JPEG_MARKER_COM(1<<6)Comment segment
V4L2_JPEG_MARKER_APP(1<<7)App segment, driver will always use APP0

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

This ioctl is not supported.


PrevHomeNext
ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUTUpioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11430.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11430.htm new file mode 100644 index 0000000000000000000000000000000000000000..34a5d9875cd0d7df72612e68a6430c5af8f8f539 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11430.htm @@ -0,0 +1,665 @@ + +ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR

Name

VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR -- Get or set modulator attributes

Synopsis

int ioctl(int fd, int request, struct v4l2_modulator +*argp);

int ioctl(int fd, int request, const struct v4l2_modulator +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR

argp

Description

To query the attributes of a modulator applications initialize +the index field and zero out the +reserved array of a struct v4l2_modulator and +call the VIDIOC_G_MODULATOR ioctl with a pointer +to this structure. Drivers fill the rest of the structure or return an +EINVAL error code when the index is out of bounds. To enumerate all modulators +applications shall begin at index zero, incrementing by one until the +driver returns EINVAL.

Modulators have two writable properties, an audio +modulation set and the radio frequency. To change the modulated audio +subprograms, applications initialize the index and txsubchans fields and the +reserved array and call the +VIDIOC_S_MODULATOR ioctl. Drivers may choose a +different audio modulation if the request cannot be satisfied. However +this is a write-only ioctl, it does not return the actual audio +modulation selected.

To change the radio frequency the VIDIOC_S_FREQUENCY ioctl +is available.

Table 1. struct v4l2_modulator

__u32indexIdentifies the modulator, set by the +application.
__u8name[32]Name of the modulator, a NUL-terminated ASCII +string. This information is intended for the user.
__u32capabilityModulator capability flags. No flags are defined +for this field, the tuner flags in struct v4l2_tuner +are used accordingly. The audio flags indicate the ability +to encode audio subprograms. They will not +change for example with the current video standard.
__u32rangelowThe lowest tunable frequency in units of 62.5 +KHz, or if the capability flag +V4L2_TUNER_CAP_LOW is set, in units of 62.5 +Hz.
__u32rangehighThe highest tunable frequency in units of 62.5 +KHz, or if the capability flag +V4L2_TUNER_CAP_LOW is set, in units of 62.5 +Hz.
__u32txsubchansWith this field applications can determine how +audio sub-carriers shall be modulated. It contains a set of flags as +defined in Table 2. Note the tuner +rxsubchans flags are reused, but the +semantics are different. Video output devices are assumed to have an +analog or PCM audio input with 1-3 channels. The +txsubchans flags select one or more +channels for modulation, together with some audio subprogram +indicator, for example a stereo pilot tone.
__u32reserved[4]Reserved for future extensions. Drivers and +applications must set the array to zero.

Table 2. Modulator Audio Transmission Flags

V4L2_TUNER_SUB_MONO0x0001Modulate channel 1 as mono audio, when the input +has more channels, a down-mix of channel 1 and 2. This flag does not +combine with V4L2_TUNER_SUB_STEREO or +V4L2_TUNER_SUB_LANG1.
V4L2_TUNER_SUB_STEREO0x0002Modulate channel 1 and 2 as left and right +channel of a stereo audio signal. When the input has only one channel +or two channels and V4L2_TUNER_SUB_SAP is also +set, channel 1 is encoded as left and right channel. This flag does +not combine with V4L2_TUNER_SUB_MONO or +V4L2_TUNER_SUB_LANG1. When the driver does not +support stereo audio it shall fall back to mono.
V4L2_TUNER_SUB_LANG10x0008Modulate channel 1 and 2 as primary and secondary +language of a bilingual audio signal. When the input has only one +channel it is used for both languages. It is not possible to encode +the primary or secondary language only. This flag does not combine +with V4L2_TUNER_SUB_MONO or +V4L2_TUNER_SUB_STEREO. If the hardware does not +support the respective audio matrix, or the current video standard +does not permit bilingual audio the +VIDIOC_S_MODULATOR ioctl shall return an EINVAL error code +and the driver shall fall back to mono or stereo mode.
V4L2_TUNER_SUB_LANG20x0004Same effect as +V4L2_TUNER_SUB_LANG1.
V4L2_TUNER_SUB_SAP0x0004When combined with V4L2_TUNER_SUB_MONO the first channel is encoded as mono audio, the last +channel as Second Audio Program. When the input has only one channel +it is used for both audio tracks. When the input has three channels +the mono track is a down-mix of channel 1 and 2. When combined with +V4L2_TUNER_SUB_STEREO channel 1 and 2 are +encoded as left and right stereo audio, channel 3 as Second Audio +Program. When the input has only two channels, the first is encoded as +left and right channel and the second as SAP. When the input has only +one channel it is used for all audio tracks. It is not possible to +encode a Second Audio Program only. This flag must combine with +V4L2_TUNER_SUB_MONO or +V4L2_TUNER_SUB_STEREO. If the hardware does not +support the respective audio matrix, or the current video standard +does not permit SAP the VIDIOC_S_MODULATOR ioctl +shall return an EINVAL error code and driver shall fall back to mono or stereo +mode.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_modulator +index is out of bounds.


PrevHomeNext
ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMPUpioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11612.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11612.htm new file mode 100644 index 0000000000000000000000000000000000000000..0573541b4cdf995e6f88abeb678c68192d15417c --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11612.htm @@ -0,0 +1,315 @@ + +ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT

Name

VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT -- Query or select the current video output

Synopsis

int ioctl(int fd, int request, int *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT

argp

Description

To query the current video output applications call the +VIDIOC_G_OUTPUT ioctl with a pointer to an integer +where the driver stores the number of the output, as in the +struct v4l2_output index field. This ioctl +will fail only when there are no video outputs, returning the +EINVAL error code.

To select a video output applications store the number of the +desired output in an integer and call the +VIDIOC_S_OUTPUT ioctl with a pointer to this integer. +Side effects are possible. For example outputs may support different +video standards, so the driver may implicitly switch the current +standard. It is good practice to select an output before querying or +negotiating any other parameters.

Information about video outputs is available using the +VIDIOC_ENUMOUTPUT ioctl.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The number of the video output is out of bounds, or +there are no video outputs at all and this ioctl is not +supported.

EBUSY

I/O is in progress, the output cannot be +switched.


PrevHomeNext
ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATORUpioctl VIDIOC_G_PARM, VIDIOC_S_PARM
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11680.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11680.htm new file mode 100644 index 0000000000000000000000000000000000000000..ac985ca8c8e9be1c9d3fa789a4adcecc84dd584d --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11680.htm @@ -0,0 +1,881 @@ + +ioctl VIDIOC_G_PARM, VIDIOC_S_PARM
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_PARM, VIDIOC_S_PARM

Name

VIDIOC_G_PARM, VIDIOC_S_PARM -- Get or set streaming parameters

Synopsis

int ioctl(int fd, int request, v4l2_streamparm *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_PARM, VIDIOC_S_PARM

argp

Description

The current video standard determines a nominal number of +frames per second. If less than this number of frames is to be +captured or output, applications can request frame skipping or +duplicating on the driver side. This is especially useful when using +the read() or write(), which +are not augmented by timestamps or sequence counters, and to avoid +unneccessary data copying.

Further these ioctls can be used to determine the number of +buffers used internally by a driver in read/write mode. For +implications see the section discussing the read() +function.

To get and set the streaming parameters applications call +the VIDIOC_G_PARM and +VIDIOC_S_PARM ioctl, respectively. They take a +pointer to a struct v4l2_streamparm which +contains a union holding separate parameters for input and output +devices.

Table 1. struct v4l2_streamparm

enum v4l2_buf_typetype The buffer (stream) type, same as struct v4l2_format +type, set by the application.
unionparm  
 struct v4l2_captureparmcaptureParameters for capture devices, used when +type is +V4L2_BUF_TYPE_VIDEO_CAPTURE.
 struct v4l2_outputparmoutputParameters for output devices, used when +type is +V4L2_BUF_TYPE_VIDEO_OUTPUT.
 __u8raw_data[200]A place holder for future extensions and custom +(driver defined) buffer types V4L2_BUF_TYPE_PRIVATE and +higher.

Table 2. struct v4l2_captureparm

__u32capabilitySee Table 4.
__u32capturemodeSet by drivers and applications, see Table 5.
struct v4l2_fracttimeperframe

This is is the desired period between +successive frames captured by the driver, in seconds. The +field is intended to skip frames on the driver side, saving I/O +bandwidth.

Applications store here the desired frame +period, drivers return the actual frame period, which must be greater +or equal to the nominal frame period determined by the current video +standard (struct v4l2_standard frameperiod +field). Changing the video standard (also implicitly by switching the +video input) may reset this parameter to the nominal frame period. To +reset manually applications can just set this field to +zero.

Drivers support this function only when they set the +V4L2_CAP_TIMEPERFRAME flag in the +capability field.

__u32extendedmodeCustom (driver specific) streaming parameters. When +unused, applications and drivers must set this field to zero. +Applications using this field should check the driver name and +version, see Section 1.2.
__u32readbuffersApplications set this field to the desired number +of buffers used internally by the driver in read() mode. Drivers +return the actual number of buffers. When an application requests zero +buffers, drivers should just return the current setting rather than +the minimum or an error code. For details see Section 3.1.
__u32reserved[4]Reserved for future extensions. Drivers and +applications must set the array to zero.

Table 3. struct v4l2_outputparm

__u32capabilitySee Table 4.
__u32outputmodeSet by drivers and applications, see Table 5.
struct v4l2_fracttimeperframeThis is is the desired period between +successive frames output by the driver, in seconds.

The field is intended to +repeat frames on the driver side in write() mode (in streaming +mode timestamps can be used to throttle the output), saving I/O +bandwidth.

Applications store here the desired frame +period, drivers return the actual frame period, which must be greater +or equal to the nominal frame period determined by the current video +standard (struct v4l2_standard frameperiod +field). Changing the video standard (also implicitly by switching the +video output) may reset this parameter to the nominal frame period. To +reset manually applications can just set this field to +zero.

Drivers support this function only when they set the +V4L2_CAP_TIMEPERFRAME flag in the +capability field.

__u32extendedmodeCustom (driver specific) streaming parameters. When +unused, applications and drivers must set this field to zero. +Applications using this field should check the driver name and +version, see Section 1.2.
__u32writebuffersApplications set this field to the desired number +of buffers used internally by the driver in +write() mode. Drivers return the actual number of +buffers. When an application requests zero buffers, drivers should +just return the current setting rather than the minimum or an error +code. For details see Section 3.1.
__u32reserved[4]Reserved for future extensions. Drivers and +applications must set the array to zero.

Table 4. Streaming Parameters Capabilites

V4L2_CAP_TIMEPERFRAME0x1000The frame skipping/repeating controlled by the +timeperframe field is supported.

Table 5. Capture Parameters Flags

V4L2_MODE_HIGHQUALITY0x0001

High quality imaging mode. High quality mode +is intended for still imaging applications. The idea is to get the +best possible image quality that the hardware can deliver. It is not +defined how the driver writer may achieve that; it will depend on the +hardware and the ingenuity of the driver writer. High quality mode is +a different mode from the the regular motion video capture modes. In +high quality mode:

  • The driver may be able to capture higher +resolutions than for motion capture.

  • The driver may support fewer pixel formats +than motion capture (eg; true color).

  • The driver may capture and arithmetically +combine multiple successive fields or frames to remove color edge +artifacts and reduce the noise in the video data.

  • The driver may capture images in slices like +a scanner in order to handle larger format images than would otherwise +be possible.

  • An image capture operation may be +significantly slower than motion capture.

  • Moving objects in the image might have +excessive motion blur.

  • Capture might only work through the +read() call.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

This ioctl is not supported.


PrevHomeNext
ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUTUpioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11946.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11946.htm new file mode 100644 index 0000000000000000000000000000000000000000..f6f53aa86cdb68b7e27aad12843777e6cfa43881 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r11946.htm @@ -0,0 +1,399 @@ + +ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY

Name

VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY -- Query or request the access priority associated with a +file descriptor

Synopsis

int ioctl(int fd, int request, enum v4l2_priority *argp);

int ioctl(int fd, int request, const enum v4l2_priority *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY

argp

Pointer to an enum v4l2_priority type.

Description

To query the current access priority +applications call the VIDIOC_G_PRIORITY ioctl +with a pointer to an enum v4l2_priority variable where the driver stores +the current priority.

To request an access priority applications store the +desired priority in an enum v4l2_priority variable and call +VIDIOC_S_PRIORITY ioctl with a pointer to this +variable.

Table 1. enum v4l2_priority

V4L2_PRIORITY_UNSET0 
V4L2_PRIORITY_BACKGROUND1Lowest priority, usually applications running in +background, for example monitoring VBI transmissions. A proxy +application running in user space will be necessary if multiple +applications want to read from a device at this priority.
V4L2_PRIORITY_INTERACTIVE2 
V4L2_PRIORITY_DEFAULT2Medium priority, usually applications started and +interactively controlled by the user. For example TV viewers, Teletext +browsers, or just "panel" applications to change the channel or video +controls. This is the default priority unless an application requests +another.
V4L2_PRIORITY_RECORD3Highest priority. Only one file descriptor can have +this priority, it blocks any other fd from changing device properties. +Usually applications which must not be interrupted, like video +recording.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The requested priority value is invalid, or the +driver does not support access priorities.

EBUSY

Another application already requested higher +priority.


PrevHomeNext
ioctl VIDIOC_G_PARM, VIDIOC_S_PARMUpioctl VIDIOC_G_SLICED_VBI_CAP
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12051.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12051.htm new file mode 100644 index 0000000000000000000000000000000000000000..58bfd6a4ef3dd3099686dc443842e071680025df --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12051.htm @@ -0,0 +1,735 @@ + +ioctl VIDIOC_G_SLICED_VBI_CAP
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_SLICED_VBI_CAP

Name

VIDIOC_G_SLICED_VBI_CAP -- Query sliced VBI capabilities

Synopsis

int ioctl(int fd, int request, struct v4l2_sliced_vbi_cap *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_SLICED_VBI_CAP

argp

Description

To find out which data services are supported by a sliced +VBI capture or output device, applications initialize the +type field of a struct v4l2_sliced_vbi_cap, +clear the reserved array and +call the VIDIOC_G_SLICED_VBI_CAP ioctl. The +driver fills in the remaining fields or returns an EINVAL error code if the +sliced VBI API is unsupported or type +is invalid.

Note the type field was added, +and the ioctl changed from read-only to write-read, in Linux 2.6.19.

Table 1. struct v4l2_sliced_vbi_cap

__u16service_setA set of all data services +supported by the driver. Equal to the union of all elements of the +service_lines array.
__u16service_lines[2][24]Each element of this array +contains a set of data services the hardware can look for or insert +into a particular scan line. Data services are defined in Table 2. Array indices map to ITU-R +line numbers (see also Figure 4-2 and Figure 4-3) as follows:
  Element525 line systems625 line systems
  service_lines[0][1]11
  service_lines[0][23]2323
  service_lines[1][1]264314
  service_lines[1][23]286336
     
  The number of VBI lines the +hardware can capture or output per frame, or the number of services it +can identify on a given line may be limited. For example on PAL line +16 the hardware may be able to look for a VPS or Teletext signal, but +not both at the same time. Applications can learn about these limits +using the VIDIOC_S_FMT ioctl as described in Section 4.8.
     
  Drivers must set +service_lines[0][0] and +service_lines[1][0] to zero.
enum v4l2_buf_typetypeType of the data stream, see Table 3-2. Should be +V4L2_BUF_TYPE_SLICED_VBI_CAPTURE or +V4L2_BUF_TYPE_SLICED_VBI_OUTPUT.  
__u32reserved[3]This array is reserved for future +extensions. Applications and drivers must set it to zero.

Table 2. Sliced VBI services

SymbolValueReferenceLines, usuallyPayload
V4L2_SLICED_TELETEXT_B (Teletext +System B)0x0001ETS 300 706, ITU BT.653PAL/SECAM line 7-22, 320-335 (second field 7-22)Last 42 of the 45 byte Teletext packet, that is +without clock run-in and framing code, lsb first transmitted.
V4L2_SLICED_VPS0x0400ETS 300 231PAL line 16Byte number 3 to 15 according to Figure 9 of +ETS 300 231, lsb first transmitted.
V4L2_SLICED_CAPTION_5250x1000EIA 608-BNTSC line 21, 284 (second field 21)Two bytes in transmission order, including parity +bit, lsb first transmitted.
V4L2_SLICED_WSS_6250x4000EN 300 294, ITU BT.1119PAL/SECAM line 23
Byte        0                 1
+     msb         lsb  msb           lsb
+Bit  7 6 5 4 3 2 1 0  x x 13 12 11 10 9
V4L2_SLICED_VBI_5250x1000Set of services applicable to 525 +line systems.
V4L2_SLICED_VBI_6250x4401Set of services applicable to 625 +line systems.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The device does not support sliced VBI capturing or +output, or the value in the type field is +wrong.


PrevHomeNext
ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITYUpioctl VIDIOC_G_STD, VIDIOC_S_STD
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12265.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12265.htm new file mode 100644 index 0000000000000000000000000000000000000000..fb345a8aad3f6edf383f10c1bb324f4b812e649c --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12265.htm @@ -0,0 +1,335 @@ + +ioctl VIDIOC_G_STD, VIDIOC_S_STD
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_STD, VIDIOC_S_STD

Name

VIDIOC_G_STD, VIDIOC_S_STD -- Query or select the video standard of the current input

Synopsis

int ioctl(int fd, int request, v4l2_std_id +*argp);

int ioctl(int fd, int request, const v4l2_std_id +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_STD, VIDIOC_S_STD

argp

Description

To query and select the current video standard applications +use the VIDIOC_G_STD and VIDIOC_S_STD ioctls which take a pointer to a +v4l2_std_id type as argument. VIDIOC_G_STD can +return a single flag or a set of flags as in struct v4l2_standard field +id. The flags must be unambiguous such +that they appear in only one enumerated v4l2_standard structure.

VIDIOC_S_STD accepts one or more +flags, being a write-only ioctl it does not return the actual new standard as +VIDIOC_G_STD does. When no flags are given or +the current input does not support the requested standard the driver +returns an EINVAL error code. When the standard set is ambiguous drivers may +return EINVAL or choose any of the requested +standards.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

This ioctl is not supported, or the +VIDIOC_S_STD parameter was unsuitable.


PrevHomeNext
ioctl VIDIOC_G_SLICED_VBI_CAPUpioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12342.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12342.htm new file mode 100644 index 0000000000000000000000000000000000000000..97c19211995e7d576a173ff125e6a3ddcc465a51 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12342.htm @@ -0,0 +1,1368 @@ + +ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER

Name

VIDIOC_G_TUNER, VIDIOC_S_TUNER -- Get or set tuner attributes

Synopsis

int ioctl(int fd, int request, struct v4l2_tuner +*argp);

int ioctl(int fd, int request, const struct v4l2_tuner +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_TUNER, VIDIOC_S_TUNER

argp

Description

To query the attributes of a tuner applications initialize the +index field and zero out the +reserved array of a struct v4l2_tuner and call the +VIDIOC_G_TUNER ioctl with a pointer to this +structure. Drivers fill the rest of the structure or return an +EINVAL error code when the index is out of bounds. To enumerate all tuners +applications shall begin at index zero, incrementing by one until the +driver returns EINVAL.

Tuners have two writable properties, the audio mode and +the radio frequency. To change the audio mode, applications initialize +the index, +audmode and +reserved fields and call the +VIDIOC_S_TUNER ioctl. This will +not change the current tuner, which is determined +by the current video input. Drivers may choose a different audio mode +if the requested mode is invalid or unsupported. Since this is a +write-only ioctl, it does not return the actually +selected audio mode.

To change the radio frequency the VIDIOC_S_FREQUENCY ioctl +is available.

Table 1. struct v4l2_tuner

__u32indexIdentifies the tuner, set by the +application.
__u8name[32]

Name of the tuner, a +NUL-terminated ASCII string. This information is intended for the +user.

enum v4l2_tuner_typetypeType of the tuner, see Table 2.
__u32capability

Tuner capability flags, see +Table 3. Audio flags indicate the ability +to decode audio subprograms. They will not +change, for example with the current video standard.

When +the structure refers to a radio tuner only the +V4L2_TUNER_CAP_LOW and +V4L2_TUNER_CAP_STEREO flags can be +set.

__u32rangelowThe lowest tunable frequency in +units of 62.5 kHz, or if the capability +flag V4L2_TUNER_CAP_LOW is set, in units of 62.5 +Hz.
__u32rangehighThe highest tunable frequency in +units of 62.5 kHz, or if the capability +flag V4L2_TUNER_CAP_LOW is set, in units of 62.5 +Hz.
__u32rxsubchans

Some tuners or audio +decoders can determine the received audio subprograms by analyzing +audio carriers, pilot tones or other indicators. To pass this +information drivers set flags defined in Table 4 in this field. For +example:

  V4L2_TUNER_SUB_MONOreceiving mono audio
  STEREO | SAPreceiving stereo audio and a secondary audio +program
  MONO | STEREOreceiving mono or stereo audio, the hardware cannot +distinguish
  LANG1 | LANG2receiving bilingual audio
  MONO | STEREO | LANG1 | LANG2receiving mono, stereo or bilingual +audio
  

When the +V4L2_TUNER_CAP_STEREO, +_LANG1, _LANG2 or +_SAP flag is cleared in the +capability field, the corresponding +V4L2_TUNER_SUB_ flag must not be set +here.

This field is valid only if this is the tuner of the +current video input, or when the structure refers to a radio +tuner.

__u32audmode

The selected audio mode, see +Table 5 for valid values. The audio mode does +not affect audio subprogram detection, and like a control it does not automatically change +unless the requested mode is invalid or unsupported. See Table 6 for possible results when +the selected and received audio programs do not +match.

Currently this is the only field of struct +v4l2_tuner applications can +change.

__u32signalThe signal strength if known, ranging +from 0 to 65535. Higher values indicate a better signal.
__s32afcAutomatic frequency control: When the +afc value is negative, the frequency is too +low, when positive too high.
__u32reserved[4]Reserved for future extensions. Drivers and +applications must set the array to zero.

Table 2. enum v4l2_tuner_type

V4L2_TUNER_RADIO1 
V4L2_TUNER_ANALOG_TV2 

Table 3. Tuner and Modulator Capability Flags

V4L2_TUNER_CAP_LOW0x0001When set, tuning frequencies are expressed in units of +62.5 Hz, otherwise in units of 62.5 kHz.
V4L2_TUNER_CAP_NORM0x0002This is a multi-standard tuner; the video standard +can or must be switched. (B/G PAL tuners for example are typically not + considered multi-standard because the video standard is automatically + determined from the frequency band.) The set of supported video + standards is available from the struct v4l2_input pointing to this tuner, + see the description of ioctl VIDIOC_ENUMINPUT for details. Only + V4L2_TUNER_ANALOG_TV tuners can have this capability.
V4L2_TUNER_CAP_STEREO0x0010Stereo audio reception is supported.
V4L2_TUNER_CAP_LANG10x0040Reception of the primary language of a bilingual +audio program is supported. Bilingual audio is a feature of +two-channel systems, transmitting the primary language monaural on the +main audio carrier and a secondary language monaural on a second +carrier. Only + V4L2_TUNER_ANALOG_TV tuners can have this capability.
V4L2_TUNER_CAP_LANG20x0020Reception of the secondary language of a bilingual +audio program is supported. Only + V4L2_TUNER_ANALOG_TV tuners can have this capability.
V4L2_TUNER_CAP_SAP0x0020

Reception of a secondary audio program is +supported. This is a feature of the BTSC system which accompanies the +NTSC video standard. Two audio carriers are available for mono or +stereo transmissions of a primary language, and an independent third +carrier for a monaural secondary language. Only + V4L2_TUNER_ANALOG_TV tuners can have this capability.

Note the +V4L2_TUNER_CAP_LANG2 and +V4L2_TUNER_CAP_SAP flags are synonyms. +V4L2_TUNER_CAP_SAP applies when the tuner +supports the V4L2_STD_NTSC_M video +standard.

Table 4. Tuner Audio Reception Flags

V4L2_TUNER_SUB_MONO0x0001The tuner receives a mono audio signal.
V4L2_TUNER_SUB_STEREO0x0002The tuner receives a stereo audio signal.
V4L2_TUNER_SUB_LANG10x0008The tuner receives the primary language of a +bilingual audio signal. Drivers must clear this flag when the current +video standard is V4L2_STD_NTSC_M.
V4L2_TUNER_SUB_LANG20x0004The tuner receives the secondary language of a +bilingual audio signal (or a second audio program).
V4L2_TUNER_SUB_SAP0x0004The tuner receives a Second Audio Program. Note the +V4L2_TUNER_SUB_LANG2 and +V4L2_TUNER_SUB_SAP flags are synonyms. The +V4L2_TUNER_SUB_SAP flag applies when the +current video standard is V4L2_STD_NTSC_M.

Table 5. Tuner Audio Modes

V4L2_TUNER_MODE_MONO0Play mono audio. When the tuner receives a stereo +signal this a down-mix of the left and right channel. When the tuner +receives a bilingual or SAP signal this mode selects the primary +language.
V4L2_TUNER_MODE_STEREO1

Play stereo audio. When the tuner receives +bilingual audio it may play different languages on the left and right +channel or the primary language on both channels. behave as in mono +mode.

Playing different languages in this mode is +deprecated. New drivers should do this only in +MODE_LANG1_LANG2.

When the tuner +receives no stereo signal or does not support stereo reception the +driver shall fall back to MODE_MONO.

V4L2_TUNER_MODE_LANG13Play the primary language, mono or stereo. Only +V4L2_TUNER_ANALOG_TV tuners support this +mode.
V4L2_TUNER_MODE_LANG22Play the secondary language, mono. When the tuner +receives no bilingual audio or SAP, or their reception is not +supported the driver shall fall back to mono or stereo mode. Only +V4L2_TUNER_ANALOG_TV tuners support this +mode.
V4L2_TUNER_MODE_SAP2Play the Second Audio Program. When the tuner +receives no bilingual audio or SAP, or their reception is not +supported the driver shall fall back to mono or stereo mode. Only +V4L2_TUNER_ANALOG_TV tuners support this mode. +Note the V4L2_TUNER_MODE_LANG2 and +V4L2_TUNER_MODE_SAP are synonyms.
V4L2_TUNER_MODE_LANG1_LANG24Play the primary language on the left channel, the +secondary language on the right channel. When the tuner receives no +bilingual audio or SAP, it shall fall back to +MODE_LANG1 or MODE_MONO. +Only V4L2_TUNER_ANALOG_TV tuners support this +mode.

Table 6. Tuner Audio Matrix

 Selected +V4L2_TUNER_MODE_
Received V4L2_TUNER_SUB_MONOSTEREOLANG1LANG2 = SAPLANG1_LANG2[a]
MONOMonoMono/MonoMonoMonoMono/Mono
MONO | SAPMonoMono/MonoMonoSAPMono/SAP (preferred) or Mono/Mono
STEREOL+RL/RStereo L/R (preferred) or Mono L+RStereo L/R (preferred) or Mono L+RL/R (preferred) or L+R/L+R
STEREO | SAPL+RL/RStereo L/R (preferred) or Mono L+RSAPL+R/SAP (preferred) or L/R or L+R/L+R
LANG1 | LANG2Language 1Lang1/Lang2 (deprecated[b]) or +Lang1/Lang1Language 1Language 2Lang1/Lang2 (preferred) or Lang1/Lang1
Notes:
a. This +mode has been added in Linux 2.6.17 and may not be supported by older +drivers.
b. Playback of +both languages in MODE_STEREO is deprecated. In +the future drivers should produce only the primary language in this +mode. Applications should request +MODE_LANG1_LANG2 to record both languages or a +stereo signal.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_tuner index is +out of bounds.


PrevHomeNext
ioctl VIDIOC_G_STD, VIDIOC_S_STDUpioctl VIDIOC_LOG_STATUS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12784.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12784.htm new file mode 100644 index 0000000000000000000000000000000000000000..2e858bb76a794ef7aec2ccc2a630619365516ac1 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12784.htm @@ -0,0 +1,228 @@ + +ioctl VIDIOC_LOG_STATUS
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_LOG_STATUS

Name

VIDIOC_LOG_STATUS -- Log driver status information

Synopsis

int ioctl(int fd, int request);

Description

As the video/audio devices become more complicated it +becomes harder to debug problems. When this ioctl is called the driver +will output the current device status to the kernel log. This is +particular useful when dealing with problems like no sound, no video +and incorrectly tuned channels. Also many modern devices autodetect +video and audio standards and this ioctl will report what the device +thinks what the standard is. Mismatches may give an indication where +the problem is.

This ioctl is optional and not all drivers support it. It +was introduced in Linux 2.6.15.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The driver does not support this ioctl.


PrevHomeNext
ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNERUpioctl VIDIOC_OVERLAY
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12816.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12816.htm new file mode 100644 index 0000000000000000000000000000000000000000..587cde3212e20ef7e52be144f3dc5687ff448a7e --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12816.htm @@ -0,0 +1,298 @@ + +ioctl VIDIOC_OVERLAY
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_OVERLAY

Name

VIDIOC_OVERLAY -- Start or stop video overlay

Synopsis

int ioctl(int fd, int request, const int *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_OVERLAY

argp

Description

This ioctl is part of the video + overlay I/O method. Applications call + VIDIOC_OVERLAY to start or stop the + overlay. It takes a pointer to an integer which must be set to + zero by the application to stop overlay, to one to start.

Drivers do not support VIDIOC_STREAMON or +VIDIOC_STREAMOFF with V4L2_BUF_TYPE_VIDEO_OVERLAY.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

Video overlay is not supported, or the +parameters have not been set up. See Section 4.2 for the necessary steps.


PrevHomeNext
ioctl VIDIOC_LOG_STATUSUpioctl VIDIOC_QBUF, VIDIOC_DQBUF
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12878.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12878.htm new file mode 100644 index 0000000000000000000000000000000000000000..9ad632d86a59a5d337db159d81c3fab41bb198d9 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r12878.htm @@ -0,0 +1,577 @@ + +ioctl VIDIOC_QBUF, VIDIOC_DQBUF
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_QBUF, VIDIOC_DQBUF

Name

VIDIOC_QBUF, VIDIOC_DQBUF -- Exchange a buffer with the driver

Synopsis

int ioctl(int fd, int request, struct v4l2_buffer *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_QBUF, VIDIOC_DQBUF

argp

Description

Applications call the VIDIOC_QBUF ioctl +to enqueue an empty (capturing) or filled (output) buffer in the +driver's incoming queue. The semantics depend on the selected I/O +method.

To enqueue a memory mapped +buffer applications set the type field of a +struct v4l2_buffer to the same buffer type as previously struct v4l2_format +type and struct v4l2_requestbuffers +type, the memory +field to V4L2_MEMORY_MMAP and the +index field. Valid index numbers range from +zero to the number of buffers allocated with VIDIOC_REQBUFS +(struct v4l2_requestbuffers count) minus one. The +contents of the struct v4l2_buffer returned +by a VIDIOC_QUERYBUF ioctl will do as well. When the buffer is +intended for output (type is +V4L2_BUF_TYPE_VIDEO_OUTPUT or +V4L2_BUF_TYPE_VBI_OUTPUT) applications must also +initialize the bytesused, +field and +timestamp fields. See Section 3.5 for details. When +VIDIOC_QBUF is called with a pointer to this +structure the driver sets the +V4L2_BUF_FLAG_MAPPED and +V4L2_BUF_FLAG_QUEUED flags and clears the +V4L2_BUF_FLAG_DONE flag in the +flags field, or it returns an +EINVAL error code.

To enqueue a user pointer +buffer applications set the type field of a +struct v4l2_buffer to the same buffer type as previously struct v4l2_format +type and struct v4l2_requestbuffers +type, the memory +field to V4L2_MEMORY_USERPTR and the +m.userptr field to the address of the +buffer and length to its size. When the +buffer is intended for output additional fields must be set as above. +When VIDIOC_QBUF is called with a pointer to this +structure the driver sets the V4L2_BUF_FLAG_QUEUED +flag and clears the V4L2_BUF_FLAG_MAPPED and +V4L2_BUF_FLAG_DONE flags in the +flags field, or it returns an error code. +This ioctl locks the memory pages of the buffer in physical memory, +they cannot be swapped out to disk. Buffers remain locked until +dequeued, until the VIDIOC_STREAMOFF or VIDIOC_REQBUFS ioctl are +called, or until the device is closed.

Applications call the VIDIOC_DQBUF +ioctl to dequeue a filled (capturing) or displayed (output) buffer +from the driver's outgoing queue. They just set the +type and memory +fields of a struct v4l2_buffer as above, when VIDIOC_DQBUF +is called with a pointer to this structure the driver fills the +remaining fields or returns an error code.

By default VIDIOC_DQBUF blocks when no +buffer is in the outgoing queue. When the +O_NONBLOCK flag was given to the open() +function, VIDIOC_DQBUF returns immediately +with an EAGAIN error code when no buffer is available.

The v4l2_buffer structure is +specified in Section 3.5.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EAGAIN

Non-blocking I/O has been selected using +O_NONBLOCK and no buffer was in the outgoing +queue.

EINVAL

The buffer type is not +supported, or the index is out of bounds, +or no buffers have been allocated yet, or the +userptr or +length are invalid.

ENOMEM

Not enough physical or virtual memory was available to +enqueue a user pointer buffer.

EIO

VIDIOC_DQBUF failed due to an +internal error. Can also indicate temporary problems like signal +loss. Note the driver might dequeue an (empty) buffer despite +returning an error, or even stop capturing.


PrevHomeNext
ioctl VIDIOC_OVERLAYUpioctl VIDIOC_QUERYBUF
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13022.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13022.htm new file mode 100644 index 0000000000000000000000000000000000000000..b44ed8fcddf169e19ef9deb378f2f2aeff9821a6 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13022.htm @@ -0,0 +1,376 @@ + +ioctl VIDIOC_QUERYBUF
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_QUERYBUF

Name

VIDIOC_QUERYBUF -- Query the status of a buffer

Synopsis

int ioctl(int fd, int request, struct v4l2_buffer *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_QUERYBUF

argp

Description

This ioctl is part of the memory +mapping I/O method. It can be used to query the status of a +buffer at any time after buffers have been allocated with the +VIDIOC_REQBUFS ioctl.

Applications set the type field + of a struct v4l2_buffer to the same buffer type as previously +struct v4l2_format type and struct v4l2_requestbuffers +type, and the index + field. Valid index numbers range from zero +to the number of buffers allocated with VIDIOC_REQBUFS + (struct v4l2_requestbuffers count) minus one. +After calling VIDIOC_QUERYBUF with a pointer to + this structure drivers return an error code or fill the rest of +the structure.

In the flags field the +V4L2_BUF_FLAG_MAPPED, +V4L2_BUF_FLAG_QUEUED and +V4L2_BUF_FLAG_DONE flags will be valid. The +memory field will be set to +V4L2_MEMORY_MMAP, the m.offset +contains the offset of the buffer from the start of the device memory, +the length field its size. The driver may +or may not set the remaining fields and flags, they are meaningless in +this context.

The v4l2_buffer structure is + specified in Section 3.5.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The buffer type is not +supported, or the index is out of bounds.


PrevHomeNext
ioctl VIDIOC_QBUF, VIDIOC_DQBUFUpioctl VIDIOC_QUERYCAP
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13105.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13105.htm new file mode 100644 index 0000000000000000000000000000000000000000..4215eb297f6ef8aaeb13a4d0ea2df3a87605a02c --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13105.htm @@ -0,0 +1,723 @@ + +ioctl VIDIOC_QUERYCAP
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_QUERYCAP

Name

VIDIOC_QUERYCAP -- Query device capabilities

Synopsis

int ioctl(int fd, int request, struct v4l2_capability *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_QUERYCAP

argp

Description

All V4L2 devices support the +VIDIOC_QUERYCAP ioctl. It is used to identify +kernel devices compatible with this specification and to obtain +information about driver and hardware capabilities. The ioctl takes a +pointer to a struct v4l2_capability which is filled by the driver. When the +driver is not compatible with this specification the ioctl returns an +EINVAL error code.

Table 1. struct v4l2_capability

__u8driver[16]

Name of the driver, a unique NUL-terminated +ASCII string. For example: "bttv". Driver specific applications can +use this information to verify the driver identity. It is also useful +to work around known bugs, or to identify drivers in error reports. +The driver version is stored in the version +field.

Storing strings in fixed sized arrays is bad +practice but unavoidable here. Drivers and applications should take +precautions to never read or write beyond the end of the array and to +make sure the strings are properly NUL-terminated.

__u8card[32]Name of the device, a NUL-terminated ASCII string. +For example: "Yoyodyne TV/FM". One driver may support different brands +or models of video hardware. This information is intended for users, +for example in a menu of available devices. Since multiple TV cards of +the same brand may be installed which are supported by the same +driver, this name should be combined with the character device file +name (e. g. /dev/video2) or the +bus_info string to avoid +ambiguities.
__u8bus_info[32]Location of the device in the system, a +NUL-terminated ASCII string. For example: "PCI Slot 4". This +information is intended for users, to distinguish multiple +identical devices. If no such information is available the field may +simply count the devices controlled by the driver, or contain the +empty string (bus_info[0] = 0).
__u32version

Version number of the driver. Together with +the driver field this identifies a +particular driver. The version number is formatted using the +KERNEL_VERSION() macro:

#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+__u32 version = KERNEL_VERSION(0, 8, 1);
+
+printf ("Version: %u.%u.%u\n",
+        (version >> 16) & 0xFF,
+        (version >> 8) & 0xFF,
+         version & 0xFF);

__u32capabilitiesDevice capabilities, see Table 2.
__u32reserved[4]Reserved for future extensions. Drivers must set +this array to zero.

Table 2. Device Capabilities Flags

V4L2_CAP_VIDEO_CAPTURE0x00000001The device supports the Video Capture interface.
V4L2_CAP_VIDEO_OUTPUT0x00000002The device supports the Video Output interface.
V4L2_CAP_VIDEO_OVERLAY0x00000004The device supports the Video Overlay interface. A video overlay device +typically stores captured images directly in the video memory of a +graphics card, with hardware clipping and scaling.
V4L2_CAP_VBI_CAPTURE0x00000010The device supports the Raw +VBI Capture interface, providing Teletext and Closed Caption +data.
V4L2_CAP_VBI_OUTPUT0x00000020The device supports the Raw VBI Output interface.
V4L2_CAP_SLICED_VBI_CAPTURE0x00000040The device supports the Sliced VBI Capture interface.
V4L2_CAP_SLICED_VBI_OUTPUT0x00000080The device supports the Sliced VBI Output interface.
V4L2_CAP_RDS_CAPTURE0x00000100[to be defined]
V4L2_CAP_VIDEO_OUTPUT_OVERLAY0x00000200The device supports the Video +Output Overlay (OSD) interface. Unlike the Video +Overlay interface, this is a secondary function of video +output devices and overlays an image onto an outgoing video signal. +When the driver sets this flag, it must clear the +V4L2_CAP_VIDEO_OVERLAY flag and vice +versa.[a]
V4L2_CAP_TUNER0x00010000The device has some sort of tuner or modulator to +receive or emit RF-modulated video signals. For more information about +tuner and modulator programming see +Section 1.6.
V4L2_CAP_AUDIO0x00020000The device has audio inputs or outputs. It may or +may not support audio recording or playback, in PCM or compressed +formats. PCM audio support must be implemented as ALSA or OSS +interface. For more information on audio inputs and outputs see Section 1.5.
V4L2_CAP_RADIO0x00040000This is a radio receiver.
V4L2_CAP_READWRITE0x01000000The device supports the read() and/or write() +I/O methods.
V4L2_CAP_ASYNCIO0x02000000The device supports the asynchronous I/O methods.
V4L2_CAP_STREAMING0x04000000The device supports the streaming I/O method.
Notes:
a. The struct v4l2_framebuffer lacks an +enum v4l2_buf_type field, therefore the type of overlay is implied by the +driver capabilities.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The device is not compatible with this +specification.


PrevHomeNext
ioctl VIDIOC_QUERYBUFUpioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13317.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13317.htm new file mode 100644 index 0000000000000000000000000000000000000000..d1b100fa0705d9e1427de462ce3a067b7718aa47 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13317.htm @@ -0,0 +1,1077 @@ + +ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU

Name

VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU -- Enumerate controls and menu control items

Synopsis

int ioctl(int fd, int request, struct v4l2_queryctrl *argp);

int ioctl(int fd, int request, struct v4l2_querymenu *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU

argp

Description

To query the attributes of a control applications set the +id field of a struct v4l2_queryctrl and call the +VIDIOC_QUERYCTRL ioctl with a pointer to this +structure. The driver fills the rest of the structure or returns an +EINVAL error code when the id is invalid.

It is possible to enumerate controls by calling +VIDIOC_QUERYCTRL with successive +id values starting from +V4L2_CID_BASE up to and exclusive +V4L2_CID_BASE_LASTP1. Drivers may return +EINVAL if a control in this range is not +supported. Further applications can enumerate private controls, which +are not defined in this specification, by starting at +V4L2_CID_PRIVATE_BASE and incrementing +id until the driver returns +EINVAL.

In both cases, when the driver sets the +V4L2_CTRL_FLAG_DISABLED flag in the +flags field this control is permanently +disabled and should be ignored by the application.[1]

When the application ORs id with +V4L2_CTRL_FLAG_NEXT_CTRL the driver returns the +next supported control, or EINVAL if there is +none. Drivers which do not support this flag yet always return +EINVAL.

Additional information is required for menu controls, the +name of menu items. To query them applications set the +id and index +fields of struct v4l2_querymenu and call the +VIDIOC_QUERYMENU ioctl with a pointer to this +structure. The driver fills the rest of the structure or returns an +EINVAL error code when the id or +index is invalid. Menu items are enumerated +by calling VIDIOC_QUERYMENU with successive +index values from struct v4l2_queryctrl +minimum (0) to +maximum, inclusive.

See also the examples in Section 1.8.

Table 1. struct v4l2_queryctrl

__u32idIdentifies the control, set by the application. See +Table 1-1 for predefined IDs. When the ID is ORed +with V4L2_CTRL_FLAG_NEXT_CTRL the driver clears the flag and returns +the first control with a higher ID. Drivers which do not support this +flag yet always return an EINVAL error code.
enum v4l2_ctrl_typetypeType of control, see Table 3.
__u8name[32]Name of the control, a NUL-terminated ASCII +string. This information is intended for the user.
__s32minimumMinimum value, inclusive. This field gives a lower +bound for V4L2_CTRL_TYPE_INTEGER controls. It may +not be valid for any other type of control, including +V4L2_CTRL_TYPE_INTEGER64 controls. Note this is a +signed value.
__s32maximumMaximum value, inclusive. This field gives an upper +bound for V4L2_CTRL_TYPE_INTEGER controls and the +highest valid index for V4L2_CTRL_TYPE_MENU +controls. It may not be valid for any other type of control, including +V4L2_CTRL_TYPE_INTEGER64 controls. Note this is a +signed value.
__s32step

This field gives a step size for +V4L2_CTRL_TYPE_INTEGER controls. It may not be +valid for any other type of control, including +V4L2_CTRL_TYPE_INTEGER64 +controls.

Generally drivers should not scale hardware +control values. It may be necessary for example when the +name or id imply +a particular unit and the hardware actually accepts only multiples of +said unit. If so, drivers must take care values are properly rounded +when scaling, such that errors will not accumulate on repeated +read-write cycles.

This field gives the smallest change of +an integer control actually affecting hardware. Often the information +is needed when the user can change controls by keyboard or GUI +buttons, rather than a slider. When for example a hardware register +accepts values 0-511 and the driver reports 0-65535, step should be +128.

Note although signed, the step value is supposed to +be always positive.

__s32default_valueThe default value of a +V4L2_CTRL_TYPE_INTEGER, +_BOOLEAN or _MENU control. +Not valid for other types of controls. Drivers reset controls only +when the driver is loaded, not later, in particular not when the +func-open; is called.
__u32flagsControl flags, see Table 4.
__u32reserved[2]Reserved for future extensions. Drivers must set +the array to zero.

Table 2. struct v4l2_querymenu

__u32idIdentifies the control, set by the application +from the respective struct v4l2_queryctrl +id.
__u32indexIndex of the menu item, starting at zero, set by + the application.
__u8name[32]Name of the menu item, a NUL-terminated ASCII +string. This information is intended for the user.
__u32reservedReserved for future extensions. Drivers must set +the array to zero.

Table 3. enum v4l2_ctrl_type

TypeminimumstepmaximumDescription
V4L2_CTRL_TYPE_INTEGERanyanyanyAn integer-valued control ranging from minimum to +maximum inclusive. The step value indicates the increment between +values which are actually different on the hardware.
V4L2_CTRL_TYPE_BOOLEAN011A boolean-valued control. Zero corresponds to +"disabled", and one means "enabled".
V4L2_CTRL_TYPE_MENU01N-1The control has a menu of N choices. The names of +the menu items can be enumerated with the +VIDIOC_QUERYMENU ioctl.
V4L2_CTRL_TYPE_BUTTON000A control which performs an action when set. +Drivers must ignore the value passed with +VIDIOC_S_CTRL and return an EINVAL error code on a +VIDIOC_G_CTRL attempt.
V4L2_CTRL_TYPE_INTEGER64n/an/an/aA 64-bit integer valued control. Minimum, maximum +and step size cannot be queried.
V4L2_CTRL_TYPE_CTRL_CLASSn/an/an/aThis is not a control. When +VIDIOC_QUERYCTRL is called with a control ID +equal to a control class code (see Table 3), the +ioctl returns the name of the control class and this control type. +Older drivers which do not support this feature return an +EINVAL error code.

Table 4. Control Flags

V4L2_CTRL_FLAG_DISABLED0x0001This control is permanently disabled and should be +ignored by the application. Any attempt to change the control will +result in an EINVAL error code.
V4L2_CTRL_FLAG_GRABBED0x0002This control is temporarily unchangeable, for +example because another application took over control of the +respective resource. Such controls may be displayed specially in a +user interface. Attempts to change the control may result in an +EBUSY error code.
V4L2_CTRL_FLAG_READ_ONLY0x0004This control is permanently readable only. Any +attempt to change the control will result in an EINVAL error code.
V4L2_CTRL_FLAG_UPDATE0x0008A hint that changing this control may affect the +value of other controls within the same control class. Applications +should update their user interface accordingly.
V4L2_CTRL_FLAG_INACTIVE0x0010This control is not applicable to the current +configuration and should be displayed accordingly in a user interface. +For example the flag may be set on a MPEG audio level 2 bitrate +control when MPEG audio encoding level 1 was selected with another +control.
V4L2_CTRL_FLAG_SLIDER0x0020A hint that this control is best represented as a +slider-like element in a user interface.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_queryctrl id +is invalid. The struct v4l2_querymenu id or +index is invalid.

Notes

[1]

V4L2_CTRL_FLAG_DISABLED was +intended for two purposes: Drivers can skip predefined controls not +supported by the hardware (although returning EINVAL would do as +well), or disable predefined and private controls after hardware +detection without the trouble of reordering control arrays and indices +(EINVAL cannot be used to skip private controls because it would +prematurely end the enumeration).


PrevHomeNext
ioctl VIDIOC_QUERYCAPUpioctl VIDIOC_QUERYSTD
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13641.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13641.htm new file mode 100644 index 0000000000000000000000000000000000000000..7ee26857c7bf263b7ed6a505948990a56b5f2811 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13641.htm @@ -0,0 +1,279 @@ + +ioctl VIDIOC_QUERYSTD
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_QUERYSTD

Name

VIDIOC_QUERYSTD -- Sense the video standard received by the current +input

Synopsis

int ioctl(int fd, int request, v4l2_std_id *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_QUERYSTD

argp

Description

The hardware may be able to detect the current video +standard automatically. To do so, applications call VIDIOC_QUERYSTD with a pointer to a v4l2_std_id type. The +driver stores here a set of candidates, this can be a single flag or a +set of supported standards if for example the hardware can only +distinguish between 50 and 60 Hz systems. When detection is not +possible or fails, the set must contain all standards supported by the +current video input or output.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

This ioctl is not supported.


PrevHomeNext
ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENUUpioctl VIDIOC_REQBUFS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13696.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13696.htm new file mode 100644 index 0000000000000000000000000000000000000000..a450b89bf48bc01c576f749e68e95fe65539ead6 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13696.htm @@ -0,0 +1,516 @@ + +ioctl VIDIOC_REQBUFS
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_REQBUFS

Name

VIDIOC_REQBUFS -- Initiate Memory Mapping or User Pointer I/O

Synopsis

int ioctl(int fd, int request, struct v4l2_requestbuffers *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_REQBUFS

argp

Description

This ioctl is used to initiate memory +mapped or user pointer +I/O. Memory mapped buffers are located in device memory and must be +allocated with this ioctl before they can be mapped into the +application's address space. User buffers are allocated by +applications themselves, and this ioctl is merely used to switch the +driver into user pointer I/O mode.

To allocate device buffers applications initialize three +fields of a v4l2_requestbuffers structure. +They set the type field to the respective +stream or buffer type, the count field to +the desired number of buffers, and memory +must be set to V4L2_MEMORY_MMAP. When the ioctl +is called with a pointer to this structure the driver attempts to +allocate the requested number of buffers and stores the actual number +allocated in the count field. It can be +smaller than the number requested, even zero, when the driver runs out +of free memory. A larger number is possible when the driver requires +more buffers to function correctly.[1] When memory mapping I/O is not supported the ioctl +returns an EINVAL error code.

Applications can call VIDIOC_REQBUFS +again to change the number of buffers, however this cannot succeed +when any buffers are still mapped. A count +value of zero frees all buffers, after aborting or finishing any DMA +in progress, an implicit VIDIOC_STREAMOFF.

To negotiate user pointer I/O, applications initialize only +the type field and set +memory to +V4L2_MEMORY_USERPTR. When the ioctl is called +with a pointer to this structure the driver prepares for user pointer +I/O, when this I/O method is not supported the ioctl returns an +EINVAL error code.

Table 1. struct v4l2_requestbuffers

__u32countThe number of buffers requested or granted. This +field is only used when memory is set to +V4L2_MEMORY_MMAP.
enum v4l2_buf_typetypeType of the stream or buffers, this is the same +as the struct v4l2_format type field. See Table 3-2 for valid values.
enum v4l2_memorymemoryApplications set this field to +V4L2_MEMORY_MMAP or +V4L2_MEMORY_USERPTR.
__u32reserved[2]A place holder for future extensions and custom +(driver defined) buffer types V4L2_BUF_TYPE_PRIVATE and +higher.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EBUSY

The driver supports multiple opens and I/O is already +in progress, or reallocation of buffers was attempted although one or +more are still mapped.

EINVAL

The buffer type (type field) or the +requested I/O method (memory) is not +supported.

Notes

[1]

For example video output requires at least two buffers, +one displayed and one filled by the application.


PrevHomeNext
ioctl VIDIOC_QUERYSTDUpioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13817.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13817.htm new file mode 100644 index 0000000000000000000000000000000000000000..f6b884a0b2f24f1b8f13025a80125ae9f327fea1 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13817.htm @@ -0,0 +1,339 @@ + +ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF

Name

VIDIOC_STREAMON, VIDIOC_STREAMOFF -- Start or stop streaming I/O

Synopsis

int ioctl(int fd, int request, const int *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_STREAMON, VIDIOC_STREAMOFF

argp

Description

The VIDIOC_STREAMON and +VIDIOC_STREAMOFF ioctl start and stop the capture +or output process during streaming (memory +mapping or user pointer) I/O.

Specifically the capture hardware is disabled and no input +buffers are filled (if there are any empty buffers in the incoming +queue) until VIDIOC_STREAMON has been called. +Accordingly the output hardware is disabled, no video signal is +produced until VIDIOC_STREAMON has been called. +The ioctl will succeed only when at least one output buffer is in the +incoming queue.

The VIDIOC_STREAMOFF ioctl, apart of +aborting or finishing any DMA in progress, unlocks any user pointer +buffers locked in physical memory, and it removes all buffers from the +incoming and outgoing queues. That means all images captured but not +dequeued yet will be lost, likewise all images enqueued for output but +not transmitted yet. I/O returns to the same state as after calling +VIDIOC_REQBUFS and can be restarted accordingly.

Both ioctls take a pointer to an integer, the desired buffer or +stream type. This is the same as struct v4l2_requestbuffers +type.

Note applications can be preempted for unknown periods right +before or after the VIDIOC_STREAMON or +VIDIOC_STREAMOFF calls, there is no notion of +starting or stopping "now". Buffer timestamps can be used to +synchronize with other events.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

Streaming I/O is not supported, the buffer +type is not supported, or no buffers have +been allocated (memory mapping) or enqueued (output) yet.


PrevHomeNext
ioctl VIDIOC_REQBUFSUpV4L2 mmap()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13889.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13889.htm new file mode 100644 index 0000000000000000000000000000000000000000..e1350d923242be28cf078b525bc2b6b6414a0a41 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r13889.htm @@ -0,0 +1,550 @@ + +V4L2 mmap()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 mmap()

Name

v4l2-mmap -- Map device memory into application address space

Synopsis

#include <unistd.h>
+#include <sys/mman.h>

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

Arguments

start

Map the buffer to this address in the +application's address space. When the MAP_FIXED +flag is specified, start must be a multiple of the +pagesize and mmap will fail when the specified address +cannot be used. Use of this option is discouraged; applications should +just specify a NULL pointer here.

length

Length of the memory area to map. This must be the +same value as returned by the driver in the struct v4l2_buffer +length field.

prot

The prot argument describes the +desired memory protection. Regardless of the device type and the +direction of data exchange it should be set to +PROT_READ | PROT_WRITE, +permitting read and write access to image buffers. Drivers should +support at least this combination of flags. Note the Linux +video-buf kernel module, which is used by the +bttv, saa7134, saa7146, cx88 and vivi driver supports only +PROT_READ | PROT_WRITE. When +the driver does not support the desired protection the +mmap() function fails.

Note device memory accesses (e. g. the memory on a +graphics card with video capturing hardware) may incur a performance +penalty compared to main memory accesses, or reads may be +significantly slower than writes or vice versa. Other I/O methods may +be more efficient in this case.

flags

The flags parameter +specifies the type of the mapped object, mapping options and whether +modifications made to the mapped copy of the page are private to the +process or are to be shared with other references.

MAP_FIXED requests that the +driver selects no other address than the one specified. If the +specified address cannot be used, mmap() will fail. If +MAP_FIXED is specified, +start must be a multiple of the pagesize. Use +of this option is discouraged.

One of the MAP_SHARED or +MAP_PRIVATE flags must be set. +MAP_SHARED allows applications to share the +mapped memory with other (e. g. child-) processes. Note the Linux +video-buf module which is used by the bttv, +saa7134, saa7146, cx88 and vivi driver supports only +MAP_SHARED. MAP_PRIVATE +requests copy-on-write semantics. V4L2 applications should not set the +MAP_PRIVATE, MAP_DENYWRITE, +MAP_EXECUTABLE or MAP_ANON +flag.

fd

File descriptor returned by open().

offset

Offset of the buffer in device memory. This must be the +same value as returned by the driver in the struct v4l2_buffer +m union offset field.

Description

The mmap() function asks to map +length bytes starting at +offset in the memory of the device specified by +fd into the application address space, +preferably at address start. This latter +address is a hint only, and is usually specified as 0.

Suitable length and offset parameters are queried with the +VIDIOC_QUERYBUF ioctl. Buffers must be allocated with the +VIDIOC_REQBUFS ioctl before they can be queried.

To unmap buffers the munmap() function is used.

Return Value

On success mmap() returns a pointer to +the mapped buffer. On error MAP_FAILED (-1) is +returned, and the errno variable is set +appropriately. Possible error codes are:

EBADF

fd is not a valid file +descriptor.

EACCES

fd is +not open for reading and writing.

EINVAL

The start or +length or offset are not +suitable. (E. g. they are too large, or not aligned on a +PAGESIZE boundary.)

The flags or +prot value is not supported.

No buffers have been allocated with the +VIDIOC_REQBUFS ioctl.

ENOMEM

Not enough physical or virtual memory was available to +complete the request.


PrevHomeNext
ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFFUpV4L2 munmap()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14037.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14037.htm new file mode 100644 index 0000000000000000000000000000000000000000..24b882dfd87a0a4fc4da5f6d09acbc42cebe69bc --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14037.htm @@ -0,0 +1,288 @@ + +V4L2 munmap()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 munmap()

Name

v4l2-munmap -- Unmap device memory

Synopsis

#include <unistd.h>
+#include <sys/mman.h>

int munmap(void *start, size_t length);

Arguments

start

Address of the mapped buffer as returned by the +mmap() function.

length

Length of the mapped buffer. This must be the same +value as given to mmap() and returned by the +driver in the struct v4l2_buffer length +field.

Description

Unmaps a previously with the mmap() function mapped +buffer and frees it, if possible.

Return Value

On success munmap() returns 0, on +failure -1 and the errno variable is set +appropriately:

EINVAL

The start or +length is incorrect, or no buffers have been +mapped yet.


PrevHomeNext
V4L2 mmap()UpV4L2 open()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14090.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14090.htm new file mode 100644 index 0000000000000000000000000000000000000000..bc7b24587a6dd9155dfea08239ce87386854d5b8 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14090.htm @@ -0,0 +1,345 @@ + +V4L2 open()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 open()

Name

v4l2-open -- Open a V4L2 device

Synopsis

#include <fcntl.h>

int open(const char *device_name, int flags);

Arguments

device_name

Device to be opened.

flags

Open flags. Access mode must be +O_RDWR. This is just a technicality, input devices +still support only reading and output devices only writing.

When the O_NONBLOCK flag is +given, the read() function and the VIDIOC_DQBUF ioctl will return +the EAGAIN error code when no data is available or no buffer is in the driver +outgoing queue, otherwise these functions block until data becomes +available. All V4L2 drivers exchanging data with applications must +support the O_NONBLOCK flag.

Other flags have no effect.

Description

To open a V4L2 device applications call +open() with the desired device name. This +function has no side effects; all data format parameters, current +input or output, control values or other properties remain unchanged. +At the first open() call after loading the driver +they will be reset to default values, drivers are never in an +undefined state.

Return Value

On success open returns the new file +descriptor. On error -1 is returned, and the errno +variable is set appropriately. Possible error codes are:

EACCES

The caller has no permission to access the +device.

EBUSY

The driver does not support multiple opens and the +device is already in use.

ENXIO

No device corresponding to this device special file +exists.

ENOMEM

Not enough kernel memory was available to complete the +request.

EMFILE

The process already has the maximum number of +files open.

ENFILE

The limit on the total number of files open on the +system has been reached.


PrevHomeNext
V4L2 munmap()UpV4L2 poll()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14169.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14169.htm new file mode 100644 index 0000000000000000000000000000000000000000..5293876461dd5822b8937d7863c54741efb953c1 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14169.htm @@ -0,0 +1,413 @@ + +V4L2 poll()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 poll()

Name

v4l2-poll -- Wait for some event on a file descriptor

Synopsis

#include <sys/poll.h>

int poll(struct pollfd *ufds, unsigned int nfds, int timeout);

Description

With the poll() function applications +can suspend execution until the driver has captured data or is ready +to accept data for output.

When streaming I/O has been negotiated this function waits +until a buffer has been filled or displayed and can be dequeued with +the VIDIOC_DQBUF ioctl. When buffers are already in the outgoing +queue of the driver the function returns immediately.

On success poll() returns the number of +file descriptors that have been selected (that is, file descriptors +for which the revents field of the +respective pollfd structure is non-zero). +Capture devices set the POLLIN and +POLLRDNORM flags in the +revents field, output devices the +POLLOUT and POLLWRNORM +flags. When the function timed out it returns a value of zero, on +failure it returns -1 and the +errno variable is set appropriately. When the +application did not call VIDIOC_QBUF or VIDIOC_STREAMON yet the +poll() function succeeds, but sets the +POLLERR flag in the +revents field.

When use of the read() function has +been negotiated and the driver does not capture yet, the +poll function starts capturing. When that fails +it returns a POLLERR as above. Otherwise it waits +until data has been captured and can be read. When the driver captures +continuously (as opposed to, for example, still images) the function +may return immediately.

When use of the write() function has +been negotiated the poll function just waits +until the driver is ready for a non-blocking +write() call.

All drivers implementing the read() or +write() function or streaming I/O must also +support the poll() function.

For more details see the +poll() manual page.

Return Value

On success, poll() returns the number +structures which have non-zero revents +fields, or zero if the call timed out. On error +-1 is returned, and the +errno variable is set appropriately:

EBADF

One or more of the ufds members +specify an invalid file descriptor.

EBUSY

The driver does not support multiple read or write +streams and the device is already in use.

EFAULT

ufds references an inaccessible +memory area.

EINTR

The call was interrupted by a signal.

EINVAL

The nfds argument is greater +than OPEN_MAX.


PrevHomeNext
V4L2 open()UpV4L2 read()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14264.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14264.htm new file mode 100644 index 0000000000000000000000000000000000000000..392ee1cfcaea44390e826f0e4f3cc53e3bcb942a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14264.htm @@ -0,0 +1,503 @@ + +V4L2 read()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 read()

Name

v4l2-read -- Read from a V4L2 device

Synopsis

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

Arguments

fd

File descriptor returned by open().

buf

count

Description

read() attempts to read up to +count bytes from file descriptor +fd into the buffer starting at +buf. The layout of the data in the buffer is +discussed in the respective device interface section, see ##. If count is zero, +read() returns zero and has no other results. If +count is greater than +SSIZE_MAX, the result is unspecified. Regardless +of the count value each +read() call will provide at most one frame (two +fields) worth of data.

By default read() blocks until data +becomes available. When the O_NONBLOCK flag was +given to the open() function it +returns immediately with an EAGAIN error code when no data is available. The +select() or poll() functions +can always be used to suspend execution until data becomes available. All +drivers supporting the read() function must also +support select() and +poll().

Drivers can implement read functionality in different +ways, using a single or multiple buffers and discarding the oldest or +newest frames once the internal buffers are filled.

read() never returns a "snapshot" of a +buffer being filled. Using a single buffer the driver will stop +capturing when the application starts reading the buffer until the +read is finished. Thus only the period of the vertical blanking +interval is available for reading, or the capture rate must fall below +the nominal frame rate of the video standard.

The behavior of +read() when called during the active picture +period or the vertical blanking separating the top and bottom field +depends on the discarding policy. A driver discarding the oldest +frames keeps capturing into an internal buffer, continuously +overwriting the previously, not read frame, and returns the frame +being received at the time of the read() call as +soon as it is complete.

A driver discarding the newest frames stops capturing until +the next read() call. The frame being received at +read() time is discarded, returning the following +frame instead. Again this implies a reduction of the capture rate to +one half or less of the nominal frame rate. An example of this model +is the video read mode of the bttv driver, initiating a DMA to user +memory when read() is called and returning when +the DMA finished.

In the multiple buffer model drivers maintain a ring of +internal buffers, automatically advancing to the next free buffer. +This allows continuous capturing when the application can empty the +buffers fast enough. Again, the behavior when the driver runs out of +free buffers depends on the discarding policy.

Applications can get and set the number of buffers used +internally by the driver with the VIDIOC_G_PARM and VIDIOC_S_PARM +ioctls. They are optional, however. The discarding policy is not +reported and cannot be changed. For minimum requirements see Chapter 4.

Return Value

On success, the number of bytes read is returned. It is not +an error if this number is smaller than the number of bytes requested, +or the amount of data required for one frame. This may happen for +example because read() was interrupted by a +signal. On error, -1 is returned, and the errno +variable is set appropriately. In this case the next read will start +at the beginning of a new frame. Possible error codes are:

EAGAIN

Non-blocking I/O has been selected using +O_NONBLOCK and no data was immediately available for reading.

EBADF

fd is not a valid file +descriptor or is not open for reading, or the process already has the +maximum number of files open.

EBUSY

The driver does not support multiple read streams and the +device is already in use.

EFAULT

buf references an inaccessible +memory area.

EINTR

The call was interrupted by a signal before any +data was read.

EIO

I/O error. This indicates some hardware problem or a +failure to communicate with a remote device (USB camera etc.).

EINVAL

The read() function is not +supported by this driver, not on this device, or generally not on this +type of device.


PrevHomeNext
V4L2 poll()UpV4L2 select()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14390.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14390.htm new file mode 100644 index 0000000000000000000000000000000000000000..04a96817766cfff31fa2ee7d28fed7f616e1a699 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14390.htm @@ -0,0 +1,470 @@ + +V4L2 select()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 select()

Name

v4l2-select -- Synchronous I/O multiplexing

Synopsis

#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

Description

With the select() function applications +can suspend execution until the driver has captured data or is ready +to accept data for output.

When streaming I/O has been negotiated this function waits +until a buffer has been filled or displayed and can be dequeued with +the VIDIOC_DQBUF ioctl. When buffers are already in the outgoing +queue of the driver the function returns immediately.

On success select() returns the total +number of bits set in the fd_sets. When the +function timed out it returns a value of zero. On failure it returns +-1 and the errno +variable is set appropriately. When the application did not call +VIDIOC_QBUF or VIDIOC_STREAMON yet the +select() function succeeds, setting the bit of +the file descriptor in readfds or +writefds, but subsequent VIDIOC_DQBUF calls +will fail.[1]

When use of the read() function has +been negotiated and the driver does not capture yet, the +select() function starts capturing. When that +fails, select() returns successful and a +subsequent read() call, which also attempts to +start capturing, will return an appropriate error code. When the +driver captures continuously (as opposed to, for example, still +images) and data is already available the +select() function returns immediately.

When use of the write() function has +been negotiated the select() function just waits +until the driver is ready for a non-blocking +write() call.

All drivers implementing the read() or +write() function or streaming I/O must also +support the select() function.

For more details see the select() +manual page.

Return Value

On success, select() returns the number +of descriptors contained in the three returned descriptor sets, which +will be zero if the timeout expired. On error +-1 is returned, and the +errno variable is set appropriately; the sets and +timeout are undefined. Possible error codes +are:

EBADF

One or more of the file descriptor sets specified a +file descriptor that is not open.

EBUSY

The driver does not support multiple read or write +streams and the device is already in use.

EFAULT

The readfds, +writefds, exceptfds or +timeout pointer references an inaccessible memory +area.

EINTR

The call was interrupted by a signal.

EINVAL

The nfds argument is less than +zero or greater than FD_SETSIZE.

Notes

[1]

The Linux kernel implements +select() like the poll() function, but +select() cannot return a +POLLERR.


PrevHomeNext
V4L2 read()UpV4L2 write()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14496.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14496.htm new file mode 100644 index 0000000000000000000000000000000000000000..d461768583a7a919eda79530982edcb5991986c0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r14496.htm @@ -0,0 +1,378 @@ + +V4L2 write()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 write()

Name

v4l2-write -- Write to a V4L2 device

Synopsis

#include <unistd.h>

ssize_t write(int fd, void *buf, size_t count);

Arguments

fd

File descriptor returned by open().

buf

count

Description

write() writes up to +count bytes to the device referenced by the +file descriptor fd from the buffer starting at +buf. When the hardware outputs are not active +yet, this function enables them. When count is +zero, write() returns +0 without any other effect.

When the application does not provide more data in time, the +previous video frame, raw VBI image, sliced VPS or WSS data is +displayed again. Sliced Teletext or Closed Caption data is not +repeated, the driver inserts a blank line instead.

Return Value

On success, the number of bytes written are returned. Zero +indicates nothing was written. On error, -1 +is returned, and the errno variable is set +appropriately. In this case the next write will start at the beginning +of a new frame. Possible error codes are:

EAGAIN

Non-blocking I/O has been selected using the O_NONBLOCK flag and no +buffer space was available to write the data immediately.

EBADF

fd is not a valid file +descriptor or is not open for writing.

EBUSY

The driver does not support multiple write streams and the +device is already in use.

EFAULT

buf references an inaccessible +memory area.

EINTR

The call was interrupted by a signal before any +data was written.

EIO

I/O error. This indicates some hardware problem.

EINVAL

The write() function is not +supported by this driver, not on this device, or generally not on this +type of device.


PrevHomeNext
V4L2 select()UpV4L2 Driver Programming
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r2492.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r2492.htm new file mode 100644 index 0000000000000000000000000000000000000000..1d136d43b928bc675b388b59c78393d802c93c38 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r2492.htm @@ -0,0 +1,3313 @@ + +Packed RGB formats
Video for Linux Two API Specification: Revision 0.24
PrevNext

Packed RGB formats

Name

Packed RGB formats -- Packed RGB formats

Description

These formats are designed to match the pixel formats of +typical PC graphics frame buffers. They occupy 8, 16, 24 or 32 bits +per pixel. These are all packed-pixel formats, meaning all the data +for a pixel lie next to each other in memory.

When one of these formats is used, drivers shall report the +colorspace V4L2_COLORSPACE_SRGB.

Table 2-1. Packed RGB Image Formats

IdentifierCode Byte 0 in memory Byte 1 Byte 2 Byte 3
  Bit76543210 76543210 76543210 76543210
V4L2_PIX_FMT_RGB332'RGB1' b1b0g2g1g0r2r1r0                          
V4L2_PIX_FMT_RGB444'R444' g3g2g1g0b3b2b1b0 a3a2a1a0r3r2r1r0                 
V4L2_PIX_FMT_RGB555'RGBO' g2g1g0r4r3r2r1r0 ab4b3b2b1b0g4g3                 
V4L2_PIX_FMT_RGB565'RGBP' g2g1g0r4r3r2r1r0 b4b3b2b1b0g5g4g3                 
V4L2_PIX_FMT_RGB555X'RGBQ' ab4b3b2b1b0g4g3 g2g1g0r4r3r2r1r0                 
V4L2_PIX_FMT_RGB565X'RGBR' b4b3b2b1b0g5g4g3 g2g1g0r4r3r2r1r0                 
V4L2_PIX_FMT_BGR24'BGR3' b7b6b5b4b3b2b1b0 g7g6g5g4g3g2g1g0 r7r6r5r4r3r2r1r0        
V4L2_PIX_FMT_RGB24'RGB3' r7r6r5r4r3r2r1r0 g7g6g5g4g3g2g1g0 b7b6b5b4b3b2b1b0        
V4L2_PIX_FMT_BGR32'BGR4' b7b6b5b4b3b2b1b0 g7g6g5g4g3g2g1g0 r7r6r5r4r3r2r1r0 a7a6a5a4a3a2a1a0
V4L2_PIX_FMT_RGB32'RGB4' r7r6r5r4r3r2r1r0 g7g6g5g4g3g2g1g0 b7b6b5b4b3b2b1b0 a7a6a5a4a3a2a1a0

Bit 7 is the most significant bit. The value of a = alpha +bits is undefined when reading from the driver, ignored when writing +to the driver, except when alpha blending has been negotiated for a +Video Overlay or Video Output Overlay.

Example 2-1. V4L2_PIX_FMT_BGR24 4 × 4 pixel +image

Byte Order. Each cell is one byte. +

start + 0:B00G00R00B01G01R01B02G02R02B03G03R03
start + 12:B10G10R10B11G11R11B12G12R12B13G13R13
start + 24:B20G20R20B21G21R21B22G22R22B23G23R23
start + 36:B30G30R30B31G31R31B32G32R32B33G33R33

+

Important: Drivers may interpret these formats differently.

Some RGB formats above are uncommon and were probably +defined in error. Drivers may interpret them as in Table 2-2.

Table 2-2. Packed RGB Image Formats (corrected)

IdentifierCode Byte 0 in memory Byte 1 Byte 2 Byte 3
  Bit76543210 76543210 76543210 76543210
V4L2_PIX_FMT_RGB332'RGB1' r2r1r0g2g1g0b1b0                          
V4L2_PIX_FMT_RGB444'R444' g3g2g1g0b3b2b1b0 a3a2a1a0r3r2r1r0                 
V4L2_PIX_FMT_RGB555'RGBO' g2g1g0b4b3b2b1b0 ar4r3r2r1r0g4g3                 
V4L2_PIX_FMT_RGB565'RGBP' g2g1g0b4b3b2b1b0 r4r3r2r1r0g5g4g3                 
V4L2_PIX_FMT_RGB555X'RGBQ' ar4r3r2r1r0g4g3 g2g1g0b4b3b2b1b0                 
V4L2_PIX_FMT_RGB565X'RGBR' r4r3r2r1r0g5g4g3 g2g1g0b4b3b2b1b0                 
V4L2_PIX_FMT_BGR24'BGR3' b7b6b5b4b3b2b1b0 g7g6g5g4g3g2g1g0 r7r6r5r4r3r2r1r0        
V4L2_PIX_FMT_RGB24'RGB3' r7r6r5r4r3r2r1r0 g7g6g5g4g3g2g1g0 b7b6b5b4b3b2b1b0        
V4L2_PIX_FMT_BGR32'BGR4' b7b6b5b4b3b2b1b0 g7g6g5g4g3g2g1g0 r7r6r5r4r3r2r1r0 a7a6a5a4a3a2a1a0
V4L2_PIX_FMT_RGB32'RGB4' a7a6a5a4a3a2a1a0 r7r6r5r4r3r2r1r0 g7g6g5g4g3g2g1g0 b7b6b5b4b3b2b1b0

A test utility to determine which RGB formats a driver +actually supports is available from the LinuxTV v4l-dvb repository. +See http://linuxtv.org/repo/ for access instructions.


PrevHomeNext
RGB FormatsUpV4L2_PIX_FMT_SBGGR8 ('BA81')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3735.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3735.htm new file mode 100644 index 0000000000000000000000000000000000000000..b8d87e6557e41291560925aa8f24d74122c7a027 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3735.htm @@ -0,0 +1,290 @@ + +V4L2_PIX_FMT_SBGGR8 ('BA81')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_SBGGR8 ('BA81')

Name

V4L2_PIX_FMT_SBGGR8 -- Bayer RGB format

Description

This is commonly the native format of digital cameras, +reflecting the arrangement of sensors on the CCD device. Only one red, +green or blue value is given for each pixel. Missing components must +be interpolated from neighbouring pixels. From left to right the first +row consists of a blue and green value, the second row of a green and +red value. This scheme repeats to the right and down for every two +columns and rows.

Example 2-1. V4L2_PIX_FMT_SBGGR8 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:B00G01B02G03
start + 4:G10R11G12R13
start + 8:B20G21B22G23
start + 12:G30R31G32R33

+


PrevHomeNext
Packed RGB formatsUpV4L2_PIX_FMT_SBGGR16 ('BA82')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3796.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3796.htm new file mode 100644 index 0000000000000000000000000000000000000000..b90de832b9c3a81cde8495d359542c1f3dc81ccb --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3796.htm @@ -0,0 +1,358 @@ + +V4L2_PIX_FMT_SBGGR16 ('BA82')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_SBGGR16 ('BA82')

Name

V4L2_PIX_FMT_SBGGR16 -- Bayer RGB format

Description

This format is similar to V4L2_PIX_FMT_SBGGR8, except each pixel has +a depth of 16 bits. The least significant byte is stored at lower +memory addresses (little-endian). Note the actual sampling precision +may be lower than 16 bits, for example 10 bits per pixel with values +in range 0 to 1023.

Example 2-1. V4L2_PIX_FMT_SBGGR16 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:B00lowB00highG01lowG01highB02lowB02highG03lowG03high
start + 8:G10lowG10highR11lowR11highG12lowG12highR13lowR13high
start + 16:B20lowB20highG21lowG21highB22lowB22highG23lowG23high
start + 24:G30lowG30highR31lowR31highG32lowG32highR33lowR33high

+


PrevHomeNext
V4L2_PIX_FMT_SBGGR8 ('BA81')UpYUV Formats
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3896.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3896.htm new file mode 100644 index 0000000000000000000000000000000000000000..496ded46ab076deed5b1275ad2787d5cb94a5b88 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r3896.htm @@ -0,0 +1,884 @@ + +Packed YUV formats
Video for Linux Two API Specification: Revision 0.24
PrevNext

Packed YUV formats

Name

Packed YUV formats -- Packed YUV formats

Description

Similar to the packed RGB formats these formats store +the Y, Cb and Cr component of each pixel in one 16 or 32 bit +word.

Table 2-1. Packed YUV Image Formats

IdentifierCode Byte 0 in memory Byte 1 Byte 2 Byte 3
  Bit76543210 76543210 76543210 76543210
V4L2_PIX_FMT_YUV444'Y444' Cb3Cb2Cb1Cb0Cr3Cr2Cr1Cr0 a3a2a1a0Y'3Y'2Y'1Y'0                 
V4L2_PIX_FMT_YUV555'YUVO' Cb2Cb1Cb0Cr4Cr3Cr2Cr1Cr0 aY'4Y'3Y'2Y'1Y'0Cb4Cb3                 
V4L2_PIX_FMT_YUV565'YUVP' Cb2Cb1Cb0Cr4Cr3Cr2Cr1Cr0 Y'4Y'3Y'2Y'1Y'0Cb5Cb4Cb3                 
V4L2_PIX_FMT_YUV32'YUV4' a7a6a5a4a3a2a1a0 Y'7Y'6Y'5Y'4Y'3Y'2Y'1Y'0 Cb7Cb6Cb5Cb4Cb3Cb2Cb1Cb0 Cr7Cr6Cr5Cr4Cr3Cr2Cr1Cr0

Bit 7 is the most significant bit. The value of a = alpha +bits is undefined when reading from the driver, ignored when writing +to the driver, except when alpha blending has been negotiated for a +Video Overlay or Video Output Overlay.


PrevHomeNext
YUV FormatsUpV4L2_PIX_FMT_GREY ('GREY')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4185.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4185.htm new file mode 100644 index 0000000000000000000000000000000000000000..25e47467cdbf8901d9d291960ab4bd763d925270 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4185.htm @@ -0,0 +1,285 @@ + +V4L2_PIX_FMT_GREY ('GREY')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_GREY ('GREY')

Name

V4L2_PIX_FMT_GREY -- Grey-scale image

Description

This is a grey-scale image. It is really a degenerate +Y'CbCr format which simply contains no Cb or Cr data.

Example 2-1. V4L2_PIX_FMT_GREY 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Y'00Y'01Y'02Y'03
start + 4:Y'10Y'11Y'12Y'13
start + 8:Y'20Y'21Y'22Y'23
start + 12:Y'30Y'31Y'32Y'33

+


PrevHomeNext
Packed YUV formatsUpV4L2_PIX_FMT_Y16 ('Y16 ')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4246.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4246.htm new file mode 100644 index 0000000000000000000000000000000000000000..60ac13d326161d4df301825b5457e8f879ec07a3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4246.htm @@ -0,0 +1,352 @@ + +V4L2_PIX_FMT_Y16 ('Y16 ')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_Y16 ('Y16 ')

Name

V4L2_PIX_FMT_Y16 -- Grey-scale image

Description

This is a grey-scale image with a depth of 16 bits per +pixel. The least significant byte is stored at lower memory addresses +(little-endian). Note the actual sampling precision may be lower than +16 bits, for example 10 bits per pixel with values in range 0 to +1023.

Example 2-1. V4L2_PIX_FMT_Y16 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Y'00lowY'00highY'01lowY'01highY'02lowY'02highY'03lowY'03high
start + 8:Y'10lowY'10highY'11lowY'11highY'12lowY'12highY'13lowY'13high
start + 16:Y'20lowY'20highY'21lowY'21highY'22lowY'22highY'23lowY'23high
start + 24:Y'30lowY'30highY'31lowY'31highY'32lowY'32highY'33lowY'33high

+


PrevHomeNext
V4L2_PIX_FMT_GREY ('GREY')UpV4L2_PIX_FMT_YUYV ('YUYV')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4339.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4339.htm new file mode 100644 index 0000000000000000000000000000000000000000..6571c78199df53ef8a4dd984e42a4415a27d7e94 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4339.htm @@ -0,0 +1,473 @@ + +V4L2_PIX_FMT_YUYV ('YUYV')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_YUYV ('YUYV')

Name

V4L2_PIX_FMT_YUYV -- Packed format with ½ horizontal chroma +resolution, also known as YUV 4:2:2

Description

In this format each four bytes is two pixels. Each four +bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and +the Cb and Cr belong to both pixels. As you can see, the Cr and Cb +components have half the horizontal resolution of the Y component. +V4L2_PIX_FMT_YUYV is known in the Windows +environment as YUY2.

Example 2-1. V4L2_PIX_FMT_YUYV 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Y'00Cb00Y'01Cr00Y'02Cb01Y'03Cr01
start + 8:Y'10Cb10Y'11Cr10Y'12Cb11Y'13Cr11
start + 16:Y'20Cb20Y'21Cr20Y'22Cb21Y'23Cr21
start + 24:Y'30Cb30Y'31Cr30Y'32Cb31Y'33Cr31

+

Color Sample Location.

 0 1 2 3
0YCY YCY
1YCY YCY
2YCY YCY
3YCY YCY

+


PrevHomeNext
V4L2_PIX_FMT_Y16 ('Y16 ')UpV4L2_PIX_FMT_UYVY ('UYVY')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4484.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4484.htm new file mode 100644 index 0000000000000000000000000000000000000000..98fafe1cc9fbdfa921e528135e583cd390db40d5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4484.htm @@ -0,0 +1,473 @@ + +V4L2_PIX_FMT_UYVY ('UYVY')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_UYVY ('UYVY')

Name

V4L2_PIX_FMT_UYVY -- Variation of +V4L2_PIX_FMT_YUYV with different order of samples +in memory

Description

In this format each four bytes is two pixels. Each four +bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and +the Cb and Cr belong to both pixels. As you can see, the Cr and Cb +components have half the horizontal resolution of the Y +component.

Example 2-1. V4L2_PIX_FMT_UYVY 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Cb00Y'00Cr00Y'01Cb01Y'02Cr01Y'03
start + 8:Cb10Y'10Cr10Y'11Cb11Y'12Cr11Y'13
start + 16:Cb20Y'20Cr20Y'21Cb21Y'22Cr21Y'23
start + 24:Cb30Y'30Cr30Y'31Cb31Y'32Cr31Y'33

+

Color Sample Location.

 0 1 2 3
0YCY YCY
1YCY YCY
2YCY YCY
3YCY YCY

+


PrevHomeNext
V4L2_PIX_FMT_YUYV ('YUYV')UpV4L2_PIX_FMT_Y41P ('Y41P')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4629.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4629.htm new file mode 100644 index 0000000000000000000000000000000000000000..8de71d59dcc4df1e7ba362473c7d5c7be8dac625 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4629.htm @@ -0,0 +1,634 @@ + +V4L2_PIX_FMT_Y41P ('Y41P')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_Y41P ('Y41P')

Name

V4L2_PIX_FMT_Y41P -- Format with ¼ horizontal chroma +resolution, also known as YUV 4:1:1

Description

In this format each 12 bytes is eight pixels. In the +twelve bytes are two CbCr pairs and eight Y's. The first CbCr pair +goes with the first four Y's, and the second CbCr pair goes with the +other four Y's. The Cb and Cr components have one fourth the +horizontal resolution of the Y component.

Do not confuse this format with V4L2_PIX_FMT_YUV411P. +Y41P is derived from "YUV 4:1:1 packed", while +YUV411P stands for "YUV 4:1:1 planar".

Example 2-1. V4L2_PIX_FMT_Y41P 8 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Cb00Y'00Cr00Y'01Cb01Y'02Cr01Y'03Y'04Y'05Y'06Y'07
start + 12:Cb10Y'10Cr10Y'11Cb11Y'12Cr11Y'13Y'14Y'15Y'16Y'17
start + 24:Cb20Y'20Cr20Y'21Cb21Y'22Cr21Y'23Y'24Y'25Y'26Y'27
start + 36:Cb30Y'30Cr30Y'31Cb31Y'32Cr31Y'33Y'34Y'35Y'36Y'37

Color Sample Location.

 0 1 2 3 4 5 6 7
0Y YCY Y Y YCY Y
1Y YCY Y Y YCY Y
2Y YCY Y Y YCY Y
3Y YCY Y Y YCY Y

+


PrevHomeNext
V4L2_PIX_FMT_UYVY ('UYVY')UpV4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4850.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4850.htm new file mode 100644 index 0000000000000000000000000000000000000000..7f21b0cb797e09c8b1d6a3b988024a0e4ba0384a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r4850.htm @@ -0,0 +1,552 @@ + +V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12')

Name

V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420 -- Planar formats with ½ horizontal and +vertical chroma resolution, also known as YUV 4:2:0

Description

These are planar formats, as opposed to a packed format. +The three components are separated into three sub- images or planes. +The Y plane is first. The Y plane has one byte per pixel. For +V4L2_PIX_FMT_YVU420, the Cr plane immediately +follows the Y plane in memory. The Cr plane is half the width and half +the height of the Y plane (and of the image). Each Cr belongs to four +pixels, a two-by-two square of the image. For example, +Cr0 belongs to Y'00, +Y'01, Y'10, and +Y'11. Following the Cr plane is the Cb plane, +just like the Cr plane. V4L2_PIX_FMT_YUV420 is +the same except the Cb plane comes first, then the Cr plane.

If the Y plane has pad bytes after each row, then the Cr +and Cb planes have half as many pad bytes after their rows. In other +words, two Cx rows (including padding) is exactly as long as one Y row +(including padding).

Example 2-1. V4L2_PIX_FMT_YVU420 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Y'00Y'01Y'02Y'03
start + 4:Y'10Y'11Y'12Y'13
start + 8:Y'20Y'21Y'22Y'23
start + 12:Y'30Y'31Y'32Y'33
start + 16:Cr00Cr01  
start + 18:Cr10Cr11  
start + 20:Cb00Cb01  
start + 22:Cb10Cb11  

+

Color Sample Location.

 0 1 2 3
0Y Y Y Y
  C   C 
1Y Y Y Y
       
2Y Y Y Y
  C   C 
3Y Y Y Y

+


PrevHomeNext
V4L2_PIX_FMT_Y41P ('Y41P')UpV4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5016.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5016.htm new file mode 100644 index 0000000000000000000000000000000000000000..29210cea58b9d909b6ba6d877a7152408e42bcb5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5016.htm @@ -0,0 +1,502 @@ + +V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9')

Name

V4L2_PIX_FMT_YVU410, V4L2_PIX_FMT_YUV410 -- Planar formats with ¼ horizontal and +vertical chroma resolution, also known as YUV 4:1:0

Description

These are planar formats, as opposed to a packed format. +The three components are separated into three sub-images or planes. +The Y plane is first. The Y plane has one byte per pixel. For +V4L2_PIX_FMT_YVU410, the Cr plane immediately +follows the Y plane in memory. The Cr plane is ¼ the width and +¼ the height of the Y plane (and of the image). Each Cr belongs +to 16 pixels, a four-by-four square of the image. Following the Cr +plane is the Cb plane, just like the Cr plane. +V4L2_PIX_FMT_YUV410 is the same, except the Cb +plane comes first, then the Cr plane.

If the Y plane has pad bytes after each row, then the Cr +and Cb planes have ¼ as many pad bytes after their rows. In +other words, four Cx rows (including padding) are exactly as long as +one Y row (including padding).

Example 2-1. V4L2_PIX_FMT_YVU410 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Y'00Y'01Y'02Y'03
start + 4:Y'10Y'11Y'12Y'13
start + 8:Y'20Y'21Y'22Y'23
start + 12:Y'30Y'31Y'32Y'33
start + 16:Cr00   
start + 17:Cb00   

+

Color Sample Location.

 0 1 2 3
0Y Y Y Y
       
1Y Y Y Y
    C   
2Y Y Y Y
       
3Y Y Y Y

+


PrevHomeNext
V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12')UpV4L2_PIX_FMT_YUV422P ('422P')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5154.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5154.htm new file mode 100644 index 0000000000000000000000000000000000000000..a1df226d96de3bd141eb21bf40522f676cdc5559 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5154.htm @@ -0,0 +1,552 @@ + +V4L2_PIX_FMT_YUV422P ('422P')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_YUV422P ('422P')

Name

V4L2_PIX_FMT_YUV422P -- Format with ½ horizontal chroma resolution, +also known as YUV 4:2:2. Planar layout as opposed to +V4L2_PIX_FMT_YUYV

Description

This format is not commonly used. This is a planar +version of the YUYV format. The three components are separated into +three sub-images or planes. The Y plane is first. The Y plane has one +byte per pixel. The Cb plane immediately follows the Y plane in +memory. The Cb plane is half the width of the Y plane (and of the +image). Each Cb belongs to two pixels. For example, +Cb0 belongs to Y'00, +Y'01. Following the Cb plane is the Cr plane, +just like the Cb plane.

If the Y plane has pad bytes after each row, then the Cr +and Cb planes have half as many pad bytes after their rows. In other +words, two Cx rows (including padding) is exactly as long as one Y row +(including padding).

Example 2-1. V4L2_PIX_FMT_YUV422P 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Y'00Y'01Y'02Y'03
start + 4:Y'10Y'11Y'12Y'13
start + 8:Y'20Y'21Y'22Y'23
start + 12:Y'30Y'31Y'32Y'33
start + 16:Cb00Cb01  
start + 18:Cb10Cb11  
start + 20:Cb20Cb21  
start + 22:Cb30Cb31  
start + 24:Cr00Cr01  
start + 26:Cr10Cr11  
start + 28:Cr20Cr21  
start + 30:Cr30Cr31  

+

Color Sample Location.

 0 1 2 3
0YCY YCY
1YCY YCY
2YCY YCY
3YCY YCY

+


PrevHomeNext
V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9')UpV4L2_PIX_FMT_YUV411P ('411P')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5319.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5319.htm new file mode 100644 index 0000000000000000000000000000000000000000..19d36981e7cec0c13564f58eb3129b36cd1298c8 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5319.htm @@ -0,0 +1,542 @@ + +V4L2_PIX_FMT_YUV411P ('411P')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_YUV411P ('411P')

Name

V4L2_PIX_FMT_YUV411P -- Format with ¼ horizontal chroma resolution, +also known as YUV 4:1:1. Planar layout as opposed to +V4L2_PIX_FMT_Y41P

Description

This format is not commonly used. This is a planar +format similar to the 4:2:2 planar format except with half as many +chroma. The three components are separated into three sub-images or +planes. The Y plane is first. The Y plane has one byte per pixel. The +Cb plane immediately follows the Y plane in memory. The Cb plane is +¼ the width of the Y plane (and of the image). Each Cb belongs +to 4 pixels all on the same row. For example, +Cb0 belongs to Y'00, +Y'01, Y'02 and +Y'03. Following the Cb plane is the Cr plane, +just like the Cb plane.

If the Y plane has pad bytes after each row, then the Cr +and Cb planes have ¼ as many pad bytes after their rows. In +other words, four C x rows (including padding) is exactly as long as +one Y row (including padding).

Example 2-1. V4L2_PIX_FMT_YUV411P 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Y'00Y'01Y'02Y'03
start + 4:Y'10Y'11Y'12Y'13
start + 8:Y'20Y'21Y'22Y'23
start + 12:Y'30Y'31Y'32Y'33
start + 16:Cb00   
start + 17:Cb10   
start + 18:Cb20   
start + 19:Cb30   
start + 20:Cr00   
start + 21:Cr10   
start + 22:Cr20   
start + 23:Cr30   

+

Color Sample Location.

 0 1 2 3
0Y YCY Y
1Y YCY Y
2Y YCY Y
3Y YCY Y

+


PrevHomeNext
V4L2_PIX_FMT_YUV422P ('422P')UpV4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21')
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5470.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5470.htm new file mode 100644 index 0000000000000000000000000000000000000000..fab55f2458d6ca40f0d1b620289020a48b61195c --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r5470.htm @@ -0,0 +1,533 @@ + +V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21')
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21')

Name

V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV21 -- Formats with ½ horizontal and vertical +chroma resolution, also known as YUV 4:2:0. One luminance and one +chrominance plane with alternating chroma samples as opposed to +V4L2_PIX_FMT_YVU420

Description

These are two-plane versions of the YUV 4:2:0 format. +The three components are separated into two sub-images or planes. The +Y plane is first. The Y plane has one byte per pixel. For +V4L2_PIX_FMT_NV12, a combined CbCr plane +immediately follows the Y plane in memory. The CbCr plane is the same +width, in bytes, as the Y plane (and of the image), but is half as +tall in pixels. Each CbCr pair belongs to four pixels. For example, +Cb0/Cr0 belongs to +Y'00, Y'01, +Y'10, Y'11. +V4L2_PIX_FMT_NV21 is the same except the Cb and +Cr bytes are swapped, the CrCb plane starts with a Cr byte.

If the Y plane has pad bytes after each row, then the +CbCr plane has as many pad bytes after its rows.

Example 2-1. V4L2_PIX_FMT_NV12 4 × 4 +pixel image

Byte Order. Each cell is one byte. +

start + 0:Y'00Y'01Y'02Y'03
start + 4:Y'10Y'11Y'12Y'13
start + 8:Y'20Y'21Y'22Y'23
start + 12:Y'30Y'31Y'32Y'33
start + 16:Cb00Cr00Cb01Cr01
start + 20:Cb10Cr10Cb11Cr11

+

Color Sample Location.

 0 1 2 3
0Y Y Y Y
  C   C 
1Y Y Y Y
       
2Y Y Y Y
  C   C 
3Y Y Y Y

+


PrevHomeNext
V4L2_PIX_FMT_YUV411P ('411P')UpCompressed Formats
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7624.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7624.htm new file mode 100644 index 0000000000000000000000000000000000000000..61fd693ff3927f3850f0b64a70c2635d1d30f0a2 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7624.htm @@ -0,0 +1,396 @@ + +Function Reference
Video for Linux Two API Specification: Revision 0.24
PrevNext

I. Function Reference

Table of Contents
V4L2 close() -- Close a V4L2 device
V4L2 ioctl() -- Program a V4L2 device
ioctl VIDIOC_CROPCAP -- Information about the video cropping and scaling abilities
ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER -- Read or write hardware registers
ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD -- Execute an encoder command
ioctl VIDIOC_ENUMAUDIO -- Enumerate audio inputs
ioctl VIDIOC_ENUMAUDOUT -- Enumerate audio outputs
ioctl VIDIOC_ENUM_FMT -- Enumerate image formats
ioctl VIDIOC_ENUM_FRAMESIZES -- Enumerate frame sizes
ioctl VIDIOC_ENUM_FRAMEINTERVALS -- Enumerate frame intervals
ioctl VIDIOC_ENUMINPUT -- Enumerate video inputs
ioctl VIDIOC_ENUMOUTPUT -- Enumerate video outputs
ioctl VIDIOC_ENUMSTD -- Enumerate supported video standards
ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO -- Query or select the current audio input and its +attributes
ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT -- Query or select the current audio output
ioctl VIDIOC_G_CHIP_IDENT -- Identify the chips on a TV card
ioctl VIDIOC_G_CROP, VIDIOC_S_CROP -- Get or set the current cropping rectangle
ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL -- Get or set the value of a control
ioctl VIDIOC_G_ENC_INDEX -- Get meta data about a compressed video stream
ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, +VIDIOC_TRY_EXT_CTRLS -- Get or set the value of several controls, try control +values
ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF -- Get or set frame buffer overlay parameters
ioctl VIDIOC_G_FMT, VIDIOC_S_FMT, +VIDIOC_TRY_FMT -- Get or set the data format, try a format
ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY -- Get or set tuner or modulator radio +frequency
ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT -- Query or select the current video input
ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP -- 
ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR -- Get or set modulator attributes
ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT -- Query or select the current video output
ioctl VIDIOC_G_PARM, VIDIOC_S_PARM -- Get or set streaming parameters
ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY -- Query or request the access priority associated with a +file descriptor
ioctl VIDIOC_G_SLICED_VBI_CAP -- Query sliced VBI capabilities
ioctl VIDIOC_G_STD, VIDIOC_S_STD -- Query or select the video standard of the current input
ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER -- Get or set tuner attributes
ioctl VIDIOC_LOG_STATUS -- Log driver status information
ioctl VIDIOC_OVERLAY -- Start or stop video overlay
ioctl VIDIOC_QBUF, VIDIOC_DQBUF -- Exchange a buffer with the driver
ioctl VIDIOC_QUERYBUF -- Query the status of a buffer
ioctl VIDIOC_QUERYCAP -- Query device capabilities
ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU -- Enumerate controls and menu control items
ioctl VIDIOC_QUERYSTD -- Sense the video standard received by the current +input
ioctl VIDIOC_REQBUFS -- Initiate Memory Mapping or User Pointer I/O
ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF -- Start or stop streaming I/O
V4L2 mmap() -- Map device memory into application address space
V4L2 munmap() -- Unmap device memory
V4L2 open() -- Open a V4L2 device
V4L2 poll() -- Wait for some event on a file descriptor
V4L2 read() -- Read from a V4L2 device
V4L2 select() -- Synchronous I/O multiplexing
V4L2 write() -- Write to a V4L2 device

PrevHomeNext
RDS Interface V4L2 close()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7626.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7626.htm new file mode 100644 index 0000000000000000000000000000000000000000..e31c9efb8b081a9f7a25598b86314e7c6eca29da --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7626.htm @@ -0,0 +1,261 @@ + +V4L2 close()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 close()

Name

v4l2-close -- Close a V4L2 device

Synopsis

#include <unistd.h>

int close(int fd);

Arguments

fd

File descriptor returned by open().

Description

Closes the device. Any I/O in progress is terminated and +resources associated with the file descriptor are freed. However data +format parameters, current input or output, control values or other +properties remain unchanged.

Return Value

The function returns 0 on +success, -1 on failure and the +errno is set appropriately. Possible error +codes:

EBADF

fd is not a valid open file +descriptor.


PrevHomeNext
Function ReferenceUpV4L2 ioctl()
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7667.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7667.htm new file mode 100644 index 0000000000000000000000000000000000000000..1f71f56170d68c29172ceb264a54ee584a191392 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7667.htm @@ -0,0 +1,415 @@ + +V4L2 ioctl()
Video for Linux Two API Specification: Revision 0.24
PrevNext

V4L2 ioctl()

Name

v4l2-ioctl -- Program a V4L2 device

Synopsis

#include <sys/ioctl.h>

int ioctl(int fd, int request, void *argp);

Arguments

fd

File descriptor returned by open().

request

V4L2 ioctl request code as defined in the videodev.h header file, for example +VIDIOC_QUERYCAP.

argp

Pointer to a function parameter, usually a structure.

Description

The ioctl() function is used to program +V4L2 devices. The argument fd must be an open +file descriptor. An ioctl request has encoded +in it whether the argument is an input, output or read/write +parameter, and the size of the argument argp in +bytes. Macros and defines specifying V4L2 ioctl requests are located +in the videodev.h header file. +Applications should use their own copy, not include the version in the +kernel sources on the system they compile on. All V4L2 ioctl requests, +their respective function and parameters are specified in Reference I, Function Reference.

Return Value

On success the ioctl() function returns +0 and does not reset the +errno variable. On failure +-1 is returned, when the ioctl takes an +output or read/write parameter it remains unmodified, and the +errno variable is set appropriately. See below for +possible error codes. Generic errors like EBADF +or EFAULT are not listed in the sections +discussing individual ioctl requests.

Note ioctls may return undefined error codes. Since errors +may have side effects such as a driver reset applications should +abort on unexpected errors.

EBADF

fd is not a valid open file +descriptor.

EBUSY

The property cannot be changed right now. Typically +this error code is returned when I/O is in progress or the driver +supports multiple opens and another process locked the property.

EFAULT

argp references an inaccessible +memory area.

ENOTTY

fd is not associated with a +character special device.

EINVAL

The request or the data pointed +to by argp is not valid. This is a very common +error code, see the individual ioctl requests listed in Reference I, Function Reference for actual causes.

ENOMEM

Not enough physical or virtual memory was available to +complete the request.

ERANGE

The application attempted to set a control with the +VIDIOC_S_CTRL ioctl to a value which is out of bounds.


PrevHomeNext
V4L2 close()Upioctl VIDIOC_CROPCAP
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7771.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7771.htm new file mode 100644 index 0000000000000000000000000000000000000000..3993cedf382c5d9d8b8443b9d0daa053eca68cdc --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7771.htm @@ -0,0 +1,503 @@ + +ioctl VIDIOC_CROPCAP
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_CROPCAP

Name

VIDIOC_CROPCAP -- Information about the video cropping and scaling abilities

Synopsis

int ioctl(int fd, int request, struct v4l2_cropcap +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_CROPCAP

argp

Description

Applications use this function to query the cropping +limits, the pixel aspect of images and to calculate scale factors. +They set the type field of a v4l2_cropcap +structure to the respective buffer (stream) type and call the +VIDIOC_CROPCAP ioctl with a pointer to this +structure. Drivers fill the rest of the structure. The results are +constant except when switching the video standard. Remember this +switch can occur implicit when switching the video input or +output.

Table 1. struct v4l2_cropcap

enum v4l2_buf_typetypeType of the data stream, set by the application. +Only these types are valid here: +V4L2_BUF_TYPE_VIDEO_CAPTURE, +V4L2_BUF_TYPE_VIDEO_OUTPUT, +V4L2_BUF_TYPE_VIDEO_OVERLAY, and custom (driver +defined) types with code V4L2_BUF_TYPE_PRIVATE +and higher.
struct v4l2_rectboundsDefines the window within capturing or output is +possible, this may exclude for example the horizontal and vertical +blanking areas. The cropping rectangle cannot exceed these limits. +Width and height are defined in pixels, the driver writer is free to +choose origin and units of the coordinate system in the analog +domain.
struct v4l2_rectdefrectDefault cropping rectangle, it shall cover the +"whole picture". Assuming pixel aspect 1/1 this could be for example a +640 × 480 rectangle for NTSC, a +768 × 576 rectangle for PAL and SECAM centered over +the active picture area. The same co-ordinate system as for + bounds is used.
struct v4l2_fractpixelaspect

This is the pixel aspect (y / x) when no +scaling is applied, the ratio of the actual sampling +frequency and the frequency required to get square +pixels.

When cropping coordinates refer to square pixels, +the driver sets pixelaspect to 1/1. Other +common values are 54/59 for PAL and SECAM, 11/10 for NTSC sampled +according to [ITU BT.601].

Table 2. struct v4l2_rect

__s32leftHorizontal offset of the top, left corner of the +rectangle, in pixels.
__s32topVertical offset of the top, left corner of the +rectangle, in pixels.
__s32widthWidth of the rectangle, in pixels.
__s32heightHeight of the rectangle, in pixels. Width +and height cannot be negative, the fields are signed for +hysterical reasons.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_cropcap type is +invalid or the ioctl is not supported. This is not permitted for +video capture, output and overlay devices, which must support +VIDIOC_CROPCAP.


PrevHomeNext
V4L2 ioctl()Upioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7900.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7900.htm new file mode 100644 index 0000000000000000000000000000000000000000..7dc961cc2dd184525c86c4afa7fe06e76e10bf29 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r7900.htm @@ -0,0 +1,677 @@ + +ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER

Name

VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER -- Read or write hardware registers

Synopsis

int ioctl(int fd, int request, struct v4l2_register *argp);

int ioctl(int fd, int request, const struct v4l2_register +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER

argp

Description

Experimental: This is an experimental +interface and may change in the future.

For driver debugging purposes these ioctls allow test +applications to access hardware registers directly. Regular +applications should not use them.

Since writing or even reading registers can jeopardize the +system security, its stability and damage the hardware, both ioctls +require superuser privileges. Additionally the Linux kernel must be +compiled with the CONFIG_VIDEO_ADV_DEBUG option +to enable these ioctls.

To write a register applications must initialize all fields +of a struct v4l2_register and call +VIDIOC_DBG_S_REGISTER with a pointer to this +structure. The match_type and +match_chip fields select a chip on the TV +card, the reg field specifies a register +number and the val field the value to be +written into the register.

To read a register applications must initialize the +match_type, +match_chip and +reg fields, and call +VIDIOC_DBG_G_REGISTER with a pointer to this +structure. On success the driver stores the register value in the +val field. On failure the structure remains +unchanged.

When match_type is +V4L2_CHIP_MATCH_HOST, +match_chip selects the nth non-I2C chip +on the TV card. Drivers may also interpret +match_chip as a random ID, but we recommend +against that. The number zero always selects the host chip, e. g. the +chip connected to the PCI bus. You can find out which chips are +present with the VIDIOC_G_CHIP_IDENT ioctl.

When match_type is +V4L2_CHIP_MATCH_I2C_DRIVER, +match_chip contains a driver ID as defined +in the linux/i2c-id.h header file. For instance +I2C_DRIVERID_SAA7127 will match any chip +supported by the saa7127 driver, regardless of its I2C bus address. +When multiple chips supported by the same driver are present, the +effect of these ioctls is undefined. Again with the +VIDIOC_G_CHIP_IDENT ioctl you can find out which I2C chips are +present.

When match_type is +V4L2_CHIP_MATCH_I2C_ADDR, +match_chip selects a chip by its 7 bit I2C +bus address.

Success not guaranteed: Due to a flaw in the Linux I2C bus driver these ioctls may +return successfully without actually reading or writing a register. To +catch the most likely failure we recommend a VIDIOC_G_CHIP_IDENT +call confirming the presence of the selected I2C chip.

These ioctls are optional, not all drivers may support them. +However when a driver supports these ioctls it must also support +VIDIOC_G_CHIP_IDENT. Conversely it may support +VIDIOC_G_CHIP_IDENT but not these ioctls.

VIDIOC_DBG_G_REGISTER and +VIDIOC_DBG_S_REGISTER were introduced in Linux +2.6.21.

We recommended the v4l2-dbg +utility over calling these ioctls directly. It is available from the +LinuxTV v4l-dvb repository; see http://linuxtv.org/repo/ for +access instructions.

Table 1. struct v4l2_register

__u32match_typeSee Table 2 for a list of + possible types. 
__u32match_chipMatch a chip by this number, interpreted according +to the match_type field. 
__u64regA register number. 
__u64valThe value read from, or to be written into the +register. 

Table 2. Chip Match Types

V4L2_CHIP_MATCH_HOST0Match the nth chip on the card, zero for the + host chip. Does not match I2C chips.
V4L2_CHIP_MATCH_I2C_DRIVER1Match an I2C chip by its driver ID from the +linux/i2c-id.h header file.
V4L2_CHIP_MATCH_I2C_ADDR2Match a chip by its 7 bit I2C bus address.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The driver does not support this ioctl, or the kernel +was not compiled with the CONFIG_VIDEO_ADV_DEBUG +option, or the match_type is invalid, or the +selected chip or register does not exist.

EPERM

Insufficient permissions. Root privileges are required +to execute these ioctls.


PrevHomeNext
ioctl VIDIOC_CROPCAPUpioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8087.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8087.htm new file mode 100644 index 0000000000000000000000000000000000000000..a5521d7f14ecc04feeef7e1494bcb244740d4194 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8087.htm @@ -0,0 +1,569 @@ + +ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD

Name

VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD -- Execute an encoder command

Synopsis

int ioctl(int fd, int request, struct v4l2_encoder_cmd *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD

argp

Description

Experimental: This is an experimental +interface and may change in the future.

These ioctls control an audio/video (usually MPEG-) encoder. +VIDIOC_ENCODER_CMD sends a command to the +encoder, VIDIOC_TRY_ENCODER_CMD can be used to +try a command without actually executing it.

To send a command applications must initialize all fields of a + struct v4l2_encoder_cmd and call + VIDIOC_ENCODER_CMD or + VIDIOC_TRY_ENCODER_CMD with a pointer to this + structure.

The cmd field must contain the +command code. The flags field is currently +only used by the STOP command and contains one bit: If the +V4L2_ENC_CMD_STOP_AT_GOP_END flag is set, +encoding will continue until the end of the current Group +Of Pictures, otherwise it will stop immediately.

A read() call sends a START command to +the encoder if it has not been started yet. After a STOP command, +read() calls will read the remaining data +buffered by the driver. When the buffer is empty, +read() will return zero and the next +read() call will restart the encoder.

A close() call sends an immediate STOP +to the encoder, and all buffered data is discarded.

These ioctls are optional, not all drivers may support +them. They were introduced in Linux 2.6.21.

Table 1. struct v4l2_encoder_cmd

__u32cmdThe encoder command, see Table 2.
__u32flagsFlags to go with the command, see Table 3. If no flags are defined for +this command, drivers and applications must set this field to +zero.
__u32data[8]Reserved for future extensions. Drivers and +applications must set the array to zero.

Table 2. Encoder Commands

V4L2_ENC_CMD_START0Start the encoder. When the encoder is already +running or paused, this command does nothing. No flags are defined for +this command.
V4L2_ENC_CMD_STOP1Stop the encoder. When the +V4L2_ENC_CMD_STOP_AT_GOP_END flag is set, +encoding will continue until the end of the current Group +Of Pictures, otherwise encoding will stop immediately. +When the encoder is already stopped, this command does +nothing.
V4L2_ENC_CMD_PAUSE2Pause the encoder. When the encoder has not been +started yet, the driver will return an EPERM error code. When the encoder is +already paused, this command does nothing. No flags are defined for +this command.
V4L2_ENC_CMD_RESUME3Resume encoding after a PAUSE command. When the +encoder has not been started yet, the driver will return an EPERM error code. +When the encoder is already running, this command does nothing. No +flags are defined for this command.

Table 3. Encoder Command Flags

V4L2_ENC_CMD_STOP_AT_GOP_END0x0001Stop encoding at the end of the current Group Of +Pictures, rather than immediately.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The driver does not support this ioctl, or the +cmd field is invalid.

EPERM

The application sent a PAUSE or RESUME command when +the encoder was not running.


PrevHomeNext
ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTERUpioctl VIDIOC_ENUMAUDIO
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8242.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8242.htm new file mode 100644 index 0000000000000000000000000000000000000000..c025d10e1b1b952c5965b3534a7765ef73121491 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8242.htm @@ -0,0 +1,302 @@ + +ioctl VIDIOC_ENUMAUDIO
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENUMAUDIO

Name

VIDIOC_ENUMAUDIO -- Enumerate audio inputs

Synopsis

int ioctl(int fd, int request, struct v4l2_audio *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENUMAUDIO

argp

Description

To query the attributes of an audio input applications +initialize the index field and zero out the +reserved array of a struct v4l2_audio +and call the VIDIOC_ENUMAUDIO ioctl with a pointer +to this structure. Drivers fill the rest of the structure or return an +EINVAL error code when the index is out of bounds. To enumerate all audio +inputs applications shall begin at index zero, incrementing by one +until the driver returns EINVAL.

See ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO(2) for a description of +struct v4l2_audio.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The number of the audio input is out of bounds, or +there are no audio inputs at all and this ioctl is not +supported.


PrevHomeNext
ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMDUpioctl VIDIOC_ENUMAUDOUT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8304.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8304.htm new file mode 100644 index 0000000000000000000000000000000000000000..36e25df59fcc80b90813458f80db9abf65fd2960 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8304.htm @@ -0,0 +1,305 @@ + +ioctl VIDIOC_ENUMAUDOUT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENUMAUDOUT

Name

VIDIOC_ENUMAUDOUT -- Enumerate audio outputs

Synopsis

int ioctl(int fd, int request, struct v4l2_audioout *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENUMAUDOUT

argp

Description

To query the attributes of an audio output applications +initialize the index field and zero out the +reserved array of a struct v4l2_audioout and +call the VIDIOC_G_AUDOUT ioctl with a pointer +to this structure. Drivers fill the rest of the structure or return an +EINVAL error code when the index is out of bounds. To enumerate all audio +outputs applications shall begin at index zero, incrementing by one +until the driver returns EINVAL.

Note connectors on a TV card to loop back the received audio +signal to a sound card are not audio outputs in this sense.

See ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT(2) for a description of +struct v4l2_audioout.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The number of the audio output is out of bounds, or +there are no audio outputs at all and this ioctl is not +supported.


PrevHomeNext
ioctl VIDIOC_ENUMAUDIOUpioctl VIDIOC_ENUM_FMT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8367.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8367.htm new file mode 100644 index 0000000000000000000000000000000000000000..bbdfdee1528b63a4d829360d06583ae1a11cc688 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8367.htm @@ -0,0 +1,483 @@ + +ioctl VIDIOC_ENUM_FMT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENUM_FMT

Name

VIDIOC_ENUM_FMT -- Enumerate image formats

Synopsis

int ioctl(int fd, int request, struct v4l2_fmtdesc +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENUM_FMT

argp

Description

To enumerate image formats applications initialize the +type and index +field of struct v4l2_fmtdesc and call the +VIDIOC_ENUM_FMT ioctl with a pointer to this +structure. Drivers fill the rest of the structure or return an +EINVAL error code. All formats are enumerable by beginning at index zero and +incrementing by one until EINVAL is +returned.

Table 1. struct v4l2_fmtdesc

__u32indexNumber of the format in the enumeration, set by +the application. This is in no way related to the pixelformat field.
enum v4l2_buf_typetypeType of the data stream, set by the application. +Only these types are valid here: +V4L2_BUF_TYPE_VIDEO_CAPTURE, +V4L2_BUF_TYPE_VIDEO_OUTPUT, +V4L2_BUF_TYPE_VIDEO_OVERLAY, and custom (driver +defined) types with code V4L2_BUF_TYPE_PRIVATE +and higher.
__u32flagsSee Table 2
__u8description[32]Description of the format, a NUL-terminated ASCII +string. This information is intended for the user, for example: "YUV +4:2:2".
__u32pixelformatThe image format identifier. This is a +four character code as computed by the v4l2_fourcc() +macro:

#define v4l2_fourcc(a,b,c,d) (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))

Several image formats are already +defined by this specification in Chapter 2. Note these +codes are not the same as those used in the Windows world.

__u32reserved[4]Reserved for future extensions. Drivers must set +the array to zero.

Table 2. Image Format Description Flags

V4L2_FMT_FLAG_COMPRESSED0x0001This is a compressed format.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_fmtdesc type +is not supported or the index is out of +bounds.


PrevHomeNext
ioctl VIDIOC_ENUMAUDOUTUpioctl VIDIOC_ENUM_FRAMESIZES
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8494.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8494.htm new file mode 100644 index 0000000000000000000000000000000000000000..da66220f59a169a41427a2862d2c27d4ac34592d --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8494.htm @@ -0,0 +1,781 @@ + +ioctl VIDIOC_ENUM_FRAMESIZES
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENUM_FRAMESIZES

Name

VIDIOC_ENUM_FRAMESIZES -- Enumerate frame sizes

Synopsis

int ioctl(int fd, int request, struct v4l2_frmsizeenum *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENUM_FRAMESIZES

argp

Pointer to a struct v4l2_frmsizeenum that contains an index +and pixel format and receives a frame width and height.

Description

Experimental: This is an experimental +interface and may change in the future.

This ioctl allows applications to enumerate all frame sizes +(i. e. width and height in pixels) that the device supports for the +given pixel format.

The supported pixel formats can be obtained by using the +VIDIOC_ENUM_FMT function.

The return value and the content of the +v4l2_frmsizeenum.type field depend on the +type of frame sizes the device supports. Here are the semantics of the +function for the different cases:

  • Discrete: The function +returns success if the given index value (zero-based) is valid. The +application should increase the index by one for each call until +EINVAL is returned. The +v4l2_frmsizeenum.type field is set to +V4L2_FRMSIZE_TYPE_DISCRETE by the driver. Of the +union only the discrete member is +valid.

  • Step-wise: The function +returns success if the given index value is zero and +EINVAL for any other index value. The +v4l2_frmsizeenum.type field is set to +V4L2_FRMSIZE_TYPE_STEPWISE by the driver. Of the +union only the stepwise member is +valid.

  • Continuous: This is a +special case of the step-wise type above. The function returns success +if the given index value is zero and EINVAL for +any other index value. The +v4l2_frmsizeenum.type field is set to +V4L2_FRMSIZE_TYPE_CONTINUOUS by the driver. Of +the union only the stepwise member is valid +and the step_width and +step_height values are set to 1.

When the application calls the function with index zero, it +must check the type field to determine the +type of frame size enumeration the device supports. Only for the +V4L2_FRMSIZE_TYPE_DISCRETE type does it make +sense to increase the index value to receive more frame sizes.

Note that the order in which the frame sizes are returned +has no special meaning. In particular does it not say anything about +potential default format sizes.

Applications can assume that the enumeration data does not +change without any interaction from the application itself. This means +that the enumeration data is consistent if the application does not +perform any other ioctl calls while it runs the frame size +enumeration.

Structs

In the structs below, IN denotes a +value that has to be filled in by the application, +OUT denotes values that the driver fills in. The +application should zero out all members except for the +IN fields.

Table 1. struct v4l2_frmsize_discrete

__u32widthWidth of the frame [pixel].
__u32heightHeight of the frame [pixel].

Table 2. struct v4l2_frmsize_stepwise

__u32min_widthMinimum frame width [pixel].
__u32max_widthMaximum frame width [pixel].
__u32step_widthFrame width step size [pixel].
__u32min_heightMinimum frame height [pixel].
__u32max_heightMaximum frame height [pixel].
__u32step_heightFrame height step size [pixel].

Table 3. struct v4l2_frmsizeenum

__u32index IN: Index of the given frame size in the enumeration.
__u32pixel_format IN: Pixel format for which the frame sizes are enumerated.
__u32type OUT: Frame size type the device supports.
union  OUT: Frame size with the given index.
 struct v4l2_frmsize_discretediscrete 
 struct v4l2_frmsize_stepwisestepwise 
__u32reserved[2] Reserved space for future use.

Enums

Table 4. enum v4l2_frmsizetypes

V4L2_FRMSIZE_TYPE_DISCRETE1Discrete frame size.
V4L2_FRMSIZE_TYPE_CONTINUOUS2Continuous frame size.
V4L2_FRMSIZE_TYPE_STEPWISE3Step-wise defined frame size.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

See the description section above for a list of return +values that errno can have.


PrevHomeNext
ioctl VIDIOC_ENUM_FMTUpioctl VIDIOC_ENUM_FRAMEINTERVALS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8724.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8724.htm new file mode 100644 index 0000000000000000000000000000000000000000..6f0a2bb7ddec68b259a4300c95be031969eebd27 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8724.htm @@ -0,0 +1,744 @@ + +ioctl VIDIOC_ENUM_FRAMEINTERVALS
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENUM_FRAMEINTERVALS

Name

VIDIOC_ENUM_FRAMEINTERVALS -- Enumerate frame intervals

Synopsis

int ioctl(int fd, int request, struct v4l2_frmivalenum *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENUM_FRAMEINTERVALS

argp

Pointer to a struct v4l2_frmivalenum structure that +contains a pixel format and size and receives a frame interval.

Description

This ioctl allows applications to enumerate all frame +intervals that the device supports for the given pixel format and +frame size.

The supported pixel formats and frame sizes can be obtained +by using the VIDIOC_ENUM_FMT and VIDIOC_ENUM_FRAMESIZES +functions.

The return value and the content of the +v4l2_frmivalenum.type field depend on the +type of frame intervals the device supports. Here are the semantics of +the function for the different cases:

  • Discrete: The function +returns success if the given index value (zero-based) is valid. The +application should increase the index by one for each call until +EINVAL is returned. The `v4l2_frmivalenum.type` +field is set to `V4L2_FRMIVAL_TYPE_DISCRETE` by the driver. Of the +union only the `discrete` member is valid.

  • Step-wise: The function +returns success if the given index value is zero and +EINVAL for any other index value. The +v4l2_frmivalenum.type field is set to +V4L2_FRMIVAL_TYPE_STEPWISE by the driver. Of the +union only the stepwise member is +valid.

  • Continuous: This is a +special case of the step-wise type above. The function returns success +if the given index value is zero and EINVAL for +any other index value. The +v4l2_frmivalenum.type field is set to +V4L2_FRMIVAL_TYPE_CONTINUOUS by the driver. Of +the union only the stepwise member is valid +and the step value is set to 1.

When the application calls the function with index zero, it +must check the type field to determine the +type of frame interval enumeration the device supports. Only for the +V4L2_FRMIVAL_TYPE_DISCRETE type does it make +sense to increase the index value to receive more frame +intervals.

Note that the order in which the frame intervals are +returned has no special meaning. In particular does it not say +anything about potential default frame intervals.

Applications can assume that the enumeration data does not +change without any interaction from the application itself. This means +that the enumeration data is consistent if the application does not +perform any other ioctl calls while it runs the frame interval +enumeration.

Notes

  • Frame intervals and frame +rates: The V4L2 API uses frame intervals instead of frame +rates. Given the frame interval the frame rate can be computed as +follows:

    frame_rate = 1 / frame_interval

Structs

In the structs below, IN denotes a +value that has to be filled in by the application, +OUT denotes values that the driver fills in. The +application should zero out all members except for the +IN fields.

Table 1. struct v4l2_frmival_stepwise

struct v4l2_fractminMinimum frame interval [s].
struct v4l2_fractmaxMaximum frame interval [s].
struct v4l2_fractstepFrame interval step size [s].

Table 2. struct v4l2_frmivalenum

__u32index IN: Index of the given frame interval in the +enumeration.
__u32pixel_format IN: Pixel format for which the frame intervals are +enumerated.
__u32width IN: Frame width for which the frame intervals are +enumerated.
__u32height IN: Frame height for which the frame intervals are +enumerated.
__u32type OUT: Frame interval type the device supports.
union  OUT: Frame interval with the given index.
 struct v4l2_fractdiscreteFrame interval [s].
 struct v4l2_frmival_stepwisestepwise 
__u32reserved[2] Reserved space for future use.

Enums

Table 3. enum v4l2_frmivaltypes

V4L2_FRMIVAL_TYPE_DISCRETE1Discrete frame interval.
V4L2_FRMIVAL_TYPE_CONTINUOUS2Continuous frame interval.
V4L2_FRMIVAL_TYPE_STEPWISE3Step-wise defined frame interval.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

See the description section above for a list of return +values that errno can have.


PrevHomeNext
ioctl VIDIOC_ENUM_FRAMESIZESUpioctl VIDIOC_ENUMINPUT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8936.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8936.htm new file mode 100644 index 0000000000000000000000000000000000000000..f5dced22678958e98c15abca7049daceb5cff20a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r8936.htm @@ -0,0 +1,704 @@ + +ioctl VIDIOC_ENUMINPUT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENUMINPUT

Name

VIDIOC_ENUMINPUT -- Enumerate video inputs

Synopsis

int ioctl(int fd, int request, struct v4l2_input +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENUMINPUT

argp

Description

To query the attributes of a video input applications +initialize the index field of struct v4l2_input +and call the VIDIOC_ENUMINPUT ioctl with a +pointer to this structure. Drivers fill the rest of the structure or +return an EINVAL error code when the index is out of bounds. To enumerate all +inputs applications shall begin at index zero, incrementing by one +until the driver returns EINVAL.

Table 1. struct v4l2_input

__u32indexIdentifies the input, set by the +application.
__u8name[32]Name of the video input, a NUL-terminated ASCII +string, for example: "Vin (Composite 2)". This information is intended +for the user, preferably the connector label on the device itself.
__u32typeType of the input, see Table 2.
__u32audioset

Drivers can enumerate up to 32 video and +audio inputs. This field shows which audio inputs were selectable as +audio source if this was the currently selected video input. It is a +bit mask. The LSB corresponds to audio input 0, the MSB to input 31. +Any number of bits can be set, or none.

When the driver +does not enumerate audio inputs no bits must be set. Applications +shall not interpret this as lack of audio support. Some drivers +automatically select audio sources and do not enumerate them since +there is no choice anyway.

For details on audio inputs and +how to select the current input see Section 1.5.

__u32tunerCapture devices can have zero or more tuners (RF +demodulators). When the type is set to +V4L2_INPUT_TYPE_TUNER this is an RF connector and +this field identifies the tuner. It corresponds to +struct v4l2_tuner field index. For details on +tuners see Section 1.6.
v4l2_std_idstdEvery video input supports one or more different +video standards. This field is a set of all supported standards. For +details on video standards and how to switch see Section 1.7.
__u32statusThis field provides status information about the +input. See Table 3 for flags. +status is only valid when this is the +current input.
__u32reserved[4]Reserved for future extensions. Drivers must set +the array to zero.

Table 2. Input Types

V4L2_INPUT_TYPE_TUNER1This input uses a tuner (RF demodulator).
V4L2_INPUT_TYPE_CAMERA2Analog baseband input, for example CVBS / +Composite Video, S-Video, RGB.

Table 3. Input Status Flags

General
V4L2_IN_ST_NO_POWER0x00000001Attached device is off.
V4L2_IN_ST_NO_SIGNAL0x00000002 
V4L2_IN_ST_NO_COLOR0x00000004The hardware supports color decoding, but does not +detect color modulation in the signal.
Analog Video
V4L2_IN_ST_NO_H_LOCK0x00000100No horizontal sync lock.
V4L2_IN_ST_COLOR_KILL0x00000200A color killer circuit automatically disables color +decoding when it detects no color modulation. When this flag is set +the color killer is enabled and has shut off +color decoding.
Digital Video
V4L2_IN_ST_NO_SYNC0x00010000No synchronization lock.
V4L2_IN_ST_NO_EQU0x00020000No equalizer lock.
V4L2_IN_ST_NO_CARRIER0x00040000Carrier recovery failed.
VCR and Set-Top Box
V4L2_IN_ST_MACROVISION0x01000000Macrovision is an analog copy prevention system +mangling the video signal to confuse video recorders. When this +flag is set Macrovision has been detected.
V4L2_IN_ST_NO_ACCESS0x02000000Conditional access denied.
V4L2_IN_ST_VTR0x04000000VTR time constant. [?]

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_input index is +out of bounds.


PrevHomeNext
ioctl VIDIOC_ENUM_FRAMEINTERVALSUpioctl VIDIOC_ENUMOUTPUT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9149.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9149.htm new file mode 100644 index 0000000000000000000000000000000000000000..093664272e8f857bcd7d7a7512216f60b916bd60 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9149.htm @@ -0,0 +1,511 @@ + +ioctl VIDIOC_ENUMOUTPUT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENUMOUTPUT

Name

VIDIOC_ENUMOUTPUT -- Enumerate video outputs

Synopsis

int ioctl(int fd, int request, struct v4l2_output *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENUMOUTPUT

argp

Description

To query the attributes of a video outputs applications +initialize the index field of struct v4l2_output +and call the VIDIOC_ENUMOUTPUT ioctl with a +pointer to this structure. Drivers fill the rest of the structure or +return an EINVAL error code when the index is out of bounds. To enumerate all +outputs applications shall begin at index zero, incrementing by one +until the driver returns EINVAL.

Table 1. struct v4l2_output

__u32indexIdentifies the output, set by the +application.
__u8name[32]Name of the video output, a NUL-terminated ASCII +string, for example: "Vout". This information is intended for the +user, preferably the connector label on the device itself.
__u32typeType of the output, see Table 2.
__u32audioset

Drivers can enumerate up to 32 video and +audio outputs. This field shows which audio outputs were +selectable as the current output if this was the currently selected +video output. It is a bit mask. The LSB corresponds to audio output 0, +the MSB to output 31. Any number of bits can be set, or +none.

When the driver does not enumerate audio outputs no +bits must be set. Applications shall not interpret this as lack of +audio support. Drivers may automatically select audio outputs without +enumerating them.

For details on audio outputs and how to +select the current output see Section 1.5.

__u32modulatorOutput devices can have zero or more RF modulators. +When the type is +V4L2_OUTPUT_TYPE_MODULATOR this is an RF +connector and this field identifies the modulator. It corresponds to +struct v4l2_modulator field index. For details +on modulators see Section 1.6.
v4l2_std_idstdEvery video output supports one or more different +video standards. This field is a set of all supported standards. For +details on video standards and how to switch see Section 1.7.
__u32reserved[4]Reserved for future extensions. Drivers must set +the array to zero.

Table 2. Output Type

V4L2_OUTPUT_TYPE_MODULATOR1This output is an analog TV modulator.
V4L2_OUTPUT_TYPE_ANALOG2Analog baseband output, for example Composite / +CVBS, S-Video, RGB.
V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY3[?]

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_output index +is out of bounds.


PrevHomeNext
ioctl VIDIOC_ENUMINPUTUpioctl VIDIOC_ENUMSTD
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9288.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9288.htm new file mode 100644 index 0000000000000000000000000000000000000000..d68603fb275cf213e05343869b587610b79f8331 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9288.htm @@ -0,0 +1,942 @@ + +ioctl VIDIOC_ENUMSTD
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_ENUMSTD

Name

VIDIOC_ENUMSTD -- Enumerate supported video standards

Synopsis

int ioctl(int fd, int request, struct v4l2_standard *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_ENUMSTD

argp

Description

To query the attributes of a video standard, +especially a custom (driver defined) one, applications initialize the +index field of struct v4l2_standard and call the +VIDIOC_ENUMSTD ioctl with a pointer to this +structure. Drivers fill the rest of the structure or return an +EINVAL error code when the index is out of bounds. To enumerate all standards +applications shall begin at index zero, incrementing by one until the +driver returns EINVAL. Drivers may enumerate a +different set of standards after switching the video input or +output.[1]

Table 1. struct v4l2_standard

__u32indexNumber of the video standard, set by the +application.
v4l2_std_ididThe bits in this field identify the standard as +one of the common standards listed in Table 3, +or if bits 32 to 63 are set as custom standards. Multiple bits can be +set if the hardware does not distinguish between these standards, +however separate indices do not indicate the opposite. The +id must be unique. No other enumerated +v4l2_standard structure, for this input or +output anyway, can contain the same set of bits.
__u8name[24]Name of the standard, a NUL-terminated ASCII +string, for example: "PAL-B/G", "NTSC Japan". This information is +intended for the user.
struct v4l2_fractframeperiodThe frame period (not field period) is numerator +/ denominator. For example M/NTSC has a frame period of 1001 / +30000 seconds.
__u32framelinesTotal lines per frame including blanking, +e. g. 625 for B/PAL.
__u32reserved[4]Reserved for future extensions. Drivers must set +the array to zero.

Table 2. struct v4l2_fract

__u32numerator 
__u32denominator 

Table 3. typedef v4l2_std_id

__u64v4l2_std_idThis type is a set, each bit representing another +video standard as listed below and in Table 4. The 32 most significant bits are reserved +for custom (driver defined) video standards.

#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
+#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
+#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
+#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
+#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
+#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
+#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
+#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
+
+#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
+#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
+#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
+#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)

V4L2_STD_PAL_60 is +a hybrid standard with 525 lines, 60 Hz refresh rate, and PAL color +modulation with a 4.43 MHz color subcarrier. Some PAL video recorders +can play back NTSC tapes in this mode for display on a 50/60 Hz agnostic +PAL TV.

#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
+#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
+#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)

V4L2_STD_NTSC_443 +is a hybrid standard with 525 lines, 60 Hz refresh rate, and NTSC +color modulation with a 4.43 MHz color +subcarrier.

#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
+
+#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
+#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
+#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
+#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
+#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
+#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
+#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
+#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
+
+/* ATSC/HDTV */
+#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
+#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)

V4L2_STD_ATSC_8_VSB and +V4L2_STD_ATSC_16_VSB are U.S. terrestrial digital +TV standards. Presently the V4L2 API does not support digital TV. See +also the Linux DVB API at http://linuxtv.org.

#define V4L2_STD_PAL_BG         (V4L2_STD_PAL_B         |\
+                                 V4L2_STD_PAL_B1        |\
+                                 V4L2_STD_PAL_G)
+#define V4L2_STD_B              (V4L2_STD_PAL_B         |\
+                                 V4L2_STD_PAL_B1        |\
+                                 V4L2_STD_SECAM_B)
+#define V4L2_STD_GH             (V4L2_STD_PAL_G         |\
+                                 V4L2_STD_PAL_H         |\
+                                 V4L2_STD_SECAM_G       |\
+                                 V4L2_STD_SECAM_H)
+#define V4L2_STD_PAL_DK         (V4L2_STD_PAL_D         |\
+                                 V4L2_STD_PAL_D1        |\
+                                 V4L2_STD_PAL_K)
+#define V4L2_STD_PAL            (V4L2_STD_PAL_BG        |\
+                                 V4L2_STD_PAL_DK        |\
+                                 V4L2_STD_PAL_H         |\
+                                 V4L2_STD_PAL_I)
+#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M        |\
+                                 V4L2_STD_NTSC_M_JP     |\
+                                 V4L2_STD_NTSC_M_KR)
+#define V4L2_STD_MN             (V4L2_STD_PAL_M         |\
+                                 V4L2_STD_PAL_N         |\
+                                 V4L2_STD_PAL_Nc        |\
+                                 V4L2_STD_NTSC)
+#define V4L2_STD_SECAM_DK       (V4L2_STD_SECAM_D       |\
+                                 V4L2_STD_SECAM_K       |\
+                                 V4L2_STD_SECAM_K1)
+#define V4L2_STD_DK             (V4L2_STD_PAL_DK        |\
+                                 V4L2_STD_SECAM_DK)
+
+#define V4L2_STD_SECAM          (V4L2_STD_SECAM_B       |\
+                                 V4L2_STD_SECAM_G       |\
+                                 V4L2_STD_SECAM_H       |\
+                                 V4L2_STD_SECAM_DK      |\
+                                 V4L2_STD_SECAM_L       |\
+                                 V4L2_STD_SECAM_LC)
+
+#define V4L2_STD_525_60         (V4L2_STD_PAL_M         |\
+                                 V4L2_STD_PAL_60        |\
+                                 V4L2_STD_NTSC          |\
+                                 V4L2_STD_NTSC_443)
+#define V4L2_STD_625_50         (V4L2_STD_PAL           |\
+                                 V4L2_STD_PAL_N         |\
+                                 V4L2_STD_PAL_Nc        |\
+                                 V4L2_STD_SECAM)
+
+#define V4L2_STD_UNKNOWN        0
+#define V4L2_STD_ALL            (V4L2_STD_525_60        |\
+                                 V4L2_STD_625_50)

Table 4. Video Standards (based on [ITU BT.470])

Characteristics

M/NTSCa

M/PAL

N/PALb

B, B1, G/PALD, D1, K/PALH/PALI/PALB, G/SECAMD, K/SECAMK1/SECAML/SECAM
Frame lines525625
Frame period (s)1001/300001/25
Chrominance sub-carrier frequency (Hz)3579545 ± 103579611.49 ± 104433618.75 ± 5 (3582056.25 +± 5)4433618.75 ± 54433618.75 ± 1fOR = +4406250 ± 2000, fOB = 4250000 +± 2000
Nominal radio-frequency channel bandwidth +(MHz)666B: 7; B1, G: 88888888
Sound carrier relative to vision carrier +(MHz)+ 4.5+ 4.5+ 4.5

+ 5.5 ± 0.001 +c d e f

+ 6.5 ± 0.001+ 5.5+ 5.9996 ± 0.0005+ 5.5 ± 0.001+ 6.5 ± 0.001+ 6.5

+ 6.5 g

Notes:
a. Japan uses a standard +similar to M/NTSC +(V4L2_STD_NTSC_M_JP).
b. The values in +brackets apply to the combination N/PAL a.k.a. +NC used in Argentina +(V4L2_STD_PAL_Nc).
c. In the Federal Republic of Germany, Austria, Italy, +the Netherlands, Slovakia and Switzerland a system of two sound +carriers is used, the frequency of the second carrier being +242.1875 kHz above the frequency of the first sound carrier. For +stereophonic sound transmissions a similar system is used in +Australia.
d. New Zealand uses a sound +carrier displaced 5.4996 ± 0.0005 MHz from the vision +carrier.
e. In Denmark, Finland, New +Zealand, Sweden and Spain a system of two sound carriers is used. In +Iceland, Norway and Poland the same system is being introduced. The +second carrier is 5.85 MHz above the vision carrier and is DQPSK +modulated with 728 kbit/s sound and data multiplex. (NICAM +system)
f. In the United Kingdom, a +system of two sound carriers is used. The second sound carrier is +6.552 MHz above the vision carrier and is DQPSK modulated with a +728 kbit/s sound and data multiplex able to carry two sound +channels. (NICAM system)
g. In France, a +digital carrier 5.85 MHz away from the vision carrier may be used in +addition to the main sound carrier. It is modulated in differentially +encoded QPSK with a 728 kbit/s sound and data multiplexer capable of +carrying two sound channels. (NICAM +system)

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The struct v4l2_standard index +is out of bounds.

Notes

[1]

The supported standards may overlap and we need an +unambiguous set to find the current standard returned by +VIDIOC_G_STD.


PrevHomeNext
ioctl VIDIOC_ENUMOUTPUTUpioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9539.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9539.htm new file mode 100644 index 0000000000000000000000000000000000000000..885606c7e95d53516ed4e1fce5fb43830e957ed3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9539.htm @@ -0,0 +1,537 @@ + +ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO

Name

VIDIOC_G_AUDIO, VIDIOC_S_AUDIO -- Query or select the current audio input and its +attributes

Synopsis

int ioctl(int fd, int request, struct v4l2_audio *argp);

int ioctl(int fd, int request, const struct v4l2_audio *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_AUDIO, VIDIOC_S_AUDIO

argp

Description

To query the current audio input applications zero out the +reserved array of a struct v4l2_audio +and call the VIDIOC_G_AUDIO ioctl with a pointer +to this structure. Drivers fill the rest of the structure or return an +EINVAL error code when the device has no audio inputs, or none which combine +with the current video input.

Audio inputs have one writable property, the audio mode. To +select the current audio input and change the +audio mode, applications initialize the +index and mode +fields, and the +reserved array of a +v4l2_audio structure and call the +VIDIOC_S_AUDIO ioctl. Drivers may switch to a +different audio mode if the request cannot be satisfied. However, this +is a write-only ioctl, it does not return the actual new audio +mode.

Table 1. struct v4l2_audio

__u32indexIdentifies the audio input, set by the +driver or application.
__u8name[32]Name of the audio input, a NUL-terminated ASCII +string, for example: "Line In". This information is intended for the +user, preferably the connector label on the device itself.
__u32capabilityAudio capability flags, see Table 2.
__u32modeAudio mode flags set by drivers and applications (on + VIDIOC_S_AUDIO ioctl), see Table 3.
__u32reserved[2]Reserved for future extensions. Drivers and +applications must set the array to zero.

Table 2. Audio Capability Flags

V4L2_AUDCAP_STEREO0x00001This is a stereo input. The flag is intended to +automatically disable stereo recording etc. when the signal is always +monaural. The API provides no means to detect if stereo is +received, unless the audio input belongs to a +tuner.
V4L2_AUDCAP_AVL0x00002Automatic Volume Level mode is supported.

Table 3. Audio Mode Flags

V4L2_AUDMODE_AVL0x00001AVL mode is on.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

No audio inputs combine with the current video input, +or the number of the selected audio input is out of bounds or it does +not combine, or there are no audio inputs at all and the ioctl is not +supported.

EBUSY

I/O is in progress, the input cannot be +switched.


PrevHomeNext
ioctl VIDIOC_ENUMSTDUpioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9688.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9688.htm new file mode 100644 index 0000000000000000000000000000000000000000..e9fe165e1a7845258cf28aa960f915a29ec9a940 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9688.htm @@ -0,0 +1,439 @@ + +ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT

Name

VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT -- Query or select the current audio output

Synopsis

int ioctl(int fd, int request, struct v4l2_audioout *argp);

int ioctl(int fd, int request, const struct v4l2_audioout *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT

argp

Description

To query the current audio output applications zero out the +reserved array of a struct v4l2_audioout and +call the VIDIOC_G_AUDOUT ioctl with a pointer +to this structure. Drivers fill the rest of the structure or return an +EINVAL error code when the device has no audio inputs, or none which combine +with the current video output.

Audio outputs have no writable properties. Nevertheless, to +select the current audio output applications can initialize the +index field and +reserved array (which in the future may +contain writable properties) of a +v4l2_audioout structure and call the +VIDIOC_S_AUDOUT ioctl. Drivers switch to the +requested output or return the EINVAL error code when the index is out of +bounds. This is a write-only ioctl, it does not return the current +audio output attributes as VIDIOC_G_AUDOUT +does.

Note connectors on a TV card to loop back the received audio +signal to a sound card are not audio outputs in this sense.

Table 1. struct v4l2_audioout

__u32indexIdentifies the audio output, set by the +driver or application.
__u8name[32]Name of the audio output, a NUL-terminated ASCII +string, for example: "Line Out". This information is intended for the +user, preferably the connector label on the device itself.
__u32capabilityAudio capability flags, none defined yet. Drivers +must set this field to zero.
__u32modeAudio mode, none defined yet. Drivers and +applications (on VIDIOC_S_AUDOUT) must set this +field to zero.
__u32reserved[2]Reserved for future extensions. Drivers and +applications must set the array to zero.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

No audio outputs combine with the current video +output, or the number of the selected audio output is out of bounds or +it does not combine, or there are no audio outputs at all and the +ioctl is not supported.

EBUSY

I/O is in progress, the output cannot be +switched.


PrevHomeNext
ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIOUpioctl VIDIOC_G_CHIP_IDENT
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9804.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9804.htm new file mode 100644 index 0000000000000000000000000000000000000000..45c7af308f2ce6f1031c1965d62eab9517ce2b13 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9804.htm @@ -0,0 +1,687 @@ + +ioctl VIDIOC_G_CHIP_IDENT
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_CHIP_IDENT

Name

VIDIOC_G_CHIP_IDENT -- Identify the chips on a TV card

Synopsis

int ioctl(int fd, int request, struct v4l2_chip_ident +*argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_CHIP_IDENT

argp

Description

Experimental: This is an experimental interface and may change in +the future.

For driver debugging purposes this ioctl allows test +applications to query the driver about the chips present on the TV +card. Regular applications should not use it. When you found a chip +specific bug, please contact the Video4Linux mailing list (https://listman.redhat.com/mailman/listinfo/video4linux-list) +so it can be fixed.

To query the driver applications must initialize the +match_type and +match_chip fields of a struct v4l2_chip_ident +and call VIDIOC_G_CHIP_IDENT with a pointer to +this structure. On success the driver stores information about the +selected chip in the ident and +revision fields. On failure the structure +remains unchanged.

When match_type is +V4L2_CHIP_MATCH_HOST, +match_chip selects the nth non-I2C chip +on the TV card. You can enumerate all chips by starting at zero and +incrementing match_chip by one until +VIDIOC_G_CHIP_IDENT fails with an EINVAL error code. +Drivers may also interpret match_chip as a +random ID, but we recommend against that. The number zero always +selects the host chip, e. g. the chip connected to the PCI bus.

When match_type is +V4L2_CHIP_MATCH_I2C_DRIVER, +match_chip contains a driver ID as defined +in the linux/i2c-id.h header file. For instance +I2C_DRIVERID_SAA7127 will match any chip +supported by the saa7127 driver, regardless of its I2C bus address. +When multiple chips supported by the same driver are present, the +ioctl will return V4L2_IDENT_AMBIGUOUS in the +ident field.

When match_type is +V4L2_CHIP_MATCH_I2C_ADDR, +match_chip selects a chip by its 7 bit +I2C bus address.

On success, the ident field will +contain a chip ID from the Linux +media/v4l2-chip-ident.h header file, and the +revision field will contain a driver +specific value, or zero if no particular revision is associated with +this chip.

When the driver could not identify the selected chip, +ident will contain +V4L2_IDENT_UNKNOWN. When no chip matched +match_type and +match_chip, the ioctl will succeed but the +ident field will contain +V4L2_IDENT_NONE. If multiple chips matched, +ident will contain +V4L2_IDENT_AMBIGUOUS. In all these cases the +revision field remains unchanged.

This ioctl is optional, not all drivers may support it. It +was introduced in Linux 2.6.21.

We recommended the v4l2-dbg +utility over calling this ioctl directly. It is available from the +LinuxTV v4l-dvb repository; see http://linuxtv.org/repo/ for +access instructions.

Table 1. struct v4l2_chip_ident

__u32match_typeSee Table 2 for a list of +possible types.
__u32match_chipMatch a chip by this number, interpreted according +to the match_type field.
__u32identA chip identifier as defined in the Linux +media/v4l2-chip-ident.h header file, or one of +the values from Table 3.
__u32revisionA chip revision, chip and driver specific.

Table 2. Chip Match Types

V4L2_CHIP_MATCH_HOST0Match the nth chip on the card, zero for the + host chip. Does not match I2C chips.
V4L2_CHIP_MATCH_I2C_DRIVER1Match an I2C chip by its driver ID from the +linux/i2c-id.h header file.
V4L2_CHIP_MATCH_I2C_ADDR2Match a chip by its 7 bit I2C bus address.

Table 3. Chip Identifiers

V4L2_IDENT_NONE0No chip matched.
V4L2_IDENT_AMBIGUOUS1Multiple chips matched.
V4L2_IDENT_UNKNOWN2A chip is present at this address, but the driver +could not identify it.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

The driver does not support this ioctl, or the +match_type is invalid.


PrevHomeNext
ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUTUpioctl VIDIOC_G_CROP, VIDIOC_S_CROP
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9994.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9994.htm new file mode 100644 index 0000000000000000000000000000000000000000..c46db3f224401cfbd47a653d34ec0b20aafab76f --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/r9994.htm @@ -0,0 +1,440 @@ + +ioctl VIDIOC_G_CROP, VIDIOC_S_CROP
Video for Linux Two API Specification: Revision 0.24
PrevNext

ioctl VIDIOC_G_CROP, VIDIOC_S_CROP

Name

VIDIOC_G_CROP, VIDIOC_S_CROP -- Get or set the current cropping rectangle

Synopsis

int ioctl(int fd, int request, struct v4l2_crop *argp);

int ioctl(int fd, int request, const struct v4l2_crop *argp);

Arguments

fd

File descriptor returned by open().

request

VIDIOC_G_CROP, VIDIOC_S_CROP

argp

Description

To query the cropping rectangle size and position +applications set the type field of a +v4l2_crop structure to the respective buffer +(stream) type and call the VIDIOC_G_CROP ioctl +with a pointer to this structure. The driver fills the rest of the +structure or returns the EINVAL error code if cropping is not supported.

To change the cropping rectangle applications initialize the +type and struct v4l2_rect substructure named +c of a v4l2_crop structure and call the +VIDIOC_S_CROP ioctl with a pointer to this +structure.

The driver first adjusts the requested dimensions against +hardware limits, i. e. the bounds given by the capture/output window, +and it rounds to the closest possible values of horizontal and +vertical offset, width and height. In particular the driver must round +the vertical offset of the cropping rectangle to frame lines modulo +two, such that the field order cannot be confused.

Second the driver adjusts the image size (the opposite +rectangle of the scaling process, source or target depending on the +data direction) to the closest size possible while maintaining the +current horizontal and vertical scaling factor.

Finally the driver programs the hardware with the actual +cropping and image parameters. VIDIOC_S_CROP is a +write-only ioctl, it does not return the actual parameters. To query +them applications must call VIDIOC_G_CROP and +VIDIOC_G_FMT. When the parameters are unsuitable the application may +modify the cropping or image parameters and repeat the cycle until +satisfactory parameters have been negotiated.

When cropping is not supported then no parameters are +changed and VIDIOC_S_CROP returns the +EINVAL error code.

Table 1. struct v4l2_crop

enum v4l2_buf_typetypeType of the data stream, set by the application. +Only these types are valid here: V4L2_BUF_TYPE_VIDEO_CAPTURE, +V4L2_BUF_TYPE_VIDEO_OUTPUT, +V4L2_BUF_TYPE_VIDEO_OVERLAY, and custom (driver +defined) types with code V4L2_BUF_TYPE_PRIVATE +and higher.
struct v4l2_rectcCropping rectangle. The same co-ordinate system as +for struct v4l2_cropcap bounds is used.

Return Value

On success 0 is returned, on error -1 and the errno variable is set appropriately:

EINVAL

Cropping is not supported.


PrevHomeNext
ioctl VIDIOC_G_CHIP_IDENTUpioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x15446.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x15446.htm new file mode 100644 index 0000000000000000000000000000000000000000..3c1f3a653ff45c08eb8adce4dcd97ca1103a7258 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x15446.htm @@ -0,0 +1,3549 @@ + +Changes of the V4L2 API
Video for Linux Two API Specification: Revision 0.24
PrevChapter 6. ChangesNext

6.2. Changes of the V4L2 API

Soon after the V4L API was added to the kernel it was +criticised as too inflexible. In August 1998 Bill Dirks proposed a +number of improvements and began to work on documentation, example +drivers and applications. With the help of other volunteers this +eventually became the V4L2 API, not just an extension but a +replacement for the V4L API. However it took another four years and +two stable kernel releases until the new API was finally accepted for +inclusion into the kernel in its present form.

6.2.1. Early Versions

1998-08-20: First version.

1998-08-27: The select() function was introduced.

1998-09-10: New video standard interface.

1998-09-18: The VIDIOC_NONCAP ioctl +was replaced by the otherwise meaningless O_TRUNC +open() flag, and the aliases O_NONCAP and +O_NOIO were defined. Applications can set this +flag if they intend to access controls only, as opposed to capture +applications which need exclusive access. The +VIDEO_STD_XXX identifiers are now ordinals +instead of flags, and the video_std_construct() +helper function takes id and transmission arguments.

1998-09-28: Revamped video standard. Made video controls +individually enumerable.

1998-10-02: The id field was +removed from struct video_standard and the +color subcarrier fields were renamed. The VIDIOC_QUERYSTD ioctl was +renamed to VIDIOC_ENUMSTD, VIDIOC_G_INPUT to VIDIOC_ENUMINPUT. A +first draft of the Codec API was released.

1998-11-08: Many minor changes. Most symbols have been +renamed. Some material changes to struct v4l2_capability.

1998-11-12: The read/write directon of some ioctls was misdefined.

1998-11-14: V4L2_PIX_FMT_RGB24 +changed to V4L2_PIX_FMT_BGR24, and +V4L2_PIX_FMT_RGB32 changed to +V4L2_PIX_FMT_BGR32. Audio controls are now +accessible with the VIDIOC_G_CTRL and VIDIOC_S_CTRL ioctls under +names starting with V4L2_CID_AUDIO. The +V4L2_MAJOR define was removed from +videodev.h since it was only used once in the +videodev kernel module. The +YUV422 and YUV411 planar +image formats were added.

1998-11-28: A few ioctl symbols changed. Interfaces for codecs and +video output devices were added.

1999-01-14: A raw VBI capture interface was added.

1999-01-19: The VIDIOC_NEXTBUF ioctl + was removed.

6.2.2. V4L2 Version 0.16 1999-01-31

1999-01-27: There is now one QBUF ioctl, VIDIOC_QWBUF and VIDIOC_QRBUF +are gone. VIDIOC_QBUF takes a v4l2_buffer as a parameter. Added +digital zoom (cropping) controls.

6.2.3. V4L2 Version 0.18 1999-03-16

Added a v4l to V4L2 ioctl compatibility layer to +videodev.c. Driver writers, this changes how you implement your ioctl +handler. See the Driver Writer's Guide. Added some more control id +codes.

6.2.4. V4L2 Version 0.19 1999-06-05

1999-03-18: Fill in the category and catname fields of +v4l2_queryctrl objects before passing them to the driver. Required a +minor change to the VIDIOC_QUERYCTRL handlers in the sample +drivers.

1999-03-31: Better compatibility for v4l memory capture +ioctls. Requires changes to drivers to fully support new compatibility +features, see Driver Writer's Guide and v4l2cap.c. Added new control +IDs: V4L2_CID_HFLIP, _VFLIP. Changed V4L2_PIX_FMT_YUV422P to _YUV422P, +and _YUV411P to _YUV411P.

1999-04-04: Added a few more control IDs.

1999-04-07: Added the button control type.

1999-05-02: Fixed a typo in videodev.h, and added the +V4L2_CTRL_FLAG_GRAYED (later V4L2_CTRL_FLAG_GRABBED) flag.

1999-05-20: Definition of VIDIOC_G_CTRL was wrong causing +a malfunction of this ioctl.

1999-06-05: Changed the value of +V4L2_CID_WHITENESS.

6.2.5. V4L2 Version 0.20 (1999-09-10)

Version 0.20 introduced a number of changes which were +not backward compatible with 0.19 and earlier +versions. Purpose of these changes was to simplify the API, while +making it more extensible and following common Linux driver API +conventions.

  1. Some typos in V4L2_FMT_FLAG +symbols were fixed. struct v4l2_clip was changed for compatibility with +v4l. (1999-08-30)

  2. V4L2_TUNER_SUB_LANG1 was added. +(1999-09-05)

  3. All ioctl() commands that used an integer argument now +take a pointer to an integer. Where it makes sense, ioctls will return +the actual new value in the integer pointed to by the argument, a +common convention in the V4L2 API. The affected ioctls are: +VIDIOC_PREVIEW, VIDIOC_STREAMON, VIDIOC_STREAMOFF, VIDIOC_S_FREQ, +VIDIOC_S_INPUT, VIDIOC_S_OUTPUT, VIDIOC_S_EFFECT. For example +

    err = ioctl (fd, VIDIOC_XXX, V4L2_XXX);
    becomes
    int a = V4L2_XXX; err = ioctl(fd, VIDIOC_XXX, &a);
    +

  4. All the different get- and set-format commands were +swept into one VIDIOC_G_FMT and VIDIOC_S_FMT ioctl taking a union +and a type field selecting the union member as parameter. Purpose is to +simplify the API by eliminating several ioctls and to allow new and +driver private data streams without adding new ioctls.

    This change obsoletes the following ioctls: +VIDIOC_S_INFMT, +VIDIOC_G_INFMT, +VIDIOC_S_OUTFMT, +VIDIOC_G_OUTFMT, +VIDIOC_S_VBIFMT and +VIDIOC_G_VBIFMT. The image format structure +v4l2_format was renamed to struct v4l2_pix_format, +while struct v4l2_format is now the envelopping structure for all format +negotiations.

  5. Similar to the changes above, the +VIDIOC_G_PARM and +VIDIOC_S_PARM ioctls were merged with +VIDIOC_G_OUTPARM and +VIDIOC_S_OUTPARM. A +type field in the new struct v4l2_streamparm +selects the respective union member.

    This change obsoletes the +VIDIOC_G_OUTPARM and +VIDIOC_S_OUTPARM ioctls.

  6. Control enumeration was simplified, and two new +control flags were introduced and one dropped. The +catname field was replaced by a +group field.

    Drivers can now flag unsupported and temporarily +unavailable controls with V4L2_CTRL_FLAG_DISABLED +and V4L2_CTRL_FLAG_GRABBED respectively. The +group name indicates a possibly narrower +classification than the category. In other +words, there may be multiple groups within a category. Controls within +a group would typically be drawn within a group box. Controls in +different categories might have a greater separation, or may even +appear in separate windows.

  7. The struct v4l2_buffer timestamp +was changed to a 64 bit integer, containing the sampling or output +time of the frame in nanoseconds. Additionally timestamps will be in +absolute system time, not starting from zero at the beginning of a +stream. The data type name for timestamps is stamp_t, defined as a +signed 64-bit integer. Output devices should not send a buffer out +until the time in the timestamp field has arrived. I would like to +follow SGI's lead, and adopt a multimedia timestamping system like +their UST (Unadjusted System Time). See +http://reality.sgi.com/cpirazzi_engr/lg/time/intro.html. [This link is +no longer valid.] UST uses timestamps that are 64-bit signed integers +(not struct timeval's) and given in nanosecond units. The UST clock +starts at zero when the system is booted and runs continuously and +uniformly. It takes a little over 292 years for UST to overflow. There +is no way to set the UST clock. The regular Linux time-of-day clock +can be changed periodically, which would cause errors if it were being +used for timestamping a multimedia stream. A real UST style clock will +require some support in the kernel that is not there yet. But in +anticipation, I will change the timestamp field to a 64-bit integer, +and I will change the v4l2_masterclock_gettime() function (used only +by drivers) to return a 64-bit integer.

  8. A sequence field was added +to struct v4l2_buffer. The sequence field counts +captured frames, it is ignored by output devices. When a capture +driver drops a frame, the sequence number of that frame is +skipped.

6.2.6. V4L2 Version 0.20 incremental changes

1999-12-23: In struct v4l2_vbi_format the +reserved1 field became +offset. Previously drivers were required to +clear the reserved1 field.

2000-01-13: The + V4L2_FMT_FLAG_NOT_INTERLACED flag was added.

2000-07-31: The linux/poll.h header +is now included by videodev.h for compatibility +with the original videodev.h file.

2000-11-20: V4L2_TYPE_VBI_OUTPUT and +V4L2_PIX_FMT_Y41P were added.

2000-11-25: V4L2_TYPE_VBI_INPUT was +added.

2000-12-04: A couple typos in symbol names were fixed.

2001-01-18: To avoid namespace conflicts the +fourcc macro defined in the +videodev.h header file was renamed to +v4l2_fourcc.

2001-01-25: A possible driver-level compatibility problem +between the videodev.h file in Linux 2.4.0 and +the videodev.h file included in the +videodevX patch was fixed. Users of an earlier +version of videodevX on Linux 2.4.0 should +recompile their V4L and V4L2 drivers.

2001-01-26: A possible kernel-level incompatibility +between the videodev.h file in the +videodevX patch and the +videodev.h file in Linux 2.2.x with devfs patches +applied was fixed.

2001-03-02: Certain V4L ioctls which pass data in both +direction although they are defined with read-only parameter, did not +work correctly through the backward compatibility layer. +[Solution?]

2001-04-13: Big endian 16-bit RGB formats were added.

2001-09-17: New YUV formats and the VIDIOC_G_FREQUENCY and +VIDIOC_S_FREQUENCY ioctls were added. (The old +VIDIOC_G_FREQ and +VIDIOC_S_FREQ ioctls did not take multiple tuners +into account.)

2000-09-18: V4L2_BUF_TYPE_VBI was +added. This may break compatibility as the +VIDIOC_G_FMT and VIDIOC_S_FMT ioctls may fail now if the struct +v4l2_fmt type +field does not contain V4L2_BUF_TYPE_VBI. In the +documentation of the struct v4l2_vbi_format +offset field the ambiguous phrase "rising +edge" was changed to "leading edge".

6.2.7. V4L2 Version 0.20 2000-11-23

A number of changes were made to the raw VBI +interface.

  1. Figures clarifying the line numbering scheme were +added to the V4L2 API specification. The +start[0] and +start[1] fields no longer count line +numbers beginning at zero. Rationale: a) The previous definition was +unclear. b) The start[] values are ordinal +numbers. c) There is no point in inventing a new line numbering +scheme. We now use line number as defined by ITU-R, period. +Compatibility: Add one to the start values. Applications depending on +the previous semantics may not function correctly.

  2. The restriction "count[0] > 0 and count[1] > 0" +has been relaxed to "(count[0] + count[1]) > 0". Rationale: +Drivers may allocate resources at scan line granularity and some data +services are transmitted only on the first field. The comment that +both count values will usually be equal is +misleading and pointless and has been removed. This change +breaks compatibility with earlier versions: +Drivers may return EINVAL, applications may not function +correctly.

  3. Drivers are again permitted to return negative +(unknown) start values as proposed earlier. Why this feature was +dropped is unclear. This change may break +compatibility with applications depending on the start +values being positive. The use of EBUSY and +EINVAL error codes with the VIDIOC_S_FMT ioctl +was clarified. The EBUSY error code was finally documented, and the +reserved2 field which was previously +mentioned only in the videodev.h header +file.

  4. New buffer types +V4L2_TYPE_VBI_INPUT and +V4L2_TYPE_VBI_OUTPUT were added. The former is an +alias for the old V4L2_TYPE_VBI, the latter was +missing in the videodev.h file.

6.2.8. V4L2 Version 0.20 2002-07-25

Added sliced VBI interface proposal.

6.2.9. V4L2 in Linux 2.5.46, 2002-10

Around October-November 2002, prior to an announced +feature freeze of Linux 2.5, the API was revised, drawing from +experience with V4L2 0.20. This unnamed version was finally merged +into Linux 2.5.46.

  1. As specified in Section 1.1.2, drivers +must make related device functions available under all minor device +numbers.

  2. The open() function requires access mode +O_RDWR regardless of the device type. All V4L2 +drivers exchanging data with applications must support the +O_NONBLOCK flag. The O_NOIO +flag, a V4L2 symbol which aliased the meaningless +O_TRUNC to indicate accesses without data +exchange (panel applications) was dropped. Drivers must stay in "panel +mode" until the application attempts to initiate a data exchange, see +Section 1.1.

  3. The struct v4l2_capability changed dramatically. Note that +also the size of the structure changed, which is encoded in the ioctl +request code, thus older V4L2 devices will respond with an EINVAL error code to +the new VIDIOC_QUERYCAP ioctl.

    There are new fields to identify the driver, a new (as +of yet unspecified) device function +V4L2_CAP_RDS_CAPTURE, the +V4L2_CAP_AUDIO flag indicates if the device has +any audio connectors, another I/O capability +V4L2_CAP_ASYNCIO can be flagged. In response to +these changes the type field became a bit +set and was merged into the flags field. +V4L2_FLAG_TUNER was renamed to +V4L2_CAP_TUNER, +V4L2_CAP_VIDEO_OVERLAY replaced +V4L2_FLAG_PREVIEW and +V4L2_CAP_VBI_CAPTURE and +V4L2_CAP_VBI_OUTPUT replaced +V4L2_FLAG_DATA_SERVICE. +V4L2_FLAG_READ and +V4L2_FLAG_WRITE were merged into +V4L2_CAP_READWRITE.

    The redundant fields +inputs, outputs +and audios were removed. These properties +can be determined as described in Section 1.4 and Section 1.5.

    The somewhat volatile and therefore barely useful +fields maxwidth, +maxheight, +minwidth, +minheight, +maxframerate were removed. This information +is available as described in Section 1.10 and +Section 1.7.

    V4L2_FLAG_SELECT was removed. We +believe the select() function is important enough to require support +of it in all V4L2 drivers exchanging data with applications. The +redundant V4L2_FLAG_MONOCHROME flag was removed, +this information is available as described in Section 1.10.

  4. In struct v4l2_input the +assoc_audio field and the +capability field and its only flag +V4L2_INPUT_CAP_AUDIO was replaced by the new +audioset field. Instead of linking one +video input to one audio input this field reports all audio inputs +this video input combines with.

    New fields are tuner +(reversing the former link from tuners to video inputs), +std and +status.

    Accordingly struct v4l2_output lost its +capability and +assoc_audio fields. +audioset, +modulator and +std where added instead.

  5. The struct v4l2_audio field +audio was renamed to +index, for consistency with other +structures. A new capability flag +V4L2_AUDCAP_STEREO was added to indicated if the +audio input in question supports stereo sound. +V4L2_AUDCAP_EFFECTS and the corresponding +V4L2_AUDMODE flags where removed. This can be +easily implemented using controls. (However the same applies to AVL +which is still there.)

    Again for consistency the struct v4l2_audioout field +audio was renamed to +index.

  6. The struct v4l2_tuner +input field was replaced by an +index field, permitting devices with +multiple tuners. The link between video inputs and tuners is now +reversed, inputs point to their tuner. The +std substructure became a +simple set (more about this below) and moved into struct v4l2_input. A +type field was added.

    Accordingly in struct v4l2_modulator the +output was replaced by an +index field.

    In struct v4l2_frequency the +port field was replaced by a +tuner field containing the respective tuner +or modulator index number. A tuner type +field was added and the reserved field +became larger for future extensions (satellite tuners in +particular).

  7. The idea of completely transparent video standards was +dropped. Experience showed that applications must be able to work with +video standards beyond presenting the user a menu. Instead of +enumerating supported standards with an ioctl applications can now +refer to standards by v4l2_std_id and symbols defined in the +videodev2.h header file. For details see Section 1.7. The VIDIOC_G_STD and +VIDIOC_S_STD now take a pointer to this type as argument. +VIDIOC_QUERYSTD was added to autodetect the received standard, if +the hardware has this capability. In struct v4l2_standard an +index field was added for VIDIOC_ENUMSTD. +A v4l2_std_id field named id was added as +machine readable identifier, also replacing the +transmission field. The misleading +framerate field was renamed +to frameperiod. The now obsolete +colorstandard information, originally +needed to distguish between variations of standards, were +removed.

    Struct v4l2_enumstd ceased to +be. VIDIOC_ENUMSTD now takes a pointer to a struct v4l2_standard +directly. The information which standards are supported by a +particular video input or output moved into struct v4l2_input and +struct v4l2_output fields named std, +respectively.

  8. The struct v4l2_queryctrl fields +category and +group did not catch on and/or were not +implemented as expected and therefore removed.

  9. The VIDIOC_TRY_FMT ioctl was added to negotiate data +formats as with VIDIOC_S_FMT, but without the overhead of +programming the hardware and regardless of I/O in progress.

    In struct v4l2_format the fmt +union was extended to contain struct v4l2_window. All image format +negotiations are now possible with VIDIOC_G_FMT, +VIDIOC_S_FMT and +VIDIOC_TRY_FMT; ioctl. The +VIDIOC_G_WIN and +VIDIOC_S_WIN ioctls to prepare for a video +overlay were removed. The type field +changed to type enum v4l2_buf_type and the buffer type names changed as +follows.

    Old definesenum v4l2_buf_type
    V4L2_BUF_TYPE_CAPTUREV4L2_BUF_TYPE_VIDEO_CAPTURE
    V4L2_BUF_TYPE_CODECINOmitted for now
    V4L2_BUF_TYPE_CODECOUTOmitted for now
    V4L2_BUF_TYPE_EFFECTSINOmitted for now
    V4L2_BUF_TYPE_EFFECTSIN2Omitted for now
    V4L2_BUF_TYPE_EFFECTSOUTOmitted for now
    V4L2_BUF_TYPE_VIDEOOUTV4L2_BUF_TYPE_VIDEO_OUTPUT
    -V4L2_BUF_TYPE_VIDEO_OVERLAY
    -V4L2_BUF_TYPE_VBI_CAPTURE
    -V4L2_BUF_TYPE_VBI_OUTPUT
    -V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
    -V4L2_BUF_TYPE_SLICED_VBI_OUTPUT
    V4L2_BUF_TYPE_PRIVATE_BASEV4L2_BUF_TYPE_PRIVATE

  10. In struct v4l2_fmtdesc a enum v4l2_buf_type field named +type was added as in struct v4l2_format. The +VIDIOC_ENUM_FBUFFMT ioctl is no longer needed and +was removed. These calls can be replaced by VIDIOC_ENUM_FMT with +type V4L2_BUF_TYPE_VIDEO_OVERLAY.

  11. In struct v4l2_pix_format the +depth field was removed, assuming +applications which recognize the format by its four-character-code +already know the color depth, and others do not care about it. The +same rationale lead to the removal of the +V4L2_FMT_FLAG_COMPRESSED flag. The +V4L2_FMT_FLAG_SWCONVECOMPRESSED flag was removed +because drivers are not supposed to convert images in kernel space. A +user library of conversion functions should be provided instead. The +V4L2_FMT_FLAG_BYTESPERLINE flag was redundant. +Applications can set the bytesperline field +to zero to get a reasonable default. Since the remaining flags were +replaced as well, the flags field itself +was removed.

    The interlace flags were replaced by a enum v4l2_field +value in a newly added field +field.

    Old flagenum v4l2_field
    V4L2_FMT_FLAG_NOT_INTERLACED?
    V4L2_FMT_FLAG_INTERLACED += V4L2_FMT_FLAG_COMBINEDV4L2_FIELD_INTERLACED
    V4L2_FMT_FLAG_TOPFIELD += V4L2_FMT_FLAG_ODDFIELDV4L2_FIELD_TOP
    V4L2_FMT_FLAG_BOTFIELD += V4L2_FMT_FLAG_EVENFIELDV4L2_FIELD_BOTTOM
    -V4L2_FIELD_SEQ_TB
    -V4L2_FIELD_SEQ_BT
    -V4L2_FIELD_ALTERNATE

    The color space flags were replaced by a +enum v4l2_colorspace value in a newly added +colorspace field, where one of +V4L2_COLORSPACE_SMPTE170M, +V4L2_COLORSPACE_BT878, +V4L2_COLORSPACE_470_SYSTEM_M or +V4L2_COLORSPACE_470_SYSTEM_BG replaces +V4L2_FMT_CS_601YUV.

  12. In struct v4l2_requestbuffers the +type field was properly defined as +enum v4l2_buf_type. Buffer types changed as mentioned above. A new +memory field of type enum v4l2_memory was +added to distinguish between I/O methods using buffers allocated +by the driver or the application. See Chapter 3 for +details.

  13. In struct v4l2_buffer the type +field was properly defined as enum v4l2_buf_type. Buffer types changed as +mentioned above. A field field of type +enum v4l2_field was added to indicate if a buffer contains a top or +bottom field. The old field flags were removed. Since no unadjusted +system time clock was added to the kernel as planned, the +timestamp field changed back from type +stamp_t, an unsigned 64 bit integer expressing the sample time in +nanoseconds, to struct timeval. With the +addition of a second memory mapping method the +offset field moved into union +m, and a new +memory field of type enum v4l2_memory was +added to distinguish between I/O methods. See Chapter 3 +for details.

    The V4L2_BUF_REQ_CONTIG +flag was used by the V4L compatibility layer, after changes to this +code it was no longer needed. The +V4L2_BUF_ATTR_DEVICEMEM flag would indicate if +the buffer was indeed allocated in device memory rather than DMA-able +system memory. It was barely useful and so was removed.

  14. In struct v4l2_framebuffer the +base[3] array anticipating double- and +triple-buffering in off-screen video memory, however without defining +a synchronization mechanism, was replaced by a single pointer. The +V4L2_FBUF_CAP_SCALEUP and +V4L2_FBUF_CAP_SCALEDOWN flags were removed. +Applications can determine this capability more accurately using the +new cropping and scaling interface. The +V4L2_FBUF_CAP_CLIPPING flag was replaced by +V4L2_FBUF_CAP_LIST_CLIPPING and +V4L2_FBUF_CAP_BITMAP_CLIPPING.

  15. In struct v4l2_clip the x, +y, width and +height field moved into a +c substructure of type struct v4l2_rect. The +x and y fields +were renamed to left and +top, i. e. offsets to a context dependent +origin.

  16. In struct v4l2_window the x, +y, width and +height field moved into a +w substructure as above. A +field field of type %v4l2-field; was added +to distinguish between field and frame (interlaced) overlay.

  17. The digital zoom interface, including struct +v4l2_zoomcap, struct +v4l2_zoom, +V4L2_ZOOM_NONCAP and +V4L2_ZOOM_WHILESTREAMING was replaced by a new +cropping and scaling interface. The previously unused struct +v4l2_cropcap and +v4l2_crop where redefined for this purpose. +See Section 1.11 for details.

  18. In struct v4l2_vbi_format the +SAMPLE_FORMAT field now contains a +four-character-code as used to identify video image formats and +V4L2_PIX_FMT_GREY replaces the +V4L2_VBI_SF_UBYTE define. The +reserved field was extended.

  19. In struct v4l2_captureparm the type of the +timeperframe field changed from unsigned +long to struct v4l2_fract. This allows the accurate expression of multiples +of the NTSC-M frame rate 30000 / 1001. A new field +readbuffers was added to control the driver +behaviour in read I/O mode.

    Similar changes were made to struct v4l2_outputparm.

  20. The struct v4l2_performance +and VIDIOC_G_PERF ioctl were dropped. Except when +using the read/write I/O method, which is +limited anyway, this information is already available to +applications.

  21. The example transformation from RGB to YCbCr color +space in the old V4L2 documentation was inaccurate, this has been +corrected in Chapter 2.

6.2.10. V4L2 2003-06-19

  1. A new capability flag +V4L2_CAP_RADIO was added for radio devices. Prior +to this change radio devices would identify solely by having exactly one +tuner whose type field reads V4L2_TUNER_RADIO.

  2. An optional driver access priority mechanism was +added, see Section 1.3 for details.

  3. The audio input and output interface was found to be +incomplete.

    Previously the VIDIOC_G_AUDIO +ioctl would enumerate the available audio inputs. An ioctl to +determine the current audio input, if more than one combines with the +current video input, did not exist. So +VIDIOC_G_AUDIO was renamed to +VIDIOC_G_AUDIO_OLD, this ioctl will be removed in +the future. The VIDIOC_ENUMAUDIO ioctl was added to enumerate +audio inputs, while VIDIOC_G_AUDIO now reports the current audio +input.

    The same changes were made to VIDIOC_G_AUDOUT and +VIDIOC_ENUMAUDOUT.

    Until further the "videodev" module will automatically +translate between the old and new ioctls, but drivers and applications +must be updated to successfully compile again.

  4. The VIDIOC_OVERLAY ioctl was incorrectly defined with +write-read parameter. It was changed to write-only, while the write-read +version was renamed to VIDIOC_OVERLAY_OLD. The old +ioctl will be removed in the future. Until further the "videodev" +kernel module will automatically translate to the new version, so drivers +must be recompiled, but not applications.

  5. Section 4.2 incorrectly stated that +clipping rectangles define regions where the video can be seen. +Correct is that clipping rectangles define regions where +no video shall be displayed and so the graphics +surface can be seen.

  6. The VIDIOC_S_PARM and VIDIOC_S_CTRL ioctls were +defined with write-only parameter, inconsistent with other ioctls +modifying their argument. They were changed to write-read, while a +_OLD suffix was added to the write-only versions. +The old ioctls will be removed in the future. Drivers and +applications assuming a constant parameter need an update.

6.2.11. V4L2 2003-11-05

  1. In Section 2.4 the following pixel +formats were incorrectly transferred from Bill Dirks' V4L2 +specification. Descriptions below refer to bytes in memory, in +ascending address order.

    SymbolIn this document prior to revision +0.5Corrected
    V4L2_PIX_FMT_RGB24B, G, RR, G, B
    V4L2_PIX_FMT_BGR24R, G, BB, G, R
    V4L2_PIX_FMT_RGB32B, G, R, XR, G, B, X
    V4L2_PIX_FMT_BGR32R, G, B, XB, G, R, X

    The +V4L2_PIX_FMT_BGR24 example was always +correct.

    In Section 6.1.5 the mapping +of the V4L VIDEO_PALETTE_RGB24 and +VIDEO_PALETTE_RGB32 formats to V4L2 pixel formats +was accordingly corrected.

  2. Unrelated to the fixes above, drivers may still +interpret some V4L2 RGB pixel formats differently. These issues have +yet to be addressed, for details see Section 2.4.

6.2.12. V4L2 in Linux 2.6.6, 2004-05-09

  1. The VIDIOC_CROPCAP ioctl was incorrectly defined +with read-only parameter. It is now defined as write-read ioctl, while +the read-only version was renamed to +VIDIOC_CROPCAP_OLD. The old ioctl will be removed +in the future.

6.2.13. V4L2 in Linux 2.6.8

  1. A new field input (former +reserved[0]) was added to the struct v4l2_buffer +structure. Purpose of this field is to alternate between video inputs +(e. g. cameras) in step with the video capturing process. This function +must be enabled with the new V4L2_BUF_FLAG_INPUT +flag. The flags field is no longer +read-only.

6.2.14. V4L2 spec erratum 2004-08-01

  1. The return value of the +V4L2 open()(2) function was incorrectly documented.

  2. Audio output ioctls end in -AUDOUT, not -AUDIOOUT.

  3. In the Current Audio Input example the +VIDIOC_G_AUDIO ioctl took the wrong +argument.

  4. The documentation of the VIDIOC_QBUF and +VIDIOC_DQBUF ioctls did not mention the struct v4l2_buffer +memory field. It was also missing from +examples. Also on the VIDIOC_DQBUF page the EIO error code +was not documented.

6.2.15. V4L2 in Linux 2.6.14

  1. A new sliced VBI interface was added. It is documented +in Section 4.8 and replaces the interface first +proposed in V4L2 specification 0.8.

6.2.16. V4L2 in Linux 2.6.15

  1. The VIDIOC_LOG_STATUS ioctl was added.

  2. New video standards +V4L2_STD_NTSC_443, +V4L2_STD_SECAM_LC, +V4L2_STD_SECAM_DK (a set of SECAM D, K and K1), +and V4L2_STD_ATSC (a set of +V4L2_STD_ATSC_8_VSB and +V4L2_STD_ATSC_16_VSB) were defined. Note the +V4L2_STD_525_60 set now includes +V4L2_STD_NTSC_443. See also Table 3.

  3. The VIDIOC_G_COMP and +VIDIOC_S_COMP ioctl were renamed to +VIDIOC_G_MPEGCOMP and +VIDIOC_S_MPEGCOMP respectively. Their argument +was replaced by a struct +v4l2_mpeg_compression pointer. (The +VIDIOC_G_MPEGCOMP and +VIDIOC_S_MPEGCOMP ioctls where removed in Linux +2.6.25.)

6.2.17. V4L2 spec erratum 2005-11-27

The capture example in Appendix B +called the VIDIOC_S_CROP ioctl without checking if cropping is +supported. In the video standard selection example in +Section 1.7 the VIDIOC_S_STD call used the wrong +argument type.

6.2.18. V4L2 spec erratum 2006-01-10

  1. The V4L2_IN_ST_COLOR_KILL flag in +struct v4l2_input not only indicates if the color killer is enabled, but +also if it is active. (The color killer disables color decoding when +it detects no color in the video signal to improve the image +quality.)

  2. VIDIOC_S_PARM is a write-read ioctl, not write-only as +stated on its reference page. The ioctl changed in 2003 as noted above.

6.2.19. V4L2 spec erratum 2006-02-03

  1. In struct v4l2_captureparm and struct v4l2_outputparm the +timeperframe field gives the time in +seconds, not microseconds.

6.2.20. V4L2 spec erratum 2006-02-04

  1. The clips field in +struct v4l2_window must point to an array of struct v4l2_clip, not a linked +list, because drivers ignore the struct +v4l2_clip.next +pointer.

6.2.21. V4L2 in Linux 2.6.17

  1. New video standard macros were added: +V4L2_STD_NTSC_M_KR (NTSC M South Korea), and the +sets V4L2_STD_MN, +V4L2_STD_B, V4L2_STD_GH and +V4L2_STD_DK. The +V4L2_STD_NTSC and +V4L2_STD_SECAM sets now include +V4L2_STD_NTSC_M_KR and +V4L2_STD_SECAM_LC respectively.

  2. A new V4L2_TUNER_MODE_LANG1_LANG2 +was defined to record both languages of a bilingual program. The +use of V4L2_TUNER_MODE_STEREO for this purpose +is deprecated now. See the VIDIOC_G_TUNER section for +details.

6.2.22. V4L2 spec erratum 2006-09-23 (Draft 0.15)

  1. In various places +V4L2_BUF_TYPE_SLICED_VBI_CAPTURE and +V4L2_BUF_TYPE_SLICED_VBI_OUTPUT of the sliced VBI +interface were not mentioned along with other buffer types.

  2. In ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO(2) it was clarified +that the struct v4l2_audio mode field is a flags +field.

  3. ioctl VIDIOC_QUERYCAP(2) did not mention the +sliced VBI and radio capability flags.

  4. In ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY(2) it was +clarified that applications must initialize the tuner +type field of struct v4l2_frequency before +calling VIDIOC_S_FREQUENCY.

  5. The reserved array +in struct v4l2_requestbuffers has 2 elements, not 32.

  6. In Section 4.3 and Section 4.7 the device file names +/dev/vout which never caught on were replaced +by /dev/video.

  7. With Linux 2.6.15 the possible range for VBI device minor +numbers was extended from 224-239 to 224-255. Accordingly device file names +/dev/vbi0 to /dev/vbi31 are +possible now.

6.2.23. V4L2 in Linux 2.6.18

  1. New ioctls VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS +and VIDIOC_TRY_EXT_CTRLS were added, a flag to skip unsupported +controls with VIDIOC_QUERYCTRL, new control types +V4L2_CTRL_TYPE_INTEGER64 and +V4L2_CTRL_TYPE_CTRL_CLASS (Table 3), and new control flags +V4L2_CTRL_FLAG_READ_ONLY, +V4L2_CTRL_FLAG_UPDATE, +V4L2_CTRL_FLAG_INACTIVE and +V4L2_CTRL_FLAG_SLIDER (Table 4). See Section 1.9 for details.

6.2.24. V4L2 in Linux 2.6.19

  1. In struct v4l2_sliced_vbi_cap a buffer type field was added +replacing a reserved field. Note on architectures where the size of +enum types differs from int types the size of the structure changed. +The VIDIOC_G_SLICED_VBI_CAP ioctl was redefined from being read-only +to write-read. Applications must initialize the type field and clear +the reserved fields now. These changes may break the +compatibility with older drivers and applications.

  2. The ioctls VIDIOC_ENUM_FRAMESIZES and +VIDIOC_ENUM_FRAMEINTERVALS were added.

  3. A new pixel format V4L2_PIX_FMT_RGB444 (Table 2-1) was added.

6.2.25. V4L2 spec erratum 2006-10-12 (Draft 0.17)

  1. V4L2_PIX_FMT_HM12 (Table 2-8) is a YUV 4:2:0, not 4:2:2 format.

6.2.26. V4L2 in Linux 2.6.21

  1. The videodev2.h header file is +now dual licensed under GNU General Public License version two or +later, and under a 3-clause BSD-style license.

6.2.27. V4L2 in Linux 2.6.22

  1. Two new field orders + V4L2_FIELD_INTERLACED_TB and + V4L2_FIELD_INTERLACED_BT were + added. See Table 3-8 for details.

  2. Three new clipping/blending methods with a global or +straight or inverted local alpha value were added to the video overlay +interface. See the description of the VIDIOC_G_FBUF and +VIDIOC_S_FBUF ioctls for details.

    A new global_alpha field +was added to v4l2_window, +extending the structure. This may break +compatibility with applications using a struct +v4l2_window directly. However the VIDIOC_G/S/TRY_FMT ioctls, which take a +pointer to a v4l2_format parent +structure with padding bytes at the end, are not affected.

  3. The format of the chromakey +field in struct v4l2_window changed from "host order RGB32" to a pixel +value in the same format as the framebuffer. This may break +compatibility with existing applications. Drivers +supporting the "host order RGB32" format are not known.

6.2.28. V4L2 in Linux 2.6.24

  1. The pixel formats +V4L2_PIX_FMT_PAL8, +V4L2_PIX_FMT_YUV444, +V4L2_PIX_FMT_YUV555, +V4L2_PIX_FMT_YUV565 and +V4L2_PIX_FMT_YUV32 were added.

6.2.29. V4L2 in Linux 2.6.25

  1. The pixel formats V4L2_PIX_FMT_Y16 and V4L2_PIX_FMT_SBGGR16 were added.

  2. New controls +V4L2_CID_POWER_LINE_FREQUENCY, +V4L2_CID_HUE_AUTO, +V4L2_CID_WHITE_BALANCE_TEMPERATURE, +V4L2_CID_SHARPNESS and +V4L2_CID_BACKLIGHT_COMPENSATION were added. The +controls V4L2_CID_BLACK_LEVEL, +V4L2_CID_WHITENESS, +V4L2_CID_HCENTER and +V4L2_CID_VCENTER were deprecated.

  3. A Camera controls +class was added, with the new controls +V4L2_CID_EXPOSURE_AUTO, +V4L2_CID_EXPOSURE_ABSOLUTE, +V4L2_CID_EXPOSURE_AUTO_PRIORITY, +V4L2_CID_PAN_RELATIVE, +V4L2_CID_TILT_RELATIVE, +V4L2_CID_PAN_RESET, +V4L2_CID_TILT_RESET, +V4L2_CID_PAN_ABSOLUTE, +V4L2_CID_TILT_ABSOLUTE, +V4L2_CID_FOCUS_ABSOLUTE, +V4L2_CID_FOCUS_RELATIVE and +V4L2_CID_FOCUS_AUTO.

  4. The VIDIOC_G_MPEGCOMP and +VIDIOC_S_MPEGCOMP ioctls, which were superseded +by the extended controls +interface in Linux 2.6.18, where finally removed from the +videodev2.h header file.


PrevHomeNext
ChangesUpRelation of V4L2 to other Linux multimedia APIs
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16430.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16430.htm new file mode 100644 index 0000000000000000000000000000000000000000..34fa78b0405b96b563c7a8ea8a87a9a77ff8e46c --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16430.htm @@ -0,0 +1,270 @@ + +Relation of V4L2 to other Linux multimedia APIs
Video for Linux Two API Specification: Revision 0.24
PrevChapter 6. ChangesNext

6.3. Relation of V4L2 to other Linux multimedia APIs

6.3.1. X Video Extension

The X Video Extension (abbreviated XVideo or just Xv) is +an extension of the X Window system, implemented for example by the +XFree86 project. Its scope is similar to V4L2, an API to video capture +and output devices for X clients. Xv allows applications to display +live video in a window, send window contents to a TV output, and +capture or output still images in XPixmaps[1]. With their implementation XFree86 makes the +extension available across many operating systems and +architectures.

Because the driver is embedded into the X server Xv has a +number of advantages over the V4L2 video +overlay interface. The driver can easily determine the overlay +target, i. e. visible graphics memory or off-screen buffers for a +destructive overlay. It can program the RAMDAC for a non-destructive +overlay, scaling or color-keying, or the clipping functions of the +video capture hardware, always in sync with drawing operations or +windows moving or changing their stacking order.

To combine the advantages of Xv and V4L a special Xv +driver exists in XFree86 and XOrg, just programming any overlay capable +Video4Linux device it finds. To enable it +/etc/X11/XF86Config must contain these lines:

Section "Module"
+    Load "v4l"
+EndSection

As of XFree86 4.2 this driver still supports only V4L +ioctls, however it should work just fine with all V4L2 devices through +the V4L2 backward-compatibility layer. Since V4L2 permits multiple +opens it is possible (if supported by the V4L2 driver) to capture +video while an X client requested video overlay. Restrictions of +simultaneous capturing and overlay are discussed in Section 4.2 apply.

Only marginally related to V4L2, XFree86 extended Xv to +support hardware YUV to RGB conversion and scaling for faster video +playback, and added an interface to MPEG-2 decoding hardware. This API +is useful to display images captured with V4L2 devices.

6.3.2. Digital Video

V4L2 does not support digital terrestrial, cable or +satellite broadcast. A separate project aiming at digital receivers +exists. You can find its homepage at http://linuxtv.org. The Linux DVB API +has no connection to the V4L2 API except that drivers for hybrid +hardware may support both.

6.3.3. Audio Interfaces

[to do - OSS/ALSA]

Notes

[1]

This is not implemented in XFree86.


PrevHomeNext
Changes of the V4L2 APIUpExperimental API Elements
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16453.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16453.htm new file mode 100644 index 0000000000000000000000000000000000000000..0556ef8659a013ce5f4d611af0d753a88155baaf --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16453.htm @@ -0,0 +1,260 @@ + +Experimental API Elements
Video for Linux Two API Specification: Revision 0.24
PrevChapter 6. ChangesNext

6.4. Experimental API Elements

The following V4L2 API elements are currently experimental +and may change in the future.


PrevHomeNext
Relation of V4L2 to other Linux multimedia APIsUpObsolete API Elements
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16497.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16497.htm new file mode 100644 index 0000000000000000000000000000000000000000..aa7c731d29264df0d8af418cae9fca03bee7ee18 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16497.htm @@ -0,0 +1,166 @@ + +Obsolete API Elements
Video for Linux Two API Specification: Revision 0.24
PrevChapter 6. ChangesNext

6.5. Obsolete API Elements

The following V4L2 API elements were superseded by new +interfaces and should not be implemented in new drivers.

  • VIDIOC_G_MPEGCOMP and +VIDIOC_S_MPEGCOMP ioctls. Use Extended Controls, +Section 1.9.


PrevHomeNext
Experimental API ElementsUpVideo For Linux Two Header File
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16743.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16743.htm new file mode 100644 index 0000000000000000000000000000000000000000..0c97fe3b95ff535adefd9be387ea3a58408289ad --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16743.htm @@ -0,0 +1,267 @@ + +1. APPLICABILITY AND DEFINITIONS
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.2. 1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work that contains a + notice placed by the copyright holder saying it can be + distributed under the terms of this License. The + "Document", below, refers to any such manual or + work. Any member of the public is a licensee, and is addressed + as "you". +

A "Modified Version" of the Document means any work + containing the Document or a portion of it, either copied + verbatim, or with modifications and/or translated into another + language. +

A "Secondary Section" is a named appendix or a + front-matter section of the Document that deals exclusively + with the relationship of the publishers or authors of the + Document to the Document's overall subject (or to related + matters) and contains nothing that could fall directly within + that overall subject. (For example, if the Document is in part a + textbook of mathematics, a Secondary Section may not explain any + mathematics.) The relationship could be a matter of historical + connection with the subject or with related matters, or of + legal, commercial, philosophical, ethical or political position + regarding them. +

The "Invariant Sections" are certain Secondary Sections whose titles + are designated, as being those of Invariant Sections, in the + notice that says that the Document is released under this + License. +

The "Cover Texts" are certain short passages of + text that are listed, as Front-Cover Texts or Back-Cover Texts, + in the notice that says that the Document is released under this + License. +

A "Transparent" copy of the Document means a machine-readable + copy, represented in a format whose specification is available + to the general public, whose contents can be viewed and edited + directly and straightforwardly with generic text editors or (for + images composed of pixels) generic paint programs or (for + drawings) some widely available drawing editor, and that is + suitable for input to text formatters or for automatic + translation to a variety of formats suitable for input to text + formatters. A copy made in an otherwise Transparent file format + whose markup has been designed to thwart or discourage + subsequent modification by readers is not Transparent. A copy + that is not "Transparent" is called + "Opaque". +

Examples of suitable formats for Transparent copies include + plain ASCII without markup, Texinfo input format, LaTeX input + format, SGML or XML using a publicly available DTD, and + standard-conforming simple HTML designed for human + modification. Opaque formats include PostScript, PDF, + proprietary formats that can be read and edited only by + proprietary word processors, SGML or XML for which the DTD + and/or processing tools are not generally available, and the + machine-generated HTML produced by some word processors for + output purposes only. +

The "Title Page" means, for a printed book, the + title page itself, plus such following pages as are needed to + hold, legibly, the material this License requires to appear in + the title page. For works in formats which do not have any title + page as such, "Title Page" means the text near the + most prominent appearance of the work's title, preceding the + beginning of the body of the text. +


PrevHomeNext
GNU Free Documentation LicenseUp2. VERBATIM COPYING
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16769.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16769.htm new file mode 100644 index 0000000000000000000000000000000000000000..0a325c32e77b9175e87ffcc08956e27a538ec6ce --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16769.htm @@ -0,0 +1,166 @@ + +2. VERBATIM COPYING
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.3. 2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either + commercially or noncommercially, provided that this License, the + copyright notices, and the license notice saying this License + applies to the Document are reproduced in all copies, and that + you add no other conditions whatsoever to those of this + License. You may not use technical measures to obstruct or + control the reading or further copying of the copies you make or + distribute. However, you may accept compensation in exchange for + copies. If you distribute a large enough number of copies you + must also follow the conditions in section 3. +

You may also lend copies, under the same conditions stated + above, and you may publicly display copies. +


PrevHomeNext
1. APPLICABILITY AND DEFINITIONSUp3. COPYING IN QUANTITY
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16775.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16775.htm new file mode 100644 index 0000000000000000000000000000000000000000..72010f7b1d2cfc149f18c8a8452019c7ea3a1802 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16775.htm @@ -0,0 +1,208 @@ + +3. COPYING IN QUANTITY
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.4. 3. COPYING IN QUANTITY

If you publish printed copies of the Document numbering more than 100, + and the Document's license notice requires Cover Texts, you must enclose + the copies in covers that carry, clearly and legibly, all these + Cover Texts: Front-Cover Texts on the front cover, and + Back-Cover Texts on the back cover. Both covers must also + clearly and legibly identify you as the publisher of these + copies. The front cover must present the full title with all + words of the title equally prominent and visible. You may add + other material on the covers in addition. Copying with changes + limited to the covers, as long as they preserve the title of the + Document and satisfy these + conditions, can be treated as verbatim copying in other + respects. +

If the required texts for either cover are too voluminous to fit + legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages. +

If you publish or distribute Opaque copies of the Document numbering more than 100, + you must either include a machine-readable Transparent copy along with + each Opaque copy, or state in or with each Opaque copy a + publicly-accessible computer-network location containing a + complete Transparent copy of the Document, free of added + material, which the general network-using public has access to + download anonymously at no charge using public-standard network + protocols. If you use the latter option, you must take + reasonably prudent steps, when you begin distribution of Opaque + copies in quantity, to ensure that this Transparent copy will + remain thus accessible at the stated location until at least one + year after the last time you distribute an Opaque copy (directly + or through your agents or retailers) of that edition to the + public. +

It is requested, but not required, that you contact the authors + of the Document well before + redistributing any large number of copies, to give them a chance + to provide you with an updated version of the Document. +


PrevHomeNext
2. VERBATIM COPYINGUp4. MODIFICATIONS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16788.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16788.htm new file mode 100644 index 0000000000000000000000000000000000000000..dbfaa5eb6776235232b22e205f6004ff523885c0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16788.htm @@ -0,0 +1,530 @@ + +4. MODIFICATIONS
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.5. 4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of + sections 2 and 3 above, provided that you release + the Modified Version under precisely this License, with the + Modified Version filling the role of the Document, thus + licensing distribution and modification of the Modified Version + to whoever possesses a copy of it. In addition, you must do + these things in the Modified Version: +

  • A. Use in the Title + Page (and on the covers, if any) a title distinct + from that of the Document, and from those of + previous versions (which should, if there were any, be + listed in the History section of the Document). You may + use the same title as a previous version if the original + publisher of that version gives permission. +

  • B. List on the Title + Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the + Modified Version, + together with at least five of the principal authors of + the Document (all of + its principal authors, if it has less than five). +

  • C. State on the Title + Page the name of the publisher of the Modified Version, as the + publisher. +

  • D. Preserve all the copyright notices of the Document. +

  • E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +

  • F. Include, immediately after the copyright notices, a + license notice giving the public permission to use the + Modified Version under + the terms of this License, in the form shown in the + Addendum below. +

  • G. Preserve in that license notice the full lists of Invariant Sections and + required Cover + Texts given in the Document's license notice. +

  • H. Include an unaltered copy of this License. +

  • I. Preserve the section entitled "History", and + its title, and add to it an item stating at least the + title, year, new authors, and publisher of the Modified Version as given on + the Title Page. If + there is no section entitled "History" in the + Document, create one + stating the title, year, authors, and publisher of the + Document as given on its Title Page, then add an item + describing the Modified Version as stated in the previous + sentence. +

  • J. Preserve the network location, if any, given in the Document for public access + to a Transparent + copy of the Document, and likewise the network locations + given in the Document for previous versions it was based + on. These may be placed in the "History" + section. You may omit a network location for a work that + was published at least four years before the Document + itself, or if the original publisher of the version it + refers to gives permission. +

  • K. In any section entitled "Acknowledgements" or + "Dedications", preserve the section's title, + and preserve in the section all the substance and tone of + each of the contributor acknowledgements and/or + dedications given therein. +

  • L. Preserve all the Invariant + Sections of the Document, unaltered in their + text and in their titles. Section numbers or the + equivalent are not considered part of the section titles. +

  • M. Delete any section entitled + "Endorsements". Such a section may not be + included in the Modified + Version. +

  • N. Do not retitle any existing section as + "Endorsements" or to conflict in title with + any Invariant + Section. +

If the Modified Version + includes new front-matter sections or appendices that qualify as + Secondary Sections and + contain no material copied from the Document, you may at your + option designate some or all of these sections as invariant. To + do this, add their titles to the list of Invariant Sections in the + Modified Version's license notice. These titles must be + distinct from any other section titles. +

You may add a section entitled "Endorsements", + provided it contains nothing but endorsements of your Modified Version by various + parties--for example, statements of peer review or that the text + has been approved by an organization as the authoritative + definition of a standard. +

You may add a passage of up to five words as a Front-Cover Text, and a passage + of up to 25 words as a Back-Cover Text, to the end of + the list of Cover Texts + in the Modified Version. + Only one passage of Front-Cover Text and one of Back-Cover Text + may be added by (or through arrangements made by) any one + entity. If the Document + already includes a cover text for the same cover, previously + added by you or by arrangement made by the same entity you are + acting on behalf of, you may not add another; but you may + replace the old one, on explicit permission from the previous + publisher that added the old one. +

The author(s) and publisher(s) of the Document do not by this License + give permission to use their names for publicity for or to + assert or imply endorsement of any Modified Version . +


PrevHomeNext
3. COPYING IN QUANTITYUp5. COMBINING DOCUMENTS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16896.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16896.htm new file mode 100644 index 0000000000000000000000000000000000000000..95e39c881abbbc2a079767c3a98dccfca58e0112 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16896.htm @@ -0,0 +1,201 @@ + +5. COMBINING DOCUMENTS
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.6. 5. COMBINING DOCUMENTS

You may combine the Document + with other documents released under this License, under the + terms defined in section 4 + above for modified versions, provided that you include in the + combination all of the Invariant + Sections of all of the original documents, unmodified, + and list them all as Invariant Sections of your combined work in + its license notice. +

The combined work need only contain one copy of this License, + and multiple identical Invariant + Sections may be replaced with a single copy. If there are + multiple Invariant Sections with the same name but different + contents, make the title of each such section unique by adding + at the end of it, in parentheses, the name of the original + author or publisher of that section if known, or else a unique + number. Make the same adjustment to the section titles in the + list of Invariant Sections in the license notice of the combined + work. +

In the combination, you must combine any sections entitled + "History" in the various original documents, + forming one section entitled "History"; likewise + combine any sections entitled "Acknowledgements", + and any sections entitled "Dedications". You must + delete all sections entitled "Endorsements." +


PrevHomeNext
4. MODIFICATIONSUp6. COLLECTIONS OF DOCUMENTS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16910.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16910.htm new file mode 100644 index 0000000000000000000000000000000000000000..ad33a8334980180963a33f07fd87b7ef8691707a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16910.htm @@ -0,0 +1,162 @@ + +6. COLLECTIONS OF DOCUMENTS
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.7. 6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents + released under this License, and replace the individual copies + of this License in the various documents with a single copy that + is included in the collection, provided that you follow the + rules of this License for verbatim copying of each of the + documents in all other respects. +

You may extract a single document from such a collection, and + dispbibute it individually under this License, provided you + insert a copy of this License into the extracted document, and + follow this License in all other respects regarding verbatim + copying of that document. +


PrevHomeNext
5. COMBINING DOCUMENTSUp7. AGGREGATION WITH INDEPENDENT WORKS
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16915.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16915.htm new file mode 100644 index 0000000000000000000000000000000000000000..00cf0c11463f47708298235d9ec0b846ea9f5fb3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16915.htm @@ -0,0 +1,176 @@ + +7. AGGREGATION WITH INDEPENDENT WORKS
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.8. 7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with + other separate and independent documents or works, in or on a + volume of a storage or distribution medium, does not as a whole + count as a Modified Version + of the Document, provided no compilation copyright is claimed + for the compilation. Such a compilation is called an + "aggregate", and this License does not apply to the + other self-contained works thus compiled with the Document , on + account of their being thus compiled, if they are not themselves + derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these + copies of the Document, then if the Document is less than one + quarter of the entire aggregate, the Document's Cover Texts may + be placed on covers that surround only the Document within the + aggregate. Otherwise they must appear on covers around the whole + aggregate. +


PrevHomeNext
6. COLLECTIONS OF DOCUMENTSUp8. TRANSLATION
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16923.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16923.htm new file mode 100644 index 0000000000000000000000000000000000000000..30adcc4a78248d7bee3ac71d95c102375b78cb4a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16923.htm @@ -0,0 +1,165 @@ + +8. TRANSLATION
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.9. 8. TRANSLATION

Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with + translations requires special permission from their copyright + holders, but you may include translations of some or all + Invariant Sections in addition to the original versions of these + Invariant Sections. You may include a translation of this + License provided that you also include the original English + version of this License. In case of a disagreement between the + translation and the original English version of this License, + the original English version will prevail. +


PrevHomeNext
7. AGGREGATION WITH INDEPENDENT WORKSUp9. TERMINATION
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16929.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16929.htm new file mode 100644 index 0000000000000000000000000000000000000000..1f0cc333f6dd0f09cdd05b1fe8d57e041ebb30d3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16929.htm @@ -0,0 +1,156 @@ + +9. TERMINATION
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.10. 9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly + provided for under this License. Any other attempt to copy, + modify, sublicense or distribute the Document is void, and will + automatically terminate your rights under this License. However, + parties who have received copies, or rights, from you under this + License will not have their licenses terminated so long as such + parties remain in full compliance. +


PrevHomeNext
8. TRANSLATIONUp10. FUTURE REVISIONS OF THIS LICENSE
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16933.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16933.htm new file mode 100644 index 0000000000000000000000000000000000000000..e7787af0358362b69b3e26dc6bf3ccdc885ca160 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16933.htm @@ -0,0 +1,177 @@ + +10. FUTURE REVISIONS OF THIS LICENSE
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.11. 10. FUTURE REVISIONS OF THIS LICENSE

The Free Software + Foundation may publish new, revised versions of the GNU + Free Documentation License from time to time. Such new versions + will be similar in spirit to the present version, but may differ + in detail to address new problems or concerns. See http://www.gnu.org/copyleft/. +

Each version of the License is given a distinguishing version + number. If the Document + specifies that a particular numbered version of this License + "or any later version" applies to it, you have the + option of following the terms and conditions either of that + specified version or of any later version that has been + published (not as a draft) by the Free Software Foundation. If + the Document does not specify a version number of this License, + you may choose any version ever published (not as a draft) by + the Free Software Foundation. +


PrevHomeNext
9. TERMINATIONUpAddendum
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16941.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16941.htm new file mode 100644 index 0000000000000000000000000000000000000000..b422d43ecd6842d3ed8ccd1e8acdd10ea6fdaaf6 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x16941.htm @@ -0,0 +1,217 @@ + +Addendum
Video for Linux Two API Specification: Revision 0.24
PrevAppendix C. GNU Free Documentation LicenseNext

C.12. Addendum

To use this License in a document you have written, include a copy of + the License in the document and put the following copyright and + license notices just after the title page: +

Copyright © YEAR YOUR NAME. +

Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation + License, Version 1.1 or any later version published by the + Free Software Foundation; with the Invariant Sections being LIST + THEIR TITLES, with the Front-Cover Texts being LIST, + and with the Back-Cover + Texts being LIST. A copy of the license is included in + the section entitled "GNU Free Documentation + License". +

If you have no Invariant + Sections, write "with no Invariant Sections" + instead of saying which ones are invariant. If you have no + Front-Cover Texts, write + "no Front-Cover Texts" instead of + "Front-Cover Texts being LIST"; likewise for Back-Cover Texts. +

If your document contains nontrivial examples of program code, + we recommend releasing these examples in parallel under your + choice of free software license, such as the GNU General Public + License, to permit their use in free software. +


PrevHomeNext
10. FUTURE REVISIONS OF THIS LICENSEUpList of Types
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x1859.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x1859.htm new file mode 100644 index 0000000000000000000000000000000000000000..57d48c42aac3dd6744a495d7320525aed84db7f5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x1859.htm @@ -0,0 +1,365 @@ + +Data Formats
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.10. Data Formats

1.10.1. Data Format Negotiation

Different devices exchange different kinds of data with +applications, for example video images, raw or sliced VBI data, RDS +datagrams. Even within one kind many different formats are possible, +in particular an abundance of image formats. Although drivers must +provide a default and the selection persists across closing and +reopening a device, applications should always negotiate a data format +before engaging in data exchange. Negotiation means the application +asks for a particular format and the driver selects and reports the +best the hardware can do to satisfy the request. Of course +applications can also just query the current selection.

A single mechanism exists to negotiate all data formats +using the aggregate struct v4l2_format and the VIDIOC_G_FMT and +VIDIOC_S_FMT ioctls. Additionally the VIDIOC_TRY_FMT ioctl can be +used to examine what the hardware could do, +without actually selecting a new data format. The data formats +supported by the V4L2 API are covered in the respective device section +in Chapter 4. For a closer look at image formats see +Chapter 2.

The VIDIOC_S_FMT ioctl is a major +turning-point in the initialization sequence. Prior to this point +multiple panel applications can access the same device concurrently to +select the current input, change controls or modify other properties. +The first VIDIOC_S_FMT assigns a logical stream +(video data, VBI data etc.) exclusively to one file descriptor.

Exclusive means no other application, more precisely no +other file descriptor, can grab this stream or change device +properties inconsistent with the negotiated parameters. A video +standard change for example, when the new standard uses a different +number of scan lines, can invalidate the selected image format. +Therefore only the file descriptor owning the stream can make +invalidating changes. Accordingly multiple file descriptors which +grabbed different logical streams prevent each other from interfering +with their settings. When for example video overlay is about to start +or already in progress, simultaneous video capturing may be restricted +to the same cropping and image size.

When applications omit the +VIDIOC_S_FMT ioctl its locking side effects are +implied by the next step, the selection of an I/O method with the +VIDIOC_REQBUFS ioctl or implicit with the first read() or +write() call.

Generally only one logical stream can be assigned to a +file descriptor, the exception being drivers permitting simultaneous +video capturing and overlay using the same file descriptor for +compatibility with V4L and earlier versions of V4L2. Switching the +logical stream or returning into "panel mode" is possible by closing +and reopening the device. Drivers may support a +switch using VIDIOC_S_FMT.

All drivers exchanging data with +applications must support the VIDIOC_G_FMT and +VIDIOC_S_FMT ioctl. Implementation of the +VIDIOC_TRY_FMT is highly recommended but +optional.

1.10.2. Image Format Enumeration

Apart of the generic format negotiation functions +a special ioctl to enumerate all image formats supported by video +capture, overlay or output devices is available.[1]

The VIDIOC_ENUM_FMT ioctl must be supported +by all drivers exchanging image data with applications.

Important: Drivers are not supposed to convert image formats in +kernel space. They must enumerate only formats directly supported by +the hardware. If necessary driver writers should publish an example +conversion routine or library for integration into applications.

Notes

[1]

Enumerating formats an application has no a-priori +knowledge of (otherwise it could explicitely ask for them and need not +enumerate) seems useless, but there are applications serving as proxy +between drivers and the actual video applications for which this is +useful.


PrevHomeNext
Extended ControlsUpImage Cropping, Insertion and Scaling
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x1904.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x1904.htm new file mode 100644 index 0000000000000000000000000000000000000000..f7146ad6bc2eb2e2f4aaebff0fba925c0c17aef7 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x1904.htm @@ -0,0 +1,674 @@ + +Image Cropping, Insertion and Scaling
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.11. Image Cropping, Insertion and Scaling

Some video capture devices can sample a subsection of the +picture and shrink or enlarge it to an image of arbitrary size. We +call these abilities cropping and scaling. Some video output devices +can scale an image up or down and insert it at an arbitrary scan line +and horizontal offset into a video signal.

Applications can use the following API to select an area in +the video signal, query the default area and the hardware limits. +Despite their name, the VIDIOC_CROPCAP, VIDIOC_G_CROP +and VIDIOC_S_CROP ioctls apply to input as well as output +devices.

Scaling requires a source and a target. On a video capture +or overlay device the source is the video signal, and the cropping +ioctls determine the area actually sampled. The target are images +read by the application or overlaid onto the graphics screen. Their +size (and position for an overlay) is negotiated with the +VIDIOC_G_FMT and VIDIOC_S_FMT ioctls.

On a video output device the source are the images passed in +by the application, and their size is again negotiated with the +VIDIOC_G/S_FMT ioctls, or may be encoded in a +compressed video stream. The target is the video signal, and the +cropping ioctls determine the area where the images are +inserted.

Source and target rectangles are defined even if the device +does not support scaling or the VIDIOC_G/S_CROP +ioctls. Their size (and position where applicable) will be fixed in +this case. All capture and output device must support the +VIDIOC_CROPCAP ioctl such that applications can +determine if scaling takes place.

1.11.1. Cropping Structures

Figure 1-1. Image Cropping, Insertion and Scaling

For capture devices the coordinates of the top left +corner, width and height of the area which can be sampled is given by +the bounds substructure of the +struct v4l2_cropcap returned by the VIDIOC_CROPCAP +ioctl. To support a wide range of hardware this specification does not +define an origin or units. However by convention drivers should +horizontally count unscaled samples relative to 0H (the leading edge +of the horizontal sync pulse, see Figure 4-1). +Vertically ITU-R line +numbers of the first field (Figure 4-2, Figure 4-3), multiplied by two if the driver can capture both +fields.

The top left corner, width and height of the source +rectangle, that is the area actually sampled, is given by struct v4l2_crop +using the same coordinate system as struct v4l2_cropcap. Applications can +use the VIDIOC_G_CROP and +VIDIOC_S_CROP ioctls to get and set this +rectangle. It must lie completely within the capture boundaries and +the driver may further adjust the requested size and/or position +according to hardware limitations.

Each capture device has a default source rectangle, given +by the defrect substructure of +struct v4l2_cropcap. The center of this rectangle shall align with the +center of the active picture area of the video signal, and cover what +the driver writer considers the complete picture. Drivers shall reset +the source rectangle to the default when the driver is first loaded, +but not later.

For output devices these structures and ioctls are used +accordingly, defining the target rectangle where +the images will be inserted into the video signal.

1.11.2. Scaling Adjustments

Video hardware can have various cropping, insertion and +scaling limitations. It may only scale up or down, support only +discrete scaling factors, or have different scaling abilities in +horizontal and vertical direction. Also it may not support scaling at +all. At the same time the struct v4l2_crop rectangle may have to be +aligned, and both the source and target rectangles may have arbitrary +upper and lower size limits. In particular the maximum +width and height +in struct v4l2_crop may be smaller than the +struct v4l2_cropcap.bounds area. Therefore, as +usual, drivers are expected to adjust the requested parameters and +return the actual values selected.

Applications can change the source or the target rectangle +first, as they may prefer a particular image size or a certain area in +the video signal. If the driver has to adjust both to satisfy hardware +limitations, the last requested rectangle shall take priority, and the +driver should preferably adjust the opposite one. The VIDIOC_TRY_FMT +ioctl however shall not change the driver state and therefore only +adjust the requested rectangle.

Suppose scaling on a video capture device is restricted to +a factor 1:1 or 2:1 in either direction and the target image size must +be a multiple of 16 × 16 pixels. The source cropping +rectangle is set to defaults, which are also the upper limit in this +example, of 640 × 400 pixels at offset 0, 0. An +application requests an image size of 300 × 225 +pixels, assuming video will be scaled down from the "full picture" +accordingly. The driver sets the image size to the closest possible +values 304 × 224, then chooses the cropping rectangle +closest to the requested size, that is 608 × 224 +(224 × 2:1 would exceed the limit 400). The offset +0, 0 is still valid, thus unmodified. Given the default cropping +rectangle reported by VIDIOC_CROPCAP the +application can easily propose another offset to center the cropping +rectangle.

Now the application may insist on covering an area using a +picture aspect ratio closer to the original request, so it asks for a +cropping rectangle of 608 × 456 pixels. The present +scaling factors limit cropping to 640 × 384, so the +driver returns the cropping size 608 × 384 and adjusts +the image size to closest possible 304 × 192.

1.11.3. Examples

Source and target rectangles shall remain unchanged across +closing and reopening a device, such that piping data into or out of a +device will work without special preparations. More advanced +applications should ensure the parameters are suitable before starting +I/O.

Example 1-10. Resetting the cropping parameters

(A video capture device is assumed; change +V4L2_BUF_TYPE_VIDEO_CAPTURE for other +devices.)

struct v4l2_cropcap cropcap;
+struct v4l2_crop crop;
+
+memset (&cropcap, 0, sizeof (cropcap));
+cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
+        perror ("VIDIOC_CROPCAP");
+        exit (EXIT_FAILURE);
+}
+
+memset (&crop, 0, sizeof (crop));
+crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+crop.c = cropcap.defrect;
+
+/* Ignore if cropping is not supported (EINVAL). */
+
+if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop)
+    && errno != EINVAL) {
+        perror ("VIDIOC_S_CROP");
+        exit (EXIT_FAILURE);
+}
+      

Example 1-11. Simple downscaling

(A video capture device is assumed.)

struct v4l2_cropcap cropcap;
+struct v4l2_format format;
+
+reset_cropping_parameters ();
+
+/* Scale down to 1/4 size of full picture. */
+
+memset (&format, 0, sizeof (format)); /* defaults */
+
+format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+format.fmt.pix.width = cropcap.defrect.width >> 1;
+format.fmt.pix.height = cropcap.defrect.height >> 1;
+format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+
+if (-1 == ioctl (fd, VIDIOC_S_FMT, &format)) {
+        perror ("VIDIOC_S_FORMAT");
+        exit (EXIT_FAILURE);
+}
+
+/* We could check the actual image size now, the actual scaling factor
+   or if the driver can scale at all. */
+        

Example 1-12. Selecting an output area

struct v4l2_cropcap cropcap;
+struct v4l2_crop crop;
+
+memset (&cropcap, 0, sizeof (cropcap));
+cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
+        perror ("VIDIOC_CROPCAP");
+        exit (EXIT_FAILURE);
+}
+
+memset (&crop, 0, sizeof (crop));
+
+crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+crop.c = cropcap.defrect;
+
+/* Scale the width and height to 50 % of their original size
+   and center the output. */
+
+crop.c.width /= 2;
+crop.c.height /= 2;
+crop.c.left += crop.c.width / 2;
+crop.c.top += crop.c.height / 2;
+
+/* Ignore if cropping is not supported (EINVAL). */
+
+if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop)
+    && errno != EINVAL) {
+        perror ("VIDIOC_S_CROP");
+        exit (EXIT_FAILURE);
+}

Example 1-13. Current scaling factor and pixel aspect

(A video capture device is assumed.)

struct v4l2_cropcap cropcap;
+struct v4l2_crop crop;
+struct v4l2_format format;
+double hscale, vscale;
+double aspect;
+int dwidth, dheight;
+
+memset (&cropcap, 0, sizeof (cropcap));
+cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
+        perror ("VIDIOC_CROPCAP");
+        exit (EXIT_FAILURE);
+}
+
+memset (&crop, 0, sizeof (crop));
+crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+if (-1 == ioctl (fd, VIDIOC_G_CROP, &crop)) {
+        if (errno != EINVAL) {
+                perror ("VIDIOC_G_CROP");
+                exit (EXIT_FAILURE);
+        }
+
+        /* Cropping not supported. */
+        crop.c = cropcap.defrect;
+}
+
+memset (&format, 0, sizeof (format));
+format.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+if (-1 == ioctl (fd, VIDIOC_G_FMT, &format)) {
+        perror ("VIDIOC_G_FMT");
+        exit (EXIT_FAILURE);
+}
+
+/* The scaling applied by the driver. */
+
+hscale = format.fmt.pix.width / (double) crop.c.width;
+vscale = format.fmt.pix.height / (double) crop.c.height;
+
+aspect = cropcap.pixelaspect.numerator /
+         (double) cropcap.pixelaspect.denominator;
+aspect = aspect * hscale / vscale;
+
+/* Devices following ITU-R BT.601 do not capture
+   square pixels. For playback on a computer monitor
+   we should scale the images to this size. */
+
+dwidth = format.fmt.pix.width / aspect;
+dheight = format.fmt.pix.height;
+        

PrevHomeNext
Data FormatsUpStreaming Parameters
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2009.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2009.htm new file mode 100644 index 0000000000000000000000000000000000000000..da701824a665d7df0a3fc8029c84667f30817553 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2009.htm @@ -0,0 +1,210 @@ + +Streaming Parameters
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.12. Streaming Parameters

Streaming parameters are intended to optimize the video +capture process as well as I/O. Presently applications can request a +high quality capture mode with the VIDIOC_S_PARM ioctl.

The current video standard determines a nominal number of +frames per second. If less than this number of frames is to be +captured or output, applications can request frame skipping or +duplicating on the driver side. This is especially useful when using +the read() or write(), which are not augmented by timestamps +or sequence counters, and to avoid unneccessary data copying.

Finally these ioctls can be used to determine the number of +buffers used internally by a driver in read/write mode. For +implications see the section discussing the read() +function.

To get and set the streaming parameters applications call +the VIDIOC_G_PARM and VIDIOC_S_PARM ioctl, respectively. They take +a pointer to a struct v4l2_streamparm, which contains a union holding +separate parameters for input and output devices.

These ioctls are optional, drivers need not implement +them. If so, they return the EINVAL error code.


PrevHomeNext
Image Cropping, Insertion and ScalingUpImage Formats
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2123.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2123.htm new file mode 100644 index 0000000000000000000000000000000000000000..d2fb197da26a203cb3f6a6489c92149af9e3abd1 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2123.htm @@ -0,0 +1,977 @@ + +Colorspaces
Video for Linux Two API Specification: Revision 0.24
PrevChapter 2. Image FormatsNext

2.2. Colorspaces

[intro]

Gamma Correction

[to do]

E'R = f(R)

E'G = f(G)

E'B = f(B)

Construction of luminance and color-difference +signals

[to do]

E'Y = +CoeffR E'R ++ CoeffG E'G ++ CoeffB E'B

(E'R - E'Y) = E'R +- CoeffR E'R +- CoeffG E'G +- CoeffB E'B

(E'B - E'Y) = E'B +- CoeffR E'R +- CoeffG E'G +- CoeffB E'B

Re-normalized color-difference signals

The color-difference signals are scaled back to unity +range [-0.5;+0.5]:

KB = 0.5 / (1 - CoeffB)

KR = 0.5 / (1 - CoeffR)

PB = +KB (E'B - E'Y) = + 0.5 (CoeffR / CoeffB) E'R ++ 0.5 (CoeffG / CoeffB) E'G ++ 0.5 E'B

PR = +KR (E'R - E'Y) = + 0.5 E'R ++ 0.5 (CoeffG / CoeffR) E'G ++ 0.5 (CoeffB / CoeffR) E'B

Quantization

[to do]

Y' = (Lum. Levels - 1) · E'Y + Lum. Offset

CB = (Chrom. Levels - 1) +· PB + Chrom. Offset

CR = (Chrom. Levels - 1) +· PR + Chrom. Offset

Rounding to the nearest integer and clamping to the range +[0;255] finally yields the digital color components Y'CbCr +stored in YUV images.

+

Example 2-1. ITU-R Rec. BT.601 color conversion

Forward Transformation

int ER, EG, EB;         /* gamma corrected RGB input [0;255] */
+int Y1, Cb, Cr;         /* output [0;255] */
+
+double r, g, b;         /* temporaries */
+double y1, pb, pr;
+
+int
+clamp (double x)
+{
+        int r = x;      /* round to nearest */
+
+        if (r < 0)         return 0;
+        else if (r > 255)  return 255;
+        else               return r;
+}
+
+r = ER / 255.0;
+g = EG / 255.0;
+b = EB / 255.0;
+
+y1  =  0.299  * r + 0.587 * g + 0.114  * b;
+pb  = -0.169  * r - 0.331 * g + 0.5    * b;
+pr  =  0.5    * r - 0.419 * g - 0.081  * b;
+
+Y1 = clamp (219 * y1 + 16);
+Cb = clamp (224 * pb + 128);
+Cr = clamp (224 * pr + 128);
+
+/* or shorter */
+
+y1 = 0.299 * ER + 0.587 * EG + 0.114 * EB;
+
+Y1 = clamp ( (219 / 255.0)                    *       y1  + 16);
+Cb = clamp (((224 / 255.0) / (2 - 2 * 0.114)) * (EB - y1) + 128);
+Cr = clamp (((224 / 255.0) / (2 - 2 * 0.299)) * (ER - y1) + 128);
+      

Inverse Transformation

int Y1, Cb, Cr;         /* gamma pre-corrected input [0;255] */
+int ER, EG, EB;         /* output [0;255] */
+
+double r, g, b;         /* temporaries */
+double y1, pb, pr;
+
+int
+clamp (double x)
+{
+        int r = x;      /* round to nearest */
+
+        if (r < 0)         return 0;
+        else if (r > 255)  return 255;
+        else               return r;
+}
+
+y1 = (255 / 219.0) * (Y1 - 16);
+pb = (255 / 224.0) * (Cb - 128);
+pr = (255 / 224.0) * (Cr - 128);
+
+r = 1.0 * y1 + 0     * pb + 1.402 * pr;
+g = 1.0 * y1 - 0.344 * pb - 0.714 * pr;
+b = 1.0 * y1 + 1.772 * pb + 0     * pr;
+
+ER = clamp (r * 255); /* [ok? one should prob. limit y1,pb,pr] */
+EG = clamp (g * 255);
+EB = clamp (b * 255);
+      

Table 2-2. enum v4l2_colorspace

IdentifierValueDescriptionChromaticities[a]White PointGamma CorrectionLuminance E'YQuantization
RedGreenBlueY'Cb, Cr
V4L2_COLORSPACE_SMPTE170M1NTSC/PAL according to SMPTE 170M, +ITU BT.601x = 0.630, y = 0.340x = 0.310, y = 0.595x = 0.155, y = 0.070x = 0.3127, y = 0.3290, + Illuminant D65E' = 4.5 I for I ≤0.018, +1.099 I0.45 - 0.099 for 0.018 < I0.299 E'R ++ 0.587 E'G ++ 0.114 E'B219 E'Y + 16224 PB,R + 128
V4L2_COLORSPACE_SMPTE240M21125-Line (US) HDTV, see SMPTE 240Mx = 0.630, y = 0.340x = 0.310, y = 0.595x = 0.155, y = 0.070x = 0.3127, y = 0.3290, + Illuminant D65E' = 4 I for I ≤0.0228, +1.1115 I0.45 - 0.1115 for 0.0228 < I0.212 E'R ++ 0.701 E'G ++ 0.087 E'B219 E'Y + 16224 PB,R + 128
V4L2_COLORSPACE_REC7093HDTV and modern devices, see ITU BT.709x = 0.640, y = 0.330x = 0.300, y = 0.600x = 0.150, y = 0.060x = 0.3127, y = 0.3290, + Illuminant D65E' = 4.5 I for I ≤0.018, +1.099 I0.45 - 0.099 for 0.018 < I0.2125 E'R ++ 0.7154 E'G ++ 0.0721 E'B219 E'Y + 16224 PB,R + 128
V4L2_COLORSPACE_BT8784Broken Bt878 extents[b], ITU BT.601?????0.299 E'R ++ 0.587 E'G ++ 0.114 E'B237 E'Y + 16224 PB,R + 128 (probably)
V4L2_COLORSPACE_470_SYSTEM_M5M/NTSC[c] according to ITU BT.470, ITU BT.601x = 0.67, y = 0.33x = 0.21, y = 0.71x = 0.14, y = 0.08x = 0.310, y = 0.316, Illuminant C?0.299 E'R ++ 0.587 E'G ++ 0.114 E'B219 E'Y + 16224 PB,R + 128
V4L2_COLORSPACE_470_SYSTEM_BG6625-line PAL and SECAM systems according to ITU BT.470, ITU BT.601x = 0.64, y = 0.33x = 0.29, y = 0.60x = 0.15, y = 0.06x = 0.313, y = 0.329, +Illuminant D65?0.299 E'R ++ 0.587 E'G ++ 0.114 E'B219 E'Y + 16224 PB,R + 128
V4L2_COLORSPACE_JPEG7JPEG Y'CbCr, see JFIF, ITU BT.601?????0.299 E'R ++ 0.587 E'G ++ 0.114 E'B256 E'Y + 16[d]256 PB,R + 128
V4L2_COLORSPACE_SRGB8[?]x = 0.640, y = 0.330x = 0.300, y = 0.600x = 0.150, y = 0.060x = 0.3127, y = 0.3290, + Illuminant D65E' = 4.5 I for I ≤0.018, +1.099 I0.45 - 0.099 for 0.018 < In/a
Notes:
a. The coordinates of the color primaries are +given in the CIE system (1931)
b. The ubiquitous Bt878 video capture chip +quantizes E'Y to 238 levels, yielding a range +of Y' = 16 … 253, unlike Rec. 601 Y' = 16 … +235. This is not a typo in the Bt878 documentation, it has been +implemented in silicon. The chroma extents are unclear.
c. No identifier exists for M/PAL which uses +the chromaticities of M/NTSC, the remaining parameters are equal to B and +G/PAL.
d. Note JFIF quantizes +Y'PBPR in range [0;+1] and +[-0.5;+0.5] to 257 levels, however Y'CbCr signals +are still clamped to [0;255].

PrevHomeNext
Image FormatsUpIndexed Format
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2428.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2428.htm new file mode 100644 index 0000000000000000000000000000000000000000..5df07239a18ab515d579557ea32a554ed7de9390 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2428.htm @@ -0,0 +1,439 @@ + +Indexed Format
Video for Linux Two API Specification: Revision 0.24
PrevChapter 2. Image FormatsNext

2.3. Indexed Format

In this format each pixel is represented by an 8 bit index +into a 256 entry ARGB palette. It is intended for Video Output Overlays only. There are no ioctls to +access the palette, this must be done with ioctls of the Linux framebuffer API.

Table 2-3. Indexed Image Format

IdentifierCode Byte 0                          
  Bit76543210                          
V4L2_PIX_FMT_PAL8'PAL8' i7i6i5i4i3i2i1i0                          

PrevHomeNext
ColorspacesUpRGB Formats
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2490.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2490.htm new file mode 100644 index 0000000000000000000000000000000000000000..4d2e57d4487967e959bbdecaf7fdb668ad573b97 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x2490.htm @@ -0,0 +1,168 @@ + +RGB Formats
Video for Linux Two API Specification: Revision 0.24
PrevChapter 2. Image FormatsNext

2.4. RGB Formats

Table of Contents
Packed RGB formats -- Packed RGB formats
V4L2_PIX_FMT_SBGGR8 ('BA81') -- Bayer RGB format
V4L2_PIX_FMT_SBGGR16 ('BA82') -- Bayer RGB format

PrevHomeNext
Indexed FormatUpPacked RGB formats
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x282.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x282.htm new file mode 100644 index 0000000000000000000000000000000000000000..4c9542305f3bbe10fe8ed1bdbabd89cc735afaf0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x282.htm @@ -0,0 +1,184 @@ + +Querying Capabilities
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.2. Querying Capabilities

Because V4L2 covers a wide variety of devices not all +aspects of the API are equally applicable to all types of devices. +Furthermore devices of the same type have different capabilities and +this specification permits the omission of a few complicated and less +important parts of the API.

The VIDIOC_QUERYCAP ioctl is available to check if the kernel +device is compatible with this specification, and to query the functions and I/O +methods supported by the device. Other features can be queried +by calling the respective ioctl, for example VIDIOC_ENUMINPUT +to learn about the number, types and names of video connectors on the +device. Although abstraction is a major objective of this API, the +ioctl also allows driver specific applications to reliable identify +the driver.

All V4L2 drivers must support +VIDIOC_QUERYCAP. Applications should always call +this ioctl after opening the device.


PrevHomeNext
Common API ElementsUpApplication Priority
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x294.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x294.htm new file mode 100644 index 0000000000000000000000000000000000000000..75c87c812913373b8bc425b003741d435ed4564f --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x294.htm @@ -0,0 +1,197 @@ + +Application Priority
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.3. Application Priority

When multiple applications share a device it may be +desirable to assign them different priorities. Contrary to the +traditional "rm -rf /" school of thought a video recording application +could for example block other applications from changing video +controls or switching the current TV channel. Another objective is to +permit low priority applications working in background, which can be +preempted by user controlled applications and automatically regain +control of the device at a later time.

Since these features cannot be implemented entirely in user +space V4L2 defines the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY +ioctls to request and query the access priority associate with a file +descriptor. Opening a device assigns a medium priority, compatible +with earlier versions of V4L2 and drivers not supporting these ioctls. +Applications requiring a different priority will usually call +VIDIOC_S_PRIORITY after verifying the device with +the VIDIOC_QUERYCAP ioctl.

Ioctls changing driver properties, such as VIDIOC_S_INPUT, +return an EBUSY error code after another application obtained higher priority. +An event mechanism to notify applications about asynchronous property +changes has been proposed but not added yet.


PrevHomeNext
Querying CapabilitiesUpVideo Inputs and Outputs
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x309.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x309.htm new file mode 100644 index 0000000000000000000000000000000000000000..de91a6eb9694e030c3088003cffb95077d753eb9 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x309.htm @@ -0,0 +1,278 @@ + +Video Inputs and Outputs
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.4. Video Inputs and Outputs

Video inputs and outputs are physical connectors of a +device. These can be for example RF connectors (antenna/cable), CVBS +a.k.a. Composite Video, S-Video or RGB connectors. Only video and VBI +capture devices have inputs, output devices have outputs, at least one +each. Radio devices have no video inputs or outputs.

To learn about the number and attributes of the +available inputs and outputs applications can enumerate them with the +VIDIOC_ENUMINPUT and VIDIOC_ENUMOUTPUT ioctl, respectively. The +struct v4l2_input returned by the VIDIOC_ENUMINPUT +ioctl also contains signal status information applicable when the +current video input is queried.

The VIDIOC_G_INPUT and VIDIOC_G_OUTPUT ioctl return the +index of the current video input or output. To select a different +input or output applications call the VIDIOC_S_INPUT and +VIDIOC_S_OUTPUT ioctl. Drivers must implement all the input ioctls +when the device has one or more inputs, all the output ioctls when the +device has one or more outputs.

Example 1-1. Information about the current video input

struct v4l2_input input;
+int index;
+
+if (-1 == ioctl (fd, VIDIOC_G_INPUT, &index)) {
+        perror ("VIDIOC_G_INPUT");
+        exit (EXIT_FAILURE);
+}
+
+memset (&input, 0, sizeof (input));
+input.index = index;
+
+if (-1 == ioctl (fd, VIDIOC_ENUMINPUT, &input)) {
+        perror ("VIDIOC_ENUMINPUT");
+        exit (EXIT_FAILURE);
+}
+
+printf ("Current input: %s\n", input.name);
+      

Example 1-2. Switching to the first video input

int index;
+
+index = 0;
+
+if (-1 == ioctl (fd, VIDIOC_S_INPUT, &index)) {
+        perror ("VIDIOC_S_INPUT");
+        exit (EXIT_FAILURE);
+}
+      

PrevHomeNext
Application PriorityUpAudio Inputs and Outputs
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x341.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x341.htm new file mode 100644 index 0000000000000000000000000000000000000000..cbe726b539d8757152c8e4d4ccbb6ae5b114f4ad --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x341.htm @@ -0,0 +1,386 @@ + +Audio Inputs and Outputs
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.5. Audio Inputs and Outputs

Audio inputs and outputs are physical connectors of a +device. Video capture devices have inputs, output devices have +outputs, zero or more each. Radio devices have no audio inputs or +outputs. They have exactly one tuner which in fact +is an audio source, but this API associates +tuners with video inputs or outputs only, and radio devices have +none of these.[1] A connector on a TV card to loop back the received +audio signal to a sound card is not considered an audio output.

Audio and video inputs and outputs are associated. Selecting +a video source also selects an audio source. This is most evident when +the video and audio source is a tuner. Further audio connectors can +combine with more than one video input or output. Assumed two +composite video inputs and two audio inputs exist, there may be up to +four valid combinations. The relation of video and audio connectors +is defined in the audioset field of the +respective struct v4l2_input or struct v4l2_output, where each bit represents +the index number, starting at zero, of one audio input or output.

To learn about the number and attributes of the +available inputs and outputs applications can enumerate them with the +VIDIOC_ENUMAUDIO and VIDIOC_ENUMAUDOUT ioctl, respectively. The +struct v4l2_audio returned by the VIDIOC_ENUMAUDIO ioctl +also contains signal status information applicable when the current +audio input is queried.

The VIDIOC_G_AUDIO and VIDIOC_G_AUDOUT ioctl report +the current audio input and output, respectively. Note that, unlike +VIDIOC_G_INPUT and VIDIOC_G_OUTPUT these ioctls return a structure +as VIDIOC_ENUMAUDIO and +VIDIOC_ENUMAUDOUT do, not just an index.

To select an audio input and change its properties +applications call the VIDIOC_S_AUDIO ioctl. To select an audio +output (which presently has no changeable properties) applications +call the VIDIOC_S_AUDOUT ioctl.

Drivers must implement all input ioctls when the device +has one or more inputs, all output ioctls when the device has one +or more outputs. When the device has any audio inputs or outputs the +driver must set the V4L2_CAP_AUDIO flag in the +struct v4l2_capability returned by the VIDIOC_QUERYCAP ioctl.

Example 1-3. Information about the current audio input

struct v4l2_audio audio;
+
+memset (&audio, 0, sizeof (audio));
+
+if (-1 == ioctl (fd, VIDIOC_G_AUDIO, &audio)) {
+        perror ("VIDIOC_G_AUDIO");
+        exit (EXIT_FAILURE);
+}
+
+printf ("Current input: %s\n", audio.name);
+      

Example 1-4. Switching to the first audio input

struct v4l2_audio audio;
+
+memset (&audio, 0, sizeof (audio)); /* clear audio.mode, audio.reserved */
+
+audio.index = 0;
+
+if (-1 == ioctl (fd, VIDIOC_S_AUDIO, &audio)) {
+        perror ("VIDIOC_S_AUDIO");
+        exit (EXIT_FAILURE);
+}
+      

Notes

[1]

Actually struct v4l2_audio ought to have a +tuner field like struct v4l2_input, not only +making the API more consistent but also permitting radio devices with +multiple tuners.


PrevHomeNext
Video Inputs and OutputsUpTuners and Modulators
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x3891.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x3891.htm new file mode 100644 index 0000000000000000000000000000000000000000..98a881b7831dfdd4c0bb3721385c41d4efcc186a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x3891.htm @@ -0,0 +1,257 @@ + +YUV Formats
Video for Linux Two API Specification: Revision 0.24
PrevChapter 2. Image FormatsNext

2.5. YUV Formats

Table of Contents
Packed YUV formats -- Packed YUV formats
V4L2_PIX_FMT_GREY ('GREY') -- Grey-scale image
V4L2_PIX_FMT_Y16 ('Y16 ') -- Grey-scale image
V4L2_PIX_FMT_YUYV ('YUYV') -- Packed format with ½ horizontal chroma +resolution, also known as YUV 4:2:2
V4L2_PIX_FMT_UYVY ('UYVY') -- Variation of +V4L2_PIX_FMT_YUYV with different order of samples +in memory
V4L2_PIX_FMT_Y41P ('Y41P') -- Format with ¼ horizontal chroma +resolution, also known as YUV 4:1:1
V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12') -- Planar formats with ½ horizontal and +vertical chroma resolution, also known as YUV 4:2:0
V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9') -- Planar formats with ¼ horizontal and +vertical chroma resolution, also known as YUV 4:1:0
V4L2_PIX_FMT_YUV422P ('422P') -- Format with ½ horizontal chroma resolution, +also known as YUV 4:2:2. Planar layout as opposed to +V4L2_PIX_FMT_YUYV
V4L2_PIX_FMT_YUV411P ('411P') -- Format with ¼ horizontal chroma resolution, +also known as YUV 4:1:1. Planar layout as opposed to +V4L2_PIX_FMT_Y41P
V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21') -- Formats with ½ horizontal and vertical +chroma resolution, also known as YUV 4:2:0. One luminance and one +chrominance plane with alternating chroma samples as opposed to +V4L2_PIX_FMT_YVU420

YUV is the format native to TV broadcast and composite video +signals. It separates the brightness information (Y) from the color +information (U and V or Cb and Cr). The color information consists of +red and blue color difference signals, this way +the green component can be reconstructed by subtracting from the +brightness component. See Section 2.2 for conversion +examples. YUV was chosen because early television would only transmit +brightness information. To add color in a way compatible with existing +receivers a new signal carrier was added to transmit the color +difference signals. Secondary in the YUV format the U and V components +usually have lower resolution than the Y component. This is an analog +video compression technique taking advantage of a property of the +human visual system, being more sensitive to brightness +information.


PrevHomeNext
V4L2_PIX_FMT_SBGGR16 ('BA82')UpPacked YUV formats
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x394.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x394.htm new file mode 100644 index 0000000000000000000000000000000000000000..0a02f493e6cdf244921062815d03aa54db335dfc --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x394.htm @@ -0,0 +1,346 @@ + +Tuners and Modulators
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.6. Tuners and Modulators

1.6.1. Tuners

Video input devices can have one or more tuners +demodulating a RF signal. Each tuner is associated with one or more +video inputs, depending on the number of RF connectors on the tuner. +The type field of the respective +struct v4l2_input returned by the VIDIOC_ENUMINPUT ioctl is set to +V4L2_INPUT_TYPE_TUNER and its +tuner field contains the index number of +the tuner.

Radio devices have exactly one tuner with index zero, no +video inputs.

To query and change tuner properties applications use the +VIDIOC_G_TUNER and VIDIOC_S_TUNER ioctl, respectively. The +struct v4l2_tuner returned by VIDIOC_G_TUNER also +contains signal status information applicable when the tuner of the +current video input, or a radio tuner is queried. Note that +VIDIOC_S_TUNER does not switch the current tuner, +when there is more than one at all. The tuner is solely determined by +the current video input. Drivers must support both ioctls and set the +V4L2_CAP_TUNER flag in the struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl when the device has one or +more tuners.

1.6.2. Modulators

Video output devices can have one or more modulators, uh, +modulating a video signal for radiation or connection to the antenna +input of a TV set or video recorder. Each modulator is associated with +one or more video outputs, depending on the number of RF connectors on +the modulator. The type field of the +respective struct v4l2_output returned by the VIDIOC_ENUMOUTPUT ioctl is +set to V4L2_OUTPUT_TYPE_MODULATOR and its +modulator field contains the index number +of the modulator. This specification does not define radio output +devices.

To query and change modulator properties applications use +the VIDIOC_G_MODULATOR and VIDIOC_S_MODULATOR ioctl. Note that +VIDIOC_S_MODULATOR does not switch the current +modulator, when there is more than one at all. The modulator is solely +determined by the current video output. Drivers must support both +ioctls and set the V4L2_CAP_TUNER (sic) flag in +the struct v4l2_capability returned by the VIDIOC_QUERYCAP ioctl when the +device has one or more modulators.

1.6.3. Radio Frequency

To get and set the tuner or modulator radio frequency +applications use the VIDIOC_G_FREQUENCY and VIDIOC_S_FREQUENCY +ioctl which both take a pointer to a struct v4l2_frequency. These ioctls +are used for TV and radio devices alike. Drivers must support both +ioctls when the tuner or modulator ioctls are supported, or +when the device is a radio device.

1.6.4. Satellite Receivers

To be discussed. See also +proposals by Peter Schlaf, video4linux-list@redhat.com on 23 Oct 2002, +subject: "Re: [V4L] Re: v4l2 api".


PrevHomeNext
Audio Inputs and OutputsUpVideo Standards
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x448.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x448.htm new file mode 100644 index 0000000000000000000000000000000000000000..8f9d41682595c3fd9d06bf253a6c7fa08347082e --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x448.htm @@ -0,0 +1,658 @@ + +Video Standards
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.7. Video Standards

Video devices typically support one or more different video +standards or variations of standards. Each video input and output may +support another set of standards. This set is reported by the +std field of struct v4l2_input and +struct v4l2_output returned by the VIDIOC_ENUMINPUT and +VIDIOC_ENUMOUTPUT ioctl, respectively.

V4L2 defines one bit for each analog video standard +currently in use worldwide, and sets aside bits for driver defined +standards, e. g. hybrid standards to watch NTSC video tapes on PAL TVs +and vice versa. Applications can use the predefined bits to select a +particular standard, although presenting the user a menu of supported +standards is preferred. To enumerate and query the attributes of the +supported standards applications use the VIDIOC_ENUMSTD ioctl.

Many of the defined standards are actually just variations +of a few major standards. The hardware may in fact not distinguish +between them, or do so internal and switch automatically. Therefore +enumerated standards also contain sets of one or more standard +bits.

Assume a hypothetic tuner capable of demodulating B/PAL, +G/PAL and I/PAL signals. The first enumerated standard is a set of B +and G/PAL, switched automatically depending on the selected radio +frequency in UHF or VHF band. Enumeration gives a "PAL-B/G" or "PAL-I" +choice. Similar a Composite input may collapse standards, enumerating +"PAL-B/G/H/I", "NTSC-M" and "SECAM-D/K".[1]

To query and select the standard used by the current video +input or output applications call the VIDIOC_G_STD and +VIDIOC_S_STD ioctl, respectively. The received +standard can be sensed with the VIDIOC_QUERYSTD ioctl. Note parameter of all these ioctls is a pointer to a v4l2_std_id type (a standard set), not an index into the standard enumeration.[2] Drivers must implement all video standard ioctls +when the device has one or more video inputs or outputs.

Special rules apply to USB cameras where the notion of video +standards makes little sense. More generally any capture device, +output devices accordingly, which is

  • incapable of capturing fields or frames at the nominal +rate of the video standard, or

  • where timestamps refer +to the instant the field or frame was received by the driver, not the +capture time, or

  • where sequence numbers +refer to the frames received by the driver, not the captured +frames.

Here the driver shall set the +std field of struct v4l2_input and struct v4l2_output +to zero, the VIDIOC_G_STD, +VIDIOC_S_STD, +VIDIOC_QUERYSTD and +VIDIOC_ENUMSTD ioctls shall return the +EINVAL error code.[3]

Example 1-5. Information about the current video standard

v4l2_std_id std_id;
+struct v4l2_standard standard;
+
+if (-1 == ioctl (fd, VIDIOC_G_STD, &std_id)) {
+        /* Note when VIDIOC_ENUMSTD always returns EINVAL this
+           is no video device or it falls under the USB exception,
+           and VIDIOC_G_STD returning EINVAL is no error. */
+
+        perror ("VIDIOC_G_STD");
+        exit (EXIT_FAILURE);
+}
+
+memset (&standard, 0, sizeof (standard));
+standard.index = 0;
+
+while (0 == ioctl (fd, VIDIOC_ENUMSTD, &standard)) {
+        if (standard.id & std_id) {
+               printf ("Current video standard: %s\n", standard.name);
+               exit (EXIT_SUCCESS);
+        }
+
+        standard.index++;
+}
+
+/* EINVAL indicates the end of the enumeration, which cannot be
+   empty unless this device falls under the USB exception. */
+
+if (errno == EINVAL || standard.index == 0) {
+        perror ("VIDIOC_ENUMSTD");
+        exit (EXIT_FAILURE);
+}
+      

Example 1-6. Listing the video standards supported by the current +input

struct v4l2_input input;
+struct v4l2_standard standard;
+
+memset (&input, 0, sizeof (input));
+
+if (-1 == ioctl (fd, VIDIOC_G_INPUT, &input.index)) {
+        perror ("VIDIOC_G_INPUT");
+        exit (EXIT_FAILURE);
+}
+
+if (-1 == ioctl (fd, VIDIOC_ENUMINPUT, &input)) {
+        perror ("VIDIOC_ENUM_INPUT");
+        exit (EXIT_FAILURE);
+}
+
+printf ("Current input %s supports:\n", input.name);
+
+memset (&standard, 0, sizeof (standard));
+standard.index = 0;
+
+while (0 == ioctl (fd, VIDIOC_ENUMSTD, &standard)) {
+        if (standard.id & input.std)
+                printf ("%s\n", standard.name);
+
+        standard.index++;
+}
+
+/* EINVAL indicates the end of the enumeration, which cannot be
+   empty unless this device falls under the USB exception. */
+
+if (errno != EINVAL || standard.index == 0) {
+        perror ("VIDIOC_ENUMSTD");
+        exit (EXIT_FAILURE);
+}
+      

Example 1-7. Selecting a new video standard

struct v4l2_input input;
+v4l2_std_id std_id;
+
+memset (&input, 0, sizeof (input));
+
+if (-1 == ioctl (fd, VIDIOC_G_INPUT, &input.index)) {
+        perror ("VIDIOC_G_INPUT");
+        exit (EXIT_FAILURE);
+}
+
+if (-1 == ioctl (fd, VIDIOC_ENUMINPUT, &input)) {
+        perror ("VIDIOC_ENUM_INPUT");
+        exit (EXIT_FAILURE);
+}
+
+if (0 == (input.std & V4L2_STD_PAL_BG)) {
+        fprintf (stderr, "Oops. B/G PAL is not supported.\n");
+        exit (EXIT_FAILURE);
+}
+
+/* Note this is also supposed to work when only B
+   or G/PAL is supported. */
+
+std_id = V4L2_STD_PAL_BG;
+
+if (-1 == ioctl (fd, VIDIOC_S_STD, &std_id)) {
+        perror ("VIDIOC_S_STD");
+        exit (EXIT_FAILURE);
+}
+      

Notes

[1]

Some users are already confused by technical terms PAL, +NTSC and SECAM. There is no point asking them to distinguish between +B, G, D, or K when the software or hardware can do that +automatically.

[2]

An alternative to the current scheme is to use pointers +to indices as arguments of VIDIOC_G_STD and +VIDIOC_S_STD, the struct v4l2_input and +struct v4l2_output std field would be a set of +indices like audioset.

Indices are consistent with the rest of the API +and identify the standard unambiguously. In the present scheme of +things an enumerated standard is looked up by v4l2_std_id. Now the +standards supported by the inputs of a device can overlap. Just +assume the tuner and composite input in the example above both +exist on a device. An enumeration of "PAL-B/G", "PAL-H/I" suggests +a choice which does not exist. We cannot merge or omit sets, because +applications would be unable to find the standards reported by +VIDIOC_G_STD. That leaves separate enumerations +for each input. Also selecting a standard by v4l2_std_id can be +ambiguous. Advantage of this method is that applications need not +identify the standard indirectly, after enumerating.

So in +summary, the lookup itself is unavoidable. The difference is only +whether the lookup is necessary to find an enumerated standard or to +switch to a standard by v4l2_std_id.

[3]

See Section 3.5 for a rationale. Probably +even USB cameras follow some well known video standard. It might have +been better to explicitly indicate elsewhere if a device cannot live +up to normal expectations, instead of this exception.


PrevHomeNext
Tuners and ModulatorsUpUser Controls
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x542.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x542.htm new file mode 100644 index 0000000000000000000000000000000000000000..0f0980f0f6fac1046bd28c8aa37fdc5eb4ed77c7 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x542.htm @@ -0,0 +1,1043 @@ + +User Controls
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.8. User Controls

Devices typically have a number of user-settable controls +such as brightness, saturation and so on, which would be presented to +the user on a graphical user interface. But, different devices +will have different controls available, and furthermore, the range of +possible values, and the default value will vary from device to +device. The control ioctls provide the information and a mechanism to +create a nice user interface for these controls that will work +correctly with any device.

All controls are accessed using an ID value. V4L2 defines +several IDs for specific purposes. Drivers can also implement their +own custom controls using V4L2_CID_PRIVATE_BASE +and higher values. The pre-defined control IDs have the prefix +V4L2_CID_, and are listed in Table 1-1. The ID is used when querying the attributes of +a control, and when getting or setting the current value.

Generally applications should present controls to the user +without assumptions about their purpose. Each control comes with a +name string the user is supposed to understand. When the purpose is +non-intuitive the driver writer should provide a user manual, a user +interface plug-in or a driver specific panel application. Predefined +IDs were introduced to change a few controls programmatically, for +example to mute a device during a channel switch.

Drivers may enumerate different controls after switching +the current video input or output, tuner or modulator, or audio input +or output. Different in the sense of other bounds, another default and +current value, step size or other menu items. A control with a certain +custom ID can also change name and +type.[1] Control values are stored globally, they do not +change when switching except to stay within the reported bounds. They +also do not change e. g. when the device is opened or closed, when the +tuner radio frequency is changed or generally never without +application request. Since V4L2 specifies no event mechanism, panel +applications intended to cooperate with other panel applications (be +they built into a larger application, as a TV viewer) may need to +regularly poll control values to update their user +interface.[2]

Table 1-1. Control IDs

IDTypeDescription
V4L2_CID_BASE First predefined ID, equal to +V4L2_CID_BRIGHTNESS.
V4L2_CID_USER_BASE Synonym of V4L2_CID_BASE.
V4L2_CID_BRIGHTNESSintegerPicture brightness, or more precisely, the black +level.
V4L2_CID_CONTRASTintegerPicture contrast or luma gain.
V4L2_CID_SATURATIONintegerPicture color saturation or chroma gain.
V4L2_CID_HUEintegerHue or color balance.
V4L2_CID_AUDIO_VOLUMEintegerOverall audio volume. Note some drivers also +provide an OSS or ALSA mixer interface.
V4L2_CID_AUDIO_BALANCEintegerAudio stereo balance. Minimum corresponds to all +the way left, maximum to right.
V4L2_CID_AUDIO_BASSintegerAudio bass adjustment.
V4L2_CID_AUDIO_TREBLEintegerAudio treble adjustment.
V4L2_CID_AUDIO_MUTEbooleanMute audio, i. e. set the volume to zero, however +without affecting V4L2_CID_AUDIO_VOLUME. Like +ALSA drivers, V4L2 drivers must mute at load time to avoid excessive +noise. Actually the entire device should be reset to a low power +consumption state.
V4L2_CID_AUDIO_LOUDNESSbooleanLoudness mode (bass boost).
V4L2_CID_BLACK_LEVELintegerAnother name for brightness (not a synonym of +V4L2_CID_BRIGHTNESS). This control is deprecated +and should not be used in new drivers and applications.
V4L2_CID_AUTO_WHITE_BALANCEbooleanAutomatic white balance (cameras).
V4L2_CID_DO_WHITE_BALANCEbuttonThis is an action control. When set (the value is +ignored), the device will do a white balance and then hold the current +setting. Contrast this with the boolean +V4L2_CID_AUTO_WHITE_BALANCE, which, when +activated, keeps adjusting the white balance.
V4L2_CID_RED_BALANCEintegerRed chroma balance.
V4L2_CID_BLUE_BALANCEintegerBlue chroma balance.
V4L2_CID_GAMMAintegerGamma adjust.
V4L2_CID_WHITENESSintegerWhiteness for grey-scale devices. This is a synonym +for V4L2_CID_GAMMA. This control is deprecated +and should not be used in new drivers and applications.
V4L2_CID_EXPOSUREintegerExposure (cameras). [Unit?]
V4L2_CID_AUTOGAINbooleanAutomatic gain/exposure control.
V4L2_CID_GAINintegerGain control.
V4L2_CID_HFLIPbooleanMirror the picture horizontally.
V4L2_CID_VFLIPbooleanMirror the picture vertically.
V4L2_CID_HCENTER_DEPRECATED (formerly V4L2_CID_HCENTER)integerHorizontal image centering. This control is +deprecated. New drivers and applications should use the Camera class controls +V4L2_CID_PAN_ABSOLUTE, +V4L2_CID_PAN_RELATIVE and +V4L2_CID_PAN_RESET instead.
V4L2_CID_VCENTER_DEPRECATED + (formerly V4L2_CID_VCENTER)integerVertical image centering. Centering is intended to +physically adjust cameras. For image cropping see +Section 1.11, for clipping Section 4.2. This +control is deprecated. New drivers and applications should use the +Camera class controls +V4L2_CID_TILT_ABSOLUTE, +V4L2_CID_TILT_RELATIVE and +V4L2_CID_TILT_RESET instead.
V4L2_CID_POWER_LINE_FREQUENCYintegerEnables a power line frequency filter to avoid +flicker. Possible values are: +V4L2_CID_POWER_LINE_FREQUENCY_DISABLED (0), +V4L2_CID_POWER_LINE_FREQUENCY_50HZ (1) and +V4L2_CID_POWER_LINE_FREQUENCY_60HZ (2).
V4L2_CID_HUE_AUTObooleanEnables automatic hue control by the device. The +effect of setting V4L2_CID_HUE while automatic +hue control is enabled is undefined, drivers should ignore such +request.
V4L2_CID_WHITE_BALANCE_TEMPERATUREintegerThis control specifies the white balance settings +as a color temperature in Kelvin. A driver should have a minimum of +2800 (incandescent) to 6500 (daylight). For more information about +color temperature see Wikipedia.
V4L2_CID_SHARPNESSintegerAdjusts the sharpness filters in a camera. The +minimum value disables the filters, higher values give a sharper +picture.
V4L2_CID_BACKLIGHT_COMPENSATIONintegerAdjusts the backlight compensation in a camera. The +minimum value disables backlight compensation.
V4L2_CID_LASTP1 End of the predefined control IDs (currently +V4L2_CID_BACKLIGHT_COMPENSATION + 1).
V4L2_CID_PRIVATE_BASE ID of the first custom (driver specific) control. +Applications depending on particular custom controls should check the +driver name and version, see Section 1.2.

Applications can enumerate the available controls with the +VIDIOC_QUERYCTRL and VIDIOC_QUERYMENU ioctls, get and set a +control value with the VIDIOC_G_CTRL and VIDIOC_S_CTRL ioctls. +Drivers must implement VIDIOC_QUERYCTRL, +VIDIOC_G_CTRL and +VIDIOC_S_CTRL when the device has one or more +controls, VIDIOC_QUERYMENU when it has one or +more menu type controls.

Example 1-8. Enumerating all controls

struct v4l2_queryctrl queryctrl;
+struct v4l2_querymenu querymenu;
+
+static void
+enumerate_menu (void)
+{
+        printf ("  Menu items:\n");
+
+        memset (&querymenu, 0, sizeof (querymenu));
+        querymenu.id = queryctrl.id;
+
+        for (querymenu.index = queryctrl.minimum;
+             querymenu.index <= queryctrl.maximum;
+              querymenu.index++) {
+                if (0 == ioctl (fd, VIDIOC_QUERYMENU, &querymenu)) {
+                        printf ("  %s\n", querymenu.name);
+                } else {
+                        perror ("VIDIOC_QUERYMENU");
+                        exit (EXIT_FAILURE);
+                }
+        }
+}
+
+memset (&queryctrl, 0, sizeof (queryctrl));
+
+for (queryctrl.id = V4L2_CID_BASE;
+     queryctrl.id < V4L2_CID_LASTP1;
+     queryctrl.id++) {
+        if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
+                if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+                        continue;
+
+                printf ("Control %s\n", queryctrl.name);
+
+                if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+                        enumerate_menu ();
+        } else {
+                if (errno == EINVAL)
+                        continue;
+
+                perror ("VIDIOC_QUERYCTRL");
+                exit (EXIT_FAILURE);
+        }
+}
+
+for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
+     queryctrl.id++) {
+        if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
+                if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+                        continue;
+
+                printf ("Control %s\n", queryctrl.name);
+
+                if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+                        enumerate_menu ();
+        } else {
+                if (errno == EINVAL)
+                        break;
+
+                perror ("VIDIOC_QUERYCTRL");
+                exit (EXIT_FAILURE);
+        }
+}

Example 1-9. Changing controls

struct v4l2_queryctrl queryctrl;
+struct v4l2_control control;
+
+memset (&queryctrl, 0, sizeof (queryctrl));
+queryctrl.id = V4L2_CID_BRIGHTNESS;
+
+if (-1 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
+        if (errno != EINVAL) {
+                perror ("VIDIOC_QUERYCTRL");
+                exit (EXIT_FAILURE);
+        } else {
+                printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+        }
+} else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
+        printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+} else {
+        memset (&control, 0, sizeof (control));
+        control.id = V4L2_CID_BRIGHTNESS;
+        control.value = queryctrl.default_value;
+
+        if (-1 == ioctl (fd, VIDIOC_S_CTRL, &control)) {
+                perror ("VIDIOC_S_CTRL");
+                exit (EXIT_FAILURE);
+        }
+}
+
+memset (&control, 0, sizeof (control));
+control.id = V4L2_CID_CONTRAST;
+
+if (0 == ioctl (fd, VIDIOC_G_CTRL, &control)) {
+        control.value += 1;
+
+        /* The driver may clamp the value or return ERANGE, ignored here */
+
+        if (-1 == ioctl (fd, VIDIOC_S_CTRL, &control)
+            && errno != ERANGE) {
+                perror ("VIDIOC_S_CTRL");
+                exit (EXIT_FAILURE);
+        }
+/* Ignore if V4L2_CID_CONTRAST is unsupported */
+} else if (errno != EINVAL) {
+        perror ("VIDIOC_G_CTRL");
+        exit (EXIT_FAILURE);
+}
+
+control.id = V4L2_CID_AUDIO_MUTE;
+control.value = TRUE; /* silence */
+
+/* Errors ignored */
+ioctl (fd, VIDIOC_S_CTRL, &control);

Notes

[1]

It will be more convenient for applications if drivers +make use of the V4L2_CTRL_FLAG_DISABLED flag, but +that was never required.

[2]

Applications could call an ioctl to request events. +After another process called VIDIOC_S_CTRL or another ioctl changing +shared properties the select() function would indicate +readability until any ioctl (querying the properties) is +called.


PrevHomeNext
Video StandardsUpExtended Controls
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5634.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5634.htm new file mode 100644 index 0000000000000000000000000000000000000000..58672c01bb29718d2a99e3a407d0c5f6d4177e8f --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5634.htm @@ -0,0 +1,228 @@ + +Compressed Formats
Video for Linux Two API Specification: Revision 0.24
PrevChapter 2. Image FormatsNext

2.6. Compressed Formats

Table 2-7. Compressed Image Formats

IdentifierCodeDetails
V4L2_PIX_FMT_JPEG'JPEG'TBD. See also VIDIOC_G_JPEGCOMP, + VIDIOC_S_JPEGCOMP.
V4L2_PIX_FMT_MPEG'MPEG'MPEG stream. The actual format is determined by +extended control V4L2_CID_MPEG_STREAM_TYPE, see +Table 1-2.

PrevHomeNext
V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21')UpReserved Format Identifiers
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5665.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5665.htm new file mode 100644 index 0000000000000000000000000000000000000000..9ecbdf911b3ef9c566b58833a7b67010353ba5a6 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5665.htm @@ -0,0 +1,369 @@ + +Reserved Format Identifiers
Video for Linux Two API Specification: Revision 0.24
PrevChapter 2. Image FormatsNext

2.7. Reserved Format Identifiers

These formats are not defined by this specification, they +are just listed for reference and to avoid naming conflicts. If you +want to register your own format, send an e-mail to the V4L mailing +list https://listman.redhat.com/mailman/listinfo/video4linux-list for inclusion in the videodev.h +file. If you want to share your format with other developers add a +link to your documentation and send a copy to the maintainer of this +document, Michael Schimek <mschimek@gmx.at>, for +inclusion in this section. If you think your format should be listed +in a standard format section please make a proposal on the V4L mailing +list.

Table 2-8. Reserved Image Formats

IdentifierCodeDetails
V4L2_PIX_FMT_DV'dvsd'unknown
V4L2_PIX_FMT_ET61X251'E625'Compressed format of the ET61X251 driver.
V4L2_PIX_FMT_HI240'HI24'

8 bit RGB format used by the BTTV driver, +http://bytesex.org/bttv/

V4L2_PIX_FMT_HM12'HM12'

YUV 4:2:0 format used by the +IVTV driver, http://www.ivtvdriver.org/

The format is documented in the +kernel sources in the file Documentation/video4linux/cx2341x/README.hm12

V4L2_PIX_FMT_MJPEG'MJPG'Compressed format used by the Zoran driver
V4L2_PIX_FMT_PWC1'PWC1'Compressed format of the PWC driver.
V4L2_PIX_FMT_PWC2'PWC2'Compressed format of the PWC driver.
V4L2_PIX_FMT_SN9C10X'S910'Compressed format of the SN9C102 driver.
V4L2_PIX_FMT_WNVA'WNVA'

Used by the Winnov Videum driver, http://www.thedirks.org/winnov/

V4L2_PIX_FMT_YYUV'YYUV'unknown

PrevHomeNext
Compressed FormatsUpInput/Output
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5791.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5791.htm new file mode 100644 index 0000000000000000000000000000000000000000..3c786f325569d73526b964d2f8799727351cdb85 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5791.htm @@ -0,0 +1,642 @@ + +Streaming I/O (Memory Mapping)
Video for Linux Two API Specification: Revision 0.24
PrevChapter 3. Input/OutputNext

3.2. Streaming I/O (Memory Mapping)

Input and output devices support this I/O method when the +V4L2_CAP_STREAMING flag in the +capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl is set. There are two +streaming methods, to determine if the memory mapping flavor is +supported applications must call the VIDIOC_REQBUFS ioctl.

Streaming is an I/O method where only pointers to buffers +are exchanged between application and driver, the data itself is not +copied. Memory mapping is primarily intended to map buffers in device +memory into the application's address space. Device memory can be for +example the video memory on a graphics card with a video capture +add-on. However, being the most efficient I/O method available for a +long time, many other drivers support streaming as well, allocating +buffers in DMA-able main memory.

A driver can support many sets of buffers. Each set is +identified by a unique buffer type value. The sets are independent and +each set can hold a different type of data. To access different sets +at the same time different file descriptors must be used.[1]

To allocate device buffers applications call the +VIDIOC_REQBUFS ioctl with the desired number of buffers and buffer +type, for example V4L2_BUF_TYPE_VIDEO_CAPTURE. +This ioctl can also be used to change the number of buffers or to free +the allocated memory, provided none of the buffers are still +mapped.

Before applications can access the buffers they must map +them into their address space with the mmap() function. The +location of the buffers in device memory can be determined with the +VIDIOC_QUERYBUF ioctl. The m.offset and +length returned in a struct v4l2_buffer are +passed as sixth and second parameter to the +mmap() function. The offset and length values +must not be modified. Remember the buffers are allocated in physical +memory, as opposed to virtual memory which can be swapped out to disk. +Applications should free the buffers as soon as possible with the +munmap() function.

Example 3-1. Mapping buffers

struct v4l2_requestbuffers reqbuf;
+struct {
+        void *start;
+        size_t length;
+} *buffers;
+unsigned int i;
+
+memset (&reqbuf, 0, sizeof (reqbuf));
+reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+reqbuf.memory = V4L2_MEMORY_MMAP;
+reqbuf.count = 20;
+
+if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
+        if (errno == EINVAL)
+                printf ("Video capturing or mmap-streaming is not supported\n");
+        else
+                perror ("VIDIOC_REQBUFS");
+
+        exit (EXIT_FAILURE);
+}
+
+/* We want at least five buffers. */
+
+if (reqbuf.count < 5) {
+        /* You may need to free the buffers here. */
+        printf ("Not enough buffer memory\n");
+        exit (EXIT_FAILURE);
+}
+
+buffers = calloc (reqbuf.count, sizeof (*buffers));
+assert (buffers != NULL);
+
+for (i = 0; i < reqbuf.count; i++) {
+        struct v4l2_buffer buffer;
+
+        memset (&buffer, 0, sizeof (buffer));
+        buffer.type = reqbuf.type;
+	buffer.memory = V4L2_MEMORY_MMAP;
+        buffer.index = i;
+
+        if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
+                perror ("VIDIOC_QUERYBUF");
+                exit (EXIT_FAILURE);
+        }
+
+        buffers[i].length = buffer.length; /* remember for munmap() */
+
+        buffers[i].start = mmap (NULL, buffer.length,
+                                 PROT_READ | PROT_WRITE, /* recommended */
+                                 MAP_SHARED,             /* recommended */
+                                 fd, buffer.m.offset);
+
+        if (MAP_FAILED == buffers[i].start) {
+                /* If you do not exit here you should unmap() and free()
+                   the buffers mapped so far. */
+                perror ("mmap");
+                exit (EXIT_FAILURE);
+        }
+}
+
+/* Cleanup. */
+
+for (i = 0; i < reqbuf.count; i++)
+        munmap (buffers[i].start, buffers[i].length);
+      

Conceptually streaming drivers maintain two buffer queues, an incoming +and an outgoing queue. They separate the synchronous capture or output +operation locked to a video clock from the application which is +subject to random disk or network delays and preemption by +other processes, thereby reducing the probability of data loss. +The queues are organized as FIFOs, buffers will be +output in the order enqueued in the incoming FIFO, and were +captured in the order dequeued from the outgoing FIFO.

The driver may require a minimum number of buffers enqueued +at all times to function, apart of this no limit exists on the number +of buffers applications can enqueue in advance, or dequeue and +process. They can also enqueue in a different order than buffers have +been dequeued, and the driver can fill enqueued +empty buffers in any order. [2] The index number of a buffer (struct v4l2_buffer +index) plays no role here, it only +identifies the buffer.

Initially all mapped buffers are in dequeued state, +inaccessible by the driver. For capturing applications it is customary +to first enqueue all mapped buffers, then to start capturing and enter +the read loop. Here the application waits until a filled buffer can be +dequeued, and re-enqueues the buffer when the data is no longer +needed. Output applications fill and enqueue buffers, when enough +buffers are stacked up the output is started with +VIDIOC_STREAMON. In the write loop, when +the application runs out of free buffers, it must wait until an empty +buffer can be dequeued and reused.

To enqueue and dequeue a buffer applications use the +VIDIOC_QBUF and VIDIOC_DQBUF ioctl. The status of a buffer being +mapped, enqueued, full or empty can be determined at any time using the +VIDIOC_QUERYBUF ioctl. Two methods exist to suspend execution of the +application until one or more buffers can be dequeued. By default +VIDIOC_DQBUF blocks when no buffer is in the +outgoing queue. When the O_NONBLOCK flag was +given to the open() function, VIDIOC_DQBUF +returns immediately with an EAGAIN error code when no buffer is available. The +select() or poll() function are always available.

To start and stop capturing or output applications call the +VIDIOC_STREAMON and VIDIOC_STREAMOFF ioctl. Note +VIDIOC_STREAMOFF removes all buffers from both +queues as a side effect. Since there is no notion of doing anything +"now" on a multitasking system, if an application needs to synchronize +with another event it should examine the struct v4l2_buffer +timestamp of captured buffers, or set the +field before enqueuing buffers for output.

Drivers implementing memory mapping I/O must +support the VIDIOC_REQBUFS, +VIDIOC_QUERYBUF, +VIDIOC_QBUF, VIDIOC_DQBUF, +VIDIOC_STREAMON and +VIDIOC_STREAMOFF ioctl, the +mmap(), munmap(), +select() and poll() +function.[3]

[capture example]

Notes

[1]

One could use one file descriptor and set the buffer +type field accordingly when calling VIDIOC_QBUF etc., but it makes +the select() function ambiguous. We also like the +clean approach of one file descriptor per logical stream. Video +overlay for example is also a logical stream, although the CPU is not +needed for continuous operation.

[2]

Random enqueue order permits applications processing +images out of order (such as video codecs) to return buffers earlier, +reducing the probability of data loss. Random fill order allows +drivers to reuse buffers on a LIFO-basis, taking advantage of caches +holding scatter-gather lists and the like.

[3]

At the driver level select() and +poll() are the same, and +select() is too important to be optional. The +rest should be evident.


PrevHomeNext
Input/OutputUpStreaming I/O (User Pointers)
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5884.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5884.htm new file mode 100644 index 0000000000000000000000000000000000000000..c10232d3cfa49c57efe7f2e39f875ce28541c179 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5884.htm @@ -0,0 +1,467 @@ + +Streaming I/O (User Pointers)
Video for Linux Two API Specification: Revision 0.24
PrevChapter 3. Input/OutputNext

3.3. Streaming I/O (User Pointers)

Input and output devices support this I/O method when the +V4L2_CAP_STREAMING flag in the +capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl is set. If the particular user +pointer method (not only memory mapping) is supported must be +determined by calling the VIDIOC_REQBUFS ioctl.

This I/O method combines advantages of the read/write and +memory mapping methods. Buffers are allocated by the application +itself, and can reside for example in virtual or shared memory. Only +pointers to data are exchanged, these pointers and meta-information +are passed in struct v4l2_buffer. The driver must be switched +into user pointer I/O mode by calling the VIDIOC_REQBUFS with the +desired buffer type. No buffers are allocated beforehands, +consequently they are not indexed and cannot be queried like mapped +buffers with the VIDIOC_QUERYBUF ioctl.

Example 3-2. Initiating streaming I/O with user pointers

struct v4l2_requestbuffers reqbuf;
+
+memset (&reqbuf, 0, sizeof (reqbuf));
+reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+reqbuf.memory = V4L2_MEMORY_USERPTR;
+
+if (ioctl (fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
+        if (errno == EINVAL)
+                printf ("Video capturing or user pointer streaming is not supported\n");
+        else
+                perror ("VIDIOC_REQBUFS");
+
+        exit (EXIT_FAILURE);
+}
+      

Buffer addresses and sizes are passed on the fly with the +VIDIOC_QBUF ioctl. Although buffers are commonly cycled, +applications can pass different addresses and sizes at each +VIDIOC_QBUF call. If required by the hardware the +driver swaps memory pages within physical memory to create a +continuous area of memory. This happens transparently to the +application in the virtual memory subsystem of the kernel. When buffer +pages have been swapped out to disk they are brought back and finally +locked in physical memory for DMA.[1]

Filled or displayed buffers are dequeued with the +VIDIOC_DQBUF ioctl. The driver can unlock the memory pages at any +time between the completion of the DMA and this ioctl. The memory is +also unlocked when VIDIOC_STREAMOFF is called, VIDIOC_REQBUFS, or +when the device is closed. Applications must take care not to free +buffers without dequeuing. For once, the buffers remain locked until +further, wasting physical memory. Second the driver will not be +notified when the memory is returned to the application's free list +and subsequently reused for other purposes, possibly completing the +requested DMA and overwriting valuable data.

For capturing applications it is customary to enqueue a +number of empty buffers, to start capturing and enter the read loop. +Here the application waits until a filled buffer can be dequeued, and +re-enqueues the buffer when the data is no longer needed. Output +applications fill and enqueue buffers, when enough buffers are stacked +up output is started. In the write loop, when the application +runs out of free buffers it must wait until an empty buffer can be +dequeued and reused. Two methods exist to suspend execution of the +application until one or more buffers can be dequeued. By default +VIDIOC_DQBUF blocks when no buffer is in the +outgoing queue. When the O_NONBLOCK flag was +given to the open() function, VIDIOC_DQBUF +returns immediately with an EAGAIN error code when no buffer is available. The +select() or poll() function are always available.

To start and stop capturing or output applications call the +VIDIOC_STREAMON and VIDIOC_STREAMOFF ioctl. Note +VIDIOC_STREAMOFF removes all buffers from both +queues and unlocks all buffers as a side effect. Since there is no +notion of doing anything "now" on a multitasking system, if an +application needs to synchronize with another event it should examine +the struct v4l2_buffer timestamp of captured +buffers, or set the field before enqueuing buffers for output.

Drivers implementing user pointer I/O must +support the VIDIOC_REQBUFS, +VIDIOC_QBUF, VIDIOC_DQBUF, +VIDIOC_STREAMON and +VIDIOC_STREAMOFF ioctl, the +select() and poll() function.[2]

Notes

[1]

We expect that frequently used buffers are typically not +swapped out. Anyway, the process of swapping, locking or generating +scatter-gather lists may be time consuming. The delay can be masked by +the depth of the incoming buffer queue, and perhaps by maintaining +caches assuming a buffer will be soon enqueued again. On the other +hand, to optimize memory usage drivers can limit the number of buffers +locked in advance and recycle the most recently used buffers first. Of +course, the pages of empty buffers in the incoming queue need not be +saved to disk. Output buffers must be saved on the incoming and +outgoing queue because an application may share them with other +processes.

[2]

At the driver level select() and +poll() are the same, and +select() is too important to be optional. The +rest should be evident.


PrevHomeNext
Streaming I/O (Memory Mapping)UpAsynchronous I/O
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5950.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5950.htm new file mode 100644 index 0000000000000000000000000000000000000000..7f5bbc787070752180db71dac078839518d27441 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5950.htm @@ -0,0 +1,146 @@ + +Asynchronous I/O
Video for Linux Two API Specification: Revision 0.24
PrevChapter 3. Input/OutputNext

3.4. Asynchronous I/O

This method is not defined yet.


PrevHomeNext
Streaming I/O (User Pointers)UpBuffers
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5953.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5953.htm new file mode 100644 index 0000000000000000000000000000000000000000..c7515ea4db0dddfba466f2dc32878a3ba33f5c57 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x5953.htm @@ -0,0 +1,1380 @@ + +Buffers
Video for Linux Two API Specification: Revision 0.24
PrevChapter 3. Input/OutputNext

3.5. Buffers

A buffer contains data exchanged by application and +driver using one of the Streaming I/O methods. Only pointers to +buffers are exchanged, the data itself is not copied. These pointers, +together with meta-information like timestamps or field parity, are +stored in a struct v4l2_buffer, argument to +the VIDIOC_QUERYBUF, VIDIOC_QBUF and VIDIOC_DQBUF ioctl.

Nominally timestamps refer to the first data byte transmitted. +In practice however the wide range of hardware covered by the V4L2 API +limits timestamp accuracy. Often an interrupt routine will +sample the system clock shortly after the field or frame was stored +completely in memory. So applications must expect a constant +difference up to one field or frame period plus a small (few scan +lines) random error. The delay and error can be much +larger due to compression or transmission over an external bus when +the frames are not properly stamped by the sender. This is frequently +the case with USB cameras. Here timestamps refer to the instant the +field or frame was received by the driver, not the capture time. These +devices identify by not enumerating any video standards, see Section 1.7.

Similar limitations apply to output timestamps. Typically +the video hardware locks to a clock controlling the video timing, the +horizontal and vertical synchronization pulses. At some point in the +line sequence, possibly the vertical blanking, an interrupt routine +samples the system clock, compares against the timestamp and programs +the hardware to repeat the previous field or frame, or to display the +buffer contents.

Apart of limitations of the video device and natural +inaccuracies of all clocks, it should be noted system time itself is +not perfectly stable. It can be affected by power saving cycles, +warped to insert leap seconds, or even turned back or forth by the +system administrator affecting long term measurements. [1]

Table 3-1. struct v4l2_buffer

__u32index Number of the buffer, set by the application. This +field is only used for memory mapping I/O +and can range from zero to the number of buffers allocated +with the VIDIOC_REQBUFS ioctl (struct v4l2_requestbuffers count) minus one.
enum v4l2_buf_typetype Type of the buffer, same as struct v4l2_format +type or struct v4l2_requestbuffers +type, set by the application.
__u32bytesused The number of bytes occupied by the data in the +buffer. It depends on the negotiated data format and may change with +each buffer for compressed variable size data like JPEG images. +Drivers must set this field when type +refers to an input stream, applications when an output stream.
__u32flags Flags set by the application or driver, see Table 3-3.
enum v4l2_fieldfield Indicates the field order of the image in the +buffer, see Table 3-8. This field is not used when +the buffer contains VBI data. Drivers must set it when +type refers to an input stream, +applications when an output stream.
struct timevaltimestamp 

For input streams this is the +system time (as returned by the gettimeofday() +function) when the first data byte was captured. For output streams +the data will not be displayed before this time, secondary to the +nominal frame rate determined by the current video standard in +enqueued order. Applications can for example zero this field to +display frames as soon as possible. The driver stores the time at +which the first data byte was actually sent out in the +timestamp field. This permits +applications to monitor the drift between the video and system +clock.

struct v4l2_timecodetimecode When type is +V4L2_BUF_TYPE_VIDEO_CAPTURE and the +V4L2_BUF_FLAG_TIMECODE flag is set in +flags, this structure contains a frame +timecode. In V4L2_FIELD_ALTERNATE +mode the top and bottom field contain the same timecode. +Timecodes are intended to help video editing and are typically recorded on +video tapes, but also embedded in compressed formats like MPEG. This +field is independent of the timestamp and +sequence fields.
__u32sequence Set by the driver, counting the frames in the +sequence.

In V4L2_FIELD_ALTERNATE mode the top and +bottom field have the same sequence number. The count starts at zero +and includes dropped or repeated frames. A dropped frame was received +by an input device but could not be stored due to lack of free buffer +space. A repeated frame was displayed again by an output device +because the application did not pass new data in +time.

Note this may count the frames received +e.g. over USB, without taking into account the frames dropped by the +remote hardware due to limited compression throughput or bus +bandwidth. These devices identify by not enumerating any video +standards, see Section 1.7.

enum v4l2_memorymemory This field must be set by applications and/or drivers +in accordance with the selected I/O method.
unionm  
 __u32offsetWhen memory is +V4L2_MEMORY_MMAP this is the offset of the buffer +from the start of the device memory. The value is returned by the +driver and apart of serving as parameter to the mmap() function +not useful for applications. See Section 3.2 for details.
 unsigned longuserptrWhen memory is +V4L2_MEMORY_USERPTR this is a pointer to the +buffer (casted to unsigned long type) in virtual memory, set by the +application. See Section 3.3 for details.
__u32length Size of the buffer (not the payload) in bytes.
__u32input Some video capture drivers support rapid and +synchronous video input changes, a function useful for example in +video surveillance applications. For this purpose applications set the +V4L2_BUF_FLAG_INPUT flag, and this field to the +number of a video input as in struct v4l2_input field +index.
__u32reserved A place holder for future extensions and custom +(driver defined) buffer types +V4L2_BUF_TYPE_PRIVATE and higher.

Table 3-2. enum v4l2_buf_type

V4L2_BUF_TYPE_VIDEO_CAPTURE1Buffer of a video capture stream, see Section 4.1.
V4L2_BUF_TYPE_VIDEO_OUTPUT2Buffer of a video output stream, see Section 4.3.
V4L2_BUF_TYPE_VIDEO_OVERLAY3Buffer for video overlay, see Section 4.2.
V4L2_BUF_TYPE_VBI_CAPTURE4Buffer of a raw VBI capture stream, see Section 4.7.
V4L2_BUF_TYPE_VBI_OUTPUT5Buffer of a raw VBI output stream, see Section 4.7.
V4L2_BUF_TYPE_SLICED_VBI_CAPTURE6Buffer of a sliced VBI capture stream, see Section 4.8.
V4L2_BUF_TYPE_SLICED_VBI_OUTPUT7Buffer of a sliced VBI output stream, see Section 4.8.
V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY8Buffer for video output overlay (OSD), see Section 4.4. Status: Experimental.
V4L2_BUF_TYPE_PRIVATE0x80This and higher values are reserved for custom +(driver defined) buffer types.

Table 3-3. Buffer Flags

V4L2_BUF_FLAG_MAPPED0x0001The buffer resides in device memory and has been mapped +into the application's address space, see Section 3.2 for details. +Drivers set or clear this flag when the +VIDIOC_QUERYBUF, VIDIOC_QBUF or VIDIOC_DQBUF ioctl is called. Set by the driver.
V4L2_BUF_FLAG_QUEUED0x0002Internally drivers maintain two buffer queues, an +incoming and outgoing queue. When this flag is set, the buffer is +currently on the incoming queue. It automatically moves to the +outgoing queue after the buffer has been filled (capture devices) or +displayed (output devices). Drivers set or clear this flag when the +VIDIOC_QUERYBUF ioctl is called. After +(successful) calling the VIDIOC_QBUF ioctl it is +always set and after VIDIOC_DQBUF always +cleared.
V4L2_BUF_FLAG_DONE0x0004When this flag is set, the buffer is currently on +the outgoing queue, ready to be dequeued from the driver. Drivers set +or clear this flag when the VIDIOC_QUERYBUF ioctl +is called. After calling the VIDIOC_QBUF or +VIDIOC_DQBUF it is always cleared. Of course a +buffer cannot be on both queues at the same time, the +V4L2_BUF_FLAG_QUEUED and +V4L2_BUF_FLAG_DONE flag are mutually exclusive. +They can be both cleared however, then the buffer is in "dequeued" +state, in the application domain to say so.
V4L2_BUF_FLAG_KEYFRAME0x0008Drivers set or clear this flag when calling the +VIDIOC_DQBUF ioctl. It may be set by video +capture devices when the buffer contains a compressed image which is a +key frame (or field), i. e. can be decompressed on its own.
V4L2_BUF_FLAG_PFRAME0x0010Similar to V4L2_BUF_FLAG_KEYFRAME +this flags predicted frames or fields which contain only differences to a +previous key frame.
V4L2_BUF_FLAG_BFRAME0x0020Similar to V4L2_BUF_FLAG_PFRAME + this is a bidirectional predicted frame or field. [ooc tbd]
V4L2_BUF_FLAG_TIMECODE0x0100The timecode field is valid. +Drivers set or clear this flag when the VIDIOC_DQBUF +ioctl is called.
V4L2_BUF_FLAG_INPUT0x0200The input field is valid. +Applications set or clear this flag before calling the +VIDIOC_QBUF ioctl.

Table 3-4. enum v4l2_memory

V4L2_MEMORY_MMAP1The buffer is used for memory +mapping I/O.
V4L2_MEMORY_USERPTR2The buffer is used for user +pointer I/O.
V4L2_MEMORY_OVERLAY3[to do]

3.5.1. Timecodes

The v4l2_timecode structure is +designed to hold a SMPTE 12M or similar timecode. +(struct timeval timestamps are stored in +struct v4l2_buffer field timestamp.)

Table 3-5. struct v4l2_timecode

__u32typeFrame rate the timecodes are based on, see Table 3-6.
__u32flagsTimecode flags, see Table 3-7.
__u8framesFrame count, 0 ... 23/24/29/49/59, depending on the + type of timecode.
__u8secondsSeconds count, 0 ... 59. This is a binary, not BCD number.
__u8minutesMinutes count, 0 ... 59. This is a binary, not BCD number.
__u8hoursHours count, 0 ... 29. This is a binary, not BCD number.
__u8userbits[4]The "user group" bits from the timecode.

Table 3-6. Timecode Types

V4L2_TC_TYPE_24FPS124 frames per second, i. e. film.
V4L2_TC_TYPE_25FPS225 frames per second, i. e. PAL or SECAM video.
V4L2_TC_TYPE_30FPS330 frames per second, i. e. NTSC video.
V4L2_TC_TYPE_50FPS4 
V4L2_TC_TYPE_60FPS5 

Table 3-7. Timecode Flags

V4L2_TC_FLAG_DROPFRAME0x0001Indicates "drop frame" semantics for counting frames +in 29.97 fps material. When set, frame numbers 0 and 1 at the start of +each minute, except minutes 0, 10, 20, 30, 40, 50 are omitted from the +count.
V4L2_TC_FLAG_COLORFRAME0x0002The "color frame" flag.
V4L2_TC_USERBITS_field0x000CField mask for the "binary group flags".
V4L2_TC_USERBITS_USERDEFINED0x0000Unspecified format.
V4L2_TC_USERBITS_8BITCHARS0x00088-bit ISO characters.

Notes

[1]

Since no other Linux multimedia +API supports unadjusted time it would be foolish to introduce here. We +must use a universally supported clock to synchronize different media, +hence time of day.


PrevHomeNext
Asynchronous I/OUpField Order
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6386.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6386.htm new file mode 100644 index 0000000000000000000000000000000000000000..adc443b674306ee1b659de8eec84852a0d86cb90 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6386.htm @@ -0,0 +1,467 @@ + +Field Order
Video for Linux Two API Specification: Revision 0.24
PrevChapter 3. Input/OutputNext

3.6. Field Order

We have to distinguish between progressive and interlaced +video. Progressive video transmits all lines of a video image +sequentially. Interlaced video divides an image into two fields, +containing only the odd and even lines of the image, respectively. +Alternating the so called odd and even field are transmitted, and due +to a small delay between fields a cathode ray TV displays the lines +interleaved, yielding the original frame. This curious technique was +invented because at refresh rates similar to film the image would +fade out too quickly. Transmitting fields reduces the flicker without +the necessity of doubling the frame rate and with it the bandwidth +required for each channel.

It is important to understand a video camera does not expose +one frame at a time, merely transmitting the frames separated into +fields. The fields are in fact captured at two different instances in +time. An object on screen may well move between one field and the +next. For applications analysing motion it is of paramount importance +to recognize which field of a frame is older, the temporal +order.

When the driver provides or accepts images field by field +rather than interleaved, it is also important applications understand +how the fields combine to frames. We distinguish between top and +bottom fields, the spatial order: The first line +of the top field is the first line of an interlaced frame, the first +line of the bottom field is the second line of that frame.

However because fields were captured one after the other, +arguing whether a frame commences with the top or bottom field is +pointless. Any two successive top and bottom, or bottom and top fields +yield a valid frame. Only when the source was progressive to begin +with, e. g. when transferring film to video, two fields may come from +the same frame, creating a natural order.

Counter to intuition the top field is not necessarily the +older field. Whether the older field contains the top or bottom lines +is a convention determined by the video standard. Hence the +distinction between temporal and spatial order of fields. The diagrams +below should make this clearer.

All video capture and output devices must report the current +field order. Some drivers may permit the selection of a different +order, to this end applications initialize the +field field of struct v4l2_pix_format before +calling the VIDIOC_S_FMT ioctl. If this is not desired it should +have the value V4L2_FIELD_ANY (0).

Table 3-8. enum v4l2_field

V4L2_FIELD_ANY0Applications request this field order when any +one of the V4L2_FIELD_NONE, +V4L2_FIELD_TOP, +V4L2_FIELD_BOTTOM, or +V4L2_FIELD_INTERLACED formats is acceptable. +Drivers choose depending on hardware capabilities or e. g. the +requested image size, and return the actual field order. struct v4l2_buffer +field can never be +V4L2_FIELD_ANY.
V4L2_FIELD_NONE1Images are in progressive format, not interlaced. +The driver may also indicate this order when it cannot distinguish +between V4L2_FIELD_TOP and +V4L2_FIELD_BOTTOM.
V4L2_FIELD_TOP2Images consist of the top field only.
V4L2_FIELD_BOTTOM3Images consist of the bottom field only. +Applications may wish to prevent a device from capturing interlaced +images because they will have "comb" or "feathering" artefacts around +moving objects.
V4L2_FIELD_INTERLACED4Images contain both fields, interleaved line by +line. The temporal order of the fields (whether the top or bottom +field is first transmitted) depends on the current video standard. +M/NTSC transmits the bottom field first, all other standards the top +field first.
V4L2_FIELD_SEQ_TB5Images contain both fields, the top field lines +are stored first in memory, immediately followed by the bottom field +lines. Fields are always stored in temporal order, the older one first +in memory. Image sizes refer to the frame, not fields.
V4L2_FIELD_SEQ_BT6Images contain both fields, the bottom field +lines are stored first in memory, immediately followed by the top +field lines. Fields are always stored in temporal order, the older one +first in memory. Image sizes refer to the frame, not fields.
V4L2_FIELD_ALTERNATE7The two fields of a frame are passed in separate +buffers, in temporal order, i. e. the older one first. To indicate the field +parity (whether the current field is a top or bottom field) the driver +or application, depending on data direction, must set struct v4l2_buffer +field to +V4L2_FIELD_TOP or +V4L2_FIELD_BOTTOM. Any two successive fields pair +to build a frame. If fields are successive, without any dropped fields +between them (fields can drop individually), can be determined from +the struct v4l2_buffer sequence field. Image +sizes refer to the frame, not fields. This format cannot be selected +when using the read/write I/O method.
V4L2_FIELD_INTERLACED_TB8Images contain both fields, interleaved line by +line, top field first. The top field is transmitted first.
V4L2_FIELD_INTERLACED_BT9Images contain both fields, interleaved line by +line, top field first. The bottom field is transmitted first.

Figure 3-1. Field Order, Top Field First Transmitted

Figure 3-2. Field Order, Bottom Field First Transmitted


PrevHomeNext
BuffersUpInterfaces
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6570.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6570.htm new file mode 100644 index 0000000000000000000000000000000000000000..84270bc377878e9ab25dde3a57e2d8f7e2732c2b --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6570.htm @@ -0,0 +1,1107 @@ + +Video Overlay Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.2. Video Overlay Interface

Also known as Framebuffer Overlay or Previewing

Video overlay devices have the ability to genlock (TV-)video +into the (VGA-)video signal of a graphics card, or to store captured +images directly in video memory of a graphics card, typically with +clipping. This can be considerable more efficient than capturing +images and displaying them by other means. In the old days when only +nuclear power plants needed cooling towers this used to be the only +way to put live video into a window.

Video overlay devices are accessed through the same character +special files as video capture devices. +Note the default function of a /dev/video device +is video capturing. The overlay function is only available after +calling the VIDIOC_S_FMT ioctl.

The driver may support simultaneous overlay and capturing +using the read/write and streaming I/O methods. If so, operation at +the nominal frame rate of the video standard is not guaranteed. Frames +may be directed away from overlay to capture, or one field may be used +for overlay and the other for capture if the capture parameters permit +this.

Applications should use different file descriptors for +capturing and overlay. This must be supported by all drivers capable +of simultaneous capturing and overlay. Optionally these drivers may +also permit capturing and overlay with a single file descriptor for +compatibility with V4L and earlier versions of V4L2.[1]

4.2.1. Querying Capabilities

Devices supporting the video overlay interface set the +V4L2_CAP_VIDEO_OVERLAY flag in the +capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl. The overlay I/O method specified +below must be supported. Tuners and audio inputs are optional.

4.2.2. Supplemental Functions

Video overlay devices shall support audio input, tuner, controls, +cropping and scaling and streaming parameter ioctls as needed. +The video input and video standard ioctls must be supported by +all video overlay devices.

4.2.3. Setup

Before overlay can commence applications must program the +driver with frame buffer parameters, namely the address and size of +the frame buffer and the image format, for example RGB 5:6:5. The +VIDIOC_G_FBUF and VIDIOC_S_FBUF ioctls are available to get +and set these parameters, respectively. The +VIDIOC_S_FBUF ioctl is privileged because it +allows to set up DMA into physical memory, bypassing the memory +protection mechanisms of the kernel. Only the superuser can change the +frame buffer address and size. Users are not supposed to run TV +applications as root or with SUID bit set. A small helper application +with suitable privileges should query the graphics system and program +the V4L2 driver at the appropriate time.

Some devices add the video overlay to the output signal +of the graphics card. In this case the frame buffer is not modified by +the video device, and the frame buffer address and pixel format are +not needed by the driver. The VIDIOC_S_FBUF ioctl +is not privileged. An application can check for this type of device by +calling the VIDIOC_G_FBUF ioctl.

A driver may support any (or none) of five clipping/blending +methods:

  1. Chroma-keying displays the overlaid image only where +pixels in the primary graphics surface assume a certain color.

  2. A bitmap can be specified where each bit corresponds +to a pixel in the overlaid image. When the bit is set, the +corresponding video pixel is displayed, otherwise a pixel of the +graphics surface.

  3. A list of clipping rectangles can be specified. In +these regions no video is displayed, so the +graphics surface can be seen here.

  4. The framebuffer has an alpha channel that can be used +to clip or blend the framebuffer with the video.

  5. A global alpha value can be specified to blend the +framebuffer contents with video images.

When simultaneous capturing and overlay is supported and +the hardware prohibits different image and frame buffer formats, the +format requested first takes precedence. The attempt to capture +(VIDIOC_S_FMT) or overlay (VIDIOC_S_FBUF) may fail with an +EBUSY error code or return accordingly modified parameters..

4.2.4. Overlay Window

The overlaid image is determined by cropping and overlay +window parameters. The former select an area of the video picture to +capture, the latter how images are overlaid and clipped. Cropping +initialization at minimum requires to reset the parameters to +defaults. An example is given in Section 1.11.

The overlay window is described by a struct v4l2_window. It +defines the size of the image, its position over the graphics surface +and the clipping to be applied. To get the current parameters +applications set the type field of a +struct v4l2_format to V4L2_BUF_TYPE_VIDEO_OVERLAY and +call the VIDIOC_G_FMT ioctl. The driver fills the +v4l2_window substructure named +win. It is not possible to retrieve a +previously programmed clipping list or bitmap.

To program the overlay window applications set the +type field of a struct v4l2_format to +V4L2_BUF_TYPE_VIDEO_OVERLAY, initialize the +win substructure and call the +VIDIOC_S_FMT ioctl. The driver adjusts the parameters against +hardware limits and returns the actual parameters as +VIDIOC_G_FMT does. Like +VIDIOC_S_FMT, the VIDIOC_TRY_FMT ioctl can be +used to learn about driver capabilities without actually changing +driver state. Unlike VIDIOC_S_FMT this also works +after the overlay has been enabled.

The scaling factor of the overlaid image is implied by the +width and height given in struct v4l2_window and the size of the cropping +rectangle. For more information see Section 1.11.

When simultaneous capturing and overlay is supported and +the hardware prohibits different image and window sizes, the size +requested first takes precedence. The attempt to capture or overlay as +well (VIDIOC_S_FMT) may fail with an EBUSY error code or return accordingly +modified parameters.

Table 4-1. struct v4l2_window

struct v4l2_rectwSize and position of the window relative to the +top, left corner of the frame buffer defined with VIDIOC_S_FBUF. The +window can extend the frame buffer width and height, the +x and y +coordinates can be negative, and it can lie completely outside the +frame buffer. The driver clips the window accordingly, or if that is +not possible, modifies its size and/or position.
enum v4l2_fieldfieldApplications set this field to determine which +video field shall be overlaid, typically one of +V4L2_FIELD_ANY (0), +V4L2_FIELD_TOP, +V4L2_FIELD_BOTTOM or +V4L2_FIELD_INTERLACED. Drivers may have to choose +a different field order and return the actual setting here.
__u32chromakeyWhen chroma-keying has been negotiated with +VIDIOC_S_FBUF applications set this field to the desired pixel value +for the chroma key. The format is the same as the pixel format of the +framebuffer (struct v4l2_framebuffer +fmt.pixelformat field), with bytes in host +order. E. g. for V4L2_PIX_FMT_BGR24 +the value should be 0xRRGGBB on a little endian, 0xBBGGRR on a big +endian host.
struct v4l2_clip *clipsWhen chroma-keying has not +been negotiated and VIDIOC_G_FBUF indicated this capability, +applications can set this field to point to an array of +clipping rectangles.
Like the window coordinates +w, clipping rectangles are defined relative +to the top, left corner of the frame buffer. However clipping +rectangles must not extend the frame buffer width and height, and they +must not overlap. If possible applications should merge adjacent +rectangles. Whether this must create x-y or y-x bands, or the order of +rectangles, is not defined. When clip lists are not supported the +driver ignores this field. Its contents after calling VIDIOC_S_FMT +are undefined.
__u32clipcountWhen the application set the +clips field, this field must contain the +number of clipping rectangles in the list. When clip lists are not +supported the driver ignores this field, its contents after calling +VIDIOC_S_FMT are undefined. When clip lists are +supported but no clipping is desired this field must be set to +zero.
void *bitmapWhen chroma-keying has +not been negotiated and VIDIOC_G_FBUF indicated +this capability, applications can set this field to point to a +clipping bit mask.

It must be of the same size +as the window, w.width and +w.height. Each bit corresponds to a pixel +in the overlaid image, which is displayed only when the bit is +set. Pixel coordinates translate to bits like: +

((__u8 *) bitmap)[w.width * y + x / 8] & (1 << (x & 7))

where 0 ≤ x < +w.width and 0 ≤ +y <w.height.a

When a clipping +bit mask is not supported the driver ignores this field, its contents +after calling VIDIOC_S_FMT are undefined. When a bit mask is supported +but no clipping is desired this field must be set to +NULL.

Applications need not create a +clip list or bit mask. When they pass both, or despite negotiating +chroma-keying, the results are undefined. Regardless of the chosen +method, the clipping abilities of the hardware may be limited in +quantity or quality. The results when these limits are exceeded are +undefined.b

__u8global_alpha

The global alpha value used to blend the +framebuffer with video images, if global alpha blending has been +negotiated (V4L2_FBUF_FLAG_GLOBAL_ALPHA, see +VIDIOC_S_FBUF, Table 3).

Note +this field was added in Linux 2.6.23, extending the structure. However +the VIDIOC_G/S/TRY_FMT ioctls, +which take a pointer to a v4l2_format parent structure with padding +bytes at the end, are not affected.

Notes:
a. Should we require + w.width to be a multiple of + eight?
b. When the image is written into frame buffer +memory it will be undesirable if the driver clips out less pixels +than expected, because the application and graphics system are not +aware these regions need to be refreshed. The driver should clip out +more pixels or not write the image at all.

Table 4-2. struct v4l2_clip[2]

struct v4l2_rectcCoordinates of the clipping rectangle, relative to +the top, left corner of the frame buffer. Only window pixels +outside all clipping rectangles are +displayed.
struct v4l2_clip *nextPointer to the next clipping rectangle, NULL when +this is the last rectangle. Drivers ignore this field, it cannot be +used to pass a linked list of clipping rectangles.

Table 4-3. struct v4l2_rect

__s32leftHorizontal offset of the top, left corner of the +rectangle, in pixels.
__s32topVertical offset of the top, left corner of the +rectangle, in pixels. Offsets increase to the right and down.
__s32widthWidth of the rectangle, in pixels.
__s32heightHeight of the rectangle, in pixels. Width and +height cannot be negative, the fields are signed for hysterical +reasons.

4.2.5. Enabling Overlay

To start or stop the frame buffer overlay applications call +the VIDIOC_OVERLAY ioctl.

Notes

[1]

A common application of two file descriptors is the +XFree86 Xv/V4L interface driver and +a V4L2 application. While the X server controls video overlay, the +application can take advantage of memory mapping and DMA.

In the opinion of the designers of this API, no driver +writer taking the efforts to support simultaneous capturing and +overlay will restrict this ability by requiring a single file +descriptor, as in V4L and earlier versions of V4L2. Making this +optional means applications depending on two file descriptors need +backup routines to be compatible with all drivers, which is +considerable more work than using two fds in applications which do +not. Also two fd's fit the general concept of one file descriptor for +each logical stream. Hence as a complexity trade-off drivers +must support two file descriptors and +may support single fd operation.

[2]

The X Window system defines "regions" which are +vectors of struct BoxRec { short x1, y1, x2, y2; } with width = x2 - +x1 and height = y2 - y1, so one cannot pass X11 clip lists +directly.


PrevHomeNext
InterfacesUpVideo Output Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6831.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6831.htm new file mode 100644 index 0000000000000000000000000000000000000000..e179053e4b87d560fbff61c13e05ad3ed69de873 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6831.htm @@ -0,0 +1,427 @@ + +Video Output Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.3. Video Output Interface

Video output devices encode stills or image sequences as +analog video signal. With this interface applications can +control the encoding process and move images from user space to +the driver.

Conventionally V4L2 video output devices are accessed through +character device special files named /dev/video +and /dev/video0 to +/dev/video63 with major number 81 and minor +numbers 0 to 63. /dev/video is typically a +symbolic link to the preferred video device. Note the same device +files are used for video capture devices.

4.3.1. Querying Capabilities

Devices supporting the video output interface set the +V4L2_CAP_VIDEO_OUTPUT flag in the +capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl. As secondary device functions +they may also support the raw VBI +output (V4L2_CAP_VBI_OUTPUT) interface. At +least one of the read/write or streaming I/O methods must be +supported. Modulators and audio outputs are optional.

4.3.2. Supplemental Functions

Video output devices shall support audio output, modulator, controls, +cropping and scaling and streaming parameter ioctls as needed. +The video output and video standard ioctls must be supported by +all video output devices.

4.3.3. Image Format Negotiation

The output is determined by cropping and image format +parameters. The former select an area of the video picture where the +image will appear, the latter how images are stored in memory, i. e. in +RGB or YUV format, the number of bits per pixel or width and height. +Together they also define how images are scaled in the process.

As usual these parameters are not reset +at open() time to permit Unix tool chains, programming a device +and then writing to it as if it was a plain file. Well written V4L2 +applications ensure they really get what they want, including cropping +and scaling.

Cropping initialization at minimum requires to reset the +parameters to defaults. An example is given in Section 1.11.

To query the current image format applications set the +type field of a struct v4l2_format to +V4L2_BUF_TYPE_VIDEO_OUTPUT and call the +VIDIOC_G_FMT ioctl with a pointer to this structure. Drivers fill +the struct v4l2_pix_format pix member of the +fmt union.

To request different parameters applications set the +type field of a struct v4l2_format as above and +initialize all fields of the struct v4l2_pix_format +vbi member of the +fmt union, or better just modify the +results of VIDIOC_G_FMT, and call the +VIDIOC_S_FMT ioctl with a pointer to this structure. Drivers may +adjust the parameters and finally return the actual parameters as +VIDIOC_G_FMT does.

Like VIDIOC_S_FMT the +VIDIOC_TRY_FMT ioctl can be used to learn about hardware limitations +without disabling I/O or possibly time consuming hardware +preparations.

The contents of struct v4l2_pix_format are discussed in Chapter 2. See also the specification of the +VIDIOC_G_FMT, VIDIOC_S_FMT +and VIDIOC_TRY_FMT ioctls for details. Video +output devices must implement both the +VIDIOC_G_FMT and +VIDIOC_S_FMT ioctl, even if +VIDIOC_S_FMT ignores all requests and always +returns default parameters as VIDIOC_G_FMT does. +VIDIOC_TRY_FMT is optional.

4.3.4. Writing Images

A video output device may support the write() function and/or streaming (memory mapping or user pointer) I/O. See Chapter 3 for details.


PrevHomeNext
Video Overlay InterfaceUpVideo Output Overlay Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6909.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6909.htm new file mode 100644 index 0000000000000000000000000000000000000000..9dbdc3310f44ffd57987a46831039433e05c946d --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6909.htm @@ -0,0 +1,494 @@ + +Video Output Overlay Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.4. Video Output Overlay Interface

Also known as On-Screen Display (OSD)

Experimental: This is an experimental +interface and may change in the future.

Some video output devices can overlay a framebuffer image onto +the outgoing video signal. Applications can set up such an overlay +using this interface, which borrows structures and ioctls of the Video Overlay interface.

The OSD function is accessible through the same character +special file as the Video Output function. +Note the default function of such a /dev/video device +is video capturing or output. The OSD function is only available after +calling the VIDIOC_S_FMT ioctl.

4.4.1. Querying Capabilities

Devices supporting the Video Output +Overlay interface set the +V4L2_CAP_VIDEO_OUTPUT_OVERLAY flag in the +capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl.

4.4.2. Framebuffer

Contrary to the Video Overlay +interface the framebuffer is normally implemented on the TV card and +not the graphics card. On Linux it is accessible as a framebuffer +device (/dev/fbN). Given a V4L2 device, +applications can find the corresponding framebuffer device by calling +the VIDIOC_G_FBUF ioctl. It returns, amongst other information, the +physical address of the framebuffer in the +base field of struct v4l2_framebuffer. The +framebuffer device ioctl FBIOGET_FSCREENINFO +returns the same address in the smem_start +field of struct fb_fix_screeninfo. The +FBIOGET_FSCREENINFO ioctl and struct +fb_fix_screeninfo are defined in the +linux/fb.h header file.

The width and height of the framebuffer depends on the +current video standard. A V4L2 driver may reject attempts to change +the video standard (or any other ioctl which would imply a framebuffer +size change) with an EBUSY error code until all applications closed the +framebuffer device.

Example 4-1. Finding a framebuffer device for OSD

#include <linux/fb.h>
+
+struct v4l2_framebuffer fbuf;
+unsigned int i;
+int fb_fd;
+
+if (-1 == ioctl (fd, VIDIOC_G_FBUF, &fbuf)) {
+        perror ("VIDIOC_G_FBUF");
+        exit (EXIT_FAILURE);
+}
+
+for (i = 0; i < 30; ++i) {
+        char dev_name[16];
+        struct fb_fix_screeninfo si;
+
+        snprintf (dev_name, sizeof (dev_name), "/dev/fb%u", i);
+
+        fb_fd = open (dev_name, O_RDWR);
+        if (-1 == fb_fd) {
+                switch (errno) {
+                case ENOENT: /* no such file */
+                case ENXIO:  /* no driver */
+                        continue;
+
+                default:
+                        perror ("open");
+                        exit (EXIT_FAILURE);
+                }
+        }
+
+        if (0 == ioctl (fb_fd, FBIOGET_FSCREENINFO, &si)) {
+                if (si.smem_start == (unsigned long) fbuf.base)
+                        break;
+        } else {
+                /* Apparently not a framebuffer device. */
+        }
+
+        close (fb_fd);
+        fb_fd = -1;
+}
+
+/* fb_fd is the file descriptor of the framebuffer device
+   for the video output overlay, or -1 if no device was found. */

4.4.3. Overlay Window and Scaling

The overlay is controlled by source and target rectangles. +The source rectangle selects a subsection of the framebuffer image to +be overlaid, the target rectangle an area in the outgoing video signal +where the image will appear. Drivers may or may not support scaling, +and arbitrary sizes and positions of these rectangles. Further drivers +may support any (or none) of the clipping/blending methods defined for +the Video Overlay interface.

A struct v4l2_window defines the size of the source rectangle, +its position in the framebuffer and the clipping/blending method to be +used for the overlay. To get the current parameters applications set +the type field of a struct v4l2_format to +V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY and call the +VIDIOC_G_FMT ioctl. The driver fills the +v4l2_window substructure named +win. It is not possible to retrieve a +previously programmed clipping list or bitmap.

To program the source rectangle applications set the +type field of a struct v4l2_format to +V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, initialize +the win substructure and call the +VIDIOC_S_FMT ioctl. The driver adjusts the parameters against +hardware limits and returns the actual parameters as +VIDIOC_G_FMT does. Like +VIDIOC_S_FMT, the VIDIOC_TRY_FMT ioctl can be +used to learn about driver capabilities without actually changing +driver state. Unlike VIDIOC_S_FMT this also works +after the overlay has been enabled.

A struct v4l2_crop defines the size and position of the target +rectangle. The scaling factor of the overlay is implied by the width +and height given in struct v4l2_window and struct v4l2_crop. The cropping API +applies to Video Output and Video +Output Overlay devices in the same way as to +Video Capture and Video +Overlay devices, merely reversing the direction of the +data flow. For more information see Section 1.11.

4.4.4. Enabling Overlay

There is no V4L2 ioctl to enable or disable the overlay, +however the framebuffer interface of the driver may support the +FBIOBLANK ioctl.


PrevHomeNext
Video Output InterfaceUpCodec Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6991.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6991.htm new file mode 100644 index 0000000000000000000000000000000000000000..37d2a7631a48e9d606c9853b517296edff9c9d3a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x6991.htm @@ -0,0 +1,177 @@ + +Codec Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.5. Codec Interface

Suspended: This interface has been be suspended from the V4L2 API +implemented in Linux 2.6 until we have more experience with codec +device interfaces.

A V4L2 codec can compress, decompress, transform, or otherwise +convert video data from one format into another format, in memory. +Applications send data to be converted to the driver through a +write() call, and receive the converted data through a +read() call. For efficiency a driver may also support streaming +I/O.

[to do]


PrevHomeNext
Video Output Overlay InterfaceUpEffect Devices Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7002.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7002.htm new file mode 100644 index 0000000000000000000000000000000000000000..d8748540bf13d15961f3edecbae45b9ede6df997 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7002.htm @@ -0,0 +1,176 @@ + +Effect Devices Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.6. Effect Devices Interface

Suspended: This interface has been be suspended from the V4L2 API +implemented in Linux 2.6 until we have more experience with effect +device interfaces.

A V4L2 video effect device can do image effects, filtering, or +combine two or more images or image streams. For example video +transitions or wipes. Applications send data to be processed and +receive the result data either with read() and write() +functions, or through the streaming I/O mechanism.

[to do]


PrevHomeNext
Codec InterfaceUpRaw VBI Data Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7013.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7013.htm new file mode 100644 index 0000000000000000000000000000000000000000..e5fe02e08d0c3175acd83a7bddfdff8e0948bba3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7013.htm @@ -0,0 +1,916 @@ + +Raw VBI Data Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.7. Raw VBI Data Interface

VBI is an abbreviation of Vertical Blanking Interval, a gap +in the sequence of lines of an analog video signal. During VBI +no picture information is transmitted, allowing some time while the +electron beam of a cathode ray tube TV returns to the top of the +screen. Using an oscilloscope you will find here the vertical +synchronization pulses and short data packages ASK +modulated[1] +onto the video signal. These are transmissions of services such as +Teletext or Closed Caption.

Subject of this interface type is raw VBI data, as sampled off +a video signal, or to be added to a signal for output. +The data format is similar to uncompressed video images, a number of +lines times a number of samples per line, we call this a VBI image.

Conventionally V4L2 VBI devices are accessed through character +device special files named /dev/vbi and +/dev/vbi0 to /dev/vbi31 with +major number 81 and minor numbers 224 to 255. +/dev/vbi is typically a symbolic link to the +preferred VBI device. This convention applies to both input and output +devices.

To address the problems of finding related video and VBI +devices VBI capturing and output is also available as device function +under /dev/video. To capture or output raw VBI +data with these devices applications must call the VIDIOC_S_FMT +ioctl. Accessed as /dev/vbi, raw VBI capturing +or output is the default device function.

4.7.1. Querying Capabilities

Devices supporting the raw VBI capturing or output API set +the V4L2_CAP_VBI_CAPTURE or +V4L2_CAP_VBI_OUTPUT flags, respectively, in the +capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl. At least one of the +read/write, streaming or asynchronous I/O methods must be +supported. VBI devices may or may not have a tuner or modulator.

4.7.2. Supplemental Functions

VBI devices shall support video +input or output, tuner or +modulator, and controls ioctls +as needed. The video standard ioctls provide +information vital to program a VBI device, therefore must be +supported.

4.7.3. Raw VBI Format Negotiation

Raw VBI sampling abilities can vary, in particular the +sampling frequency. To properly interpret the data V4L2 specifies an +ioctl to query the sampling parameters. Moreover, to allow for some +flexibility applications can also suggest different parameters.

As usual these parameters are not +reset at open() time to permit Unix tool chains, programming a +device and then reading from it as if it was a plain file. Well +written V4L2 applications should always ensure they really get what +they want, requesting reasonable parameters and then checking if the +actual parameters are suitable.

To query the current raw VBI capture parameters +applications set the type field of a +struct v4l2_format to V4L2_BUF_TYPE_VBI_CAPTURE or +V4L2_BUF_TYPE_VBI_OUTPUT, and call the +VIDIOC_G_FMT ioctl with a pointer to this structure. Drivers fill +the struct v4l2_vbi_format vbi member of the +fmt union.

To request different parameters applications set the +type field of a struct v4l2_format as above and +initialize all fields of the struct v4l2_vbi_format +vbi member of the +fmt union, or better just modify the +results of VIDIOC_G_FMT, and call the +VIDIOC_S_FMT ioctl with a pointer to this structure. Drivers return +an EINVAL error code only when the given parameters are ambiguous, otherwise +they modify the parameters according to the hardware capabilites and +return the actual parameters. When the driver allocates resources at +this point, it may return an EBUSY error code to indicate the returned +parameters are valid but the required resources are currently not +available. That may happen for instance when the video and VBI areas +to capture would overlap, or when the driver supports multiple opens +and another process already requested VBI capturing or output. Anyway, +applications must expect other resource allocation points which may +return EBUSY, at the VIDIOC_STREAMON ioctl +and the first read(), write() and select() call.

VBI devices must implement both the +VIDIOC_G_FMT and +VIDIOC_S_FMT ioctl, even if +VIDIOC_S_FMT ignores all requests and always +returns default parameters as VIDIOC_G_FMT does. +VIDIOC_TRY_FMT is optional.

Table 4-4. struct v4l2_vbi_format

__u32sampling_rateSamples per second, i. e. unit 1 Hz.
__u32offset

Horizontal offset of the VBI image, +relative to the leading edge of the line synchronization pulse and +counted in samples: The first sample in the VBI image will be located +offset / +sampling_rate seconds following the leading +edge. See also Figure 4-1.

__u32samples_per_line 
__u32sample_format

Defines the sample format as in Chapter 2, a four-character-code.a Usually this is +V4L2_PIX_FMT_GREY, i. e. each sample +consists of 8 bits with lower values oriented towards the black level. +Do not assume any other correlation of values with the signal level. +For example, the MSB does not necessarily indicate if the signal is +'high' or 'low' because 128 may not be the mean value of the +signal. Drivers shall not convert the sample format by software.

__u32start[2]This is the scanning system line number +associated with the first line of the VBI image, of the first and the +second field respectively. See Figure 4-2 and +Figure 4-3 for valid values. VBI input drivers can +return start values 0 if the hardware cannot reliable identify +scanning lines, VBI acquisition may not require this +information.
__u32count[2]The number of lines in the first and second +field image, respectively.

Drivers should be as +flexibility as possible. For example, it may be possible to extend or +move the VBI capture window down to the picture area, implementing a +'full field mode' to capture data service transmissions embedded in +the picture.

An application can set the first or second +count value to zero if no data is required +from the respective field; count[1] if the +scanning system is progressive, i. e. not interlaced. The +corresponding start value shall be ignored by the application and +driver. Anyway, drivers may not support single field capturing and +return both count values non-zero.

Both +count values set to zero, or line numbers +outside the bounds depicted in Figure 4-2 and Figure 4-3, or a field image covering +lines of two fields, are invalid and shall not be returned by the +driver.

To initialize the start +and count fields, applications must first +determine the current video standard selection. The v4l2_std_id or +the framelines field of struct v4l2_standard can +be evaluated for this purpose.

__u32flagsSee Table 4-5 below. Currently +only drivers set flags, applications must set this field to +zero.
__u32reserved[2]This array is reserved for future extensions. +Drivers and applications must set it to zero.
Notes:
a. A few devices may be unable to +sample VBI data at all but can extend the video capture window to the +VBI region.

Table 4-5. Raw VBI Format Flags

V4L2_VBI_UNSYNC0x0001

This flag indicates hardware which does not +properly distinguish between fields. Normally the VBI image stores the +first field (lower scanning line numbers) first in memory. This may be +a top or bottom field depending on the video standard. When this flag +is set the first or second field may be stored first, however the +fields are still in correct temporal order with the older field first +in memory.a

V4L2_VBI_INTERLACED0x0002By default the two field images will be passed +sequentially; all lines of the first field followed by all lines of +the second field (compare Section 3.6 +V4L2_FIELD_SEQ_TB and +V4L2_FIELD_SEQ_BT, whether the top or bottom +field is first in memory depends on the video standard). When this +flag is set, the two fields are interlaced (cf. +V4L2_FIELD_INTERLACED). The first line of the +first field followed by the first line of the second field, then the +two second lines, and so on. Such a layout may be necessary when the +hardware has been programmed to capture or output interlaced video +images and is unable to separate the fields for VBI capturing at +the same time. For simplicity setting this flag implies that both +count values are equal and non-zero.
Notes:
a. Most VBI services transmit on both fields, but +some have different semantics depending on the field number. These +cannot be reliable decoded or encoded when +V4L2_VBI_UNSYNC is set.

Figure 4-1. Line synchronization

Figure 4-2. ITU-R 525 line numbering (M/NTSC and M/PAL)

(1) For the purpose of this specification field 2 +starts in line 264 and not 263.5 because half line capturing is not +supported.

Figure 4-3. ITU-R 625 line numbering

(1) For the purpose of this specification field 2 +starts in line 314 and not 313.5 because half line capturing is not +supported.

Remember the VBI image format depends on the selected +video standard, therefore the application must choose a new standard or +query the current standard first. Attempts to read or write data ahead +of format negotiation, or after switching the video standard which may +invalidate the negotiated VBI parameters, should be refused by the +driver. A format change during active I/O is not permitted.

4.7.4. Reading and writing VBI images

To assure synchronization with the field number and easier +implementation, the smallest unit of data passed at a time is one +frame, consisting of two fields of VBI images immediately following in +memory.

The total size of a frame computes as follows:

(count[0] + count[1]) *
+samples_per_line * sample size in bytes

The sample size is most likely always one byte, +applications must check the sample_format +field though, to function properly with other drivers.

A VBI device may support read/write and/or streaming (memory mapping or user pointer) I/O. The latter bears the +possibility of synchronizing video and +VBI data by using buffer timestamps.

Remember the VIDIOC_STREAMON ioctl and the first read(), +write() and select() call can be resource allocation points returning +an EBUSY error code if the required hardware resources are temporarily +unavailable, for example the device is already in use by another +process.

Notes

[1]

ASK: Amplitude-Shift Keying. A high signal +level represents a '1' bit, a low level a '0' bit.


PrevHomeNext
Effect Devices InterfaceUpSliced VBI Data Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7236.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7236.htm new file mode 100644 index 0000000000000000000000000000000000000000..dfb6764218eac20a08245cc87d4d04a89ffc8ef5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7236.htm @@ -0,0 +1,1196 @@ + +Sliced VBI Data Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.8. Sliced VBI Data Interface

VBI stands for Vertical Blanking Interval, a gap in the +sequence of lines of an analog video signal. During VBI no picture +information is transmitted, allowing some time while the electron beam +of a cathode ray tube TV returns to the top of the screen.

Sliced VBI devices use hardware to demodulate data transmitted +in the VBI. V4L2 drivers shall not do this by +software, see also the raw VBI +interface. The data is passed as short packets of fixed size, +covering one scan line each. The number of packets per video frame is +variable.

Sliced VBI capture and output devices are accessed through the +same character special files as raw VBI devices. When a driver +supports both interfaces, the default function of a +/dev/vbi device is raw VBI +capturing or output, and the sliced VBI function is only available +after calling the VIDIOC_S_FMT ioctl as defined below. Likewise a +/dev/video device may support the sliced VBI API, +however the default function here is video capturing or output. +Different file descriptors must be used to pass raw and sliced VBI +data simultaneously, if this is supported by the driver.

4.8.1. Querying Capabilities

Devices supporting the sliced VBI capturing or output API +set the V4L2_CAP_SLICED_VBI_CAPTURE or +V4L2_CAP_SLICED_VBI_OUTPUT flag respectively, in +the capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl. At least one of the +read/write, streaming or asynchronous I/O +methods must be supported. Sliced VBI devices may have a tuner +or modulator.

4.8.2. Supplemental Functions

Sliced VBI devices shall support video +input or output and tuner or +modulator ioctls if they have these capabilities, and they may +support control ioctls. The video standard ioctls provide information +vital to program a sliced VBI device, therefore must be +supported.

4.8.3. Sliced VBI Format Negotiation

To find out which data services are supported by the +hardware applications can call the VIDIOC_G_SLICED_VBI_CAP ioctl. +All drivers implementing the sliced VBI interface must support this +ioctl. The results may differ from those of the VIDIOC_S_FMT ioctl +when the number of VBI lines the hardware can capture or output per +frame, or the number of services it can identify on a given line are +limited. For example on PAL line 16 the hardware may be able to look +for a VPS or Teletext signal, but not both at the same time.

To determine the currently selected services applications +set the type field of struct v4l2_format to + V4L2_BUF_TYPE_SLICED_VBI_CAPTURE or V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, and the VIDIOC_G_FMT +ioctl fills the fmt.sliced member, a +struct v4l2_sliced_vbi_format.

Applications can request different parameters by +initializing or modifying the fmt.sliced +member and calling the VIDIOC_S_FMT ioctl with a pointer to the +v4l2_format structure.

The sliced VBI API is more complicated than the raw VBI API +because the hardware must be told which VBI service to expect on each +scan line. Not all services may be supported by the hardware on all +lines (this is especially true for VBI output where Teletext is often +unsupported and other services can only be inserted in one specific +line). In many cases, however, it is sufficient to just set the +service_set field to the required services +and let the driver fill the service_lines +array according to hardware capabilities. Only if more precise control +is needed should the programmer set the +service_lines array explicitly.

The VIDIOC_S_FMT ioctl returns an EINVAL error code only when the +given parameters are ambiguous, otherwise it modifies the parameters +according to hardware capabilities. When the driver allocates +resources at this point, it may return an EBUSY error code if the required +resources are temporarily unavailable. Other resource allocation +points which may return EBUSY can be the +VIDIOC_STREAMON ioctl and the first read(), write() and +select() call.

Table 4-6. struct +v4l2_sliced_vbi_format

__u32service_set

If +service_set is non-zero when passed with +VIDIOC_S_FMT or VIDIOC_TRY_FMT, the +service_lines array will be filled by the +driver according to the services specified in this field. For example, +if service_set is initialized with +V4L2_SLICED_TELETEXT_B | V4L2_SLICED_WSS_625, a +driver for the cx25840 video decoder sets lines 7-22 of both +fieldsa to V4L2_SLICED_TELETEXT_B +and line 23 of the first field to +V4L2_SLICED_WSS_625. If +service_set is set to zero, then the values +of service_lines will be used instead.

On return the driver sets this field to the union of all +elements of the returned service_lines +array. It may contain less services than requested, perhaps just one, +if the hardware cannot handle more services simultaneously. It may be +empty (zero) if none of the requested services are supported by the +hardware.

__u16service_lines[2][24]

Applications initialize this +array with sets of data services the driver shall look for or insert +on the respective scan line. Subject to hardware capabilities drivers +return the requested set, a subset, which may be just a single +service, or an empty set. When the hardware cannot handle multiple +services on the same line the driver shall choose one. No assumptions +can be made on which service the driver chooses.

Data +services are defined in Table 4-7. Array indices +map to ITU-R line numbers (see also Figure 4-2 and Figure 4-3) as follows:

  Element525 line systems625 line systems
  service_lines[0][1]11
  service_lines[0][23]2323
  service_lines[1][1]264314
  service_lines[1][23]286336
  Drivers must set +service_lines[0][0] and +service_lines[1][0] to zero.
__u32io_sizeMaximum number of bytes passed by +one read() or write() call, and the buffer size in bytes for +the VIDIOC_QBUF and VIDIOC_DQBUF ioctl. Drivers set this field to +the size of struct v4l2_sliced_vbi_data times the number of non-zero +elements in the returned service_lines +array (that is the number of lines potentially carrying data).
__u32reserved[2]This array is reserved for future +extensions. Applications and drivers must set it to zero.
Notes:
a. According to ETS 300 706 lines 6-22 of the +first field and lines 5-22 of the second field may carry Teletext +data.

Table 4-7. Sliced VBI services

SymbolValueReferenceLines, usuallyPayload
V4L2_SLICED_TELETEXT_B +(Teletext System B)0x0001ETS 300 706, ITU BT.653PAL/SECAM line 7-22, 320-335 (second field 7-22)Last 42 of the 45 byte Teletext packet, that is +without clock run-in and framing code, lsb first transmitted.
V4L2_SLICED_VPS0x0400ETS 300 231PAL line 16Byte number 3 to 15 according to Figure 9 of +ETS 300 231, lsb first transmitted.
V4L2_SLICED_CAPTION_5250x1000EIA 608-BNTSC line 21, 284 (second field 21)Two bytes in transmission order, including parity +bit, lsb first transmitted.
V4L2_SLICED_WSS_6250x4000ITU BT.1119, EN 300 294PAL/SECAM line 23
Byte         0                 1
+      msb         lsb  msb           lsb
+ Bit  7 6 5 4 3 2 1 0  x x 13 12 11 10 9
V4L2_SLICED_VBI_5250x1000Set of services applicable to 525 +line systems.
V4L2_SLICED_VBI_6250x4401Set of services applicable to 625 +line systems.

Drivers may return an EINVAL error code when applications attempt to +read or write data without prior format negotiation, after switching +the video standard (which may invalidate the negotiated VBI +parameters) and after switching the video input (which may change the +video standard as a side effect). The VIDIOC_S_FMT ioctl may return +an EBUSY error code when applications attempt to change the format while i/o is +in progress (between a VIDIOC_STREAMON and VIDIOC_STREAMOFF call, +and after the first read() or write() call).

4.8.4. Reading and writing sliced VBI data

A single read() or write() call must pass all data +belonging to one video frame. That is an array of +v4l2_sliced_vbi_data structures with one or +more elements and a total size not exceeding +io_size bytes. Likewise in streaming I/O +mode one buffer of io_size bytes must +contain data of one video frame. The id of +unused v4l2_sliced_vbi_data elements must be +zero.

Table 4-8. struct +v4l2_sliced_vbi_data

__u32idA flag from Table 2 +identifying the type of data in this packet. Only a single bit must be +set. When the id of a captured packet is +zero, the packet is empty and the contents of other fields are +undefined. Applications shall ignore empty packets. When the +id of a packet for output is zero the +contents of the data field are undefined +and the driver must no longer insert data on the requested +field and +line.
__u32fieldThe video field number this data has been captured +from, or shall be inserted at. 0 for the first +field, 1 for the second field.
__u32lineThe field (as opposed to frame) line number this +data has been captured from, or shall be inserted at. See Figure 4-2 and Figure 4-3 for valid +values. Sliced VBI capture devices can set the line number of all +packets to 0 if the hardware cannot reliably +identify scan lines. The field number must always be valid.
__u32reservedThis field is reserved for future extensions. +Applications and drivers must set it to zero.
__u8data[48]The packet payload. See Table 2 for the contents and number of +bytes passed for each data type. The contents of padding bytes at the +end of this array are undefined, drivers and applications shall ignore +them.

Packets are always passed in ascending line number order, +without duplicate line numbers. The write() function and the +VIDIOC_QBUF ioctl must return an EINVAL error code when applications violate +this rule. They must also return an EINVAL error code when applications pass an +incorrect field or line number, or a combination of +field, line and +id which has not been negotiated with the +VIDIOC_G_FMT or VIDIOC_S_FMT ioctl. When the line numbers are +unknown the driver must pass the packets in transmitted order. The +driver can insert empty packets with id set +to zero anywhere in the packet array.

To assure synchronization and to distinguish from frame +dropping, when a captured frame does not carry any of the requested +data services drivers must pass one or more empty packets. When an +application fails to pass VBI data in time for output, the driver +must output the last VPS and WSS packet again, and disable the output +of Closed Caption and Teletext data, or output data which is ignored +by Closed Caption and Teletext decoders.

A sliced VBI device may support read/write and/or streaming (memory mapping and/or user +pointer) I/O. The latter bears the possibility of synchronizing +video and VBI data by using buffer timestamps.


PrevHomeNext
Raw VBI Data InterfaceUpTeletext Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7561.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7561.htm new file mode 100644 index 0000000000000000000000000000000000000000..c265e146b3971858633b51446c2f9ab69faafbc3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7561.htm @@ -0,0 +1,214 @@ + +Teletext Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.9. Teletext Interface

This interface aims at devices receiving and demodulating +Teletext data [ETS 300 706, ITU BT.653], evaluating the +Teletext packages and storing formatted pages in cache memory. Such +devices are usually implemented as microcontrollers with serial +interface (I2C) and can be found on older +TV cards, dedicated Teletext decoding cards and home-brew devices +connected to the PC parallel port.

The Teletext API was designed by Martin Buck. It is defined in +the kernel header file linux/videotext.h, the +specification is available from http://home.pages.de/~videotext/. (Videotext is the name of +the German public television Teletext service.) Conventional character +device file names are /dev/vtx and +/dev/vttuner, with device number 83, 0 and 83, 16 +respectively. A similar interface exists for the Philips SAA5249 +Teletext decoder [specification?] with character device file names +/dev/tlkN, device number 102, N.

Eventually the Teletext API was integrated into the V4L API +with character device file names /dev/vtx0 to +/dev/vtx31, device major number 81, minor numbers +192 to 223. For reference the V4L Teletext API specification is +reproduced here in full: "Teletext interfaces talk the existing VTX +API." Teletext devices with major number 83 and 102 will be removed in +Linux 2.6.

There are no plans to replace the Teletext API or to integrate +it into V4L2. Please write to the Video4Linux mailing list: https://listman.redhat.com/mailman/listinfo/video4linux-list +when the need arises.


PrevHomeNext
Sliced VBI Data InterfaceUpRadio Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7578.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7578.htm new file mode 100644 index 0000000000000000000000000000000000000000..651a48f73c157ae79a4bffcca90d4351cd56ead3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7578.htm @@ -0,0 +1,248 @@ + +Radio Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.10. Radio Interface

This interface is intended for AM and FM (analog) radio +receivers.

Conventionally V4L2 radio devices are accessed through +character device special files named /dev/radio +and /dev/radio0 to +/dev/radio63 with major number 81 and minor +numbers 64 to 127.

4.10.1. Querying Capabilities

Devices supporting the radio interface set the +V4L2_CAP_RADIO and +V4L2_CAP_TUNER flag in the +capabilities field of struct v4l2_capability +returned by the VIDIOC_QUERYCAP ioctl. Other combinations of +capability flags are reserved for future extensions.

4.10.2. Supplemental Functions

Radio devices can support controls, and must support the tuner ioctls.

They do not support the video input or output, audio input +or output, video standard, cropping and scaling, compression and +streaming parameter, or overlay ioctls. All other ioctls and I/O +methods are reserved for future extensions.

4.10.3. Programming

Radio devices may have a couple audio controls (as discussed +in Section 1.8) such as a volume control, possibly custom +controls. Further all radio devices have one tuner (these are +discussed in Section 1.6) with index number zero to select +the radio frequency and to determine if a monaural or FM stereo +program is received. Drivers switch automatically between AM and FM +depending on the selected frequency. The VIDIOC_G_TUNER ioctl +reports the supported frequency range.


PrevHomeNext
Teletext InterfaceUpRDS Interface
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7607.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7607.htm new file mode 100644 index 0000000000000000000000000000000000000000..510b8cd04b9585a84f032919b0110cefc49d8b4e --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x7607.htm @@ -0,0 +1,197 @@ + +RDS Interface
Video for Linux Two API Specification: Revision 0.24
PrevChapter 4. InterfacesNext

4.11. RDS Interface

The Radio Data System transmits supplementary +information in binary format, for example the station name or travel +information, on a inaudible audio subcarrier of a radio program. This +interface aims at devices capable of receiving and decoding RDS +information.

The V4L API defines its RDS API as follows.

From radio devices supporting it, RDS data can be read +with the read() function. The data is packed in groups of three, +as follows:

  1. First Octet Least Significant Byte of RDS Block

  2. Second Octet Most Significant Byte of RDS Block

  3. Third Octet Bit 7: Error bit. Indicates that an +uncorrectable error occurred during reception of this block. Bit 6: +Corrected bit. Indicates that an error was corrected for this data +block. Bits 5-3: Received Offset. Indicates the offset received by the +sync system. Bits 2-0: Offset Name. Indicates the offset applied to +this data.

It was argued the RDS API should be +extended before integration into V4L2, no new API has been devised yet. +Please write to the Video4Linux mailing list for discussion: https://listman.redhat.com/mailman/listinfo/video4linux-list. +Meanwhile no V4L2 driver should set the +V4L2_CAP_RDS_CAPTURE capability flag.


PrevHomeNext
Radio InterfaceUpFunction Reference
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x802.htm b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x802.htm new file mode 100644 index 0000000000000000000000000000000000000000..61bd97d698a66537a61d9a9c29bc1f643d9ae59d --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/doc/spec/x802.htm @@ -0,0 +1,3637 @@ + +Extended Controls
Video for Linux Two API Specification: Revision 0.24
PrevChapter 1. Common API ElementsNext

1.9. Extended Controls

1.9.1. Introduction

The control mechanism as originally designed was meant +to be used for user settings (brightness, saturation, etc). However, +it turned out to be a very useful model for implementing more +complicated driver APIs where each driver implements only a subset of +a larger API.

The MPEG encoding API was the driving force behind +designing and implementing this extended control mechanism: the MPEG +standard is quite large and the currently supported hardware MPEG +encoders each only implement a subset of this standard. Further more, +many parameters relating to how the video is encoded into an MPEG +stream are specific to the MPEG encoding chip since the MPEG standard +only defines the format of the resulting MPEG stream, not how the +video is actually encoded into that format.

Unfortunately, the original control API lacked some +features needed for these new uses and so it was extended into the +(not terribly originally named) extended control API.

1.9.2. The Extended Control API

Three new ioctls are available: VIDIOC_G_EXT_CTRLS, +VIDIOC_S_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS. These ioctls act on +arrays of controls (as opposed to the VIDIOC_G_CTRL and +VIDIOC_S_CTRL ioctls that act on a single control). This is needed +since it is often required to atomically change several controls at +once.

Each of the new ioctls expects a pointer to a +struct v4l2_ext_controls. This structure contains a pointer to the control +array, a count of the number of controls in that array and a control +class. Control classes are used to group similar controls into a +single class. For example, control class +V4L2_CTRL_CLASS_USER contains all user controls +(i. e. all controls that can also be set using the old +VIDIOC_S_CTRL ioctl). Control class +V4L2_CTRL_CLASS_MPEG contains all controls +relating to MPEG encoding, etc.

All controls in the control array must belong to the +specified control class. An error is returned if this is not the +case.

It is also possible to use an empty control array (count +== 0) to check whether the specified control class is +supported.

The control array is a struct v4l2_ext_control array. The +v4l2_ext_control structure is very similar to +struct v4l2_control, except for the fact that it also allows for 64-bit +values and pointers to be passed (although the latter is not yet used +anywhere).

It is important to realize that due to the flexibility of +controls it is necessary to check whether the control you want to set +actually is supported in the driver and what the valid range of values +is. So use the VIDIOC_QUERYCTRL and VIDIOC_QUERYMENU ioctls to +check this. Also note that it is possible that some of the menu +indices in a control of type V4L2_CTRL_TYPE_MENU +may not be supported (VIDIOC_QUERYMENU will +return an error). A good example is the list of supported MPEG audio +bitrates. Some drivers only support one or two bitrates, others +support a wider range.

1.9.3. Enumerating Extended Controls

The recommended way to enumerate over the extended +controls is by using VIDIOC_QUERYCTRL in combination with the +V4L2_CTRL_FLAG_NEXT_CTRL flag:

struct v4l2_queryctrl qctrl;
+
+qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl (fd, VIDIOC_QUERYCTRL, &qctrl)) {
+        /* ... */
+        qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}

The initial control ID is set to 0 ORed with the +V4L2_CTRL_FLAG_NEXT_CTRL flag. The +VIDIOC_QUERYCTRL ioctl will return the first +control with a higher ID than the specified one. When no such controls +are found an error is returned.

If you want to get all controls within a specific control +class, then you can set the initial +qctrl.id value to the control class and add +an extra check to break out of the loop when a control of another +control class is found:

qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl (fd, VIDIOC_QUERYCTRL, &qctrl)) {
+        if (V4L2_CTRL_ID2CLASS (qctrl.id) != V4L2_CTRL_CLASS_MPEG)
+                break;
+                /* ... */
+                qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+        }

The 32-bit qctrl.id value is +subdivided into three bit ranges: the top 4 bits are reserved for +flags (e. g. V4L2_CTRL_FLAG_NEXT_CTRL) and are not +actually part of the ID. The remaining 28 bits form the control ID, of +which the most significant 12 bits define the control class and the +least significant 16 bits identify the control within the control +class. It is guaranteed that these last 16 bits are always non-zero +for controls. The range of 0x1000 and up are reserved for +driver-specific controls. The macro +V4L2_CTRL_ID2CLASS(id) returns the control class +ID based on a control ID.

If the driver does not support extended controls, then +VIDIOC_QUERYCTRL will fail when used in +combination with V4L2_CTRL_FLAG_NEXT_CTRL. In +that case the old method of enumerating control should be used (see +1.8). But if it is supported, then it is guaranteed to enumerate over +all controls, including driver-private controls.

1.9.4. Creating Control Panels

It is possible to create control panels for a graphical +user interface where the user can select the various controls. +Basically you will have to iterate over all controls using the method +described above. Each control class starts with a control of type +V4L2_CTRL_TYPE_CTRL_CLASS. +VIDIOC_QUERYCTRL will return the name of this +control class which can be used as the title of a tab page within a +control panel.

The flags field of struct v4l2_queryctrl also contains hints on +the behavior of the control. See the VIDIOC_QUERYCTRL documentation +for more details.

1.9.5. MPEG Control Reference

Below all controls within the MPEG control class are +described. First the generic controls, then controls specific for +certain hardware.

1.9.5.1. Generic MPEG Controls

Table 1-2. MPEG Control IDs

IDType 
 Description
    
V4L2_CID_MPEG_CLASS class 
 The MPEG class +descriptor. Calling VIDIOC_QUERYCTRL for this control will return a +description of this control class. This description can be used as the +caption of a Tab page in a GUI, for example.
    
V4L2_CID_MPEG_STREAM_TYPE enum 
 The MPEG-1, -2 or -4 +output stream type. One cannot assume anything here. Each hardware +MPEG encoder tends to support different subsets of the available MPEG +stream types. The currently defined stream types are:
 
V4L2_MPEG_STREAM_TYPE_MPEG2_PS MPEG-2 program stream
V4L2_MPEG_STREAM_TYPE_MPEG2_TS MPEG-2 transport stream
V4L2_MPEG_STREAM_TYPE_MPEG1_SS MPEG-1 system stream
V4L2_MPEG_STREAM_TYPE_MPEG2_DVD MPEG-2 DVD-compatible stream
V4L2_MPEG_STREAM_TYPE_MPEG1_VCD MPEG-1 VCD-compatible stream
V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD MPEG-2 SVCD-compatible stream
    
V4L2_CID_MPEG_STREAM_PID_PMT integer 
 Program Map Table +Packet ID for the MPEG transport stream (default 16)
    
V4L2_CID_MPEG_STREAM_PID_AUDIO integer 
 Audio Packet ID for +the MPEG transport stream (default 256)
    
V4L2_CID_MPEG_STREAM_PID_VIDEO integer 
 Video Packet ID for +the MPEG transport stream (default 260)
    
V4L2_CID_MPEG_STREAM_PID_PCR integer 
 Packet ID for the +MPEG transport stream carrying PCR fields (default 259)
    
V4L2_CID_MPEG_STREAM_PES_ID_AUDIO integer 
 Audio ID for MPEG +PES
    
V4L2_CID_MPEG_STREAM_PES_ID_VIDEO integer 
 Video ID for MPEG +PES
    
V4L2_CID_MPEG_STREAM_VBI_FMT enum 
 Some cards can embed +VBI data (e. g. Closed Caption, Teletext) into the MPEG stream. This +control selects whether VBI data should be embedded, and if so, what +embedding method should be used. The list of possible VBI formats +depends on the driver. The currently defined VBI format types +are:
 
V4L2_MPEG_STREAM_VBI_FMT_NONE No VBI in the MPEG stream
V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI in private packets, IVTV format (documented +in the kernel sources in the file Documentation/video4linux/cx2341x/README.vbi)
    
V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ enum 
 MPEG Audio sampling +frequency. Possible values are:
 
V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 44.1 kHz
V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 48 kHz
V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 32 kHz
    
V4L2_CID_MPEG_AUDIO_ENCODING enum 
 MPEG Audio encoding. +Possible values are:
 
V4L2_MPEG_AUDIO_ENCODING_LAYER_1 MPEG Layer I encoding
V4L2_MPEG_AUDIO_ENCODING_LAYER_2 MPEG Layer II encoding
V4L2_MPEG_AUDIO_ENCODING_LAYER_3 MPEG Layer III encoding
    
V4L2_CID_MPEG_AUDIO_L1_BITRATE enum 
 Layer I bitrate. +Possible values are:
 
V4L2_MPEG_AUDIO_L1_BITRATE_32K 32 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_64K 64 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_96K 96 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_128K 128 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_160K 160 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_192K 192 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_224K 224 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_256K 256 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_288K 288 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_320K 320 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_352K 352 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_384K 384 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_416K 416 kbit/s
V4L2_MPEG_AUDIO_L1_BITRATE_448K 448 kbit/s
    
V4L2_CID_MPEG_AUDIO_L2_BITRATE enum 
 Layer II bitrate. +Possible values are:
 
V4L2_MPEG_AUDIO_L2_BITRATE_32K 32 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_48K 48 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_56K 56 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_64K 64 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_80K 80 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_96K 96 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_112K 112 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_128K 128 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_160K 160 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_192K 192 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_224K 224 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_256K 256 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_320K 320 kbit/s
V4L2_MPEG_AUDIO_L2_BITRATE_384K 384 kbit/s
    
V4L2_CID_MPEG_AUDIO_L3_BITRATE enum 
 Layer III bitrate. +Possible values are:
 
V4L2_MPEG_AUDIO_L3_BITRATE_32K 32 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_40K 40 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_48K 48 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_56K 56 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_64K 64 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_80K 80 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_96K 96 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_112K 112 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_128K 128 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_160K 160 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_192K 192 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_224K 224 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_256K 256 kbit/s
V4L2_MPEG_AUDIO_L3_BITRATE_320K 320 kbit/s
    
V4L2_CID_MPEG_AUDIO_MODE enum 
 MPEG Audio mode. +Possible values are:
 
V4L2_MPEG_AUDIO_MODE_STEREO Stereo
V4L2_MPEG_AUDIO_MODE_JOINT_STEREO Joint Stereo
V4L2_MPEG_AUDIO_MODE_DUAL Bilingual
V4L2_MPEG_AUDIO_MODE_MONO Mono
    
V4L2_CID_MPEG_AUDIO_MODE_EXTENSION enum 
 Joint Stereo +audio mode extension. In Layer I and II they indicate which subbands +are in intensity stereo. All other subbands are coded in stereo. Layer +III is not (yet) supported. Possible values +are:
 
V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4 Subbands 4-31 in intensity stereo
V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8 Subbands 8-31 in intensity stereo
V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 Subbands 12-31 in intensity stereo
V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 Subbands 16-31 in intensity stereo
    
V4L2_CID_MPEG_AUDIO_EMPHASIS enum 
 Audio Emphasis. +Possible values are:
 
V4L2_MPEG_AUDIO_EMPHASIS_NONE None
V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS 50/15 microsecond emphasis
V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17 CCITT J.17
    
V4L2_CID_MPEG_AUDIO_CRC enum 
 CRC method. Possible +values are:
 
V4L2_MPEG_AUDIO_CRC_NONE None
V4L2_MPEG_AUDIO_CRC_CRC16 16 bit parity check
    
V4L2_CID_MPEG_AUDIO_MUTE bool 
 Mutes the audio when +capturing. This is not done by muting audio hardware, which can still +produce a slight hiss, but in the encoder itself, guaranteeing a fixed +and reproducable audio bitstream. 0 = unmuted, 1 = muted.
    
V4L2_CID_MPEG_VIDEO_ENCODING enum 
 MPEG Video encoding +method. Possible values are:
 
V4L2_MPEG_VIDEO_ENCODING_MPEG_1 MPEG-1 Video encoding
V4L2_MPEG_VIDEO_ENCODING_MPEG_2 MPEG-2 Video encoding
    
V4L2_CID_MPEG_VIDEO_ASPECT enum 
 Video aspect. +Possible values are:
 
V4L2_MPEG_VIDEO_ASPECT_1x1  
V4L2_MPEG_VIDEO_ASPECT_4x3  
V4L2_MPEG_VIDEO_ASPECT_16x9  
V4L2_MPEG_VIDEO_ASPECT_221x100  
    
V4L2_CID_MPEG_VIDEO_B_FRAMES integer 
 Number of B-Frames +(default 2)
    
V4L2_CID_MPEG_VIDEO_GOP_SIZE integer 
 GOP size (default +12)
    
V4L2_CID_MPEG_VIDEO_GOP_CLOSURE bool 
 GOP closure (default +1)
    
V4L2_CID_MPEG_VIDEO_PULLDOWN bool 
 Enable 3:2 pulldown +(default 0)
    
V4L2_CID_MPEG_VIDEO_BITRATE_MODE enum 
 Video bitrate mode. +Possible values are:
 
V4L2_MPEG_VIDEO_BITRATE_MODE_VBR Variable bitrate
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR Constant bitrate
    
V4L2_CID_MPEG_VIDEO_BITRATE integer 
 Video bitrate in bits +per second.
    
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK integer 
 Peak video bitrate in +bits per second. Must be larger or equal to the average video bitrate. +It is ignored if the video bitrate mode is set to constant +bitrate.
    
V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION integer 
 For every captured +frame, skip this many subsequent frames (default 0).
    
V4L2_CID_MPEG_VIDEO_MUTE bool 
 "Mutes" the video to a +fixed color when capturing. This is useful for testing, to produce a +fixed video bitstream. 0 = unmuted, 1 = muted.
    
V4L2_CID_MPEG_VIDEO_MUTE_YUV integer 
 Sets the "mute" color +of the video. The supplied 32-bit integer is interpreted as follows (bit +0 = least significant bit):
 
Bit 0:7V chrominance information
Bit 8:15U chrominance information
Bit 16:23Y luminance information
Bit 24:31Must be zero.

1.9.5.2. CX2341x MPEG Controls

The following MPEG class controls deal with MPEG +encoding settings that are specific to the Conexant CX23415 and +CX23416 MPEG encoding chips.

Table 1-3. CX2341x Control IDs

IDType 
 Description
    
V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE enum 
 Sets the Spatial +Filter mode (default MANUAL). Possible values +are:
 
V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL Choose the filter manually
V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO Choose the filter automatically
    
V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER integer (0-15) 
 The setting for the +Spatial Filter. 0 = off, 15 = maximum. (Default is 0.)
    
V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE enum 
 Select the algorithm +to use for the Luma Spatial Filter (default +1D_HOR). Possible values:
 
V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF No filter
V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR One-dimensional horizontal
V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT One-dimensional vertical
V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE Two-dimensional separable
V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE Two-dimensional symmetrical +non-separable
    
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE enum 
 Select the algorithm +for the Chroma Spatial Filter (default 1D_HOR). +Possible values are:
 
V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF No filter
V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR One-dimensional horizontal
    
V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE enum 
 Sets the Temporal +Filter mode (default MANUAL). Possible values +are:
 
V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL Choose the filter manually
V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO Choose the filter automatically
    
V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER integer (0-31) 
 The setting for the +Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale +capturing and 0 for scaled capturing.)
    
V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE enum 
 Median Filter Type +(default OFF). Possible values are:
 
V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF No filter
V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR Horizontal filter
V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT Vertical filter
V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT Horizontal and vertical filter
V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG Diagonal filter
    
V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM integer (0-255) 
 Threshold above which +the luminance median filter is enabled (default 0)
    
V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP integer (0-255) 
 Threshold below which +the luminance median filter is enabled (default 255)
    
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM integer (0-255) 
 Threshold above which +the chroma median filter is enabled (default 0)
    
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP integer (0-255) 
 Threshold below which +the chroma median filter is enabled (default 255)
    
V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS bool 
 The CX2341X MPEG encoder +can insert one empty MPEG-2 PES packet into the stream between every +four video frames. The packet size is 2048 bytes, including the +packet_start_code_prefix and stream_id fields. The stream_id is 0xBF +(private stream 2). The payload consists of 0x00 bytes, to be filled +in by the application. 0 = do not insert, 1 = insert packets.

1.9.6. Camera Control Reference

The Camera class includes controls for mechanical (or +equivalent digital) features of a device such as controllable lenses +or sensors.

Table 1-4. Camera Control IDs

IDType 
 Description
    
V4L2_CID_CAMERA_CLASS class 
 The Camera class +descriptor. Calling VIDIOC_QUERYCTRL for this control will return a +description of this control class.
    
V4L2_CID_EXPOSURE_AUTO integer 
 Enables automatic +adjustments of the exposure time and/or iris aperture. The effect of +manual changes of the exposure time or iris aperture while these +features are enabled is undefined, drivers should ignore such +requests. Possible values are:
 
V4L2_EXPOSURE_AUTO Automatic exposure time, automatic iris +aperture.
V4L2_EXPOSURE_MANUAL Manual exposure time, manual iris.
V4L2_EXPOSURE_SHUTTER_PRIORITY Manual exposure time, auto iris.
V4L2_EXPOSURE_APERTURE_PRIORITY Auto exposure time, manual iris.
    
V4L2_CID_EXPOSURE_ABSOLUTE integer 
 Determines the exposure +time of the camera sensor. The exposure time is limited by the frame +interval. Drivers should interpret the values as 100 µs units, +where the value 1 stands for 1/10000th of a second, 10000 for 1 second +and 100000 for 10 seconds.
    
V4L2_CID_EXPOSURE_AUTO_PRIORITY boolean 
 When +V4L2_CID_EXPOSURE_AUTO is set to +AUTO or SHUTTER_PRIORITY, +this control determines if the device may dynamically vary the frame +rate. By default this feature is disabled (0) and the frame rate must +remain constant.
    
V4L2_CID_PAN_RELATIVE integer 
 This control turns the +camera horizontally by the specified amount. The unit is undefined. A +positive value moves the camera to the right (clockwise when viewed +from above), a negative value to the left. A value of zero does not +cause motion.
    
V4L2_CID_TILT_RELATIVE integer 
 This control turns the +camera vertically by the specified amount. The unit is undefined. A +positive value moves the camera up, a negative value down. A value of +zero does not cause motion.
    
V4L2_CID_PAN_RESET boolean 
 When this control is set +to TRUE (1), the camera moves horizontally to the +default position.
    
V4L2_CID_TILT_RESET boolean 
 When this control is set +to TRUE (1), the camera moves vertically to the +default position.
    
V4L2_CID_PAN_ABSOLUTE integer 
 This control +turns the camera horizontally to the specified position. Positive +values move the camera to the right (clockwise when viewed from above), +negative values to the left. Drivers should interpret the values as arc +seconds, with valid values between -180 * 3600 and +180 * 3600 +inclusive.
    
V4L2_CID_TILT_ABSOLUTE integer 
 This control +turns the camera vertically to the specified position. Positive values +move the camera up, negative values down. Drivers should interpret the +values as arc seconds, with valid values between -180 * 3600 and +180 +* 3600 inclusive.
    
V4L2_CID_FOCUS_ABSOLUTE integer 
 This control sets the +focal point of the camera to the specified position. The unit is +undefined. Positive values set the focus closer to the camera, +negative values towards infinity.
    
V4L2_CID_FOCUS_RELATIVE integer 
 This control moves the +focal point of the camera by the specified amount. The unit is +undefined. Positive values move the focus closer to the camera, +negative values towards infinity.
    
V4L2_CID_FOCUS_AUTO boolean 
 Enables automatic focus +adjustments. The effect of manual focus adjustments while this feature +is enabled is undefined, drivers should ignore such requests.
    

PrevHomeNext
User ControlsUpData Formats
diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDIO.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDIO.c new file mode 100644 index 0000000000000000000000000000000000000000..5b6dca05f638819e28af82b86322e482721aa7a5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDIO.c @@ -0,0 +1,526 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.7 Added string content validation + * 18 Apr 2009 0.6 More strict check for strings + * 29 Mar 2009 0.5 Clean up test case for NULL parameter + * 25 Mar 2009 0.4 Cleaned up dprintf() outputs and ret and errno names + * 9 Feb 2009 0.3 Typo corrected; added some debug messages + * 7 Feb 2009 0.2 Test case test_VIDIOC_G_AUDIO_ignore_index added + * 3 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_ENUMAUDIO.h" + +int valid_audio_capability(__u32 capability) +{ + int valid = 0; + + if ((capability & ~(V4L2_AUDCAP_STEREO | V4L2_AUDCAP_AVL)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +int valid_audio_mode(__u32 mode) +{ + int valid = 0; + + if ((mode & ~(V4L2_AUDMODE_AVL)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +void test_VIDIOC_G_AUDIO() +{ + int ret_get, errno_get; + struct v4l2_audio audio; + struct v4l2_audio audio2; + + memset(&audio, 0xff, sizeof(audio)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + //CU_ASSERT_EQUAL(audio.index, ?); + + CU_ASSERT(0 < strlen((char *)audio.name)); + CU_ASSERT(valid_string((char *)audio.name, sizeof(audio.name))); + + CU_ASSERT(valid_audio_capability(audio.capability)); + CU_ASSERT(valid_audio_mode(audio.mode)); + + CU_ASSERT_EQUAL(audio.reserved[0], 0); + CU_ASSERT_EQUAL(audio.reserved[1], 0); + + /* Check if the unused bytes of the name string are + * also filled with zeros. Also check if there is any + * padding byte between any two fields then this + * padding byte is also filled with zeros. + */ + memset(&audio2, 0, sizeof(audio2)); + audio2.index = audio.index; + strncpy((char *)audio2.name, (char *)audio.name, + sizeof(audio2.name)); + audio2.capability = audio.capability; + audio2.mode = audio.mode; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); + + dprintf("\taudio = {.index=%u, .name=\"%s\", " + ".capability=0x%X, .mode=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", + audio.index, + audio.name, + audio.capability, + audio.mode, audio.reserved[0], audio.reserved[1] + ); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + /* check if the audio structure is untouched */ + memset(&audio2, 0xff, sizeof(audio2)); + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); + + } + +} + +void test_VIDIOC_G_AUDIO_ignore_index() +{ + int ret_get, errno_get; + int ret2, errno2; + struct v4l2_audio audio; + struct v4l2_audio audio2; + + /* check whether the "index" field is ignored by VIDIOC_G_AUDIO */ + + memset(&audio, 0, sizeof(audio)); + dprintf("\t%s:%u: audio.index=%u\n", __FILE__, __LINE__, audio.index); + ret_get = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + memset(&audio2, 0, sizeof(audio2)); + audio2.index = U32_MAX; + ret2 = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio2); + errno2 = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret2=%i, errno2=%i\n", + __FILE__, __LINE__, ret2, errno2); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret2, 0); + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret2, -1); + CU_ASSERT_EQUAL(errno2, EINVAL); + } + +} + +void test_VIDIOC_G_AUDIO_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + struct v4l2_audio audio; + + memset(&audio, 0xff, sizeof(audio)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_AUDIO, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* check if VIDIOC_G_AUDIO is supported at all or not */ + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + /* VIDIOC_G_AUDIO is supported, the parameter should be checked */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + /* VIDIOC_G_AUDIO not supported at all, the parameter should not be evaluated */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +void test_VIDIOC_S_AUDIO() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + int ret_enum, errno_enum; + __u32 index; + __u32 i; + struct v4l2_audio audio_orig; + struct v4l2_audio audio_enum; + struct v4l2_audio audio_set; + + /* This testcase tries to find out the relations between the following + * commands: + * - VIDIOC_ENUMAUDIO + * - VIDIOC_G_AUDIO + * - VIDIOC_S_AUDIO + */ + + /* remember the original settings */ + memset(&audio_orig, 0, sizeof(audio_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + + if (ret_orig == 0) { + CU_ASSERT_EQUAL(ret_orig, 0); + } else { + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, EINVAL); + } + + /* try to continue even if VIDIOC_G_AUDIO seems to be not supported */ + + index = 0; + do { + memset(&audio_enum, 0, sizeof(audio_enum)); + audio_enum.index = index; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDIO, &audio_enum); + errno_enum = errno; + + if (ret_enum == 0) { + memset(&audio_set, 0xff, sizeof(audio_set)); + audio_set.index = index; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio_set); + errno_set = errno; + + /* It shall be always possible to set the audio input to the + * enumerated values. + */ + CU_ASSERT_EQUAL(ret_enum, 0); + + index++; + } + + } while (ret_enum == 0); + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* try to set audio input to beyond the enumerated values */ + for (i = 0; i <= 32; i++) { + memset(&audio_set, 0xff, sizeof(audio_set)); + audio_set.index = index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio_set); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + index++; + } + + /* restore the original audio input settings */ + memset(&audio_set, 0, sizeof(audio_set)); + audio_set.index = audio_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio_set); + errno_set = errno; + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio input then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio input value at the start + * of this test case: the VIDIOC_S_AUDIO shall also fail. + */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } + +} + +void test_VIDIOC_S_AUDIO_S32_MAX() +{ + int ret_set, errno_set; + int ret_orig, errno_orig; + struct v4l2_audio audio; + struct v4l2_audio audio2; + struct v4l2_audio audio_orig; + struct v4l2_audio audio_set; + + /* remember the original settings */ + memset(&audio_orig, 0, sizeof(audio_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + + /* test invalid index */ + memset(&audio, 0xff, sizeof(audio)); + audio.index = (__u32) S32_MAX; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + /* Check whether the original audio struct is untouched */ + memset(&audio2, 0xff, sizeof(audio2)); + audio2.index = (__u32) S32_MAX; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); + + /* restore the original audio input settings */ + memset(&audio_set, 0, sizeof(audio_set)); + audio_set.index = audio_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio_set); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio input then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio input value at the start + * of this test case: the VIDIOC_S_AUDIO shall also fail. + */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} + +void test_VIDIOC_S_AUDIO_S32_MAX_1() +{ + int ret_set, errno_set; + int ret_orig, errno_orig; + struct v4l2_audio audio; + struct v4l2_audio audio2; + struct v4l2_audio audio_orig; + struct v4l2_audio audio_set; + + /* remember the original settings */ + memset(&audio_orig, 0, sizeof(audio_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + + /* test invalid index */ + memset(&audio, 0xff, sizeof(audio)); + audio.index = ((__u32) S32_MAX) + 1; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + /* Check whether the original audio struct is untouched */ + memset(&audio2, 0xff, sizeof(audio2)); + audio2.index = ((__u32) S32_MAX) + 1; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); + + /* restore the original audio input settings */ + memset(&audio_set, 0, sizeof(audio_set)); + audio_set.index = audio_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio_set); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio input then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio input value at the start + * of this test case: the VIDIOC_S_AUDIO shall also fail. + */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} + +void test_VIDIOC_S_AUDIO_U32_MAX() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + struct v4l2_audio audio; + struct v4l2_audio audio2; + struct v4l2_audio audio_orig; + struct v4l2_audio audio_set; + + /* remember the original settings */ + memset(&audio_orig, 0, sizeof(audio_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + /* test invalid index */ + memset(&audio, 0xff, sizeof(audio)); + audio.index = U32_MAX; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + /* Check whether the original audio struct is untouched */ + memset(&audio2, 0xff, sizeof(audio2)); + audio2.index = U32_MAX; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); + + /* restore the original audio input settings */ + memset(&audio_set, 0, sizeof(audio_set)); + audio_set.index = audio_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio_set); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio input then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio input value at the start + * of this test case: the VIDIOC_S_AUDIO shall also fail. + */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} + +void test_VIDIOC_S_AUDIO_NULL() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + int ret_null, errno_null; + struct v4l2_audio audio_orig; + struct v4l2_audio audio_set; + + /* remember the original settings */ + memset(&audio_orig, 0, sizeof(audio_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDIO, &audio_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_AUDIO, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + + memset(&audio_set, 0, sizeof(audio_set)); + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio_set); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + ret_null = ioctl(get_video_fd(), VIDIOC_S_AUDIO, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + + /* restore the original audio input settings */ + memset(&audio_set, 0, sizeof(audio_set)); + audio_set.index = audio_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDIO, &audio_set); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_AUDIO, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio input then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_orig, 0); + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio input value at the start + * of this test case: the VIDIOC_S_AUDIO shall also fail. + */ + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDIO.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDIO.h new file mode 100644 index 0000000000000000000000000000000000000000..3d9217efa33bd755be44ddb83be2330ff5c75071 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDIO.h @@ -0,0 +1,19 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 7 Feb 2009 0.2 Test case test_VIDIOC_G_AUDIO_ignore_index added + * 3 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_AUDIO(void); +void test_VIDIOC_G_AUDIO_ignore_index(void); +void test_VIDIOC_G_AUDIO_NULL(void); + +void test_VIDIOC_S_AUDIO(void); +void test_VIDIOC_S_AUDIO_S32_MAX(void); +void test_VIDIOC_S_AUDIO_S32_MAX_1(void); +void test_VIDIOC_S_AUDIO_U32_MAX(void); +void test_VIDIOC_S_AUDIO_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDOUT.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDOUT.c new file mode 100644 index 0000000000000000000000000000000000000000..801798b2a3c1e6e3927903abd002467bea8af5a8 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDOUT.c @@ -0,0 +1,510 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.7 Added string content validation + * 18 Apr 2009 0.6 More strict check for strings + * 29 Mar 2009 0.5 Clean up test case for NULL parameter + * 22 Mar 2009 0.4 Cleaned up dprintf() messages + * 9 Feb 2009 0.3 Typo corrected; added some debug messages + * 7 Feb 2009 0.2 Test case test_VIDIOC_G_AUDOUT_ignore_index added + * 3 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_AUDOUT.h" + +int valid_audioout_mode(__u32 mode) +{ + int valid = 0; + + if ((mode & ~(V4L2_AUDMODE_AVL)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +void test_VIDIOC_G_AUDOUT() +{ + int ret_get, errno_get; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + + memset(&audioout, 0xff, sizeof(audioout)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audioout); + errno_get = errno; + + dprintf("\tVIDIOC_AUDIOOUT, ret_get=%i, errno_get=%i\n", ret_get, + errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + //CU_ASSERT_EQUAL(audioout.index, ?); + + CU_ASSERT(0 < strlen((char *)audioout.name)); + CU_ASSERT(valid_string + ((char *)audioout.name, sizeof(audioout.name))); + + CU_ASSERT_EQUAL(audioout.capability, 0); + CU_ASSERT_EQUAL(audioout.mode, 0); + + CU_ASSERT_EQUAL(audioout.reserved[0], 0); + CU_ASSERT_EQUAL(audioout.reserved[1], 0); + + /* Check if the unused bytes of the name string is also filled + * with zeros. Also check if there is any padding byte between + * any two fields then this padding byte is also filled with zeros. + */ + memset(&audioout2, 0, sizeof(audioout2)); + audioout2.index = audioout.index; + strncpy((char *)audioout2.name, (char *)audioout.name, + sizeof(audioout2.name)); + audioout2.capability = audioout.capability; + audioout2.mode = audioout.mode; + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), + 0); + + dprintf("\taudioout = {.index=%u, .name=\"%s\", " + ".capability=0x%X, .mode=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", + audioout.index, + audioout.name, + audioout.capability, + audioout.mode, + audioout.reserved[0], audioout.reserved[1] + ); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + /* check if the audioout structure is untouched */ + memset(&audioout2, 0xff, sizeof(audioout2)); + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), + 0); + + } + +} + +void test_VIDIOC_G_AUDOUT_ignore_index() +{ + int reg_get1, errno1; + int reg_get2, errno2; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + + /* check whether the "index" field is ignored by VIDIOC_G_AUDOUT */ + + memset(&audioout, 0, sizeof(audioout)); + reg_get1 = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audioout); + errno1 = errno; + + dprintf("\tVIDIOC_G_AUDOUT, reg_get1=%i, errno1=%i\n", reg_get1, + errno1); + + memset(&audioout2, 0, sizeof(audioout2)); + audioout2.index = U32_MAX; + reg_get2 = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audioout2); + errno2 = errno; + + dprintf("\tVIDIOC_G_AUDOUT, reg_get2=%i, errno2=%i\n", reg_get2, + errno2); + + if (reg_get1 == 0) { + CU_ASSERT_EQUAL(reg_get2, 0); + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), + 0); + } else { + CU_ASSERT_EQUAL(reg_get1, -1); + CU_ASSERT_EQUAL(errno1, EINVAL); + CU_ASSERT_EQUAL(reg_get2, -1); + CU_ASSERT_EQUAL(errno2, EINVAL); + } + +} + +void test_VIDIOC_G_AUDOUT_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + struct v4l2_audioout audioout; + + memset(&audioout, 0xff, sizeof(audioout)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audioout); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_AUDIOOUT, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_AUDIOOUT, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* check if VIDIOC_G_AUDOUT is supported at all or not */ + if (ret_get == 0) { + /* VIDIOC_G_AUDOUT is supported, the parameter should be checked */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + /* VIDIOC_G_AUDOUT not supported at all, the parameter should not be evaluated */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +/* TODO: - try with all possible outputs (VIDIOC_ENUMOUTPUT) + * - try with STREAM_ON + */ + +void test_VIDIOC_S_AUDOUT() +{ + int ret_orig, errno_orig; + int ret_enum, errno_enum; + int ret_set, errno_set; + __u32 index; + __u32 i; + struct v4l2_audioout audioout_orig; + struct v4l2_audioout audioout_enum; + struct v4l2_audioout audioout_set; + + /* This testcase tries to find out the relations between the following + * commands: + * - VIDIOC_ENUMAUDOUT + * - VIDIOC_G_AUDOUT + * - VIDIOC_S_AUDOUT + */ + + /* remember the original settings */ + memset(&audioout_orig, 0, sizeof(audioout_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audioout_orig); + errno_orig = errno; + + dprintf("\tVIDIOC_G_AUDOUT, ret_orig=%i, errno_orig=%i\n", ret_orig, + errno_orig); + + if (ret_orig == 0) { + CU_ASSERT_EQUAL(ret_orig, 0); + } else { + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, EINVAL); + } + + /* try to continue even if VIDIOC_G_AUDOUT seems to be not supported */ + + index = 0; + do { + memset(&audioout_enum, 0, sizeof(audioout_enum)); + audioout_enum.index = index; + ret_enum = + ioctl(get_video_fd(), VIDIOC_ENUMAUDOUT, &audioout_enum); + errno_enum = errno; + + if (ret_enum == 0) { + memset(&audioout_set, 0xff, sizeof(audioout_set)); + audioout_set.index = index; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_AUDOUT, + &audioout_set); + errno_set = errno; + + /* It shall be always possible to set the audio output to the + * enumerated values. + */ + CU_ASSERT_EQUAL(ret_set, 0); + + index++; + } + + } while (ret_enum == 0); + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* try to set audio output to beyond the enumerated values */ + for (i = 0; i <= 32; i++) { + memset(&audioout_set, 0xff, sizeof(audioout_set)); + audioout_set.index = index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audioout_set); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + index++; + } + + /* restore the original audio output settings */ + memset(&audioout_set, 0, sizeof(audioout_set)); + audioout_set.index = audioout_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audioout_set); + errno_set = errno; + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio output then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio output value at the start + * of this test case: the VIDIOC_S_AUDOUT shall also fail. + */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } + +} + +void test_VIDIOC_S_AUDOUT_S32_MAX() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + struct v4l2_audioout audioout_orig; + struct v4l2_audioout audioout_set; + + /* remember the original settings */ + memset(&audioout_orig, 0, sizeof(audioout_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audioout_orig); + errno_orig = errno; + + dprintf("\tVIDIOC_G_AUDOUT, ret_orig=%i, errno_orig=%i\n", ret_orig, + errno_orig); + + /* test invalid index */ + memset(&audioout, 0xff, sizeof(audioout)); + audioout.index = (__u32) S32_MAX; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audioout); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + /* Check whether the original audioout struct is untouched */ + memset(&audioout2, 0xff, sizeof(audioout2)); + audioout2.index = (__u32) S32_MAX; + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), 0); + + /* restore the original audio output settings */ + memset(&audioout_set, 0, sizeof(audioout_set)); + audioout_set.index = audioout_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audioout_set); + errno_set = errno; + + dprintf("\tVIDIOC_S_AUDOUT, ret_set=%i, errno_set=%i\n", ret_set, + errno_set); + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio output then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio output value at the start + * of this test case: the VIDIOC_S_AUDOUT shall also fail. + */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} + +void test_VIDIOC_S_AUDOUT_S32_MAX_1() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + struct v4l2_audioout audioout_orig; + struct v4l2_audioout audioout_set; + + /* remember the original settings */ + memset(&audioout_orig, 0, sizeof(audioout_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audioout_orig); + errno_orig = errno; + + dprintf("\tVIDIOC_G_AUDOUT, ret_orig=%i, errno_orig=%i\n", ret_orig, + errno_orig); + + /* test invalid index */ + memset(&audioout, 0xff, sizeof(audioout)); + audioout.index = ((__u32) S32_MAX) + 1; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audioout); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + /* Check whether the original audioout struct is untouched */ + memset(&audioout2, 0xff, sizeof(audioout2)); + audioout2.index = ((__u32) S32_MAX) + 1; + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), 0); + + /* restore the original audio output settings */ + memset(&audioout_set, 0, sizeof(audioout_set)); + audioout_set.index = audioout_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audioout_set); + errno_set = errno; + + dprintf("\tVIDIOC_S_AUDOUT, ret_set=%i, errno_set=%i\n", ret_set, + errno_set); + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio output then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio output value at the start + * of this test case: the VIDIOC_S_AUDOUT shall also fail. + */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} + +void test_VIDIOC_S_AUDOUT_U32_MAX() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + struct v4l2_audioout audioout_orig; + struct v4l2_audioout audioout_set; + + /* remember the original settings */ + memset(&audioout_orig, 0, sizeof(audioout_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audioout_orig); + errno_orig = errno; + + dprintf("\tVIDIOC_G_AUDOUT, ret_orig=%i, errno_orig=%i\n", ret_orig, + errno_orig); + /* test invalid index */ + memset(&audioout, 0xff, sizeof(audioout)); + audioout.index = U32_MAX; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audioout); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + /* Check whether the original audioout struct is untouched */ + memset(&audioout2, 0xff, sizeof(audioout2)); + audioout2.index = U32_MAX; + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), 0); + + /* restore the original audio output settings */ + memset(&audioout_set, 0, sizeof(audioout_set)); + audioout_set.index = audioout_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audioout_set); + errno_set = errno; + + dprintf("\tVIDIOC_S_AUDOUT, ret_set=%i, errno_set=%i\n", ret_set, + errno_set); + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio output then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio output value at the start + * of this test case: the VIDIOC_S_AUDOUT shall also fail. + */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} + +void test_VIDIOC_S_AUDOUT_NULL() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + int ret_get, errno_get; + struct v4l2_audio audio_orig; + struct v4l2_audio audio_set; + + /* remember the original settings */ + memset(&audio_orig, 0, sizeof(audio_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_AUDOUT, &audio_orig); + errno_orig = errno; + + dprintf("\tVIDIOC_G_AUDOUT, ret_orig=%i, errno_orig=%i\n", ret_orig, + errno_orig); + + memset(&audio_set, 0, sizeof(audio_set)); + ret_get = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audio_set); + errno_get = errno; + + dprintf("\tVIDIOC_S_AUDOUT, ret_get=%i, errno_get=%i\n", ret_get, + errno_get); + + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, NULL); + errno_set = errno; + + dprintf("\tVIDIOC_S_AUDOUT, ret_set=%i, errno_set=%i\n", ret_set, + errno_set); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } + + /* restore the original audio input settings */ + memset(&audio_set, 0, sizeof(audio_set)); + audio_set.index = audio_orig.index; + ret_set = ioctl(get_video_fd(), VIDIOC_S_AUDOUT, &audio_set); + errno_set = errno; + + dprintf("\tVIDIOC_S_AUDOUT, ret_set=%i, errno_set=%i\n", ret_set, + errno_set); + + if (ret_orig == 0) { + /* If it was possible at the beginning to get the audio input then + * it shall be possible to set it again. + */ + CU_ASSERT_EQUAL(ret_orig, 0); + CU_ASSERT_EQUAL(ret_set, 0); + } else { + /* In case we could not fetch the audio input value at the start + * of this test case: the VIDIOC_S_AUDOUT shall also fail. + */ + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDOUT.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDOUT.h new file mode 100644 index 0000000000000000000000000000000000000000..4d5bd13c89bd6972cdc94d1724e8b2c53f685dc0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_AUDOUT.h @@ -0,0 +1,19 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 7 Feb 2009 0.2 Test case test_VIDIOC_G_AUDOUT_ignore_index added + * 3 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_AUDOUT(void); +void test_VIDIOC_G_AUDOUT_ignore_index(void); +void test_VIDIOC_G_AUDOUT_NULL(void); + +void test_VIDIOC_S_AUDOUT(void); +void test_VIDIOC_S_AUDOUT_S32_MAX(void); +void test_VIDIOC_S_AUDOUT_S32_MAX_1(void); +void test_VIDIOC_S_AUDOUT_U32_MAX(void); +void test_VIDIOC_S_AUDOUT_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROP.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROP.c new file mode 100644 index 0000000000000000000000000000000000000000..273fda46d427537807ec35bea578c4bfaabd7e9e --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROP.c @@ -0,0 +1,799 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 3 Apr 2009 0.4 Minor style cleanup + * 7 Mar 2009 0.3 Test cases added for VIDIOC_S_CROP + * 13 Feb 2009 0.2 Test cases added for VIDIOC_G_CROP + * 7 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_CROP.h" + +void do_get_crop(enum v4l2_buf_type type) +{ + int ret1, errno1; + struct v4l2_crop crop; + + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + ret1 = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop); + errno1 = errno; + + dprintf("\tVIDIOC_G_CROP: type=%i, ret1=%i, errno1=%i\n", + type, ret1, errno1); + + if (ret1 == 0) { + CU_ASSERT_EQUAL(ret1, 0); + + } else { + CU_ASSERT_EQUAL(ret1, -1); + CU_ASSERT_EQUAL(errno1, EINVAL); + } + +} + +void test_VIDIOC_G_CROP() +{ + do_get_crop(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_get_crop(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_get_crop(V4L2_BUF_TYPE_VIDEO_OVERLAY); +} + +void do_get_crop_invalid(enum v4l2_buf_type type) +{ + int ret1, errno1; + struct v4l2_crop crop; + + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + ret1 = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop); + errno1 = errno; + + dprintf("\tVIDIOC_G_CROP: type=%i, ret1=%i, errno1=%i\n", + type, ret1, errno1); + + CU_ASSERT_EQUAL(ret1, -1); + CU_ASSERT_EQUAL(errno1, EINVAL); +} + +void test_VIDIOC_G_CROP_invalid() +{ + do_get_crop_invalid(0); + do_get_crop_invalid(V4L2_BUF_TYPE_VBI_CAPTURE); + do_get_crop_invalid(V4L2_BUF_TYPE_VBI_OUTPUT); + do_get_crop_invalid(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_get_crop_invalid(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); + do_get_crop_invalid(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_get_crop_invalid(V4L2_BUF_TYPE_PRIVATE); + do_get_crop_invalid(S32_MAX); + do_get_crop_invalid(((__u32) S32_MAX) + 1); + do_get_crop_invalid(U32_MAX); +} + +void test_VIDIOC_G_CROP_NULL() +{ + int ret_get1, errno_get1; + int ret_get2, errno_get2; + int ret_get3, errno_get3; + int ret_null, errno_null; + struct v4l2_crop crop; + + memset(&crop, 0, sizeof(crop)); + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret_get1 = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop); + errno_get1 = errno; + + dprintf("\t%s:%u: VIDIOC_G_CROP ret_get1=%i, errno_get1=%i\n", + __FILE__, __LINE__, ret_get1, errno_get1); + + memset(&crop, 0, sizeof(crop)); + crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + ret_get2 = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop); + errno_get2 = errno; + + dprintf("\t%s:%u: VIDIOC_G_CROP ret_get2=%i, errno_get2=%i\n", + __FILE__, __LINE__, ret_get2, errno_get2); + + memset(&crop, 0, sizeof(crop)); + crop.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + + ret_get3 = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop); + errno_get3 = errno; + + dprintf("\t%s:%u: VIDIOC_G_CROP ret_get3=%i, errno_get3=%i\n", + __FILE__, __LINE__, ret_get3, errno_get3); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_CROP, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_CROP ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_get1 == 0 || ret_get2 == 0 || ret_get3 == 0) { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + + } else { + CU_ASSERT_EQUAL(ret_get1, -1); + CU_ASSERT_EQUAL(errno_get1, EINVAL); + CU_ASSERT_EQUAL(ret_get2, -1); + CU_ASSERT_EQUAL(errno_get2, EINVAL); + CU_ASSERT_EQUAL(ret_get3, -1); + CU_ASSERT_EQUAL(errno_get3, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + + } + +} + +void do_set_crop(enum v4l2_buf_type type) +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + int ret_new, errno_new; + int ret_cap, errno_cap; + struct v4l2_crop crop_orig; + struct v4l2_crop crop; + struct v4l2_crop crop_new; + struct v4l2_cropcap cropcap; + __s32 i; + + memset(&crop_orig, 0, sizeof(crop_orig)); + crop_orig.type = type; + ret_orig = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_orig); + errno_orig = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_orig=%i, errno_orig=%i, " + "crop_orig = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_orig, errno_orig, + crop_orig.type, + crop_orig.c.left, + crop_orig.c.top, crop_orig.c.width, crop_orig.c.height); + + memset(&cropcap, 0, sizeof(cropcap)); + cropcap.type = type; + ret_cap = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_cap = errno; + + dprintf + ("\t%s:%u: VIDIOC_CROPCAP, ret_cap=%i, errno_cap=%i, cropcap = { .type = %i, " + ".bounds = { .left = %i, .top = %i, .width = %i, .height = %i }, " + ".defrect = { .left = %i, .top = %i, .width = %i, .height = %i }, " + ".pixelaspect = { .numerator = %u, .denominator = %u } " "}\n", + __FILE__, __LINE__, ret_cap, errno_cap, cropcap.type, + cropcap.bounds.left, cropcap.bounds.top, cropcap.bounds.width, + cropcap.bounds.height, cropcap.defrect.left, cropcap.defrect.top, + cropcap.defrect.width, cropcap.defrect.height, + cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator); + + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + crop.c = cropcap.bounds; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i, " + "crop = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_set, errno_set, + crop.type, + crop.c.left, crop.c.top, crop.c.width, crop.c.height); + + memset(&crop_new, 0, sizeof(crop_new)); + crop_new.type = type; + ret_new = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_new); + errno_new = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_new=%i, errno_new=%i, " + "crop_new = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_new, errno_new, + crop_new.type, + crop_new.c.left, + crop_new.c.top, crop_new.c.width, crop_new.c.height); + + if (ret_cap == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_new, 0); + + if (ret_cap == 0 && ret_new == 0) { + + /* | left x */ + /* ----+----+--------------------------------------> */ + /* | : */ + /* top + +------ cropcap.bounds -------+ ^ */ + /* | | | | */ + /* | | +------- crop_new --------+ | | */ + /* | | | | | | */ + /* | | | | | | */ + /* | | | | | | height */ + /* | | +-------------------------+ | | */ + /* | | | | */ + /* | | | | */ + /* | +-----------------------------+ v */ + /* | : : */ + /* | <---------- width ------------> */ + /* | */ + /* v y */ + + CU_ASSERT(cropcap.bounds.left <= crop_new.c.left); + CU_ASSERT(cropcap.bounds.top <= crop_new.c.top); + + CU_ASSERT(crop_new.c.left + crop_new.c.width <= + cropcap.bounds.left + cropcap.bounds.width); + CU_ASSERT(crop_new.c.top + crop_new.c.height <= + cropcap.bounds.top + cropcap.bounds.height); + } + + } else { + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_new, -1); + CU_ASSERT_EQUAL(errno_new, EINVAL); + + } + + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + crop.c = cropcap.defrect; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i, " + "crop = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_set, errno_set, + crop.type, + crop.c.left, crop.c.top, crop.c.width, crop.c.height); + + memset(&crop_new, 0, sizeof(crop_new)); + crop_new.type = type; + ret_new = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_new); + errno_new = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_new=%i, errno_new=%i, " + "crop_new = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_new, errno_new, + crop_new.type, + crop_new.c.left, + crop_new.c.top, crop_new.c.width, crop_new.c.height); + + if (ret_cap == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_new, 0); + + if (ret_cap == 0 && ret_new == 0) { + + /* | left x */ + /* ----+----+--------------------------------------> */ + /* | : */ + /* top + +------ cropcap.defrect ------+ ^ */ + /* | | | | */ + /* | | +------- crop_new --------+ | | */ + /* | | | | | | */ + /* | | | | | | */ + /* | | | | | | height */ + /* | | +-------------------------+ | | */ + /* | | | | */ + /* | | | | */ + /* | +-----------------------------+ v */ + /* | : : */ + /* | <---------- width ------------> */ + /* | */ + /* v y */ + + CU_ASSERT(cropcap.defrect.left <= crop_new.c.left); + CU_ASSERT(cropcap.defrect.top <= crop_new.c.top); + + CU_ASSERT(crop_new.c.left + crop_new.c.width <= + cropcap.defrect.left + cropcap.defrect.width); + CU_ASSERT(crop_new.c.top + crop_new.c.height <= + cropcap.defrect.top + cropcap.defrect.height); + } + + } else { + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_new, -1); + CU_ASSERT_EQUAL(errno_new, EINVAL); + + } + + /* | left x */ + /* ----+----+--------------------------------------> */ + /* | : */ + /* top + +-------- crop.c -------------+ ^ */ + /* | | : | | */ + /* | | : | | */ + /* | | : | | */ + /* | | :<----| | */ + /* | | : | | height */ + /* | | : | | */ + /* | | : | | */ + /* | | : | | */ + /* | +-----------------------------+ v */ + /* | : : */ + /* | <---------- width ------------> */ + /* | */ + /* v y */ + for (i = 0; i < cropcap.bounds.width; i++) { + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + crop.c.left = cropcap.bounds.left; + crop.c.top = cropcap.bounds.top; + crop.c.width = cropcap.bounds.width - i; + crop.c.height = cropcap.bounds.height; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i, " + "crop = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_set, errno_set, + crop.type, + crop.c.left, crop.c.top, crop.c.width, crop.c.height); + + memset(&crop_new, 0, sizeof(crop_new)); + crop_new.type = type; + ret_new = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_new); + errno_new = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_new=%i, errno_new=%i, " + "crop_new = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_new, errno_new, + crop_new.type, + crop_new.c.left, + crop_new.c.top, crop_new.c.width, crop_new.c.height); + + if (ret_cap == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_new, 0); + + if (ret_cap == 0 && ret_new == 0) { + + CU_ASSERT(cropcap.defrect.left <= + crop_new.c.left); + CU_ASSERT(cropcap.defrect.top <= + crop_new.c.top); + + CU_ASSERT(crop_new.c.left + crop_new.c.width <= + cropcap.defrect.left + + cropcap.defrect.width); + CU_ASSERT(crop_new.c.top + crop_new.c.height <= + cropcap.defrect.top + + cropcap.defrect.height); + } + + } else { + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_new, -1); + CU_ASSERT_EQUAL(errno_new, EINVAL); + } + } + + /* | left x */ + /* ----+----+--------------------------------------> */ + /* | : */ + /* top + +---------- crop.c -----------+ ^ */ + /* | | | | */ + /* | | | | */ + /* | | | | */ + /* | | | | */ + /* | |.............................| | height */ + /* | | ^ | | */ + /* | | | | | */ + /* | | | | | */ + /* | +-----------------------------+ v */ + /* | : : */ + /* | <---------- width ------------> */ + /* | */ + /* v y */ + for (i = 0; i < cropcap.bounds.height; i++) { + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + crop.c.left = cropcap.bounds.left; + crop.c.top = cropcap.bounds.top; + crop.c.width = cropcap.bounds.width; + crop.c.height = cropcap.bounds.height - i; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i, " + "crop = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_set, errno_set, + crop.type, + crop.c.left, crop.c.top, crop.c.width, crop.c.height); + + memset(&crop_new, 0, sizeof(crop_new)); + crop_new.type = type; + ret_new = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_new); + errno_new = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_new=%i, errno_new=%i, " + "crop_new = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_new, errno_new, + crop_new.type, + crop_new.c.left, + crop_new.c.top, crop_new.c.width, crop_new.c.height); + + if (ret_cap == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_new, 0); + + if (ret_cap == 0 && ret_new == 0) { + + CU_ASSERT(cropcap.defrect.left <= + crop_new.c.left); + CU_ASSERT(cropcap.defrect.top <= + crop_new.c.top); + + CU_ASSERT(crop_new.c.left + crop_new.c.width <= + cropcap.defrect.left + + cropcap.defrect.width); + CU_ASSERT(crop_new.c.top + crop_new.c.height <= + cropcap.defrect.top + + cropcap.defrect.height); + } + + } else { + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_new, -1); + CU_ASSERT_EQUAL(errno_new, EINVAL); + } + } + + /* | left x */ + /* ----+----+--------------------------------------> */ + /* | : */ + /* top + +---------- crop.c -----------+ ^ */ + /* | | : | | */ + /* | | : | | */ + /* | | : | | */ + /* | |--->: | | */ + /* | | : | | height */ + /* | | : | | */ + /* | | : | | */ + /* | | : | | */ + /* | +-----------------------------+ v */ + /* | : : */ + /* | <---------- width ------------> */ + /* | */ + /* v y */ + for (i = 0; i < cropcap.bounds.width; i++) { + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + crop.c.left = cropcap.bounds.left + i; + crop.c.top = cropcap.bounds.top; + crop.c.width = cropcap.bounds.width - i; + crop.c.height = cropcap.bounds.height; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i, " + "crop = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_set, errno_set, + crop.type, + crop.c.left, crop.c.top, crop.c.width, crop.c.height); + + memset(&crop_new, 0, sizeof(crop_new)); + crop_new.type = type; + ret_new = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_new); + errno_new = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_new=%i, errno_new=%i, " + "crop_new = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_new, errno_new, + crop_new.type, + crop_new.c.left, + crop_new.c.top, crop_new.c.width, crop_new.c.height); + + if (ret_cap == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_new, 0); + + if (ret_cap == 0 && ret_new == 0) { + + CU_ASSERT(cropcap.defrect.left <= + crop_new.c.left); + CU_ASSERT(cropcap.defrect.top <= + crop_new.c.top); + + CU_ASSERT(crop_new.c.left + crop_new.c.width <= + cropcap.defrect.left + + cropcap.defrect.width); + CU_ASSERT(crop_new.c.top + crop_new.c.height <= + cropcap.defrect.top + + cropcap.defrect.height); + } + + } else { + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_new, -1); + CU_ASSERT_EQUAL(errno_new, EINVAL); + } + } + + /* | left x */ + /* ----+----+--------------------------------------> */ + /* | : */ + /* top + +---------- crop.c -----------+ ^ */ + /* | | | | | */ + /* | | | | | */ + /* | | v | | */ + /* | |.............................| | */ + /* | | | | height */ + /* | | | | */ + /* | | | | */ + /* | | | | */ + /* | +-----------------------------+ v */ + /* | : : */ + /* | <---------- width ------------> */ + /* | */ + /* v y */ + for (i = 0; i < cropcap.bounds.height; i++) { + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + crop.c.left = cropcap.bounds.left; + crop.c.top = cropcap.bounds.top + i; + crop.c.width = cropcap.bounds.width; + crop.c.height = cropcap.bounds.height - i; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i, " + "crop = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_set, errno_set, + crop.type, + crop.c.left, crop.c.top, crop.c.width, crop.c.height); + + memset(&crop_new, 0, sizeof(crop_new)); + crop_new.type = type; + ret_new = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_new); + errno_new = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_new=%i, errno_new=%i, " + "crop_new = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_new, errno_new, + crop_new.type, + crop_new.c.left, + crop_new.c.top, crop_new.c.width, crop_new.c.height); + + if (ret_cap == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_new, 0); + + if (ret_cap == 0 && ret_new == 0) { + + CU_ASSERT(cropcap.defrect.left <= + crop_new.c.left); + CU_ASSERT(cropcap.defrect.top <= + crop_new.c.top); + + CU_ASSERT(crop_new.c.left + crop_new.c.width <= + cropcap.defrect.left + + cropcap.defrect.width); + CU_ASSERT(crop_new.c.top + crop_new.c.height <= + cropcap.defrect.top + + cropcap.defrect.height); + } + + } else { + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_new, -1); + CU_ASSERT_EQUAL(errno_new, EINVAL); + } + } + + if (ret_orig == 0) { + /* it shall be possible to restore the original settings */ + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop_orig); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + CU_ASSERT_EQUAL(ret_set, 0); + } +} + +void test_VIDIOC_S_CROP() +{ + + do_set_crop(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_set_crop(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_set_crop(V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_set_crop(V4L2_BUF_TYPE_PRIVATE); + +} + +void do_set_crop_invalid(enum v4l2_buf_type type) +{ + int ret_set, errno_set; + int ret_new, errno_new; + int ret_cap, errno_cap; + struct v4l2_crop crop; + struct v4l2_crop crop_new; + struct v4l2_cropcap cropcap; + + memset(&cropcap, 0, sizeof(cropcap)); + cropcap.type = type; + ret_cap = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_cap = errno; + + dprintf + ("\t%s:%u: VIDIOC_CROPCAP, ret_cap=%i, errno_cap=%i, cropcap = { .type = %i, " + ".bounds = { .left = %i, .top = %i, .width = %i, .height = %i }, " + ".defrect = { .left = %i, .top = %i, .width = %i, .height = %i }, " + ".pixelaspect = { .numerator = %u, .denominator = %u } " "}\n", + __FILE__, __LINE__, ret_cap, errno_cap, cropcap.type, + cropcap.bounds.left, cropcap.bounds.top, cropcap.bounds.width, + cropcap.bounds.height, cropcap.defrect.left, cropcap.defrect.top, + cropcap.defrect.width, cropcap.defrect.height, + cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator); + + memset(&crop, 0xff, sizeof(crop)); + crop.type = type; + crop.c = cropcap.bounds; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i, " + "crop = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_set, errno_set, + crop.type, + crop.c.left, crop.c.top, crop.c.width, crop.c.height); + + memset(&crop_new, 0, sizeof(crop_new)); + crop_new.type = type; + ret_new = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_new); + errno_new = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_new=%i, errno_new=%i, " + "crop_new = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_new, errno_new, + crop_new.type, + crop_new.c.left, + crop_new.c.top, crop_new.c.width, crop_new.c.height); + + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_new, -1); + CU_ASSERT_EQUAL(errno_new, EINVAL); + +} + +void test_VIDIOC_S_CROP_invalid() +{ + do_set_crop_invalid(0); + do_set_crop_invalid(V4L2_BUF_TYPE_VBI_CAPTURE); + do_set_crop_invalid(V4L2_BUF_TYPE_VBI_OUTPUT); + do_set_crop_invalid(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_set_crop_invalid(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); + do_set_crop_invalid(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_set_crop_invalid(V4L2_BUF_TYPE_PRIVATE); + do_set_crop_invalid(S32_MAX); + do_set_crop_invalid(((__u32) S32_MAX) + 1); + do_set_crop_invalid(U32_MAX); +} + +void do_set_crop_null(enum v4l2_buf_type type) +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + int ret_cap, errno_cap; + int ret_null, errno_null; + struct v4l2_crop crop; + struct v4l2_crop crop_orig; + struct v4l2_cropcap cropcap; + + memset(&crop_orig, 0, sizeof(crop_orig)); + crop_orig.type = type; + ret_orig = ioctl(get_video_fd(), VIDIOC_G_CROP, &crop_orig); + errno_orig = errno; + dprintf("\t%s:%u: VIDIOC_G_CROP, ret_orig=%i, errno_orig=%i, " + "crop_orig = { .type=%i, .c={ .left=%i, .top=%i, .width=%i, .height=%i }}\n", + __FILE__, __LINE__, + ret_orig, errno_orig, + crop_orig.type, + crop_orig.c.left, + crop_orig.c.top, crop_orig.c.width, crop_orig.c.height); + + memset(&cropcap, 0, sizeof(cropcap)); + cropcap.type = type; + ret_cap = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_cap = errno; + + dprintf + ("\t%s:%u: VIDIOC_CROPCAP, ret_cap=%i, errno_cap=%i, cropcap = { .type = %i, " + ".bounds = { .left = %i, .top = %i, .width = %i, .height = %i }, " + ".defrect = { .left = %i, .top = %i, .width = %i, .height = %i }, " + ".pixelaspect = { .numerator = %u, .denominator = %u } " "}\n", + __FILE__, __LINE__, ret_cap, errno_cap, cropcap.type, + cropcap.bounds.left, cropcap.bounds.top, cropcap.bounds.width, + cropcap.bounds.height, cropcap.defrect.left, cropcap.defrect.top, + cropcap.defrect.width, cropcap.defrect.height, + cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator); + + memset(&crop, 0, sizeof(crop)); + crop.type = type; + crop.c = cropcap.bounds; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + ret_null = ioctl(get_video_fd(), VIDIOC_S_CROP, NULL); + errno_null = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + + } + + if (ret_orig == 0) { + /* it shall be possible to restore the original settings */ + ret_set = ioctl(get_video_fd(), VIDIOC_S_CROP, &crop_orig); + errno_set = errno; + dprintf("\t%s:%u: VIDIOC_S_CROP, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + CU_ASSERT_EQUAL(ret_set, 0); + } + +} + +void test_VIDIOC_S_CROP_NULL() +{ + + do_set_crop_null(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_set_crop_null(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_set_crop_null(V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_set_crop_null(V4L2_BUF_TYPE_PRIVATE); + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROP.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROP.h new file mode 100644 index 0000000000000000000000000000000000000000..9c78e9711c52e091c1978bd21403f58f6c9aba98 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROP.h @@ -0,0 +1,17 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 7 Mar 2009 0.3 Test cases added for VIDIOC_S_CROP + * 13 Feb 2009 0.2 Test cases added for VIDIOC_G_CROP + * 7 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_CROP(void); +void test_VIDIOC_G_CROP_invalid(void); +void test_VIDIOC_G_CROP_NULL(void); +void test_VIDIOC_S_CROP(void); +void test_VIDIOC_S_CROP_invalid(void); +void test_VIDIOC_S_CROP_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROPCAP.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROPCAP.c new file mode 100644 index 0000000000000000000000000000000000000000..a793c6be6c08b4d2b4f8c9c551ade4659a967f13 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROPCAP.c @@ -0,0 +1,287 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 3 Apr 2009 0.6 Test case for with NULL parameter reworked + * 28 Mar 2009 0.5 Clean up ret and errno variable names and dprintf() output + * 7 Mar 2009 0.4 Typo corrected + * 9 Feb 2009 0.3 Modify test_VIDIOC_CROPCAP_enum_INPUT() to support drivers + * without any inputs + * 3 Feb 2009 0.2 Typo fixed + * 21 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_CROPCAP.h" + +static void do_ioctl_VIDIOC_CROPCAP(enum v4l2_buf_type buf_type, + int expected_ret) +{ + int ret_cap, errno_cap; + struct v4l2_cropcap cropcap; + struct v4l2_cropcap cropcap2; + + memset(&cropcap, 0xff, sizeof(cropcap)); + cropcap.type = buf_type; + ret_cap = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_cap = errno; + + dprintf("\t%s:%u: type=%i, ret_cap=%i, errno_cap=%i, expected_ret=%i\n", + __FILE__, __LINE__, buf_type, ret_cap, errno_cap, expected_ret); + + if (expected_ret != 0) { + CU_ASSERT_EQUAL(ret_cap, expected_ret); + } + if (ret_cap == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT_EQUAL(cropcap.type, buf_type); + + /* | left x */ + /* ----+----+--------------------------------------> */ + /* | : */ + /* top + +-------- cropcap ------------+ ^ */ + /* | | | | */ + /* | | +------- defrect ---------+ | | */ + /* | | | | | | */ + /* | | | | | | */ + /* | | | | | | height */ + /* | | +-------------------------+ | | */ + /* | | | | */ + /* | | | | */ + /* | +-----------------------------+ v */ + /* | : : */ + /* | <---------- width ------------> */ + /* | */ + /* v y */ + + /* top left corner */ + CU_ASSERT(cropcap.bounds.left <= cropcap.defrect.left); + CU_ASSERT(cropcap.bounds.top <= cropcap.defrect.top); + + /* size of default cropping rectangle should be smaller or */ + /* equal to the cropping bounds */ + CU_ASSERT(cropcap.defrect.width <= cropcap.bounds.width); + CU_ASSERT(cropcap.defrect.height <= cropcap.bounds.height); + + /* the right bottom corner should not exceed bounds */ + CU_ASSERT(cropcap.defrect.left + cropcap.defrect.width <= + cropcap.bounds.left + cropcap.bounds.width); + CU_ASSERT(cropcap.defrect.top + cropcap.defrect.height <= + cropcap.bounds.top + cropcap.bounds.height); + + //CU_ASSERT_EQUAL(cropcap.pixelaspect.numerator, ?); + CU_ASSERT_NOT_EQUAL(cropcap.pixelaspect.numerator, 0); + //CU_ASSERT_EQUAL(cropcap.pixelaspect.denominator, ?); + CU_ASSERT_NOT_EQUAL(cropcap.pixelaspect.denominator, 0); + + dprintf("\tcropcap = { .type = %i, " + ".bounds = { .left = %i, .top = %i, .width = %i, .height = %i }, " + ".defrect = { .left = %i, .top = %i, .width = %i, .height = %i }, " + ".pixelaspect = { .numerator = %u, .denominator = %u } " + "}\n", + cropcap.type, + cropcap.bounds.left, + cropcap.bounds.top, + cropcap.bounds.width, + cropcap.bounds.height, + cropcap.defrect.left, + cropcap.defrect.top, + cropcap.defrect.width, + cropcap.defrect.height, + cropcap.pixelaspect.numerator, + cropcap.pixelaspect.denominator); + + } else { + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + + memset(&cropcap2, 0xff, sizeof(cropcap2)); + cropcap2.type = buf_type; + CU_ASSERT_EQUAL(memcmp(&cropcap, &cropcap2, sizeof(cropcap)), + 0); + + } + +} + +void test_VIDIOC_CROPCAP() +{ + + do_ioctl_VIDIOC_CROPCAP(0, -1); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_VIDEO_CAPTURE, 0); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_VIDEO_OUTPUT, 0); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_VIDEO_OVERLAY, 0); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_VBI_CAPTURE, -1); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_VBI_OUTPUT, -1); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, -1); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, -1); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, -1); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_PRIVATE - 1, -1); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_PRIVATE, 0); + do_ioctl_VIDIOC_CROPCAP(V4L2_BUF_TYPE_PRIVATE + 1, 0); + do_ioctl_VIDIOC_CROPCAP(S32_MAX, -1); + do_ioctl_VIDIOC_CROPCAP(((__u32) S32_MAX) + 1, -1); + do_ioctl_VIDIOC_CROPCAP(U32_MAX - 1, -1); + do_ioctl_VIDIOC_CROPCAP(U32_MAX, -1); + +} + +void test_VIDIOC_CROPCAP_enum_INPUT() +{ + int ret_get, errno_get; + int ret_set, errno_set; + int enum_ret; + __u32 input_index_orig; + struct v4l2_input input; + __u32 i; + int f; + + f = get_video_fd(); + + memset(&input_index_orig, 0xff, sizeof(input_index_orig)); + ret_get = ioctl(f, VIDIOC_G_INPUT, &input_index_orig); + errno_get = errno; + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + i = 0; + do { + memset(&input, 0xff, sizeof(input)); + input.index = i; + enum_ret = ioctl(f, VIDIOC_ENUMINPUT, &input); + + dprintf + ("\t%s:%u: ENUMINPUT: i=%u, enum_ret=%i, errno=%i\n", + __FILE__, __LINE__, i, enum_ret, errno); + + if (enum_ret == 0) { + ret_set = + ioctl(f, VIDIOC_S_INPUT, &input.index); + errno_set = errno; + + dprintf + ("\t%s:%u: input.index=0x%X, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, input.index, ret_set, + errno_set); + + CU_ASSERT_EQUAL(ret_set, 0); + if (ret_set == 0) { + test_VIDIOC_CROPCAP(); + } + + } + i++; + } while (enum_ret == 0 && i != 0); + + /* Setting the original input_id should not fail */ + ret_set = ioctl(f, VIDIOC_S_INPUT, &input_index_orig); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } +} + +void test_VIDIOC_CROPCAP_NULL() +{ + int ret_capture, errno_capture; + int ret_output, errno_output; + int ret_overlay, errno_overlay; + int ret_private, errno_private; + int ret_private_1, errno_private_1; + int ret_null, errno_null; + struct v4l2_cropcap cropcap; + + memset(&cropcap, 0xff, sizeof(cropcap)); + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret_capture = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_capture = errno; + + dprintf("\t%s:%u: VIDIOC_CROPCAP, ret_capture=%i, errno_capture=%i\n", + __FILE__, __LINE__, ret_capture, errno_capture); + + memset(&cropcap, 0xff, sizeof(cropcap)); + cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ret_output = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_output = errno; + + dprintf("\t%s:%u: VIDIOC_CROPCAP, ret_output=%i, errno_output=%i\n", + __FILE__, __LINE__, ret_output, errno_output); + + memset(&cropcap, 0xff, sizeof(cropcap)); + cropcap.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + ret_overlay = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_overlay = errno; + + dprintf("\t%s:%u: VIDIOC_CROPCAP, ret_overlay=%i, errno_overlay=%i\n", + __FILE__, __LINE__, ret_overlay, errno_overlay); + + memset(&cropcap, 0xff, sizeof(cropcap)); + cropcap.type = V4L2_BUF_TYPE_PRIVATE; + ret_private = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_private = errno; + + dprintf("\t%s:%u: VIDIOC_CROPCAP, ret_private=%i, errno_private=%i\n", + __FILE__, __LINE__, ret_private, errno_private); + + memset(&cropcap, 0xff, sizeof(cropcap)); + cropcap.type = V4L2_BUF_TYPE_PRIVATE + 1; + ret_private_1 = ioctl(get_video_fd(), VIDIOC_CROPCAP, &cropcap); + errno_private_1 = errno; + + dprintf + ("\t%s:%u: VIDIOC_CROPCAP, ret_private_1=%i, errno_private_1=%i\n", + __FILE__, __LINE__, ret_private_1, errno_private_1); + + ret_null = ioctl(get_video_fd(), VIDIOC_CROPCAP, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_CROPCAP, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* Check if at least one type was supported */ + if (ret_capture == 0 || ret_output == 0 || ret_overlay == 0 || + ret_private == 0 || ret_private_1 == 0) { + /* the parameter shall be validated */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + /* VIDIOC_CROPCAP is not supported at all, the parameter + * shall also not be checked. + */ + CU_ASSERT_EQUAL(ret_capture, -1); + CU_ASSERT_EQUAL(errno_capture, EINVAL); + CU_ASSERT_EQUAL(ret_output, -1); + CU_ASSERT_EQUAL(errno_output, EINVAL); + CU_ASSERT_EQUAL(ret_overlay, -1); + CU_ASSERT_EQUAL(errno_overlay, EINVAL); + CU_ASSERT_EQUAL(ret_private, -1); + CU_ASSERT_EQUAL(errno_private, EINVAL); + CU_ASSERT_EQUAL(ret_private_1, -1); + CU_ASSERT_EQUAL(errno_private_1, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROPCAP.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROPCAP.h new file mode 100644 index 0000000000000000000000000000000000000000..52aaa8bf3ed5ceda55fcbd41766c48ed6c711508 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CROPCAP.h @@ -0,0 +1,12 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 21 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_CROPCAP(void); +void test_VIDIOC_CROPCAP_enum_INPUT(void); +void test_VIDIOC_CROPCAP_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CTRL.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CTRL.c new file mode 100644 index 0000000000000000000000000000000000000000..3ade93d54d46db2328778738f9f66f1a6ad2d23d --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CTRL.c @@ -0,0 +1,924 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 25 Mar 2009 0.5 Cleaned up ret and errno variable names + * 14 Mar 2009 0.4 Added test steps for S16_MIN, S16_MAX, U16_MIN and U16_MAX + * 6 Mar 2009 0.3 Check whether the newly set value is converted to the + * closest valid value when setting out of bounds value + * 22 Feb 2009 0.2 Added test cases for VIDIOC_S_CTRL + * 19 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +/* + * Note: V4L2_CID_LASTP1 != V4L2_CID_BASE_LASTP1 + */ + +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_CTRL.h" + +static int do_get_control(__u32 id) +{ + int ret_query, errno_query; + int ret_get, errno_get; + struct v4l2_queryctrl queryctrl; + struct v4l2_control control; + + /* The expected return value of VIDIOC_G_CTRL depens on the value + * reported by VIDIOC_QUERYCTRL + */ + + memset(&queryctrl, 0, sizeof(queryctrl)); + queryctrl.id = id; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_query, + errno_query); + if (ret_query == 0) { + dprintf("\t%s:%u: queryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " + ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", + __FILE__, __LINE__, + queryctrl.id, + queryctrl.type, + queryctrl.name, + queryctrl.minimum, + queryctrl.maximum, + queryctrl.step, + queryctrl.default_value, + queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + } + + memset(&control, 0xff, sizeof(control)); + control.id = id; + ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get, errno_get); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + + switch (queryctrl.type) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT(queryctrl.minimum <= control.value); + CU_ASSERT(control.value <= queryctrl.maximum); + } + break; + + case V4L2_CTRL_TYPE_BUTTON: + /* This control only performs an action, does not have + * any value + */ + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + break; + + case V4L2_CTRL_TYPE_INTEGER64: /* TODO: what about this case? */ + case V4L2_CTRL_TYPE_CTRL_CLASS: + default: + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + } + + return ret_query; +} + +void test_VIDIOC_G_CTRL() +{ + int ret1; + __u32 i; + + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + ret1 = do_get_control(i); + } + + ret1 = do_get_control(V4L2_CID_BASE - 1); + ret1 = do_get_control(V4L2_CID_LASTP1); + ret1 = do_get_control(V4L2_CID_PRIVATE_BASE - 1); + + i = V4L2_CID_PRIVATE_BASE; + do { + ret1 = do_get_control(i); + i++; + } while (ret1 == 0); + + ret1 = do_get_control(i); +} + +void test_VIDIOC_G_CTRL_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + struct v4l2_control control; + __u32 id; + + id = V4L2_CID_BASE; + ret_get = -1; + while (ret_get == -1 && id < V4L2_CID_LASTP1) { + memset(&control, 0xff, sizeof(control)); + control.id = id; + ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control); + errno_get = errno; + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get, + errno_get); + } + + ret_null = ioctl(get_video_fd(), VIDIOC_G_CTRL, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_CTRL, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +int do_set_control(__u32 id) +{ + int ret_query, errno_query; + int ret_set, errno_set; + int ret_get, errno_get; + int ret_orig, errno_orig; + struct v4l2_queryctrl queryctrl; + struct v4l2_control control_orig; + struct v4l2_control control; + struct v4l2_control control_new; + __s32 value; + + /* The expected return value of VIDIOC_S_CTRL depens on the value + * reported by VIDIOC_QUERYCTRL. The allowed limits are also + * reported by VIDIOC_QUERYCTRL. + */ + + memset(&queryctrl, 0, sizeof(queryctrl)); + queryctrl.id = id; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_query, + errno_query); + if (ret_query == 0) { + dprintf("\t%s:%u: queryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " + ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", + __FILE__, __LINE__, + queryctrl.id, + queryctrl.type, + queryctrl.name, + queryctrl.minimum, + queryctrl.maximum, + queryctrl.step, + queryctrl.default_value, + queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + } + + memset(&control_orig, 0, sizeof(control_orig)); + control_orig.id = id; + ret_orig = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_orig); + errno_orig = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_orig=%i, errno_orig=%i, control_orig.value=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_orig, errno_orig, + control_orig.value); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + + switch (queryctrl.type) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + + /* TODO: this is an infinite loop if queryctrl.maximum == S32_MAX */ + for (value = queryctrl.minimum; + value <= queryctrl.maximum; value++) { + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = value; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_CTRL, + &control); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_CTRL, id=%u (V4L2_CID_BASE+%i), value=%i, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, + value, ret_set, errno_set); + + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED || + queryctrl. + flags & V4L2_CTRL_FLAG_READ_ONLY) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } else if (queryctrl. + flags & V4L2_CTRL_FLAG_GRABBED) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EBUSY); + } else { + CU_ASSERT_EQUAL(ret_set, 0); + } + + memset(&control_new, 0, sizeof(control_new)); + control_new.id = id; + ret_get = + ioctl(get_video_fd(), VIDIOC_G_CTRL, + &control_new); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, + ret_get, errno_get, control_new.value); + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT(queryctrl.minimum <= + control_new.value); + CU_ASSERT(control_new.value <= + queryctrl.maximum); + + if (ret_set == 0) { + /* TODO: the following checks works correctly only if + * S32_MIN <= queryctrl.minimum-queryctrl.step and + * queryctrl.maximum+queryctrl.step <= S32_MAX + */ + +/* + * If we try to set the new control value to "value" then the possible results can be + * "x" and "x-step". These two values can be expressed with the range + * (value-step, value+step) where the ranges are not included. + * + * value-step value value+step + * | | | + * | v | + * +----------------+----------------+ + * ********************************* + * ... -+----------------+----------------+----------------+----------------+- ... + * | | | | | + * x-2*step x-step x x+step x+2*step + * + * The following figure shows the case when we try to set value to "x" which is + * a possible set value. In this case the only valid result is the "x". + * + * value-step value value+step + * | | | + * | v | + * +----------------+----------------+ + * ********************************* + * ... -+----------------+----------------+----------------+----------------+- ... + * | | | | | + * x-2*step x-step x x+step x+2*step + * + * + * value-step value value+step + * | | | + * | v | + * +----------------+----------------+ + * ********************************* + * ... -+----------------+----------------+----------------+----------------+- ... + * | | | | | + * x-2*step x-step x x+step x+2*step + * + * + */ + CU_ASSERT(value - + queryctrl.step < + control_new.value); + CU_ASSERT(control_new.value < + value + + queryctrl.step); + } + } + + } + + break; + + case V4L2_CTRL_TYPE_BUTTON: + /* This control only performs an action, does not have + * any value + */ + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, EINVAL); + + /* The set value shall be ignored by button controls */ + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = S32_MIN; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED || + queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EBUSY); + } else { + CU_ASSERT_EQUAL(ret_set, 0); + } + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = -1; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED || + queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EBUSY); + } else { + CU_ASSERT_EQUAL(ret_set, 0); + } + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = 0; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED || + queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EBUSY); + } else { + CU_ASSERT_EQUAL(ret_set, 0); + } + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = 1; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED || + queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EBUSY); + } else { + CU_ASSERT_EQUAL(ret_set, 0); + } + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = S32_MAX; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED || + queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EBUSY); + } else { + CU_ASSERT_EQUAL(ret_set, 0); + } + + break; + + case V4L2_CTRL_TYPE_INTEGER64: /* TODO: what about this case? */ + case V4L2_CTRL_TYPE_CTRL_CLASS: + default: + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, -1); + } + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, EINVAL); + + } + + if (ret_orig == 0) { + CU_ASSERT_EQUAL(ret_orig, 0); + + /* restore the original control value */ + value = control_orig.value; + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = value; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_CTRL, id=%u (V4L2_CID_BASE+%i), value=%i, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, value, ret_set, + errno_set); + + /* it shall be possible to set to the original value if the control + * is not disabled, read only or grabbed by other application + */ + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED || + queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EBUSY); + } else { + CU_ASSERT_EQUAL(ret_set, 0); + } + + memset(&control_new, 0, sizeof(control_new)); + control_new.id = id; + ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_new); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get, + errno_get, control_new.value); + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT(queryctrl.minimum <= control_new.value); + CU_ASSERT(control_new.value <= queryctrl.maximum); + CU_ASSERT_EQUAL(control_new.value, control_orig.value); + } + + } + + return ret_query; +} + +static void do_set_control_value(__u32 id, __s32 value, + struct v4l2_queryctrl *queryctrl); +static void do_set_control_value(__u32 id, __s32 value, + struct v4l2_queryctrl *queryctrl) +{ + int ret_set, errno_set; + int ret_get, errno_get; + struct v4l2_control control; + struct v4l2_control control_new; + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = value; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_CTRL, id=%u (V4L2_CID_BASE+%i), value=%i, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, value, ret_set, + errno_set); + + /* The driver can decide if it returns ERANGE or + * accepts the value and converts it to + * the nearest limit + */ + if (ret_set == -1) { + CU_ASSERT_EQUAL(ret_set, -1); + if (!(queryctrl->flags & V4L2_CTRL_FLAG_DISABLED) && + !(queryctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) { + CU_ASSERT_EQUAL(errno_set, ERANGE); + } else { + CU_ASSERT_EQUAL(errno_set, EINVAL); + } + + /* check whether the new value is not out of bounds */ + memset(&control_new, 0, sizeof(control_new)); + control_new.id = id; + ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_new); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get, + errno_get, control_new.value); + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT(queryctrl->minimum <= control_new.value); + CU_ASSERT(control_new.value <= queryctrl->maximum); + } + + } else { + CU_ASSERT_EQUAL(ret_set, 0); + + /* check whether the new value is not out of bounds */ + memset(&control_new, 0, sizeof(control_new)); + control_new.id = id; + ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_new); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get, + errno_get, control_new.value); + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT(queryctrl->minimum <= control_new.value); + CU_ASSERT(control_new.value <= queryctrl->maximum); + CU_ASSERT_EQUAL(control_new.value, queryctrl->minimum); + } + } +} + +int do_set_control_invalid(__u32 id) +{ + int ret_query, errno_query; + int ret_set, errno_set; + int ret_get, errno_get; + int ret_orig, errno_orig; + struct v4l2_queryctrl queryctrl; + struct v4l2_control control_orig; + struct v4l2_control control; + struct v4l2_control control_new; + __s32 value; + + /* The expected return value of VIDIOC_S_CTRL depens on the value + * reported by VIDIOC_QUERYCTRL. The allowed limits are also + * reported by VIDIOC_QUERYCTRL. + */ + + memset(&queryctrl, 0, sizeof(queryctrl)); + queryctrl.id = id; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_query, + errno_query); + if (ret_query == 0) { + dprintf("\t%s:%u: queryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " + ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", + __FILE__, __LINE__, + queryctrl.id, + queryctrl.type, + queryctrl.name, + queryctrl.minimum, + queryctrl.maximum, + queryctrl.step, + queryctrl.default_value, + queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + } + + memset(&control_orig, 0, sizeof(control_orig)); + control_orig.id = id; + ret_orig = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_orig); + errno_orig = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_orig=%i, errno_orig=%i, control_orig.value=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_orig, errno_orig, + control_orig.value); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + + switch (queryctrl.type) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + if (S32_MIN < queryctrl.minimum) { + do_set_control_value(id, S32_MIN, &queryctrl); + } + + if (S32_MIN < queryctrl.minimum) { + do_set_control_value(id, queryctrl.minimum - 1, + &queryctrl); + } + + if (S16_MIN < queryctrl.minimum) { + do_set_control_value(id, S16_MIN, &queryctrl); + } + + if (U16_MIN < queryctrl.minimum) { + do_set_control_value(id, U16_MIN, &queryctrl); + } + + if (queryctrl.maximum < S16_MAX) { + do_set_control_value(id, S16_MAX, &queryctrl); + } + + if (queryctrl.maximum < (__s32) U16_MAX) { + do_set_control_value(id, (__s32) U16_MAX, + &queryctrl); + } + + if (queryctrl.maximum < S32_MAX) { + do_set_control_value(id, queryctrl.maximum + 1, + &queryctrl); + } + + if (queryctrl.maximum < S32_MAX) { + do_set_control_value(id, S32_MAX, &queryctrl); + } + + break; + + case V4L2_CTRL_TYPE_BUTTON: + /* This control only performs an action, does not have + * any value + */ + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, EINVAL); + + /* there is no invalid value for button control */ + + break; + + case V4L2_CTRL_TYPE_INTEGER64: /* TODO: what about this case? */ + case V4L2_CTRL_TYPE_CTRL_CLASS: + default: + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, -1); + } + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + CU_ASSERT_EQUAL(ret_orig, -1); + CU_ASSERT_EQUAL(errno_orig, EINVAL); + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = S32_MIN; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = -1; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = 0; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = 1; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = S32_MAX; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + } + + if (ret_orig == 0) { + CU_ASSERT_EQUAL(ret_orig, 0); + + /* restore the original control value */ + value = control_orig.value; + memset(&control, 0xff, sizeof(control)); + control.id = id; + control.value = value; + ret_set = ioctl(get_video_fd(), VIDIOC_S_CTRL, &control); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_CTRL, id=%u (V4L2_CID_BASE+%i), value=%i, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, value, ret_set, + errno_set); + + /* it shall be possible to set to the original value if the control + * is not disabled, read only or grabbed by other application + */ + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED || + queryctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } else if (queryctrl.flags & V4L2_CTRL_FLAG_GRABBED) { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EBUSY); + } else { + CU_ASSERT_EQUAL(ret_set, 0); + } + + memset(&control_new, 0, sizeof(control_new)); + control_new.id = id; + ret_get = ioctl(get_video_fd(), VIDIOC_G_CTRL, &control_new); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_CTRL, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i, control_new.value=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get, + errno_get, control_new.value); + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT(queryctrl.minimum <= control_new.value); + CU_ASSERT(control_new.value <= queryctrl.maximum); + CU_ASSERT_EQUAL(control_new.value, control_orig.value); + } + + } + + return ret_query; +} + +void test_VIDIOC_S_CTRL() +{ + int ret1; + __u32 i; + + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + if (i != V4L2_CID_AUTO_WHITE_BALANCE && + i != V4L2_CID_DO_WHITE_BALANCE && + i != V4L2_CID_RED_BALANCE && + i != V4L2_CID_BLUE_BALANCE && + i != V4L2_CID_AUTOGAIN && i != V4L2_CID_GAIN) + ret1 = do_set_control(i); + } + + ret1 = do_set_control(V4L2_CID_BASE - 1); + ret1 = do_set_control(V4L2_CID_LASTP1); + ret1 = do_set_control(V4L2_CID_PRIVATE_BASE - 1); + + i = V4L2_CID_PRIVATE_BASE; + do { + ret1 = do_set_control(i); + i++; + } while (ret1 == 0); + + ret1 = do_set_control(i); +} + +void test_VIDIOC_S_CTRL_invalid() +{ + int ret1; + __u32 i; + + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + if (i != V4L2_CID_AUTO_WHITE_BALANCE && + i != V4L2_CID_DO_WHITE_BALANCE && + i != V4L2_CID_RED_BALANCE && + i != V4L2_CID_BLUE_BALANCE && + i != V4L2_CID_AUTOGAIN && i != V4L2_CID_GAIN) + ret1 = do_set_control_invalid(i); + } + + ret1 = do_set_control_invalid(V4L2_CID_BASE - 1); + ret1 = do_set_control_invalid(V4L2_CID_LASTP1); + ret1 = do_set_control_invalid(V4L2_CID_PRIVATE_BASE - 1); + + i = V4L2_CID_PRIVATE_BASE; + do { + ret1 = do_set_control_invalid(i); + i++; + } while (ret1 == 0); + + ret1 = do_set_control_invalid(i); +} + +void test_VIDIOC_S_CTRL_white_balance() +{ + int ret1; + + /* TODO: handle V4L2_CID_AUTO_WHITE_BALANCE activated and deactivated separately */ + ret1 = do_set_control(V4L2_CID_AUTO_WHITE_BALANCE); + ret1 = do_set_control(V4L2_CID_DO_WHITE_BALANCE); + ret1 = do_set_control(V4L2_CID_RED_BALANCE); + ret1 = do_set_control(V4L2_CID_BLUE_BALANCE); +} + +void test_VIDIOC_S_CTRL_white_balance_invalid() +{ + int ret1; + + /* TODO: handle V4L2_CID_AUTO_WHITE_BALANCE activated and deactivated separately */ + ret1 = do_set_control_invalid(V4L2_CID_AUTO_WHITE_BALANCE); + ret1 = do_set_control_invalid(V4L2_CID_DO_WHITE_BALANCE); + ret1 = do_set_control_invalid(V4L2_CID_RED_BALANCE); + ret1 = do_set_control_invalid(V4L2_CID_BLUE_BALANCE); +} + +void test_VIDIOC_S_CTRL_gain() +{ + int ret1; + + /* TODO: handle V4L2_CID_AUTOGAIN activated and deactivated separately */ + ret1 = do_set_control(V4L2_CID_AUTOGAIN); + ret1 = do_set_control(V4L2_CID_GAIN); +} + +void test_VIDIOC_S_CTRL_gain_invalid() +{ + int ret1; + + /* TODO: handle V4L2_CID_AUTOGAIN activated and deactivated separately */ + ret1 = do_set_control_invalid(V4L2_CID_AUTOGAIN); + ret1 = do_set_control_invalid(V4L2_CID_GAIN); +} + +void test_VIDIOC_S_CTRL_NULL() +{ + int ret_null, errno_null; + + /* TODO: check whether VIDIOC_S_CTRL is supported or not */ + + ret_null = ioctl(get_video_fd(), VIDIOC_S_CTRL, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_S_CTRL, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CTRL.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CTRL.h new file mode 100644 index 0000000000000000000000000000000000000000..ead76917d5ecf6c36877332b412a08aad986f757 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_CTRL.h @@ -0,0 +1,19 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 19 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_CTRL(void); +void test_VIDIOC_G_CTRL_NULL(void); + +void test_VIDIOC_S_CTRL(void); +void test_VIDIOC_S_CTRL_invalid(void); +void test_VIDIOC_S_CTRL_white_balance(void); +void test_VIDIOC_S_CTRL_white_balance_invalid(void); +void test_VIDIOC_S_CTRL_gain(void); +void test_VIDIOC_S_CTRL_gain_invalid(void); +void test_VIDIOC_S_CTRL_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDIO.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDIO.c new file mode 100644 index 0000000000000000000000000000000000000000..9a0854856055474a7634985f2340b2feeb47f6b1 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDIO.c @@ -0,0 +1,198 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.7 Added string content validation + * 18 Apr 2009 0.6 More strict check for strings + * 29 Mar 2009 0.5 Clean up test case for NULL parameter + * 28 Mar 2009 0.4 Clean up ret and errno variable names and dprintf() output + * 1 Jan 2009 0.3 Added index=S32_MAX, S32_MAX+1 and U32_MAX + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_ENUMAUDIO.h" + +void test_VIDIOC_ENUMAUDIO() +{ + int ret_enum, errno_enum; + struct v4l2_audio audio; + struct v4l2_audio audio2; + __u32 i; + + i = 0; + do { + memset(&audio, 0xff, sizeof(audio)); + audio.index = i; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDIO, &audio); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUMAUDIO, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(audio.index, i); + + CU_ASSERT(0 < strlen((char *)audio.name)); + CU_ASSERT(valid_string + ((char *)audio.name, sizeof(audio.name))); + + //CU_ASSERT_EQUAL(audio.capability, ?); + //CU_ASSERT_EQUAL(audio.mode, ?); + CU_ASSERT_EQUAL(audio.reserved[0], 0); + CU_ASSERT_EQUAL(audio.reserved[1], 0); + + /* Check if the unused bytes of the name string are + * also filled with zeros. Also check if there is any + * padding byte between any two fields then this + * padding byte is also filled with zeros. + */ + memset(&audio2, 0, sizeof(audio2)); + audio2.index = audio.index; + strncpy((char *)audio2.name, (char *)audio.name, + sizeof(audio2.name)); + audio2.capability = audio.capability; + audio2.mode = audio.mode; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), + 0); + + dprintf("\taudio = {.index=%u, .name=\"%s\", " + ".capability=0x%X, .mode=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", + audio.index, + audio.name, + audio.capability, + audio.mode, audio.reserved[0], audio.reserved[1] + ); + + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&audio2, 0xff, sizeof(audio2)); + audio2.index = i; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), + 0); + + } + i++; + } while (ret_enum == 0); + +} + +void test_VIDIOC_ENUMAUDIO_S32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_audio audio; + struct v4l2_audio audio2; + + memset(&audio, 0xff, sizeof(audio)); + audio.index = (__u32) S32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDIO, &audio); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original audio struct is untouched */ + memset(&audio2, 0xff, sizeof(audio2)); + audio2.index = (__u32) S32_MAX; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); +} + +void test_VIDIOC_ENUMAUDIO_S32_MAX_1() +{ + int ret_enum, errno_enum; + struct v4l2_audio audio; + struct v4l2_audio audio2; + + memset(&audio, 0xff, sizeof(audio)); + audio.index = ((__u32) S32_MAX) + 1; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDIO, &audio); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original audio struct is untouched */ + memset(&audio2, 0xff, sizeof(audio2)); + audio2.index = ((__u32) S32_MAX) + 1; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); +} + +void test_VIDIOC_ENUMAUDIO_U32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_audio audio; + struct v4l2_audio audio2; + + memset(&audio, 0xff, sizeof(audio)); + audio.index = U32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDIO, &audio); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original audio struct is untouched */ + memset(&audio2, 0xff, sizeof(audio2)); + audio2.index = U32_MAX; + CU_ASSERT_EQUAL(memcmp(&audio, &audio2, sizeof(audio)), 0); +} + +void test_VIDIOC_ENUMAUDIO_NULL() +{ + int ret_enum, errno_enum; + int ret_null, errno_null; + struct v4l2_audio audio; + + memset(&audio, 0, sizeof(audio)); + audio.index = 0; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDIO, &audio); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMAUDIO, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + ret_null = ioctl(get_video_fd(), VIDIOC_ENUMAUDIO, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMAUDIO, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDIO.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDIO.h new file mode 100644 index 0000000000000000000000000000000000000000..75ef6d477aa894f5c675a7f45df6530cfe949e26 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDIO.h @@ -0,0 +1,16 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 1 Jan 2009 0.3 Added index=S32_MAX, S32_MAX+1 and U32_MAX + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_ENUMAUDIO(void); +void test_VIDIOC_ENUMAUDIO_S32_MAX(void); +void test_VIDIOC_ENUMAUDIO_S32_MAX_1(void); +void test_VIDIOC_ENUMAUDIO_U32_MAX(void); +void test_VIDIOC_ENUMAUDIO_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDOUT.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDOUT.c new file mode 100644 index 0000000000000000000000000000000000000000..e959d3e04a538be34a0f3a3381345394b76fe8f0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDOUT.c @@ -0,0 +1,207 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.4 Added string content validation + * 18 Apr 2009 0.3 More strict check for strings + * 25 Mar 2009 0.2 Typos corrected, cleaned up dprintf() outputs; + * cleaned up ret and errno variable names + * 1 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + * + * Note: in ioctl VIDIOC_ENUMAUDOUT reference (doc/spec/r8304.htm) + * the description text mentions the VIDIOC_G_AUDOUT should + * be called. This is a typo in the V4L2 specification (revision 0.24). + * To enumerate the audio outputs the VIDIOC_ENUMAUDOUT should be + * called. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_ENUMAUDOUT.h" + +void test_VIDIOC_ENUMAUDOUT() +{ + int ret_enum, errno_enum; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + __u32 i; + + i = 0; + do { + memset(&audioout, 0xff, sizeof(audioout)); + audioout.index = i; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDOUT, &audioout); + errno_enum = errno; + + dprintf("\tVIDIOC_ENUMAUDOUT, ret_enum=%i, errno_enum=%i\n", + ret_enum, errno_enum); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(audioout.index, i); + + CU_ASSERT(0 < strlen((char *)audioout.name)); + CU_ASSERT(valid_string + ((char *)audioout.name, + sizeof(audioout.name))); + + //CU_ASSERT_EQUAL(audioout.capability, ?); + //CU_ASSERT_EQUAL(audioout.mode, ?); + CU_ASSERT_EQUAL(audioout.reserved[0], 0); + CU_ASSERT_EQUAL(audioout.reserved[1], 0); + + /* Check if the unused bytes of the name string are + * also filled with zeros. Also check if there is any + * padding byte between any two fields then this + * padding byte is also filled with zeros. + */ + memset(&audioout2, 0, sizeof(audioout2)); + audioout2.index = audioout.index; + strncpy((char *)audioout2.name, (char *)audioout.name, + sizeof(audioout2.name)); + audioout2.capability = audioout.capability; + audioout2.mode = audioout.mode; + CU_ASSERT_EQUAL(memcmp + (&audioout, &audioout2, + sizeof(audioout)), 0); + + dprintf("\taudioout = {.index=%u, .name=\"%s\", " + ".capability=0x%X, .mode=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", + audioout.index, + audioout.name, + audioout.capability, + audioout.mode, + audioout.reserved[0], audioout.reserved[1] + ); + + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* check whether the structure is untouched */ + memset(&audioout2, 0xff, sizeof(audioout2)); + audioout2.index = i; + CU_ASSERT_EQUAL(memcmp + (&audioout, &audioout2, + sizeof(audioout)), 0); + + } + i++; + } while (ret_enum == 0); + +} + +void test_VIDIOC_ENUMAUDOUT_S32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + + memset(&audioout, 0xff, sizeof(audioout)); + audioout.index = (__u32) S32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDOUT, &audioout); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original audioout struct is untouched */ + memset(&audioout2, 0xff, sizeof(audioout2)); + audioout2.index = (__u32) S32_MAX; + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), 0); +} + +void test_VIDIOC_ENUMAUDOUT_S32_MAX_1() +{ + int ret_enum, errno_enum; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + + memset(&audioout, 0xff, sizeof(audioout)); + audioout.index = ((__u32) S32_MAX) + 1; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDOUT, &audioout); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original audioout struct is untouched */ + memset(&audioout2, 0xff, sizeof(audioout2)); + audioout2.index = ((__u32) S32_MAX) + 1; + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), 0); +} + +void test_VIDIOC_ENUMAUDOUT_U32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_audioout audioout; + struct v4l2_audioout audioout2; + + memset(&audioout, 0xff, sizeof(audioout)); + audioout.index = U32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDOUT, &audioout); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original audioout struct is untouched */ + memset(&audioout2, 0xff, sizeof(audioout2)); + audioout2.index = U32_MAX; + CU_ASSERT_EQUAL(memcmp(&audioout, &audioout2, sizeof(audioout)), 0); +} + +void test_VIDIOC_ENUMAUDOUT_NULL() +{ + int ret_enum, errno_enum; + struct v4l2_audioout audioout; + int ret_null, errno_null; + + memset(&audioout, 0, sizeof(audioout)); + audioout.index = 0; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMAUDOUT, &audioout); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMAUDOUT, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + ret_null = ioctl(get_video_fd(), VIDIOC_ENUMAUDOUT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMAUDOUT, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDOUT.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDOUT.h new file mode 100644 index 0000000000000000000000000000000000000000..90cf62d4833e6b25753ff906691959ec4fe4c2cf --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMAUDOUT.h @@ -0,0 +1,14 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 1 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_ENUMAUDOUT(void); +void test_VIDIOC_ENUMAUDOUT_S32_MAX(void); +void test_VIDIOC_ENUMAUDOUT_S32_MAX_1(void); +void test_VIDIOC_ENUMAUDOUT_U32_MAX(void); +void test_VIDIOC_ENUMAUDOUT_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMINPUT.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMINPUT.c new file mode 100644 index 0000000000000000000000000000000000000000..3b52a729b692c7614fb35a8cbeb14cabf667a086 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMINPUT.c @@ -0,0 +1,210 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 5 Jul 2009 0.10 show_v4l2_input() introduced + * 20 Apr 2009 0.9 Added string content validation + * 19 Apr 2009 0.8 Also check std field + * 18 Apr 2009 0.7 More strict check for strings + * 3 Apr 2009 0.6 Test case for NULL parameter reworked + * 28 Mar 2009 0.5 Clean up ret and errno variable names and dprintf() output + * 18 Jan 2009 0.4 Test case for MAX_EM28XX_INPUT removed, test cases with + * U32_MAX and S32_MAX are enough + * 1 Jan 2009 0.3 Added index=S32_MAX and S32_MAX+1 + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" +#include "v4l2_show.h" + +#include "test_VIDIOC_ENUMINPUT.h" + +void test_VIDIOC_ENUMINPUT() +{ + int ret_enum, errno_enum; + struct v4l2_input input; + struct v4l2_input input2; + __u32 i; + + i = 0; + do { + memset(&input, 0xff, sizeof(input)); + input.index = i; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMINPUT, &input); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUMINPUT, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(input.index, i); + + CU_ASSERT(0 < strlen((char *)input.name)); + CU_ASSERT(valid_string + ((char *)input.name, sizeof(input.name))); + + //CU_ASSERT_EQUAL(input.type, ?); + //CU_ASSERT_EQUAL(input.audioset, ?); + //CU_ASSERT_EQUAL(input.tuner, ?); + CU_ASSERT(valid_v4l2_std_id(input.std)); + //CU_ASSERT_EQUAL(input.status, ?); + CU_ASSERT_EQUAL(input.reserved[0], 0); + CU_ASSERT_EQUAL(input.reserved[1], 0); + CU_ASSERT_EQUAL(input.reserved[2], 0); + CU_ASSERT_EQUAL(input.reserved[3], 0); + + /* Check if the unused bytes of the name string are + * also filled with zeros. Also check if there is any + * padding byte between any two fields then this + * padding byte is also filled with zeros. + */ + memset(&input2, 0, sizeof(input2)); + input2.index = input.index; + strncpy((char *)input2.name, (char *)input.name, + sizeof(input2.name)); + input2.type = input.type; + input2.audioset = input.audioset; + input2.tuner = input.tuner; + input2.std = input.std; + input2.status = input.status; + CU_ASSERT_EQUAL(memcmp(&input, &input2, sizeof(input)), + 0); + + show_v4l2_input(&input); + + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&input2, 0xff, sizeof(input2)); + input2.index = i; + CU_ASSERT_EQUAL(memcmp(&input, &input2, sizeof(input)), + 0); + + } + i++; + } while (ret_enum == 0); + +} + +void test_VIDIOC_ENUMINPUT_S32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_input input; + struct v4l2_input input2; + + memset(&input, 0xff, sizeof(input)); + input.index = (__u32) S32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMINPUT, &input); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMINPUT, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&input2, 0xff, sizeof(input2)); + input2.index = (__u32) S32_MAX; + CU_ASSERT_EQUAL(memcmp(&input, &input2, sizeof(input)), 0); +} + +void test_VIDIOC_ENUMINPUT_S32_MAX_1() +{ + int ret_enum, errno_enum; + struct v4l2_input input; + struct v4l2_input input2; + + memset(&input, 0xff, sizeof(input)); + input.index = ((__u32) S32_MAX) + 1; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMINPUT, &input); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMINPUT, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&input2, 0xff, sizeof(input2)); + input2.index = ((__u32) S32_MAX) + 1; + CU_ASSERT_EQUAL(memcmp(&input, &input2, sizeof(input)), 0); +} + +void test_VIDIOC_ENUMINPUT_U32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_input input; + struct v4l2_input input2; + + memset(&input, 0xff, sizeof(input)); + input.index = U32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMINPUT, &input); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMINPUT, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&input2, 0xff, sizeof(input2)); + input2.index = U32_MAX; + CU_ASSERT_EQUAL(memcmp(&input, &input2, sizeof(input)), 0); +} + +void test_VIDIOC_ENUMINPUT_NULL() +{ + int ret_enum, errno_enum; + int ret_null, errno_null; + struct v4l2_input input; + + memset(&input, 0xff, sizeof(input)); + input.index = 0; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMINPUT, &input); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMINPUT, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + ret_null = ioctl(get_video_fd(), VIDIOC_ENUMINPUT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMINPUT, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMINPUT.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMINPUT.h new file mode 100644 index 0000000000000000000000000000000000000000..a8fd2679dc866207fff9f7e4b62270d42033a600 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMINPUT.h @@ -0,0 +1,17 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 1 Jan 2009 0.3 Added index=S32_MAX and S32_MAX+1 + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_ENUMINPUT(void); +void test_VIDIOC_ENUMINPUT_S32_MAX(void); +void test_VIDIOC_ENUMINPUT_S32_MAX_1(void); +void test_VIDIOC_ENUMINPUT_U32_MAX(void); +void test_VIDIOC_ENUMINPUT_3(void); +void test_VIDIOC_ENUMINPUT_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMOUTPUT.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMOUTPUT.c new file mode 100644 index 0000000000000000000000000000000000000000..b95d60e9a2aff9edd8995263e43b742c6df18d78 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMOUTPUT.c @@ -0,0 +1,208 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.6 Added string content validation + * 19 Apr 2009 0.5 Also check std field + * 18 Apr 2009 0.4 More strict check for strings + * 3 Apr 2009 0.3 Test case for NULL parameter reworked + * 28 Mar 2009 0.2 Clean up ret and errno variable names and dprintf() output + * 1 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_ENUMOUTPUT.h" + +void test_VIDIOC_ENUMOUTPUT() +{ + int ret_enum, errno_enum; + struct v4l2_output output; + struct v4l2_output output2; + __u32 i; + + i = 0; + do { + memset(&output, 0xff, sizeof(output)); + output.index = i; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMOUTPUT, &output); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUMOUTPUT, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(output.index, i); + + CU_ASSERT(0 < strlen((char *)output.name)); + CU_ASSERT(valid_string + ((char *)output.name, sizeof(output.name))); + + //CU_ASSERT_EQUAL(output.type, ?); + //CU_ASSERT_EQUAL(output.audioset, ?); + //CU_ASSERT_EQUAL(output.modulator, ?); + CU_ASSERT(valid_v4l2_std_id(output.std)); + CU_ASSERT_EQUAL(output.reserved[0], 0); + CU_ASSERT_EQUAL(output.reserved[1], 0); + CU_ASSERT_EQUAL(output.reserved[2], 0); + CU_ASSERT_EQUAL(output.reserved[3], 0); + + /* Check if the unused bytes of the name string are + * also filled with zeros. Also check if there is any + * padding byte between any two fields then this + * padding byte is also filled with zeros. + */ + memset(&output2, 0, sizeof(output2)); + output2.index = output.index; + strncpy((char *)output2.name, (char *)output.name, + sizeof(output2.name)); + output2.type = output.type; + output2.audioset = output.audioset; + output2.modulator = output.modulator; + output2.std = output.std; + CU_ASSERT_EQUAL(memcmp + (&output, &output2, sizeof(output)), 0); + + dprintf("\toutput = {.index=%u, .name=\"%s\", " + ".type=0x%X, .audioset=0x%X, .modulator=0x%X, " + ".std=%llX, " + ".reserved[]={ 0x%X, 0x%X, 0x%X, 0x%X } }\n", + output.index, + output.name, + output.type, + output.audioset, + output.modulator, + output.std, + output.reserved[0], + output.reserved[1], + output.reserved[2], output.reserved[3] + ); + + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&output2, 0xff, sizeof(output2)); + output2.index = i; + CU_ASSERT_EQUAL(memcmp + (&output, &output2, sizeof(output)), 0); + + dprintf("\terrno=%i\n", errno); + + } + i++; + } while (ret_enum == 0); + +} + +void test_VIDIOC_ENUMOUTPUT_S32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_output output; + struct v4l2_output output2; + + memset(&output, 0xff, sizeof(output)); + output.index = (__u32) S32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMOUTPUT, &output); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&output2, 0xff, sizeof(output2)); + output2.index = (__u32) S32_MAX; + CU_ASSERT_EQUAL(memcmp(&output, &output2, sizeof(output)), 0); +} + +void test_VIDIOC_ENUMOUTPUT_S32_MAX_1() +{ + int ret_enum, errno_enum; + struct v4l2_output output; + struct v4l2_output output2; + + memset(&output, 0xff, sizeof(output)); + output.index = ((__u32) S32_MAX) + 1; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMOUTPUT, &output); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&output2, 0xff, sizeof(output2)); + output2.index = ((__u32) S32_MAX) + 1; + CU_ASSERT_EQUAL(memcmp(&output, &output2, sizeof(output)), 0); +} + +void test_VIDIOC_ENUMOUTPUT_U32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_output output; + struct v4l2_output output2; + + memset(&output, 0xff, sizeof(output)); + output.index = U32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMOUTPUT, &output); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&output2, 0xff, sizeof(output2)); + output2.index = U32_MAX; + CU_ASSERT_EQUAL(memcmp(&output, &output2, sizeof(output)), 0); +} + +void test_VIDIOC_ENUMOUTPUT_NULL() +{ + int ret_enum, errno_enum; + int ret_null, errno_null; + struct v4l2_output output; + + memset(&output, 0xff, sizeof(output)); + output.index = 0; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMOUTPUT, &output); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMOUTPUT, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + ret_null = ioctl(get_video_fd(), VIDIOC_ENUMOUTPUT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMOUTPUT, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMOUTPUT.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMOUTPUT.h new file mode 100644 index 0000000000000000000000000000000000000000..f1fb6cd1aa14a604f005976be4fbaf95697f874a --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMOUTPUT.h @@ -0,0 +1,14 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 1 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_ENUMOUTPUT(void); +void test_VIDIOC_ENUMOUTPUT_S32_MAX(void); +void test_VIDIOC_ENUMOUTPUT_S32_MAX_1(void); +void test_VIDIOC_ENUMOUTPUT_U32_MAX(void); +void test_VIDIOC_ENUMOUTPUT_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMSTD.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMSTD.c new file mode 100644 index 0000000000000000000000000000000000000000..2e4451651771cd448581d93de97f74e0d24cac9d --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMSTD.c @@ -0,0 +1,214 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.9 Added string content validation + * 19 Apr 2009 0.8 Also check std field + * 18 Apr 2009 0.7 More strict check for strings + * 3 Apr 2009 0.6 Test case for NULL parameter reworked + * 28 Mar 2009 0.5 Clean up ret and errno variable names and dprintf() output + * 18 Jan 2009 0.4 Test case for MAX_EM28XX_TVNORMS removed, test cases for + * S32_MAX & U32_MAX are enough + * 1 Jan 2009 0.3 Added index=S32_MAX and S32_MAX+1 + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +/* TODO: from V4L2 Spec: + * "Drivers may enumerate a different set of standards after switching the video input or output." + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_ENUMSTD.h" + +void test_VIDIOC_ENUMSTD() +{ + int ret_enum, errno_enum; + struct v4l2_standard std; + struct v4l2_standard std2; + __u32 i; + + i = 0; + do { + memset(&std, 0xff, sizeof(std)); + std.index = i; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMSTD, &std); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMSTD, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(std.index, i); + CU_ASSERT(valid_v4l2_std_id(std.id)); + + CU_ASSERT(0 < strlen((char *)std.name)); + CU_ASSERT(valid_string + ((char *)std.name, sizeof(std.name))); + + //CU_ASSERT_EQUAL(std.frameperiod.numerator, ?); + //CU_ASSERT_EQUAL(std.frameperiod.denominator, ?); + //CU_ASSERT_EQUAL(std.framelines, ?); + CU_ASSERT_EQUAL(std.reserved[0], 0); + CU_ASSERT_EQUAL(std.reserved[1], 0); + CU_ASSERT_EQUAL(std.reserved[2], 0); + CU_ASSERT_EQUAL(std.reserved[3], 0); + + /* Check if the unused bytes of the name string is also filled + * with zeros. Also check if there is any padding byte between + * any two fields then this padding byte is also filled with zeros. + */ + memset(&std2, 0, sizeof(std2)); + std2.index = std.index; + std2.id = std.id; + strncpy((char *)std2.name, (char *)std.name, + sizeof(std2.name)); + std2.frameperiod.numerator = std.frameperiod.numerator; + std2.frameperiod.denominator = + std.frameperiod.denominator; + std2.framelines = std.framelines; + CU_ASSERT_EQUAL(memcmp(&std, &std2, sizeof(std)), 0); + + dprintf("\tstd = {.index=%u, .id=%llX, .name=\"%s\", " + ".frameperiod={ .numerator=%u, .denominator=%u }, " + ".framelines=%u, " + ".reserved[]={ 0x%X, 0x%X, 0x%X, 0x%X } }\n", + std.index, + std.id, + std.name, + std.frameperiod.numerator, + std.frameperiod.denominator, + std.framelines, + std.reserved[0], + std.reserved[1], + std.reserved[2], std.reserved[3] + ); + + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&std2, 0xff, sizeof(std2)); + std2.index = i; + CU_ASSERT_EQUAL(memcmp(&std, &std2, sizeof(std)), 0); + + } + i++; + } while (ret_enum == 0); +} + +void test_VIDIOC_ENUMSTD_S32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_standard std; + struct v4l2_standard std2; + + memset(&std, 0xff, sizeof(std)); + std.index = (__u32) S32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMSTD, &std); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&std2, 0xff, sizeof(std2)); + std2.index = (__u32) S32_MAX; + CU_ASSERT_EQUAL(memcmp(&std, &std2, sizeof(std)), 0); +} + +void test_VIDIOC_ENUMSTD_S32_MAX_1() +{ + int ret_enum, errno_enum; + struct v4l2_standard std; + struct v4l2_standard std2; + + memset(&std, 0xff, sizeof(std)); + std.index = ((__u32) S32_MAX) + 1; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMSTD, &std); + errno_enum = errno; + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&std2, 0xff, sizeof(std2)); + std2.index = ((__u32) S32_MAX) + 1; + CU_ASSERT_EQUAL(memcmp(&std, &std2, sizeof(std)), 0); +} + +void test_VIDIOC_ENUMSTD_U32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_standard std; + struct v4l2_standard std2; + + memset(&std, 0xff, sizeof(std)); + std.index = U32_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMSTD, &std); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMSTD, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&std2, 0xff, sizeof(std2)); + std2.index = U32_MAX; + CU_ASSERT_EQUAL(memcmp(&std, &std2, sizeof(std)), 0); +} + +void test_VIDIOC_ENUMSTD_NULL() +{ + int ret_enum, errno_enum; + int ret_null, errno_null; + struct v4l2_standard std; + + memset(&std, 0xff, sizeof(std)); + std.index = 0; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUMSTD, &std); + errno_enum = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMSTD, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, ret_enum, errno_enum); + + ret_null = ioctl(get_video_fd(), VIDIOC_ENUMSTD, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_ENUMSTD, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMSTD.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMSTD.h new file mode 100644 index 0000000000000000000000000000000000000000..37da4a255b1369866b8b8c62782b203d953c74f0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUMSTD.h @@ -0,0 +1,17 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 1 Jan 2009 0.3 Added index=S32_MAX and S32_MAX+1 + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_ENUMSTD(void); +void test_VIDIOC_ENUMSTD_S32_MAX(void); +void test_VIDIOC_ENUMSTD_S32_MAX_1(void); +void test_VIDIOC_ENUMSTD_U32_MAX(void); +void test_VIDIOC_ENUMSTD_3(void); +void test_VIDIOC_ENUMSTD_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FMT.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FMT.c new file mode 100644 index 0000000000000000000000000000000000000000..b51a2b329734fd40eec6519b1240814dd2bac4f0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FMT.c @@ -0,0 +1,483 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.9 Added string content validation + * 18 Apr 2009 0.8 More strict check for strings + * 13 Apr 2009 0.7 Also show type in debug output; + * Add some debug output + * 3 Apr 2009 0.6 Test case for NULL parameter reworked + * 28 Mar 2009 0.5 Clean up ret and errno variable names and dprintf() output + * 18 Mar 2009 0.4 Duplicated test for V4L2_BUF_TYPE_VIDEO_CAPTURE removed + * 1 Jan 2009 0.3 Test cases added for index=S32_MAX and S32_MAX+1; + * Test functions renamed + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_ENUM_FMT.h" + +static void do_enumerate_formats(enum v4l2_buf_type type) +{ + int ret_enum, errno_enum; + struct v4l2_fmtdesc format; + struct v4l2_fmtdesc format2; + __u32 i; + + i = 0; + do { + memset(&format, 0xff, sizeof(format)); + format.index = i; + format.type = type; + + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, i, type, ret_enum, errno_enum); + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + CU_ASSERT_EQUAL(format.index, i); + //CU_ASSERT_EQUAL(format.type, ?); + //CU_ASSERT_EQUAL(format.flags, ?); + + CU_ASSERT(0 < strlen((char *)format.description)); + CU_ASSERT(valid_string + ((char *)format.description, + sizeof(format.description))); + + //CU_ASSERT_EQUAL(format.pixelformat, ?); + CU_ASSERT_EQUAL(format.reserved[0], 0); + CU_ASSERT_EQUAL(format.reserved[1], 0); + CU_ASSERT_EQUAL(format.reserved[2], 0); + CU_ASSERT_EQUAL(format.reserved[3], 0); + + /* Check if the unused bytes of the description string is also filled + * with zeros. Also check if there is any padding byte between + * any two fields then this padding byte is also filled with zeros. + */ + memset(&format2, 0, sizeof(format2)); + format2.index = format.index; + format2.type = format.type; + format2.flags = format.flags; + strncpy((char *)format2.description, + (char *)format.description, + sizeof(format2.description)); + format2.pixelformat = format.pixelformat; + CU_ASSERT_EQUAL(memcmp + (&format, &format2, sizeof(format)), 0); + + dprintf + ("\tformat = {.index=%u, .type=0x%X, .flags=0x%X, " + ".description=\"%s\", .pixelformat=0x%X, " + ".reserved[]={ 0x%X, 0x%X, 0x%X, 0x%X } }\n", + format.index, format.type, format.flags, + format.description, format.pixelformat, + format.reserved[0], format.reserved[1], + format.reserved[2], format.reserved[3] + ); + + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + memset(&format2, 0xff, sizeof(format2)); + format2.index = i; + format2.type = type; + CU_ASSERT_EQUAL(memcmp + (&format, &format2, sizeof(format)), 0); + + } + i++; + } while (ret_enum == 0); + +} + +void test_VIDIOC_ENUM_FMT() +{ + do_enumerate_formats(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_enumerate_formats(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_enumerate_formats(V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_enumerate_formats(V4L2_BUF_TYPE_VBI_CAPTURE); + do_enumerate_formats(V4L2_BUF_TYPE_VBI_OUTPUT); + do_enumerate_formats(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_enumerate_formats(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); + do_enumerate_formats(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_enumerate_formats(V4L2_BUF_TYPE_PRIVATE); +} + +void test_VIDIOC_ENUM_FMT_S32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_fmtdesc format; + struct v4l2_fmtdesc format2; + + /* test invalid index */ + memset(&format, 0xff, sizeof(format)); + format.index = (__u32) S32_MAX; + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, format.index, format.type, ret_enum, + errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.index = (__u32) S32_MAX; + format2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); +} + +void test_VIDIOC_ENUM_FMT_S32_MAX_1() +{ + int ret_enum, errno_enum; + struct v4l2_fmtdesc format; + struct v4l2_fmtdesc format2; + + /* test invalid index */ + memset(&format, 0xff, sizeof(format)); + format.index = ((__u32) S32_MAX) + 1; + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, format.index, format.type, ret_enum, + errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.index = ((__u32) S32_MAX) + 1; + format2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); +} + +void test_VIDIOC_ENUM_FMT_U32_MAX() +{ + int ret_enum, errno_enum; + struct v4l2_fmtdesc format; + struct v4l2_fmtdesc format2; + + /* test invalid index */ + memset(&format, 0xff, sizeof(format)); + format.index = U32_MAX; + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, format.index, format.type, ret_enum, + errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.index = U32_MAX; + format2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); +} + +void test_VIDIOC_ENUM_FMT_invalid_type() +{ + int ret_enum, errno_enum; + struct v4l2_fmtdesc format; + struct v4l2_fmtdesc format2; + int i; + + /* In this test case the .index is valid (0) and only the .type + * is invalid. The .type filed is an enum which is stored in an 'int'. + */ + + /* test invalid .type=0 */ + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = 0; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, format.index, format.type, ret_enum, + errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.index = 0; + format2.type = 0; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); + + /* test invalid .type=SINT_MIN */ + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = SINT_MIN; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, format.index, format.type, ret_enum, + errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.index = 0; + format2.type = SINT_MIN; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); + + /* test invalid .type=-1 */ + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = -1; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, format.index, format.type, ret_enum, + errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.index = 0; + format2.type = -1; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); + + /* test invalid .type= 8..0x7F */ + for (i = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY + 1; + i < V4L2_BUF_TYPE_PRIVATE; i++) { + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = i; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, format.index, format.type, ret_enum, + errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.index = 0; + format2.type = i; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); + } + + /* .type = 0x80..0x7FFF FFFF is the private range */ + + /* Assume that 0x7FFF FFFF is invalid in the private range. + * This might be a wrong assumption, but let's have a test case like + * this for now. + */ + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = SINT_MAX; + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, format.index, format.type, ret_enum, + errno_enum); + + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.index = 0; + format2.type = SINT_MAX; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); +} + +void test_VIDIOC_ENUM_FMT_NULL() +{ + int ret_capture, errno_capture; + int ret_output, errno_output; + int ret_video_overlay, errno_video_overlay; + int ret_vbi_capture, errno_vbi_capture; + int ret_vbi_output, errno_vbi_output; + int ret_sliced_vbi_capture, errno_sliced_vbi_capture; + int ret_sliced_vbi_output, errno_sliced_vbi_output; + int ret_video_output_overlay, errno_video_output_overlay; + int ret_private, errno_private; + int ret_null, errno_null; + struct v4l2_fmtdesc format; + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret_capture = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_capture = errno; + + dprintf("\t%s:%u: VIDIOC_ENUM_FMT, ret_capture=%i, errno_capture=%i\n", + __FILE__, __LINE__, ret_capture, errno_capture); + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ret_output = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_output = errno; + + dprintf("\t%s:%u: VIDIOC_ENUM_FMT, ret_output=%i, errno_output=%i\n", + __FILE__, __LINE__, ret_output, errno_output); + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + ret_video_overlay = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_video_overlay = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, ret_video_overlay=%i, errno_video_overlay=%i\n", + __FILE__, __LINE__, ret_video_overlay, errno_video_overlay); + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_VBI_CAPTURE; + ret_vbi_capture = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_vbi_capture = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, ret_vbi_capture=%i, errno_vbi_capture=%i\n", + __FILE__, __LINE__, ret_vbi_capture, errno_vbi_capture); + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_VBI_OUTPUT; + ret_vbi_output = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_vbi_output = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, ret_vbi_output=%i, errno_vbi_output=%i\n", + __FILE__, __LINE__, ret_vbi_output, errno_vbi_output); + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + ret_sliced_vbi_capture = + ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_sliced_vbi_capture = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, ret_sliced_vbi_capture=%i, errno_sliced_vbi_capture=%i\n", + __FILE__, __LINE__, ret_sliced_vbi_capture, + errno_sliced_vbi_capture); + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + ret_sliced_vbi_output = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_sliced_vbi_output = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, ret_sliced_vbi_output=%i, errno_sliced_vbi_output=%i\n", + __FILE__, __LINE__, ret_sliced_vbi_output, + errno_sliced_vbi_output); + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; + ret_video_output_overlay = + ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_video_output_overlay = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, ret_video_output_overlay=%i, errno_video_output_overlay=%i\n", + __FILE__, __LINE__, ret_video_output_overlay, + errno_video_output_overlay); + + memset(&format, 0xff, sizeof(format)); + format.index = 0; + format.type = V4L2_BUF_TYPE_PRIVATE; + ret_private = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_private = errno; + + dprintf("\t%s:%u: VIDIOC_ENUM_FMT, ret_private=%i, errno_private=%i\n", + __FILE__, __LINE__, ret_private, errno_private); + + ret_null = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_ENUM_FMT, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_capture == 0 || ret_output == 0 || + ret_video_overlay == 0 || ret_vbi_capture == 0 || + ret_vbi_output == 0 || ret_sliced_vbi_capture == 0 || + ret_sliced_vbi_output == 0 || ret_video_output_overlay == 0 || + ret_private == 0) { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_capture, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + CU_ASSERT_EQUAL(ret_output, -1); + CU_ASSERT_EQUAL(errno_output, EINVAL); + CU_ASSERT_EQUAL(ret_video_overlay, -1); + CU_ASSERT_EQUAL(errno_video_overlay, EINVAL); + CU_ASSERT_EQUAL(ret_vbi_capture, -1); + CU_ASSERT_EQUAL(errno_vbi_capture, EINVAL); + CU_ASSERT_EQUAL(ret_vbi_output, -1); + CU_ASSERT_EQUAL(errno_vbi_output, EINVAL); + CU_ASSERT_EQUAL(ret_sliced_vbi_capture, -1); + CU_ASSERT_EQUAL(errno_sliced_vbi_capture, EINVAL); + CU_ASSERT_EQUAL(ret_sliced_vbi_output, -1); + CU_ASSERT_EQUAL(errno_sliced_vbi_output, EINVAL); + CU_ASSERT_EQUAL(ret_video_output_overlay, -1); + CU_ASSERT_EQUAL(errno_video_output_overlay, EINVAL); + CU_ASSERT_EQUAL(ret_private, -1); + CU_ASSERT_EQUAL(errno_private, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FMT.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FMT.h new file mode 100644 index 0000000000000000000000000000000000000000..c797d9d8e9d6174d1bc2e12961750d557953caea --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FMT.h @@ -0,0 +1,18 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 1 Jan 2009 0.3 Test cases added for index=S32_MAX and S32_MAX+1; + * Test functions renamed + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_ENUM_FMT(void); +void test_VIDIOC_ENUM_FMT_S32_MAX(void); +void test_VIDIOC_ENUM_FMT_S32_MAX_1(void); +void test_VIDIOC_ENUM_FMT_U32_MAX(void); +void test_VIDIOC_ENUM_FMT_invalid_type(void); +void test_VIDIOC_ENUM_FMT_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FRAMESIZES.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FRAMESIZES.c new file mode 100644 index 0000000000000000000000000000000000000000..a7043b0d6b3f357f87737ad995ff388223a496dd --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FRAMESIZES.c @@ -0,0 +1,675 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 16 Jun 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" +#include "v4l2_foreach.h" +#include "v4l2_show.h" + +#include "test_VIDIOC_ENUM_FRAMESIZES.h" + +static int valid_framesize_type(__u32 type) +{ + int valid = 0; + + if ((type == V4L2_FRMSIZE_TYPE_DISCRETE) || + (type == V4L2_FRMSIZE_TYPE_CONTINUOUS) || + (type == V4L2_FRMSIZE_TYPE_STEPWISE)) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +static void do_test_VIDIOC_ENUM_FRAMESIZES(__u32 fmt) +{ + struct v4l2_frmsizeenum framesize; + int ret_frame, errno_frame; + __u32 i; + __u32 first_type; + + i = 0; + first_type = 0; + do { + memset(&framesize, 0xff, sizeof(framesize)); + framesize.index = i; + framesize.pixel_format = fmt; + ret_frame = + ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, &framesize); + errno_frame = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FRAMESIZES, index=%u, pixel_format=0x%x, ret_frame=%i, errno_frame=%i\n", + __FILE__, __LINE__, i, fmt, ret_frame, errno_frame); + + if (i != 0 && first_type != V4L2_FRMSIZE_TYPE_DISCRETE) { + CU_ASSERT_EQUAL(ret_frame, -1); + CU_ASSERT_EQUAL(errno_frame, EINVAL); + } + + if (ret_frame == 0) { + CU_ASSERT_EQUAL(ret_frame, 0); + CU_ASSERT_EQUAL(framesize.index, i); + CU_ASSERT_EQUAL(framesize.pixel_format, fmt); + CU_ASSERT(valid_framesize_type(framesize.type)); + + if (i == 0) { + first_type = framesize.type; + } else { + CU_ASSERT_EQUAL(framesize.type, first_type); + } + + switch (framesize.type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + CU_ASSERT(0 < framesize.discrete.width); + CU_ASSERT(0 < framesize.discrete.height); + break; + + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + CU_ASSERT(0 < framesize.stepwise.min_width); + CU_ASSERT(0 < framesize.stepwise.max_width); + CU_ASSERT_EQUAL(framesize.stepwise.step_width, + 1); + + CU_ASSERT(framesize.stepwise.min_width < + framesize.stepwise.max_width); + + CU_ASSERT(0 < framesize.stepwise.min_height); + CU_ASSERT(0 < framesize.stepwise.max_height); + CU_ASSERT_EQUAL(framesize.stepwise.step_height, + 1); + + CU_ASSERT(framesize.stepwise.min_height < + framesize.stepwise.max_height); + break; + + case V4L2_FRMSIZE_TYPE_STEPWISE: + CU_ASSERT(0 < framesize.stepwise.min_width); + CU_ASSERT(0 < framesize.stepwise.max_width); + CU_ASSERT(0 < framesize.stepwise.step_width); + + CU_ASSERT(framesize.stepwise.min_width < + framesize.stepwise.max_width); + + /* check if the given step is unambigous: min + n * step = max */ + if (framesize.stepwise.step_width != 0) { + CU_ASSERT_EQUAL((framesize.stepwise. + max_width - + framesize.stepwise. + min_width) % + framesize.stepwise. + step_width, 0); + } + + CU_ASSERT(0 < framesize.stepwise.min_height); + CU_ASSERT(0 < framesize.stepwise.max_height); + CU_ASSERT(0 < framesize.stepwise.step_height); + + CU_ASSERT(framesize.stepwise.min_height < + framesize.stepwise.max_height); + + /* check if the given step is unambigous: min + n * step = max */ + if (framesize.stepwise.step_height != 0) { + CU_ASSERT_EQUAL((framesize.stepwise. + max_height - + framesize.stepwise. + min_height) % + framesize.stepwise. + step_height, 0); + } + + break; + } + + CU_ASSERT_EQUAL(framesize.reserved[0], 0); + CU_ASSERT_EQUAL(framesize.reserved[1], 0); + + show_v4l2_frmsizeenum(&framesize); + + } else { + CU_ASSERT_EQUAL(ret_frame, -1); + CU_ASSERT_EQUAL(errno_frame, EINVAL); + } + i++; + } while (ret_frame == 0 && i != 0); + +} + +static void do_test_VIDIOC_ENUM_FRAMESIZES_type(enum v4l2_buf_type type) +{ + int ret_enum, errno_enum; + struct v4l2_fmtdesc format; + __u32 i; + + i = 0; + do { + memset(&format, 0xff, sizeof(format)); + format.index = i; + format.type = type; + + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, i, format.type, ret_enum, errno_enum); + + /* Ensure that VIDIOC_ENUM_FRAMESIZES is called at least once + * even if VIDIOC_ENUM_FMT returns error + */ + do_test_VIDIOC_ENUM_FRAMESIZES(format.pixelformat); + + i++; + } while (ret_enum == 0 && i != 0); + +} + +void test_VIDIOC_ENUM_FRAMESIZES() +{ + do_test_VIDIOC_ENUM_FRAMESIZES_type(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_test_VIDIOC_ENUM_FRAMESIZES_type(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_test_VIDIOC_ENUM_FRAMESIZES_type(V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_test_VIDIOC_ENUM_FRAMESIZES_type(V4L2_BUF_TYPE_PRIVATE); +} + +static void do_test_VIDIOC_ENUM_FRAMESIZES_invalid_index(__u32 fmt) +{ + struct v4l2_frmsizeenum framesize; + int ret_frame, errno_frame; + __u32 i; + __u32 max_index; + + i = 0; + do { + memset(&framesize, 0xff, sizeof(framesize)); + framesize.index = i; + framesize.pixel_format = fmt; + ret_frame = + ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, &framesize); + errno_frame = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FRAMESIZES, index=%u, pixel_format=0x%x, ret_frame=%i, errno_frame=%i\n", + __FILE__, __LINE__, i, fmt, ret_frame, errno_frame); + + i++; + } while (ret_frame == 0 && i != 0); + + max_index = i - 1; + + i = max_index + 1; + memset(&framesize, 0xff, sizeof(framesize)); + framesize.index = i; + framesize.pixel_format = fmt; + ret_frame = ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, &framesize); + errno_frame = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FRAMESIZES, index=%u, pixel_format=0x%x, ret_frame=%i, errno_frame=%i\n", + __FILE__, __LINE__, i, fmt, ret_frame, errno_frame); + + CU_ASSERT_EQUAL(ret_frame, -1); + CU_ASSERT_EQUAL(errno_frame, EINVAL); + + i = (__u32) S32_MIN; + if (max_index < i) { + memset(&framesize, 0xff, sizeof(framesize)); + framesize.index = i; + framesize.pixel_format = fmt; + ret_frame = + ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, &framesize); + errno_frame = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FRAMESIZES, index=0x%x, pixel_format=0x%x, ret_frame=%i, errno_frame=%i\n", + __FILE__, __LINE__, i, fmt, ret_frame, errno_frame); + + CU_ASSERT_EQUAL(ret_frame, -1); + CU_ASSERT_EQUAL(errno_frame, EINVAL); + } + + i = (__u32) S32_MAX; + if (max_index < i) { + memset(&framesize, 0xff, sizeof(framesize)); + framesize.index = i; + framesize.pixel_format = fmt; + ret_frame = + ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, &framesize); + errno_frame = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FRAMESIZES, index=0x%x, pixel_format=0x%x, ret_frame=%i, errno_frame=%i\n", + __FILE__, __LINE__, i, fmt, ret_frame, errno_frame); + + CU_ASSERT_EQUAL(ret_frame, -1); + CU_ASSERT_EQUAL(errno_frame, EINVAL); + } + + i = (__u32) U32_MAX; + if (max_index < i) { + memset(&framesize, 0xff, sizeof(framesize)); + framesize.index = i; + framesize.pixel_format = fmt; + ret_frame = + ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, &framesize); + errno_frame = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FRAMESIZES, index=0x%x, pixel_format=0x%x, ret_frame=%i, errno_frame=%i\n", + __FILE__, __LINE__, i, fmt, ret_frame, errno_frame); + + CU_ASSERT_EQUAL(ret_frame, -1); + CU_ASSERT_EQUAL(errno_frame, EINVAL); + } + +} + +static void do_test_VIDIOC_ENUM_FRAMESIZES_type_invalid_index(enum v4l2_buf_type + type) +{ + int ret_enum, errno_enum; + struct v4l2_fmtdesc format; + __u32 i; + + i = 0; + do { + memset(&format, 0xff, sizeof(format)); + format.index = i; + format.type = type; + + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, i, format.type, ret_enum, errno_enum); + + /* Ensure that VIDIOC_ENUM_FRAMESIZES is called at least once + * even if VIDIOC_ENUM_FMT returns error + */ + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_index(format. + pixelformat); + + i++; + } while (ret_enum == 0 && i != 0); + +} + +void test_VIDIOC_ENUM_FRAMESIZES_invalid_index() +{ + do_test_VIDIOC_ENUM_FRAMESIZES_type_invalid_index + (V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_test_VIDIOC_ENUM_FRAMESIZES_type_invalid_index + (V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_test_VIDIOC_ENUM_FRAMESIZES_type_invalid_index + (V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_test_VIDIOC_ENUM_FRAMESIZES_type_invalid_index + (V4L2_BUF_TYPE_PRIVATE); +} + +static int supported_pixel_format_type(enum v4l2_buf_type type, + __u32 pixel_format) +{ + int ret_enum, errno_enum; + struct v4l2_fmtdesc format; + __u32 i; + int supported = 0; + + i = 0; + do { + memset(&format, 0xff, sizeof(format)); + format.index = i; + format.type = type; + + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, i, format.type, ret_enum, errno_enum); + + i++; + } while (ret_enum == 0 && i != 0 && format.pixelformat != pixel_format); + + if (ret_enum == 0 && i != 0 && format.pixelformat == pixel_format) { + supported = 1; + } + + return supported; +} + +static int supported_pixel_format(__u32 pixel_format) +{ + int supported = 0; + + supported = + supported_pixel_format_type(V4L2_BUF_TYPE_VIDEO_CAPTURE, + pixel_format); + if (!supported) { + supported = + supported_pixel_format_type(V4L2_BUF_TYPE_VIDEO_OUTPUT, + pixel_format); + if (!supported) { + supported = + supported_pixel_format_type + (V4L2_BUF_TYPE_VIDEO_OVERLAY, pixel_format); + if (!supported) { + supported = + supported_pixel_format_type + (V4L2_BUF_TYPE_PRIVATE, pixel_format); + } + } + } + + return supported; +} + +static void do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(__u32 fmt) +{ + struct v4l2_frmsizeenum framesize; + int ret_frame, errno_frame; + __u32 i; + + if (!supported_pixel_format(fmt)) { + i = 0; + memset(&framesize, 0xff, sizeof(framesize)); + framesize.index = i; + framesize.pixel_format = fmt; + ret_frame = + ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, &framesize); + errno_frame = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FRAMESIZES, index=%u, pixel_format=0x%x, ret_frame=%i, errno_frame=%i\n", + __FILE__, __LINE__, i, fmt, ret_frame, errno_frame); + + CU_ASSERT_EQUAL(ret_frame, -1); + CU_ASSERT_EQUAL(errno_frame, EINVAL); + } + +} + +void test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format() +{ + + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(U32_MIN); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format((__u32) S32_MIN); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format((__u32) S32_MAX); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(U32_MAX); + + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_RGB332); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_RGB444); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_RGB555); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_RGB565); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_RGB555X); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_RGB565X); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_BGR24); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_RGB24); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_BGR32); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_RGB32); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_GREY); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_Y16); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_PAL8); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YVU410); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YVU420); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_YUYV); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_UYVY); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YUV422P); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YUV411P); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_Y41P); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YUV444); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YUV555); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YUV565); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_YUV32); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_NV12); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_NV21); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YUV410); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_YUV420); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_YYUV); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_HI240); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_HM12); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SBGGR8); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SBGGR16); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_MJPEG); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_JPEG); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_DV); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_MPEG); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_WNVA); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SN9C10X); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_PWC1); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_PWC2); + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_ET61X251); + +#ifdef V4L2_PIX_FMT_VYUY + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_VYUY); +#endif + +#ifdef V4L2_PIX_FMT_NV16 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_NV16); +#endif + +#ifdef V4L2_PIX_FMT_NV61 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_NV61); +#endif + +#ifdef V4L2_PIX_FMT_SGBRG8 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SGBRG8); +#endif + +#ifdef V4L2_PIX_FMT_SGRBG8 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SGRBG8); +#endif + +#ifdef V4L2_PIX_FMT_SGRBG10 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SGRBG10); +#endif + +#ifdef V4L2_PIX_FMT_SGRBG10DPCM8 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SGRBG10DPCM8); +#endif + +#ifdef V4L2_PIX_FMT_SPCA501 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SPCA501); +#endif + +#ifdef V4L2_PIX_FMT_SPCA505 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SPCA505); +#endif + +#ifdef V4L2_PIX_FMT_SPCA508 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SPCA508); +#endif + +#ifdef V4L2_PIX_FMT_SPCA561 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SPCA561); +#endif + +#ifdef V4L2_PIX_FMT_PAC207 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_PAC207); +#endif + +#ifdef V4L2_PIX_FMT_MR97310A + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_MR97310A); +#endif + +#ifdef V4L2_PIX_FMT_SQ905C + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format + (V4L2_PIX_FMT_SQ905C); +#endif + +#ifdef V4L2_PIX_FMT_PJPG + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_PJPG); +#endif + +#ifdef V4L2_PIX_FMT_YVYU + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_YVYU); +#endif + +#ifdef V4L2_PIX_FMT_OV511 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_OV511); +#endif + +#ifdef V4L2_PIX_FMT_OV518 + do_test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(V4L2_PIX_FMT_OV518); +#endif + +} + +void test_VIDIOC_ENUM_FRAMESIZES_NULL() +{ + struct v4l2_fmtdesc format_capture; + struct v4l2_fmtdesc format_output; + struct v4l2_fmtdesc format_overlay; + struct v4l2_fmtdesc format_private; + struct v4l2_frmsizeenum framesize; + int ret_fmt_capture, errno_fmt_capture; + int ret_fmt_output, errno_fmt_output; + int ret_fmt_overlay, errno_fmt_overlay; + int ret_fmt_private, errno_fmt_private; + int ret_size, errno_size; + int ret_null, errno_null; + __u32 fmt; + + memset(&format_capture, 0xff, sizeof(format_capture)); + format_capture.index = 0; + format_capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret_fmt_capture = + ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format_capture); + errno_fmt_capture = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_fmt_capture=%i, errno_fmt_capture=%i\n", + __FILE__, __LINE__, format_capture.index, format_capture.type, + ret_fmt_capture, errno_fmt_capture); + + memset(&format_output, 0xff, sizeof(format_output)); + format_output.index = 0; + format_output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + ret_fmt_output = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format_output); + errno_fmt_output = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_fmt_output=%i, errno_fmt_output=%i\n", + __FILE__, __LINE__, format_output.index, format_output.type, + ret_fmt_output, errno_fmt_output); + + memset(&format_overlay, 0xff, sizeof(format_overlay)); + format_overlay.index = 0; + format_overlay.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + + ret_fmt_overlay = + ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format_overlay); + errno_fmt_overlay = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_fmt_overlay=%i, errno_fmt_overlay=%i\n", + __FILE__, __LINE__, format_overlay.index, format_overlay.type, + ret_fmt_overlay, errno_fmt_overlay); + + memset(&format_private, 0xff, sizeof(format_private)); + format_private.index = 0; + format_private.type = V4L2_BUF_TYPE_PRIVATE; + + ret_fmt_private = + ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &format_private); + errno_fmt_private = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_fmt_private=%i, errno_fmt_private=%i\n", + __FILE__, __LINE__, format_private.index, format_private.type, + ret_fmt_private, errno_fmt_private); + + if (ret_fmt_capture == 0) { + fmt = format_capture.pixelformat; + } else if (ret_fmt_output == 0) { + fmt = format_output.pixelformat; + } else if (ret_fmt_overlay == 0) { + fmt = format_overlay.pixelformat; + } else if (ret_fmt_private == 0) { + fmt = format_private.pixelformat; + } else { + fmt = 0; + } + + memset(&framesize, 0xff, sizeof(framesize)); + framesize.index = 0; + framesize.pixel_format = fmt; + ret_size = ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, &framesize); + errno_size = errno; + + dprintf + ("\tVIDIOC_ENUM_FRAMESIZES, index=%u, pixel_format=0x%x, ret_size=%i, errno_size=%i\n", + framesize.index, framesize.pixel_format, ret_size, errno_size); + + ret_null = ioctl(get_video_fd(), VIDIOC_ENUM_FRAMESIZES, NULL); + errno_null = errno; + + dprintf("\tVIDIOC_ENUM_FRAMESIZES, ret_null=%i, errno_null=%i\n", + ret_null, errno_null); + + if (ret_size == 0) { + CU_ASSERT_EQUAL(ret_size, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_size, -1); + CU_ASSERT_EQUAL(errno_size, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FRAMESIZES.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FRAMESIZES.h new file mode 100644 index 0000000000000000000000000000000000000000..368210a166340b83e7df15d4ba3630c6f9536482 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_ENUM_FRAMESIZES.h @@ -0,0 +1,13 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 16 Jul 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_ENUM_FRAMESIZES(void); +void test_VIDIOC_ENUM_FRAMESIZES_invalid_index(void); +void test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format(void); +void test_VIDIOC_ENUM_FRAMESIZES_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_EXT_CTRLS.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_EXT_CTRLS.c new file mode 100644 index 0000000000000000000000000000000000000000..13c2838d985431bd64679ab55cd0753eac94b23f --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_EXT_CTRLS.c @@ -0,0 +1,716 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 19 May 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +/* + * Note: V4L2_CID_LASTP1 != V4L2_CID_BASE_LASTP1 + */ + +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_EXT_CTRLS.h" + +void test_VIDIOC_G_EXT_CTRLS_zero() +{ + struct v4l2_ext_controls controls; + int ret_get, errno_get; + + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = 0; + controls.controls = NULL; + + ret_get = ioctl(get_video_fd(), VIDIOC_G_EXT_CTRLS, &controls); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_EXT_CTRLS, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + CU_ASSERT_EQUAL(controls.ctrl_class, V4L2_CTRL_CLASS_USER); + CU_ASSERT_EQUAL(controls.count, 0); + // The value of controls.error_idx is not defined when ret_get == 0 + CU_ASSERT_EQUAL(controls.reserved[0], 0); + CU_ASSERT_EQUAL(controls.reserved[1], 0); + CU_ASSERT_EQUAL(controls.controls, NULL); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } +} + +void test_VIDIOC_G_EXT_CTRLS_zero_invalid_count() +{ + struct v4l2_ext_controls controls; + int ret_get, errno_get; + int ret_get_invalid, errno_get_invalid; + __u32 count; + + count = 0; + memset(&controls, 0, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_get = ioctl(get_video_fd(), VIDIOC_G_EXT_CTRLS, &controls); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_EXT_CTRLS, count=0%x, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, count, ret_get, errno_get); + + count = 1; + /* Note: this loop also covers ((__u32)S32_MAX)+1 = 0x80000000 */ + do { + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_get_invalid = + ioctl(get_video_fd(), VIDIOC_G_EXT_CTRLS, &controls); + errno_get_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_EXT_CTRLS, count=0x%x, ret_get_invalid=%i, errno_get_invalid=%i\n", + __FILE__, __LINE__, count, ret_get_invalid, + errno_get_invalid); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + /* if the VIDIOC_G_EXT_CTRLS is supported by the driver + * it shall complain about the NULL pointer at + * cotrols.controls because this does not match the + * controls.count value + */ + CU_ASSERT_EQUAL(ret_get_invalid, -1); + CU_ASSERT(errno_get_invalid == EFAULT + || errno_get_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + CU_ASSERT_EQUAL(ret_get_invalid, -1); + CU_ASSERT_EQUAL(errno_get_invalid, EINVAL); + } + count <<= 1; + } while (count != 0); + + count = (__u32) S32_MAX; + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_get_invalid = ioctl(get_video_fd(), VIDIOC_G_EXT_CTRLS, &controls); + errno_get_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_EXT_CTRLS, count=0x%x, ret_get_invalid=%i, errno_get_invalid=%i\n", + __FILE__, __LINE__, count, ret_get_invalid, errno_get_invalid); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + CU_ASSERT_EQUAL(ret_get_invalid, -1); + CU_ASSERT(errno_get_invalid == EFAULT + || errno_get_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + CU_ASSERT_EQUAL(ret_get_invalid, -1); + CU_ASSERT_EQUAL(errno_get_invalid, EINVAL); + } + + count = U32_MAX; + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_get_invalid = ioctl(get_video_fd(), VIDIOC_G_EXT_CTRLS, &controls); + errno_get_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_EXT_CTRLS, count=0x%x, ret_get_invalid=%i, errno_get_invalid=%i\n", + __FILE__, __LINE__, count, ret_get_invalid, errno_get_invalid); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + CU_ASSERT_EQUAL(ret_get_invalid, -1); + CU_ASSERT(errno_get_invalid == EFAULT + || errno_get_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + CU_ASSERT_EQUAL(ret_get_invalid, -1); + CU_ASSERT_EQUAL(errno_get_invalid, EINVAL); + } + +} + +static int do_get_ext_control_one(__u32 ctrl_class, __u32 id) +{ + int ret_query, errno_query; + int ret_get, errno_get; + struct v4l2_queryctrl queryctrl; + struct v4l2_ext_controls controls; + struct v4l2_ext_control control; + + /* The expected return value of VIDIOC_G_EXT_CTRLS depens on the value + * reported by VIDIOC_QUERYCTRL + */ + + memset(&queryctrl, 0, sizeof(queryctrl)); + queryctrl.id = id; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_query, + errno_query); + if (ret_query == 0) { + dprintf("\t%s:%u: queryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " + ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", + __FILE__, __LINE__, + queryctrl.id, + queryctrl.type, + queryctrl.name, + queryctrl.minimum, + queryctrl.maximum, + queryctrl.step, + queryctrl.default_value, + queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + } + + memset(&control, 0xff, sizeof(control)); + control.id = id; + + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = ctrl_class; + controls.count = 1; + controls.controls = &control; + + ret_get = ioctl(get_video_fd(), VIDIOC_G_EXT_CTRLS, &controls); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_EXT_CTRLS, id=%u (V4L2_CID_BASE+%i), ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, ret_get, errno_get); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + + switch (queryctrl.type) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + CU_ASSERT(queryctrl.minimum <= control.value); + CU_ASSERT(control.value <= queryctrl.maximum); + } else { + /* This is the case when VIDIOC_G_CTRLS is not + * supported at all. + */ + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + break; + + case V4L2_CTRL_TYPE_BUTTON: + /* This control only performs an action, does not have + * any value + */ + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + break; + + case V4L2_CTRL_TYPE_INTEGER64: /* TODO: what about this case? */ + case V4L2_CTRL_TYPE_CTRL_CLASS: + default: + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + } + + return ret_query; +} + +void test_VIDIOC_G_EXT_CTRLS_one() +{ + int ret1; + __u32 i; + + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + ret1 = do_get_ext_control_one(V4L2_CTRL_CLASS_USER, i); + } + + ret1 = do_get_ext_control_one(V4L2_CTRL_CLASS_USER, V4L2_CID_BASE - 1); + ret1 = do_get_ext_control_one(V4L2_CTRL_CLASS_USER, V4L2_CID_LASTP1); + ret1 = + do_get_ext_control_one(V4L2_CTRL_CLASS_USER, + V4L2_CID_PRIVATE_BASE - 1); + + i = V4L2_CID_PRIVATE_BASE; + do { + ret1 = do_get_ext_control_one(V4L2_CTRL_CLASS_USER, i); + i++; + } while (ret1 == 0); + + ret1 = do_get_ext_control_one(V4L2_CTRL_CLASS_USER, i); +} + +void test_VIDIOC_G_EXT_CTRLS_NULL() +{ + struct v4l2_ext_controls controls; + int ret_get, errno_get; + int ret_null, errno_null; + + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = 0; + controls.controls = NULL; + + ret_get = ioctl(get_video_fd(), VIDIOC_G_EXT_CTRLS, &controls); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_EXT_CTRLS, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_EXT_CTRLS, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_EXT_CTRLS, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } +} + +void test_VIDIOC_S_EXT_CTRLS_zero() +{ + struct v4l2_ext_controls controls; + int ret_set, errno_set; + + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = 0; + controls.controls = NULL; + + ret_set = ioctl(get_video_fd(), VIDIOC_S_EXT_CTRLS, &controls); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_EXT_CTRLS, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + + CU_ASSERT_EQUAL(controls.ctrl_class, V4L2_CTRL_CLASS_USER); + CU_ASSERT_EQUAL(controls.count, 0); + // The value of controls.error_idx is not defined when ret_set == 0 + CU_ASSERT_EQUAL(controls.reserved[0], 0); + CU_ASSERT_EQUAL(controls.reserved[1], 0); + CU_ASSERT_EQUAL(controls.controls, NULL); + + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } +} + +void test_VIDIOC_S_EXT_CTRLS_zero_invalid_count() +{ + struct v4l2_ext_controls controls; + int ret_set, errno_set; + int ret_set_invalid, errno_set_invalid; + __u32 count; + + count = 0; + memset(&controls, 0, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_set = ioctl(get_video_fd(), VIDIOC_S_EXT_CTRLS, &controls); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_EXT_CTRLS, count=0%x, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, count, ret_set, errno_set); + + count = 1; + /* Note: this loop also covers ((__u32)S32_MAX)+1 = 0x80000000 */ + do { + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_set_invalid = + ioctl(get_video_fd(), VIDIOC_S_EXT_CTRLS, &controls); + errno_set_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_EXT_CTRLS, count=0x%x, ret_set_invalid=%i, errno_set_invalid=%i\n", + __FILE__, __LINE__, count, ret_set_invalid, + errno_set_invalid); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + + /* if the VIDIOC_S_EXT_CTRLS is supported by the driver + * it shall complain about the NULL pointer at + * cotrols.controls because this does not match the + * controls.count value + */ + CU_ASSERT_EQUAL(ret_set_invalid, -1); + CU_ASSERT(errno_set_invalid == EFAULT + || errno_set_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + CU_ASSERT_EQUAL(ret_set_invalid, -1); + CU_ASSERT_EQUAL(errno_set_invalid, EINVAL); + } + count <<= 1; + } while (count != 0); + + count = (__u32) S32_MAX; + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_set_invalid = ioctl(get_video_fd(), VIDIOC_S_EXT_CTRLS, &controls); + errno_set_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_EXT_CTRLS, count=0x%x, ret_set_invalid=%i, errno_set_invalid=%i\n", + __FILE__, __LINE__, count, ret_set_invalid, errno_set_invalid); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + + CU_ASSERT_EQUAL(ret_set_invalid, -1); + CU_ASSERT(errno_set_invalid == EFAULT + || errno_set_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + CU_ASSERT_EQUAL(ret_set_invalid, -1); + CU_ASSERT_EQUAL(errno_set_invalid, EINVAL); + } + + count = U32_MAX; + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_set_invalid = ioctl(get_video_fd(), VIDIOC_S_EXT_CTRLS, &controls); + errno_set_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_EXT_CTRLS, count=0x%x, ret_set_invalid=%i, errno_set_invalid=%i\n", + __FILE__, __LINE__, count, ret_set_invalid, errno_set_invalid); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + + CU_ASSERT_EQUAL(ret_set_invalid, -1); + CU_ASSERT(errno_set_invalid == EFAULT + || errno_set_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + CU_ASSERT_EQUAL(ret_set_invalid, -1); + CU_ASSERT_EQUAL(errno_set_invalid, EINVAL); + } + +} + +void test_VIDIOC_S_EXT_CTRLS_NULL() +{ + struct v4l2_ext_controls controls; + int ret_set, errno_set; + int ret_null, errno_null; + + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = 0; + controls.controls = NULL; + + ret_set = ioctl(get_video_fd(), VIDIOC_S_EXT_CTRLS, &controls); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_EXT_CTRLS, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + ret_null = ioctl(get_video_fd(), VIDIOC_S_EXT_CTRLS, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_S_EXT_CTRLS, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } +} + +void test_VIDIOC_TRY_EXT_CTRLS_zero() +{ + struct v4l2_ext_controls controls; + int ret_try, errno_try; + + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = 0; + controls.controls = NULL; + + ret_try = ioctl(get_video_fd(), VIDIOC_TRY_EXT_CTRLS, &controls); + errno_try = errno; + + dprintf("\t%s:%u: VIDIOC_TRY_EXT_CTRLS, ret_try=%i, errno_try=%i\n", + __FILE__, __LINE__, ret_try, errno_try); + + if (ret_try == 0) { + CU_ASSERT_EQUAL(ret_try, 0); + + CU_ASSERT_EQUAL(controls.ctrl_class, V4L2_CTRL_CLASS_USER); + CU_ASSERT_EQUAL(controls.count, 0); + // The value of controls.error_idx is not defined when ret_try == 0 + CU_ASSERT_EQUAL(controls.reserved[0], 0); + CU_ASSERT_EQUAL(controls.reserved[1], 0); + CU_ASSERT_EQUAL(controls.controls, NULL); + + } else { + CU_ASSERT_EQUAL(ret_try, -1); + CU_ASSERT_EQUAL(errno_try, EINVAL); + } +} + +void test_VIDIOC_TRY_EXT_CTRLS_zero_invalid_count() +{ + struct v4l2_ext_controls controls; + int ret_try, errno_try; + int ret_try_invalid, errno_try_invalid; + __u32 count; + + count = 0; + memset(&controls, 0, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_try = ioctl(get_video_fd(), VIDIOC_TRY_EXT_CTRLS, &controls); + errno_try = errno; + + dprintf + ("\t%s:%u: VIDIOC_TRY_EXT_CTRLS, count=0x%x, ret_try=%i, errno_try=%i\n", + __FILE__, __LINE__, count, ret_try, errno_try); + + count = 1; + /* Note: this loop also covers ((__u32)S32_MAX)+1 = 0x80000000 */ + do { + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_try_invalid = + ioctl(get_video_fd(), VIDIOC_TRY_EXT_CTRLS, &controls); + errno_try_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_TRY_EXT_CTRLS, count=0x%x, ret_try_invalid=%i, errno_try_invalid=%i\n", + __FILE__, __LINE__, count, ret_try_invalid, + errno_try_invalid); + + if (ret_try == 0) { + CU_ASSERT_EQUAL(ret_try, 0); + + /* if the VIDIOC_TRY_EXT_CTRLS is supported by the driver + * it shall complain about the NULL pointer at + * cotrols.controls because this does not match the + * controls.count value + */ + CU_ASSERT_EQUAL(ret_try_invalid, -1); + CU_ASSERT(errno_try_invalid == EFAULT + || errno_try_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_try, -1); + CU_ASSERT_EQUAL(errno_try, EINVAL); + + CU_ASSERT_EQUAL(ret_try_invalid, -1); + CU_ASSERT_EQUAL(errno_try_invalid, EINVAL); + } + count <<= 1; + } while (count != 0); + + count = (__u32) S32_MAX; + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_try_invalid = + ioctl(get_video_fd(), VIDIOC_TRY_EXT_CTRLS, &controls); + errno_try_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_TRY_EXT_CTRLS, count=0x%x, ret_try_invalid=%i, errno_try_invalid=%i\n", + __FILE__, __LINE__, count, ret_try_invalid, errno_try_invalid); + + if (ret_try == 0) { + CU_ASSERT_EQUAL(ret_try, 0); + + CU_ASSERT_EQUAL(ret_try_invalid, -1); + CU_ASSERT(errno_try_invalid == EFAULT + || errno_try_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_try, -1); + CU_ASSERT_EQUAL(errno_try, EINVAL); + + CU_ASSERT_EQUAL(ret_try_invalid, -1); + CU_ASSERT_EQUAL(errno_try_invalid, EINVAL); + } + + count = U32_MAX; + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = count; + controls.controls = NULL; + + ret_try_invalid = + ioctl(get_video_fd(), VIDIOC_TRY_EXT_CTRLS, &controls); + errno_try_invalid = errno; + + dprintf + ("\t%s:%u: VIDIOC_TRY_EXT_CTRLS, count=0x%x, ret_try_invalid=%i, errno_try_invalid=%i\n", + __FILE__, __LINE__, count, ret_try_invalid, errno_try_invalid); + + if (ret_try == 0) { + CU_ASSERT_EQUAL(ret_try, 0); + + CU_ASSERT_EQUAL(ret_try_invalid, -1); + CU_ASSERT(errno_try_invalid == EFAULT + || errno_try_invalid == ENOMEM); + + } else { + CU_ASSERT_EQUAL(ret_try, -1); + CU_ASSERT_EQUAL(errno_try, EINVAL); + + CU_ASSERT_EQUAL(ret_try_invalid, -1); + CU_ASSERT_EQUAL(errno_try_invalid, EINVAL); + } + +} + +void test_VIDIOC_TRY_EXT_CTRLS_NULL() +{ + struct v4l2_ext_controls controls; + int ret_try, errno_try; + int ret_null, errno_null; + + memset(&controls, 0xff, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_USER; + controls.count = 0; + controls.controls = NULL; + + ret_try = ioctl(get_video_fd(), VIDIOC_TRY_EXT_CTRLS, &controls); + errno_try = errno; + + dprintf("\t%s:%u: VIDIOC_TRY_EXT_CTRLS, ret_try=%i, errno_try=%i\n", + __FILE__, __LINE__, ret_try, errno_try); + + ret_null = ioctl(get_video_fd(), VIDIOC_TRY_EXT_CTRLS, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_TRY_EXT_CTRLS, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_try == 0) { + CU_ASSERT_EQUAL(ret_try, 0); + + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + + } else { + CU_ASSERT_EQUAL(ret_try, -1); + CU_ASSERT_EQUAL(errno_try, EINVAL); + + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_EXT_CTRLS.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_EXT_CTRLS.h new file mode 100644 index 0000000000000000000000000000000000000000..df95cd3e2da000b0fee85d66d6b2e212b6b99b1e --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_EXT_CTRLS.h @@ -0,0 +1,21 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 19 May 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_EXT_CTRLS_zero(void); +void test_VIDIOC_G_EXT_CTRLS_zero_invalid_count(void); +void test_VIDIOC_G_EXT_CTRLS_one(void); +void test_VIDIOC_G_EXT_CTRLS_NULL(void); + +void test_VIDIOC_S_EXT_CTRLS_zero(void); +void test_VIDIOC_S_EXT_CTRLS_zero_invalid_count(void); +void test_VIDIOC_S_EXT_CTRLS_NULL(void); + +void test_VIDIOC_TRY_EXT_CTRLS_zero(void); +void test_VIDIOC_TRY_EXT_CTRLS_zero_invalid_count(void); +void test_VIDIOC_TRY_EXT_CTRLS_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FMT.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FMT.c new file mode 100644 index 0000000000000000000000000000000000000000..3beff070e43c39d2b65f10a148a2b7a980c3bf43 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FMT.c @@ -0,0 +1,1590 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 19 Jul 2009 0.4 More V4L2_PIX_FMT_* formats added to valid_poxelformat() + * 18 Apr 2009 0.3 Type added to debug printouts + * 15 Apr 2009 0.2 Added test case for VIDIOC_S_FMT + * 4 Apr 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_FMT.h" + +int valid_pixelformat(__u32 pixelformat) +{ + int valid = 0; + + switch (pixelformat) { + case V4L2_PIX_FMT_RGB332: + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_Y16: + case V4L2_PIX_FMT_PAL8: + case V4L2_PIX_FMT_YVU410: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV411P: + case V4L2_PIX_FMT_Y41P: + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_YUV555: + case V4L2_PIX_FMT_YUV565: + case V4L2_PIX_FMT_YUV32: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YYUV: + case V4L2_PIX_FMT_HI240: + case V4L2_PIX_FMT_HM12: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_MJPEG: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_DV: + case V4L2_PIX_FMT_MPEG: + case V4L2_PIX_FMT_WNVA: + case V4L2_PIX_FMT_SN9C10X: + case V4L2_PIX_FMT_PWC1: + case V4L2_PIX_FMT_PWC2: + case V4L2_PIX_FMT_ET61X251: + + /* formats from Linux kernel 2.6.31-rc2 */ + +#ifdef V4L2_PIX_FMT_VYUY + case V4L2_PIX_FMT_VYUY: +#endif + +#ifdef V4L2_PIX_FMT_NV16 + case V4L2_PIX_FMT_NV16: +#endif + +#ifdef V4L2_PIX_FMT_NV61 + case V4L2_PIX_FMT_NV61: +#endif + +#ifdef V4L2_PIX_FMT_SGBRG8 + case V4L2_PIX_FMT_SGBRG8: +#endif + +#ifdef V4L2_PIX_FMT_SGRBG8 + case V4L2_PIX_FMT_SGRBG8: +#endif + +#ifdef V4L2_PIX_FMT_SGRBG10 + case V4L2_PIX_FMT_SGRBG10: +#endif + +#ifdef V4L2_PIX_FMT_SGRBG10DPCM8 + case V4L2_PIX_FMT_SGRBG10DPCM8: +#endif + +#ifdef V4L2_PIX_FMT_SPCA501 + case V4L2_PIX_FMT_SPCA501: +#endif + +#ifdef V4L2_PIX_FMT_SPCA505 + case V4L2_PIX_FMT_SPCA505: +#endif + +#ifdef V4L2_PIX_FMT_SPCA508 + case V4L2_PIX_FMT_SPCA508: +#endif + +#ifdef V4L2_PIX_FMT_SPCA561 + case V4L2_PIX_FMT_SPCA561: +#endif + +#ifdef V4L2_PIX_FMT_PAC207 + case V4L2_PIX_FMT_PAC207: +#endif + +#ifdef V4L2_PIX_FMT_MR97310A + case V4L2_PIX_FMT_MR97310A: +#endif + +#ifdef V4L2_PIX_FMT_SQ905C + case V4L2_PIX_FMT_SQ905C: +#endif + +#ifdef V4L2_PIX_FMT_PJPG + case V4L2_PIX_FMT_PJPG: +#endif + +#ifdef V4L2_PIX_FMT_YVYU + case V4L2_PIX_FMT_YVYU: +#endif + +#ifdef V4L2_PIX_FMT_OV511 + case V4L2_PIX_FMT_OV511: +#endif + +#ifdef V4L2_PIX_FMT_OV518 + case V4L2_PIX_FMT_OV518: +#endif + + valid = 1; + break; + default: + valid = 0; + } + + return valid; +} + +int valid_colorspace(enum v4l2_colorspace colorspace) +{ + int valid = 0; + + switch (colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_SMPTE240M: + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_BT878: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + case V4L2_COLORSPACE_JPEG: + case V4L2_COLORSPACE_SRGB: + valid = 1; + break; + default: + valid = 0; + } + + return valid; +} + +static void do_get_formats(enum v4l2_buf_type type) +{ + int ret_get, errno_get; + struct v4l2_format format; + struct v4l2_format format2; + unsigned int j; + + memset(&format, 0xff, sizeof(format)); + format.type = type; + + ret_get = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, type, ret_get, errno_get); + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(format.type, type); + + switch (format.type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + dprintf("\tformat = {.type=0x%X, .fmt.pix = { " + ".width=%u, " + ".height=%u, " + ".pixelformat=0x%X, " + ".field=%i, " + ".bytesperline=%i, " + ".sizeimage=%u, " + ".colorspace=%i, " + ".priv=0x%X " + " } }\n", + format.type, + format.fmt.pix.width, + format.fmt.pix.height, + format.fmt.pix.pixelformat, + format.fmt.pix.field, + format.fmt.pix.bytesperline, + format.fmt.pix.sizeimage, + format.fmt.pix.colorspace, format.fmt.pix.priv); + if (sizeof(format.fmt.pix) < + sizeof(format.fmt.raw_data)) { + dprintf1 + ("\tformat = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format.fmt.pix); + j < sizeof(format.fmt.raw_data); j++) { + dprintf(", 0x%x", + format.fmt.raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check different fields */ + //CU_ASSERT_EQUAL(format.fmt.pix.width, ???); + //CU_ASSERT_EQUAL(format.fmt.pix.height, ???); + //CU_ASSERT_EQUAL(format.fmt.pix.pixelformat, ???); + CU_ASSERT(valid_pixelformat + (format.fmt.pix.pixelformat)); + + //CU_ASSERT_EQUAL(format.fmt.pix.field, ???); + //CU_ASSERT_EQUAL(format.fmt.pix.bytesperline, ???); + //CU_ASSERT_EQUAL(format.fmt.pix.sizeimage, ???); + //CU_ASSERT_EQUAL(format.fmt.pix.colorspace, ???); + CU_ASSERT(valid_colorspace(format.fmt.pix.colorspace)); + //CU_ASSERT_EQUAL(format.fmt.pix.priv, ???); + + /* Check whether the remaining bytes of rawdata is set to zero */ + memset(&format2, 0, sizeof(format2)); + CU_ASSERT_EQUAL(memcmp + (format.fmt.raw_data + + sizeof(format.fmt.pix), + format2.fmt.raw_data + + sizeof(format2.fmt.pix), + sizeof(format.fmt.raw_data) - + sizeof(format.fmt.pix)), 0); + break; + + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + dprintf("\tformat = {.type=0x%X, .fmt.win={ " + ".w = { .left=%i, .top=%i, .width=%i, .height=%i, }, " + ".field = %i, " + ".chromakey = 0x%X, " + ".clips = %p, " + ".clipcount = %u, " + ".bitmap = %p, " + ".global_alpha = %u " + "} }\n", + format.type, + format.fmt.win.w.left, + format.fmt.win.w.top, + format.fmt.win.w.width, + format.fmt.win.w.height, + format.fmt.win.field, + format.fmt.win.chromakey, + format.fmt.win.clips, + format.fmt.win.clipcount, + format.fmt.win.bitmap, + format.fmt.win.global_alpha); + if (sizeof(format.fmt.win) < + sizeof(format.fmt.raw_data)) { + dprintf1 + ("\tformat = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format.fmt.win); + j < sizeof(format.fmt.raw_data); j++) { + dprintf(", 0x%x", + format.fmt.raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check different fields */ + //CU_ASSERT_EQUAL(format.fmt.win.w.left, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.top, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.width, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.height, ???); + //CU_ASSERT_EQUAL(format.fmt.win.field, ???); + //CU_ASSERT_EQUAL(format.fmt.win.chromakey, ???); + //CU_ASSERT_EQUAL(format.fmt.win.clips, ???); + //CU_ASSERT_EQUAL(format.fmt.win.clipcount, ???); + //CU_ASSERT_EQUAL(format.fmt.win.bitmap, ???); + //CU_ASSERT_EQUAL(format.fmt.win.global_alpha ???); + + /* Check whether the remaining bytes of raw_data is set to zero */ + memset(&format2, 0, sizeof(format2)); + CU_ASSERT_EQUAL(memcmp + (format.fmt.raw_data + + sizeof(format.fmt.win), + format2.fmt.raw_data + + sizeof(format2.fmt.win), + sizeof(format.fmt.raw_data) - + sizeof(format.fmt.win)), 0); + break; + + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + dprintf("\tformat = {.type=0x%X, .fmt.vbi={ " + ".sampling_rate=%u, " + ".offset=%u, " + ".samples_per_line=%u " + ".sample_format=0x%X " + ".start = { %u, %u }, " + ".count = { %u, %u }, " + ".flags = 0x%X, " + ".reserved = { 0x%X, 0x%X } " + "} }\n", + format.type, + format.fmt.vbi.sampling_rate, + format.fmt.vbi.offset, + format.fmt.vbi.samples_per_line, + format.fmt.vbi.sample_format, + format.fmt.vbi.start[0], + format.fmt.vbi.start[1], + format.fmt.vbi.count[0], + format.fmt.vbi.count[1], + format.fmt.vbi.flags, + format.fmt.vbi.reserved[0], + format.fmt.vbi.reserved[1] + ); + if (sizeof(format.fmt.vbi) < + sizeof(format.fmt.raw_data)) { + dprintf1 + ("\tformat = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format.fmt.vbi); + j < sizeof(format.fmt.raw_data); j++) { + dprintf(", 0x%x", + format.fmt.raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check different fields */ + //CU_ASSERT_EQUAL(format.fmt.vbi.sampling_rate, ???); + //CU_ASSERT_EQUAL(format.fmt.vbi.offset, ???); + //CU_ASSERT_EQUAL(format.fmt.vbi.samples_per_line, ???); + //CU_ASSERT_EQUAL(format.fmt.vbi.sample_format, ???); + //CU_ASSERT_EQUAL(format.fmt.vbi.start[0], ???); + //CU_ASSERT_EQUAL(format.fmt.vbi.start[1], ???); + //CU_ASSERT_EQUAL(format.fmt.vbi.count[0], ???); + //CU_ASSERT_EQUAL(format.fmt.vbi.count[1], ???); + //CU_ASSERT_EQUAL(format.fmt.vbi.flags, ???); + CU_ASSERT_EQUAL(format.fmt.vbi.reserved[0], 0); + CU_ASSERT_EQUAL(format.fmt.vbi.reserved[1], 0); + + /* Check whether the remaining bytes of raw_data is set to zero */ + memset(&format2, 0, sizeof(format2)); + CU_ASSERT_EQUAL(memcmp + (format.fmt.raw_data + + sizeof(format.fmt.vbi), + format2.fmt.raw_data + + sizeof(format2.fmt.vbi), + sizeof(format.fmt.raw_data) - + sizeof(format.fmt.vbi)), 0); + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + dprintf("\tformat = {.type=0x%X, " + ".fmt.sliced = { .service_set = 0x%X, " + ".service_lines = { ... }, " + ".io_size = %u, " + ".reserved[0] = 0x%X, " + ".reserved[1] = 0x%X " + "} }\n", + format.type, format.fmt.sliced.service_set, + //format.fmt.sliced.service_lines[][], + format.fmt.sliced.io_size, + format.fmt.sliced.reserved[0], + format.fmt.sliced.reserved[1] + ); + if (sizeof(format.fmt.sliced) < + sizeof(format.fmt.raw_data)) { + dprintf1 + ("\tformat = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format.fmt.sliced); + j < sizeof(format.fmt.raw_data); j++) { + dprintf(", 0x%x", + format.fmt.raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check different fields */ + //CU_ASSERT_EQUAL(format.fmt.sliced.service_set, ???); + CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][0], + 0); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][1], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][2], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][3], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][4], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][5], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][6], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][7], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][8], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][9], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][10], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][11], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][12], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][13], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][14], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][15], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][16], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][17], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][18], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][19], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][20], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][21], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][22], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[0][23], ???); + CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][0], + 0); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][1], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][2], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][3], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][4], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][5], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][6], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][7], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][8], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][9], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][10], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][11], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][12], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][13], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][14], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][15], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][16], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][17], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][18], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][19], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][20], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][21], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][22], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.service_lines[1][23], ???); + //CU_ASSERT_EQUAL(format.fmt.sliced.io_size, ???); + CU_ASSERT_EQUAL(format.fmt.sliced.reserved[0], 0); + CU_ASSERT_EQUAL(format.fmt.sliced.reserved[1], 0); + + /* Check whether the remaining bytes of raw_data is set to zero */ + memset(&format2, 0, sizeof(format2)); + CU_ASSERT_EQUAL(memcmp + (format.fmt.raw_data + + sizeof(format.fmt.sliced), + format2.fmt.raw_data + + sizeof(format2.fmt.sliced), + sizeof(format.fmt.raw_data) - + sizeof(format.fmt.sliced)), 0); + break; + + case V4L2_BUF_TYPE_PRIVATE: + dprintf("\tformat = {.type=0x%X, ... }\n", format.type); + /* TODO: check different fields */ + } + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + memset(&format2, 0xff, sizeof(format2)); + format2.type = type; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); + + } + +} + +void test_VIDIOC_G_FMT() +{ + do_get_formats(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_get_formats(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_get_formats(V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_get_formats(V4L2_BUF_TYPE_VBI_CAPTURE); + do_get_formats(V4L2_BUF_TYPE_VBI_OUTPUT); + do_get_formats(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_get_formats(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); + do_get_formats(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_get_formats(V4L2_BUF_TYPE_PRIVATE); +} + +static void do_get_format_invalid(enum v4l2_buf_type type) +{ + int ret_get, errno_get; + struct v4l2_format format; + struct v4l2_format format2; + + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_get = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, type, ret_get, errno_get); + + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + /* Check whether the original format struct is untouched */ + memset(&format2, 0xff, sizeof(format2)); + format2.type = type; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); +} + +void test_VIDIOC_G_FMT_invalid_type() +{ + int i; + + /* In this test case the .index is valid (0) and only the .type + * is invalid. The .type filed is an enum which is stored in an 'int'. + */ + + /* test invalid .type=0 */ + do_get_format_invalid(0); + + /* test invalid .type=SINT_MIN */ + do_get_format_invalid(SINT_MIN); + + /* test invalid .type=-1 */ + do_get_format_invalid(-1); + + /* test invalid .type= 8..0x7F */ + for (i = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY + 1; + i < V4L2_BUF_TYPE_PRIVATE; i++) { + do_get_format_invalid(i); + } + + /* .type = 0x80..0x7FFF FFFF is the private range */ + + /* Assume that 0x7FFF FFFF is invalid in the private range. + * This might be a wrong assumption, but let's have a test case like + * this for now. + */ + do_get_format_invalid(SINT_MAX); + +} + +void test_VIDIOC_G_FMT_NULL() +{ + int ret_capture, errno_capture; + int ret_output, errno_output; + int ret_video_overlay, errno_video_overlay; + int ret_vbi_capture, errno_vbi_capture; + int ret_vbi_output, errno_vbi_output; + int ret_sliced_vbi_capture, errno_sliced_vbi_capture; + int ret_sliced_vbi_output, errno_sliced_vbi_output; + int ret_video_output_overlay, errno_video_output_overlay; + int ret_private, errno_private; + int ret_null, errno_null; + struct v4l2_format format; + enum v4l2_buf_type type; + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_capture = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_capture = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_capture=%i, errno_capture=%i\n", + __FILE__, __LINE__, type, ret_capture, errno_capture); + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_output = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_output = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_output=%i, errno_output=%i\n", + __FILE__, __LINE__, type, ret_output, errno_output); + + type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_video_overlay = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_video_overlay = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_video_overlay=%i, errno_video_overlay=%i\n", + __FILE__, __LINE__, type, ret_video_overlay, errno_video_overlay); + + type = V4L2_BUF_TYPE_VBI_CAPTURE; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_vbi_capture = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_vbi_capture = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_vbi_capture=%i, errno_vbi_capture=%i\n", + __FILE__, __LINE__, type, ret_vbi_capture, errno_vbi_capture); + + type = V4L2_BUF_TYPE_VBI_OUTPUT; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_vbi_output = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_vbi_output = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_vbi_output=%i, errno_vbi_output=%i\n", + __FILE__, __LINE__, type, ret_vbi_output, errno_vbi_output); + + type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_sliced_vbi_capture = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_sliced_vbi_capture = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_sliced_vbi_capture=%i, errno_sliced_vbi_capture=%i\n", + __FILE__, __LINE__, type, ret_sliced_vbi_capture, + errno_sliced_vbi_capture); + + type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_sliced_vbi_output = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_sliced_vbi_output = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_sliced_vbi_output=%i, errno_sliced_vbi_output=%i\n", + __FILE__, __LINE__, type, ret_sliced_vbi_output, + errno_sliced_vbi_output); + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_video_output_overlay = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_video_output_overlay = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_video_output_overlay=%i, errno_video_output_overlay=%i\n", + __FILE__, __LINE__, type, ret_video_output_overlay, + errno_video_output_overlay); + + type = V4L2_BUF_TYPE_PRIVATE; + memset(&format, 0xff, sizeof(format)); + format.type = type; + ret_private = ioctl(get_video_fd(), VIDIOC_G_FMT, &format); + errno_private = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_private=%i, errno_private=%i\n", + __FILE__, __LINE__, type, ret_private, errno_private); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_FMT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_FMT, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_capture == 0 || ret_output == 0 || + ret_video_overlay == 0 || ret_vbi_capture == 0 || + ret_vbi_output == 0 || ret_sliced_vbi_capture == 0 || + ret_sliced_vbi_output == 0 || ret_video_output_overlay == 0 || + ret_private == 0) { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_capture, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + CU_ASSERT_EQUAL(ret_output, -1); + CU_ASSERT_EQUAL(errno_output, EINVAL); + CU_ASSERT_EQUAL(ret_video_overlay, -1); + CU_ASSERT_EQUAL(errno_video_overlay, EINVAL); + CU_ASSERT_EQUAL(ret_vbi_capture, -1); + CU_ASSERT_EQUAL(errno_vbi_capture, EINVAL); + CU_ASSERT_EQUAL(ret_vbi_output, -1); + CU_ASSERT_EQUAL(errno_vbi_output, EINVAL); + CU_ASSERT_EQUAL(ret_sliced_vbi_capture, -1); + CU_ASSERT_EQUAL(errno_sliced_vbi_capture, EINVAL); + CU_ASSERT_EQUAL(ret_sliced_vbi_output, -1); + CU_ASSERT_EQUAL(errno_sliced_vbi_output, EINVAL); + CU_ASSERT_EQUAL(ret_video_output_overlay, -1); + CU_ASSERT_EQUAL(errno_video_output_overlay, EINVAL); + CU_ASSERT_EQUAL(ret_private, -1); + CU_ASSERT_EQUAL(errno_private, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +static void do_set_formats_enum(enum v4l2_buf_type type) +{ + int ret_get, errno_get; + int ret_enum, errno_enum; + int ret_max, errno_max; + int ret_min, errno_min; + int ret_set, errno_set; + struct v4l2_format format_orig; + struct v4l2_format format_min; + struct v4l2_format format_max; + struct v4l2_format format_set; + struct v4l2_format format2; + struct v4l2_fmtdesc fmtdesc; + __u32 i; + unsigned int j; + + memset(&format_orig, 0xff, sizeof(format_orig)); + format_orig.type = type; + + ret_get = ioctl(get_video_fd(), VIDIOC_G_FMT, &format_orig); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FMT, type=%i, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, type, ret_get, errno_get); + + i = 0; + do { + memset(&fmtdesc, 0, sizeof(fmtdesc)); + fmtdesc.index = i; + fmtdesc.type = type; + + ret_enum = ioctl(get_video_fd(), VIDIOC_ENUM_FMT, &fmtdesc); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUM_FMT, index=%u, type=%i, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, i, type, ret_enum, errno_enum); + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + memset(&format_max, 0xff, sizeof(format_max)); + format_max.type = type; + format_max.fmt.pix.pixelformat = fmtdesc.pixelformat; + format_max.fmt.pix.field = V4L2_FIELD_ANY; + + ret_max = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_max); + errno_max = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_max=%i, errno_max=%i\n", + __FILE__, __LINE__, type, ret_max, errno_max); + + if (ret_max == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + + dprintf + ("\tformat_max = {.type=0x%X, .fmt.pix = { " + ".width=%u, " ".height=%u, " + ".pixelformat=0x%X, " ".field=%i, " + ".bytesperline=%i, " ".sizeimage=%u, " + ".colorspace=%i, " ".priv=0x%X " "} }\n", + format_max.type, format_max.fmt.pix.width, + format_max.fmt.pix.height, + format_max.fmt.pix.pixelformat, + format_max.fmt.pix.field, + format_max.fmt.pix.bytesperline, + format_max.fmt.pix.sizeimage, + format_max.fmt.pix.colorspace, + format_max.fmt.pix.priv); + if (sizeof(format_max.fmt.pix) < + sizeof(format_max.fmt.raw_data)) { + dprintf1 + ("\tformat_max = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format_max.fmt.pix); + j < + sizeof(format_max.fmt.raw_data); + j++) { + dprintf(", 0x%x", + format_max.fmt. + raw_data[j]); + } + dprintf1(" }}\n"); + } + + CU_ASSERT_EQUAL(ret_max, 0); + CU_ASSERT(valid_pixelformat + (format_max.fmt.pix.pixelformat)); + CU_ASSERT_EQUAL(format_max.fmt.pix.pixelformat, + fmtdesc.pixelformat); + CU_ASSERT(0 < format_max.fmt.pix.width); + CU_ASSERT(0 < format_max.fmt.pix.height); + CU_ASSERT_NOT_EQUAL(format_max.fmt.pix.field, + V4L2_FIELD_ANY); + CU_ASSERT(0 < format_max.fmt.pix.bytesperline); + CU_ASSERT(0 < format_max.fmt.pix.sizeimage); + CU_ASSERT(valid_colorspace + (format_max.fmt.pix.colorspace)); + //CU_ASSERT_EQUAL(format_max.fmt.pix.priv, ???); + + /* Check whether the remaining bytes of rawdata is set to zero */ + memset(&format2, 0, sizeof(format2)); + CU_ASSERT_EQUAL(memcmp + (format_max.fmt.raw_data + + sizeof(format_max.fmt.pix), + format2.fmt.raw_data + + sizeof(format2.fmt.pix), + sizeof(format_max.fmt. + raw_data) - + sizeof(format_max.fmt.pix)), + 0); + + } else { + CU_ASSERT_EQUAL(ret_max, -1); + CU_ASSERT_EQUAL(errno_max, EINVAL); + } + + memset(&format_min, 0, sizeof(format_min)); + format_min.type = type; + format_min.fmt.pix.pixelformat = fmtdesc.pixelformat; + format_min.fmt.pix.field = V4L2_FIELD_ANY; + + ret_min = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_min); + errno_min = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_min=%i, errno_min=%i\n", + __FILE__, __LINE__, type, ret_min, errno_min); + + if (ret_min == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + + dprintf + ("\tformat_min = {.type=0x%X, .fmt.pix = { " + ".width=%u, " ".height=%u, " + ".pixelformat=0x%X, " ".field=%i, " + ".bytesperline=%i, " ".sizeimage=%u, " + ".colorspace=%i, " ".priv=0x%X " "} }\n", + format_min.type, format_min.fmt.pix.width, + format_min.fmt.pix.height, + format_min.fmt.pix.pixelformat, + format_min.fmt.pix.field, + format_min.fmt.pix.bytesperline, + format_min.fmt.pix.sizeimage, + format_min.fmt.pix.colorspace, + format_min.fmt.pix.priv); + if (sizeof(format_min.fmt.pix) < + sizeof(format_min.fmt.raw_data)) { + dprintf1 + ("\tformat_min = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format_min.fmt.pix); + j < + sizeof(format_min.fmt.raw_data); + j++) { + dprintf(", 0x%x", + format_min.fmt. + raw_data[j]); + } + dprintf1(" }}\n"); + } + + CU_ASSERT_EQUAL(ret_min, 0); + CU_ASSERT(valid_pixelformat + (format_min.fmt.pix.pixelformat)); + CU_ASSERT_EQUAL(format_min.fmt.pix.pixelformat, + fmtdesc.pixelformat); + CU_ASSERT(0 < format_min.fmt.pix.width); + CU_ASSERT(0 < format_min.fmt.pix.height); + CU_ASSERT_NOT_EQUAL(format_min.fmt.pix.field, + V4L2_FIELD_ANY); + CU_ASSERT(0 < format_min.fmt.pix.bytesperline); + CU_ASSERT(0 < format_min.fmt.pix.sizeimage); + CU_ASSERT(valid_colorspace + (format_min.fmt.pix.colorspace)); + //CU_ASSERT_EQUAL(format_min.fmt.pix.priv, ???); + + /* Check whether the remaining bytes of rawdata is set to zero */ + memset(&format2, 0, sizeof(format2)); + CU_ASSERT_EQUAL(memcmp + (format_min.fmt.raw_data + + sizeof(format_min.fmt.pix), + format2.fmt.raw_data + + sizeof(format2.fmt.pix), + sizeof(format_min.fmt. + raw_data) - + sizeof(format_min.fmt.pix)), + 0); + } else { + CU_ASSERT_EQUAL(ret_min, -1); + CU_ASSERT_EQUAL(errno_min, EINVAL); + } + + if (ret_max == 0 && ret_min == 0) { + CU_ASSERT(format_min.fmt.pix.width <= + format_max.fmt.pix.width); + CU_ASSERT(format_min.fmt.pix.height <= + format_max.fmt.pix.height); + CU_ASSERT_EQUAL(format_min.fmt.pix.colorspace, + format_max.fmt.pix.colorspace); + + /* If priv equals zero then this field is not used and shall + * be set to zero each case. Otherwise it can have any driver + * specific value which cannot be checked here. + */ + if (format_min.fmt.pix.priv == 0) { + CU_ASSERT_EQUAL(format_min.fmt.pix.priv, + 0); + CU_ASSERT_EQUAL(format_max.fmt.pix.priv, + 0); + } + } + + if (ret_max == -1 && ret_min == -1) { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + } + + break; + + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + memset(&format_max, 0xff, sizeof(format_max)); + format_max.type = type; + + ret_max = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_max); + errno_max = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_max=%i, errno_max=%i\n", + __FILE__, __LINE__, type, ret_max, errno_max); + + if (ret_max == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + + dprintf + ("\tformat_max = {.type=0x%X, .fmt.win={ " + ".w = { .left=%i, .top=%i, .width=%i, .height=%i, }, " + ".field = %i, " ".chromakey = 0x%X, " + ".clips = %p, " ".clipcount = %u, " + ".bitmap = %p, " ".global_alpha = %u " + "} }\n", format_max.type, + format_max.fmt.win.w.left, + format_max.fmt.win.w.top, + format_max.fmt.win.w.width, + format_max.fmt.win.w.height, + format_max.fmt.win.field, + format_max.fmt.win.chromakey, + format_max.fmt.win.clips, + format_max.fmt.win.clipcount, + format_max.fmt.win.bitmap, + format_max.fmt.win.global_alpha); + if (sizeof(format_max.fmt.win) < + sizeof(format_max.fmt.raw_data)) { + dprintf1 + ("\tformat_max = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format_max.fmt.win); + j < + sizeof(format_max.fmt.raw_data); + j++) { + dprintf(", 0x%x", + format_max.fmt. + raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check the different fields */ + //CU_ASSERT_EQUAL(format.fmt.win.w.left, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.top, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.width, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.height, ???); + //CU_ASSERT_EQUAL(format.fmt.win.field, ???); + //CU_ASSERT_EQUAL(format.fmt.win.chromakey, ???); + //CU_ASSERT_EQUAL(format.fmt.win.clips, ???); + //CU_ASSERT_EQUAL(format.fmt.win.clipcount, ???); + //CU_ASSERT_EQUAL(format.fmt.win.bitmap, ???); + //CU_ASSERT_EQUAL(format.fmt.win.global_alpha ???); + } else { + CU_ASSERT_EQUAL(ret_max, -1); + CU_ASSERT_EQUAL(errno_max, EINVAL); + } + + memset(&format_min, 0, sizeof(format_min)); + format_min.type = type; + format_min.fmt.pix.pixelformat = fmtdesc.pixelformat; + + ret_min = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_min); + errno_min = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_min=%i, errno_min=%i\n", + __FILE__, __LINE__, type, ret_min, errno_min); + + if (ret_min == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + dprintf + ("\tformat_min = {.type=0x%X, .fmt.win={ " + ".w = { .left=%i, .top=%i, .width=%i, .height=%i, }, " + ".field = %i, " ".chromakey = 0x%X, " + ".clips = %p, " ".clipcount = %u, " + ".bitmap = %p, " ".global_alpha = %u " + "} }\n", format_min.type, + format_min.fmt.win.w.left, + format_min.fmt.win.w.top, + format_min.fmt.win.w.width, + format_min.fmt.win.w.height, + format_min.fmt.win.field, + format_min.fmt.win.chromakey, + format_min.fmt.win.clips, + format_min.fmt.win.clipcount, + format_min.fmt.win.bitmap, + format_min.fmt.win.global_alpha); + if (sizeof(format_min.fmt.win) < + sizeof(format_min.fmt.raw_data)) { + dprintf1 + ("\tformat_min = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format_min.fmt.win); + j < + sizeof(format_min.fmt.raw_data); + j++) { + dprintf(", 0x%x", + format_min.fmt. + raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check the different fields */ + //CU_ASSERT_EQUAL(format.fmt.win.w.left, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.top, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.width, ???); + //CU_ASSERT_EQUAL(format.fmt.win.w.height, ???); + //CU_ASSERT_EQUAL(format.fmt.win.field, ???); + //CU_ASSERT_EQUAL(format.fmt.win.chromakey, ???); + //CU_ASSERT_EQUAL(format.fmt.win.clips, ???); + //CU_ASSERT_EQUAL(format.fmt.win.clipcount, ???); + //CU_ASSERT_EQUAL(format.fmt.win.bitmap, ???); + //CU_ASSERT_EQUAL(format.fmt.win.global_alpha ???); + + } else { + CU_ASSERT_EQUAL(ret_min, -1); + CU_ASSERT_EQUAL(errno_min, EINVAL); + } + + if (ret_max == -1 && ret_min == -1) { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + } + break; + + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + memset(&format_max, 0xff, sizeof(format_max)); + format_max.type = type; + + ret_max = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_max); + errno_max = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_max=%i, errno_max=%i\n", + __FILE__, __LINE__, type, ret_max, errno_max); + + if (ret_max == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + dprintf + ("\tformat_max = {.type=0x%X, .fmt.vbi={ " + ".sampling_rate=%u, " ".offset=%u, " + ".samples_per_line=%u " + ".sample_format=0x%X " + ".start = { %u, %u }, " + ".count = { %u, %u }, " ".flags = 0x%X, " + ".reserved = { 0x%X, 0x%X } " "} }\n", + format_max.type, + format_max.fmt.vbi.sampling_rate, + format_max.fmt.vbi.offset, + format_max.fmt.vbi.samples_per_line, + format_max.fmt.vbi.sample_format, + format_max.fmt.vbi.start[0], + format_max.fmt.vbi.start[1], + format_max.fmt.vbi.count[0], + format_max.fmt.vbi.count[1], + format_max.fmt.vbi.flags, + format_max.fmt.vbi.reserved[0], + format_max.fmt.vbi.reserved[1] + ); + if (sizeof(format_max.fmt.vbi) < + sizeof(format_max.fmt.raw_data)) { + dprintf1 + ("\tformat_max = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format_max.fmt.vbi); + j < + sizeof(format_max.fmt.raw_data); + j++) { + dprintf(", 0x%x", + format_max.fmt. + raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check the different fields */ + //CU_ASSERT_EQUAL(format_max.fmt.vbi.sampling_rate, ???); + //CU_ASSERT_EQUAL(format_max.fmt.vbi.offset, ???); + //CU_ASSERT_EQUAL(format_max.fmt.vbi.samples_per_line, ???); + //CU_ASSERT_EQUAL(format_max.fmt.vbi.sample_format, ???); + //CU_ASSERT_EQUAL(format_max.fmt.vbi.start[0], ???); + //CU_ASSERT_EQUAL(format_max.fmt.vbi.start[1], ???); + //CU_ASSERT_EQUAL(format_max.fmt.vbi.count[0], ???); + //CU_ASSERT_EQUAL(format_max.fmt.vbi.count[1], ???); + //CU_ASSERT_EQUAL(format_max.fmt.vbi.flags, ???); + CU_ASSERT_EQUAL(format_max.fmt.vbi.reserved[0], + 0); + CU_ASSERT_EQUAL(format_max.fmt.vbi.reserved[1], + 0); + + } else { + CU_ASSERT_EQUAL(ret_max, -1); + CU_ASSERT_EQUAL(errno_max, EINVAL); + } + + memset(&format_min, 0, sizeof(format_min)); + format_min.type = type; + format_min.fmt.pix.pixelformat = fmtdesc.pixelformat; + + ret_min = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_min); + errno_min = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_min=%i, errno_min=%i\n", + __FILE__, __LINE__, type, ret_min, errno_min); + + if (ret_min == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + dprintf + ("\tformat_min = {.type=0x%X, .fmt.vbi={ " + ".sampling_rate=%u, " ".offset=%u, " + ".samples_per_line=%u " + ".sample_format=0x%X " + ".start = { %u, %u }, " + ".count = { %u, %u }, " ".flags = 0x%X, " + ".reserved = { 0x%X, 0x%X } " "} }\n", + format_min.type, + format_min.fmt.vbi.sampling_rate, + format_min.fmt.vbi.offset, + format_min.fmt.vbi.samples_per_line, + format_min.fmt.vbi.sample_format, + format_min.fmt.vbi.start[0], + format_min.fmt.vbi.start[1], + format_min.fmt.vbi.count[0], + format_min.fmt.vbi.count[1], + format_min.fmt.vbi.flags, + format_min.fmt.vbi.reserved[0], + format_min.fmt.vbi.reserved[1] + ); + if (sizeof(format_min.fmt.vbi) < + sizeof(format_min.fmt.raw_data)) { + dprintf1 + ("\tformat_min = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format_min.fmt.vbi); + j < + sizeof(format_min.fmt.raw_data); + j++) { + dprintf(", 0x%x", + format_min.fmt. + raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check the different fields */ + //CU_ASSERT_EQUAL(format_min.fmt.vbi.sampling_rate, ???); + //CU_ASSERT_EQUAL(format_min.fmt.vbi.offset, ???); + //CU_ASSERT_EQUAL(format_min.fmt.vbi.samples_per_line, ???); + //CU_ASSERT_EQUAL(format_min.fmt.vbi.sample_format, ???); + //CU_ASSERT_EQUAL(format_min.fmt.vbi.start[0], ???); + //CU_ASSERT_EQUAL(format_min.fmt.vbi.start[1], ???); + //CU_ASSERT_EQUAL(format_min.fmt.vbi.count[0], ???); + //CU_ASSERT_EQUAL(format_min.fmt.vbi.count[1], ???); + //CU_ASSERT_EQUAL(format_min.fmt.vbi.flags, ???); + CU_ASSERT_EQUAL(format_min.fmt.vbi.reserved[0], + 0); + CU_ASSERT_EQUAL(format_min.fmt.vbi.reserved[1], + 0); + } else { + CU_ASSERT_EQUAL(ret_min, -1); + CU_ASSERT_EQUAL(errno_min, EINVAL); + } + + if (ret_max == -1 && ret_min == -1) { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + } + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + memset(&format_max, 0xff, sizeof(format_max)); + format_max.type = type; + + ret_max = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_max); + errno_max = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_max=%i, errno_max=%i\n", + __FILE__, __LINE__, type, ret_max, errno_max); + + if (ret_max == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + dprintf("\tformat_max = {.type=0x%X, " + ".fmt.sliced = { .service_set = 0x%X, " + ".service_lines = { ... }, " + ".io_size = %u, " + ".reserved[0] = 0x%X, " + ".reserved[1] = 0x%X " + "} }\n", + format_max.type, + format_max.fmt.sliced.service_set, + //format_max.fmt.sliced.service_lines[][], + format_max.fmt.sliced.io_size, + format_max.fmt.sliced.reserved[0], + format_max.fmt.sliced.reserved[1] + ); + if (sizeof(format_max.fmt.sliced) < + sizeof(format_max.fmt.raw_data)) { + dprintf1 + ("\tformat_max = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format_max.fmt.sliced); + j < + sizeof(format_max.fmt.raw_data); + j++) { + dprintf(", 0x%x", + format_max.fmt. + raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check the different fields */ + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_set, ???); + CU_ASSERT_EQUAL(format_max.fmt.sliced. + service_lines[0][0], 0); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][1], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][2], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][3], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][4], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][5], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][6], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][7], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][8], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][9], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][10], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][11], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][12], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][13], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][14], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][15], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][16], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][17], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][18], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][19], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][20], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][21], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][22], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[0][23], ???); + CU_ASSERT_EQUAL(format_max.fmt.sliced. + service_lines[1][0], 0); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][1], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][2], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][3], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][4], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][5], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][6], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][7], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][8], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][9], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][10], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][11], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][12], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][13], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][14], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][15], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][16], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][17], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][18], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][19], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][20], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][21], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][22], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.service_lines[1][23], ???); + //CU_ASSERT_EQUAL(format_max.fmt.sliced.io_size, ???); + CU_ASSERT_EQUAL(format_max.fmt.sliced. + reserved[0], 0); + CU_ASSERT_EQUAL(format_max.fmt.sliced. + reserved[1], 0); + + } else { + CU_ASSERT_EQUAL(ret_max, -1); + CU_ASSERT_EQUAL(errno_max, EINVAL); + } + + memset(&format_min, 0, sizeof(format_min)); + format_min.type = type; + format_min.fmt.pix.pixelformat = fmtdesc.pixelformat; + + ret_min = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_min); + errno_min = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_min=%i, errno_min=%i\n", + __FILE__, __LINE__, type, ret_min, errno_min); + + if (ret_min == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + dprintf("\tformat_min = {.type=0x%X, " + ".fmt.sliced = { .service_set = 0x%X, " + ".service_lines = { ... }, " + ".io_size = %u, " + ".reserved[0] = 0x%X, " + ".reserved[1] = 0x%X " + "} }\n", + format_min.type, + format_min.fmt.sliced.service_set, + //format_min.fmt.sliced.service_lines[][], + format_min.fmt.sliced.io_size, + format_min.fmt.sliced.reserved[0], + format_min.fmt.sliced.reserved[1] + ); + if (sizeof(format_min.fmt.sliced) < + sizeof(format_min.fmt.raw_data)) { + dprintf1 + ("\tformat_min = { ..., .fmt.raw_data[] = { ..."); + for (j = sizeof(format_min.fmt.sliced); + j < + sizeof(format_min.fmt.raw_data); + j++) { + dprintf(", 0x%x", + format_min.fmt. + raw_data[j]); + } + dprintf1(" }}\n"); + } + + /* TODO: check the different fields */ + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_set, ???); + CU_ASSERT_EQUAL(format_min.fmt.sliced. + service_lines[0][0], 0); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][1], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][2], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][3], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][4], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][5], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][6], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][7], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][8], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][9], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][10], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][11], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][12], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][13], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][14], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][15], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][16], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][17], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][18], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][19], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][20], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][21], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][22], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[0][23], ???); + CU_ASSERT_EQUAL(format_min.fmt.sliced. + service_lines[1][0], 0); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][1], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][2], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][3], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][4], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][5], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][6], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][7], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][8], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][9], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][10], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][11], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][12], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][13], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][14], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][15], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][16], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][17], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][18], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][19], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][20], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][21], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][22], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.service_lines[1][23], ???); + //CU_ASSERT_EQUAL(format_min.fmt.sliced.io_size, ???); + CU_ASSERT_EQUAL(format_min.fmt.sliced. + reserved[0], 0); + CU_ASSERT_EQUAL(format_min.fmt.sliced. + reserved[1], 0); + + } else { + CU_ASSERT_EQUAL(ret_min, -1); + CU_ASSERT_EQUAL(errno_min, EINVAL); + } + + if (ret_max == -1 && ret_min == -1) { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + } + break; + + case V4L2_BUF_TYPE_PRIVATE: + memset(&format_max, 0xff, sizeof(format_max)); + format_max.type = type; + + ret_max = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_max); + errno_max = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_max=%i, errno_max=%i\n", + __FILE__, __LINE__, type, ret_max, errno_max); + + if (ret_max == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + dprintf1 + ("\tformat_max = { ..., .fmt.raw_data[] = { "); + for (j = 0; j < sizeof(format_max.fmt.raw_data); + j++) { + dprintf("0x%x", + format_max.fmt.raw_data[j]); + if (j < sizeof(format_max.fmt.raw_data)) { + dprintf1(", "); + } + } + dprintf1(" }}\n"); + + /* TODO: check the different fields */ + + } else { + CU_ASSERT_EQUAL(ret_max, -1); + CU_ASSERT_EQUAL(errno_max, EINVAL); + } + + memset(&format_min, 0, sizeof(format_min)); + format_min.type = type; + format_min.fmt.pix.pixelformat = fmtdesc.pixelformat; + + ret_min = + ioctl(get_video_fd(), VIDIOC_S_FMT, &format_min); + errno_min = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_min=%i, errno_min=%i\n", + __FILE__, __LINE__, type, ret_min, errno_min); + + if (ret_min == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + dprintf1 + ("\tformat_min = { ..., .fmt.raw_data[] = { "); + for (j = 0; j < sizeof(format_min.fmt.raw_data); + j++) { + dprintf("0x%x", + format_min.fmt.raw_data[j]); + if (j < sizeof(format_min.fmt.raw_data)) { + dprintf1(", "); + } + } + dprintf1(" }}\n"); + + /* TODO: check the different fields */ + + } else { + CU_ASSERT_EQUAL(ret_min, -1); + CU_ASSERT_EQUAL(errno_min, EINVAL); + } + + if (ret_max == -1 && ret_min == -1) { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + } + break; + } + + if (ret_enum == 0) { + CU_ASSERT_EQUAL(ret_enum, 0); + } else { + CU_ASSERT_EQUAL(ret_enum, -1); + CU_ASSERT_EQUAL(errno_enum, EINVAL); + } + + i++; + } while (ret_enum == 0 && i != 0); + + memset(&format_set, 0xff, sizeof(format_set)); + format_set = format_orig; + + ret_set = ioctl(get_video_fd(), VIDIOC_S_FMT, &format_set); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, format_orig.type, ret_set, errno_set); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_set, 0); + + CU_ASSERT_EQUAL(format_orig.type, type); + CU_ASSERT_EQUAL(format_set.type, type); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + } + +} + +void test_VIDIOC_S_FMT_enum() +{ + do_set_formats_enum(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_set_formats_enum(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_set_formats_enum(V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_set_formats_enum(V4L2_BUF_TYPE_VBI_CAPTURE); + do_set_formats_enum(V4L2_BUF_TYPE_VBI_OUTPUT); + do_set_formats_enum(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_set_formats_enum(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); + do_set_formats_enum(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_set_formats_enum(V4L2_BUF_TYPE_PRIVATE); +} + +static void do_set_formats_type(enum v4l2_buf_type type) +{ + int ret_set, errno_set; + struct v4l2_format format; + struct v4l2_format format2; + + memset(&format, 0, sizeof(format)); + format.type = type; + + ret_set = ioctl(get_video_fd(), VIDIOC_S_FMT, &format); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_FMT, type=%i, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, type, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + /* Check whether the format structure is untouched */ + memset(&format2, 0, sizeof(format2)); + format2.type = type; + CU_ASSERT_EQUAL(memcmp(&format, &format2, sizeof(format)), 0); + +} + +void test_VIDIOC_S_FMT_type() +{ + do_set_formats_type(0); + do_set_formats_type(9); + do_set_formats_type(V4L2_BUF_TYPE_PRIVATE - 1); + do_set_formats_type(S16_MIN); + do_set_formats_type(S16_MAX); + do_set_formats_type(S32_MAX); +} + +/* TODO: test cases for VIDIOC_TRY_FMT */ + +/* + TODO: test case for VIDIOC_TRY_FMT with invalid type + + TODO: test case for VIDIOC_S_FMT with type=V4L2_BUF_TYPE_VIDEO_CAPTURE and + V4L2_BUF_TYPE_VIDEO_OUTPUT + - with different field settings +*/ diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FMT.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FMT.h new file mode 100644 index 0000000000000000000000000000000000000000..b13463a3b7fd1cc7c6c1f7feed77dac2bc688a19 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FMT.h @@ -0,0 +1,17 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 15 Apr 2009 0.2 Added test cases for VIDIOC_S_FMT + * 4 Apr 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_FMT(void); +void test_VIDIOC_G_FMT_invalid_type(void); +void test_VIDIOC_G_FMT_NULL(void); + +void test_VIDIOC_S_FMT_enum(void); +void test_VIDIOC_S_FMT_type(void); + diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FREQUENCY.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FREQUENCY.c new file mode 100644 index 0000000000000000000000000000000000000000..687bc60e8dcc7dc8833e11f539acf84c34253160 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FREQUENCY.c @@ -0,0 +1,791 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 18 Apr 2009 0.4 More cleanup in frequency scan test case + * 28 Mar 2009 0.3 Clean up ret and errno variable names and dprintf() output + * 1 Feb 2009 0.2 Added test cases for VIDIOC_S_FREQUENCY + * 31 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_FREQUENCY.h" + +void test_VIDIOC_G_FREQUENCY() +{ + int ret_get, errno_get; + __u32 tuner; + struct v4l2_frequency freq; + + tuner = 0; + + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = tuner; + ret_get = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &freq); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + CU_ASSERT_EQUAL(freq.tuner, tuner); + + //CU_ASSERT(freq.type, ???); + //CU_ASSERT_EQUAL(freq.frequency, ???); + + CU_ASSERT_EQUAL(freq.reserved[0], 0); + CU_ASSERT_EQUAL(freq.reserved[1], 0); + CU_ASSERT_EQUAL(freq.reserved[2], 0); + CU_ASSERT_EQUAL(freq.reserved[3], 0); + CU_ASSERT_EQUAL(freq.reserved[4], 0); + CU_ASSERT_EQUAL(freq.reserved[5], 0); + CU_ASSERT_EQUAL(freq.reserved[6], 0); + CU_ASSERT_EQUAL(freq.reserved[7], 0); + + dprintf("\tfreq = { " + ".tuner = %u, " + ".type = 0x%X, " + ".frequency = %u " + ".reserved[]={ 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X } }\n", + freq.tuner, + freq.type, + freq.frequency, + freq.reserved[0], + freq.reserved[1], + freq.reserved[2], + freq.reserved[3], + freq.reserved[4], + freq.reserved[5], freq.reserved[6], freq.reserved[7] + ); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + +} + +void test_VIDIOC_G_FREQUENCY_S32_MAX() +{ + int ret_get, errno_get; + __u32 tuner; + struct v4l2_frequency freq; + + tuner = (__u32) S32_MAX; + + memset(&tuner, 0xff, sizeof(tuner)); + freq.tuner = tuner; + ret_get = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &freq); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_FREQUENCY_S32_MAX_1() +{ + int ret_get, errno_get; + __u32 tuner; + struct v4l2_frequency freq; + + tuner = (__u32) S32_MAX + 1; + + memset(&tuner, 0xff, sizeof(tuner)); + freq.tuner = tuner; + ret_get = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &freq); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_FREQUENCY_U32_MAX() +{ + int ret_get, errno_get; + __u32 tuner; + struct v4l2_frequency freq; + + tuner = U32_MAX; + + memset(&tuner, 0xff, sizeof(tuner)); + freq.tuner = tuner; + ret_get = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &freq); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_FREQUENCY_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + struct v4l2_frequency freq; + __u32 tuner; + + tuner = 0; + + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = tuner; + freq.type = V4L2_TUNER_ANALOG_TV; + ret_get = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &freq); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* check if VIDIOC_G_FREQUENCY is supported at all or not */ + if (ret_get == 0) { + /* VIDIOC_G_FREQUENCY is supported, the parameter should be checked */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + /* VIDIOC_G_FREQUENCY not supported at all, the parameter should not be evaluated */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } +} + +void test_VIDIOC_S_FREQUENCY() +{ + int ret_get, errno_get; + int ret_set, errno_set; + __u32 tuner; + struct v4l2_frequency orig_freq; + struct v4l2_frequency freq; + struct v4l2_frequency new_freq; + + tuner = 0; + + /* fetch the current frequency setting */ + memset(&orig_freq, 0xff, sizeof(orig_freq)); + orig_freq.tuner = tuner; + ret_get = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &orig_freq); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(orig_freq.tuner, tuner); + + /* try to set the frequency again to the actual value */ + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = tuner; + freq.frequency = orig_freq.frequency; + freq.type = V4L2_TUNER_ANALOG_TV; + ret_set = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &orig_freq); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FREQUENCY, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, 0); + if (ret_set == 0) { + + /* check wheteher the frequency has not been changed */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = tuner; + ret_get = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + dprintf + ("\t%s:%u: current frequency=%u (expected %u)\n", + __FILE__, __LINE__, new_freq.frequency, + orig_freq.frequency); + CU_ASSERT_EQUAL(new_freq.frequency, + orig_freq.frequency); + } + + } + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + /* VIDIOC_G_FREQUENCY not supported, so shall be VIDIOC_S_FREQUENCY */ + + memset(&freq, 0, sizeof(freq)); + freq.tuner = tuner; + freq.type = V4L2_TUNER_ANALOG_TV; + freq.frequency = 0; + ret_set = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FREQUENCY, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + } + +} + +void test_VIDIOC_S_FREQUENCY_boundaries() +{ + int ret_g_tuner = 0; + int ret_g_freq = 0; + int errno_g_tuner = 0; + int errno_g_freq = 0; + int ret; + __u32 index; + struct v4l2_frequency orig_freq; + struct v4l2_frequency freq; + struct v4l2_frequency new_freq; + struct v4l2_tuner tuner; + + /* this test case depends on working VIDIOC_G_TUNER and VIDIOC_G_FREQUENCY commands */ + + index = 0; + + /* fetch the minimum (tuner.rangelow) and maximum (tuner.rangehigh) frequency */ + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = index; + ret_g_tuner = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner); + errno_g_tuner = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_TUNER, ret=%i, tuner.rangelow=%u, tuner.rangehigh=%u\n", + __FILE__, __LINE__, ret_g_tuner, tuner.rangelow, tuner.rangehigh); + CU_ASSERT_EQUAL(tuner.index, index); + + /* fetch the current frequency setting */ + memset(&orig_freq, 0xff, sizeof(orig_freq)); + orig_freq.tuner = index; + ret_g_freq = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &orig_freq); + errno_g_freq = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret_g_freq=%i, orig_freq.frequency=%u\n", + __FILE__, __LINE__, ret_g_freq, orig_freq.frequency); + CU_ASSERT_EQUAL(orig_freq.tuner, index); + + if (ret_g_tuner == 0 && ret_g_freq == 0) { + CU_ASSERT_EQUAL(orig_freq.tuner, index); + + /* try to set the frequency to zero */ + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + freq.frequency = 0; + ret = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + dprintf("\t%s:%u: set to %u: VIDIOC_S_FREQUENCY, ret=%i\n", + __FILE__, __LINE__, 0, ret); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + + /* check wheteher the frequency has been changed to the lowest + * possible value + */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret, new_freq.frequency); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + CU_ASSERT_EQUAL(new_freq.frequency, + tuner.rangelow); + } + } + + /* try to set the frequency to tuner.rangelow-1, if applicable */ + if (0 < tuner.rangelow) { + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + freq.frequency = tuner.rangelow - 1; + ret = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + + dprintf + ("\t%s:%u: set to %u: VIDIOC_S_FREQUENCY, ret=%i\n", + __FILE__, __LINE__, tuner.rangelow - 1, ret); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + + /* check wheteher the frequency has been changed to the lowest + * possible value + */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret, + new_freq.frequency); + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + dprintf + ("\t%s:%u: current frequency=%u (expected %u)\n", + __FILE__, __LINE__, + new_freq.frequency, + tuner.rangelow); + CU_ASSERT_EQUAL(new_freq.frequency, + tuner.rangelow); + } + } + } + + /* try to set the frequency to tuner.rangelow */ + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + freq.frequency = tuner.rangelow; + ret = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + + dprintf("\t%s:%u: set to %u: VIDIOC_S_FREQUENCY, ret=%i\n", + __FILE__, __LINE__, tuner.rangelow, ret); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + + /* check wheteher the frequency has been changed to the lowest + * possible value + */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret, new_freq.frequency); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + dprintf + ("\t%s:%u: current frequency=%u (expected %u)\n", + __FILE__, __LINE__, new_freq.frequency, + tuner.rangelow); + CU_ASSERT_EQUAL(new_freq.frequency, + tuner.rangelow); + } + } + + /* try to set the frequency to tuner.rangehigh */ + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + freq.frequency = tuner.rangehigh; + ret = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + + dprintf("\t%s:%u: set to %u: VIDIOC_S_FREQUENCY, ret=%i\n", + __FILE__, __LINE__, tuner.rangehigh, ret); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + + /* check wheteher the frequency has been changed to the highest + * possible value + */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret, new_freq.frequency); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + dprintf + ("\t%s:%u: current frequency=%u (expected %u)\n", + __FILE__, __LINE__, new_freq.frequency, + tuner.rangehigh); + CU_ASSERT_EQUAL(new_freq.frequency, + tuner.rangehigh); + } + } + + /* try to set the frequency to tuner.rangehigh+1, if applicable */ + if (tuner.rangehigh < U32_MAX) { + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + freq.frequency = tuner.rangehigh + 1; + ret = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + + dprintf + ("\t%s:%u: set to %u: VIDIOC_S_FREQUENCY, ret=%i\n", + __FILE__, __LINE__, tuner.rangehigh + 1, ret); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + + /* check wheteher the frequency has been changed to the highest + * possible value + */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret, + new_freq.frequency); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + dprintf + ("\t%s:%u: current frequency=%u (expected %u)\n", + __FILE__, __LINE__, + new_freq.frequency, + tuner.rangehigh); + CU_ASSERT_EQUAL(new_freq.frequency, + tuner.rangehigh); + } + } + } + + /* try to set the frequency to U32_MAX */ + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + freq.frequency = U32_MAX; + ret = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + + dprintf("\t%s:%u: set to %u: VIDIOC_S_FREQUENCY, ret=%i\n", + __FILE__, __LINE__, U32_MAX, ret); + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + + /* check wheteher the frequency has been changed to the highest + * possible value + */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret, new_freq.frequency); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + dprintf + ("\t%s:%u: current frequency=%u (expected %u)\n", + __FILE__, __LINE__, new_freq.frequency, + tuner.rangehigh); + CU_ASSERT_EQUAL(new_freq.frequency, + tuner.rangehigh); + } + } + + /* try restore the original frequency settings */ + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + freq.frequency = orig_freq.frequency; + ret = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + + dprintf("\t%s:%u: set to %u: VIDIOC_S_FREQUENCY, ret=%i\n", + __FILE__, __LINE__, orig_freq.frequency, ret); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + + /* check wheteher the frequency has been restored */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret, new_freq.frequency); + + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + dprintf + ("\t%s:%u: current frequency=%u (expected %u)\n", + __FILE__, __LINE__, new_freq.frequency, + orig_freq.frequency); + CU_ASSERT_EQUAL(new_freq.frequency, + orig_freq.frequency); + } + } + } + + if (ret_g_freq != 0) { + dprintf("\t%s:%u: ret_g_freq=%d (expected %d)\n", __FILE__, + __LINE__, ret_g_freq, -1); + dprintf("\t%s:%u: errno_g_freq=%d (expected %d)\n", __FILE__, + __LINE__, errno_g_freq, EINVAL); + CU_ASSERT_EQUAL(ret_g_freq, -1); + CU_ASSERT_EQUAL(errno, EINVAL); + } + + if (ret_g_tuner != 0) { + dprintf("\t%s:%u: ret_g_tuner=%d (expected %d)\n", __FILE__, + __LINE__, ret_g_tuner, -1); + dprintf("\t%s:%u: errno_g_tuner=%d (expected %d)\n", __FILE__, + __LINE__, errno_g_tuner, EINVAL); + CU_ASSERT_EQUAL(ret_g_tuner, -1); + CU_ASSERT_EQUAL(errno, EINVAL); + } + +} + +void test_VIDIOC_S_FREQUENCY_scan() +{ + int ret_g_tuner, errno_g_tuner; + int ret_g_freq, errno_g_freq; + int ret_get, errno_get; + int ret_set, errno_set; + __u32 index; + struct v4l2_frequency orig_freq; + struct v4l2_frequency freq; + struct v4l2_frequency new_freq; + struct v4l2_frequency prev_freq; + struct v4l2_tuner tuner; + __u32 i; + + /* this test case depends on working VIDIOC_G_FREQUENCY command */ + + index = 0; + + /* fetch the minimum (tuner.rangelow) and maximum (tuner.rangehigh) frequency */ + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = index; + ret_g_tuner = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner); + errno_g_tuner = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER, ret_g_tuner=%i, errno_g_tuner=%i\n", + __FILE__, __LINE__, ret_g_tuner, errno_g_tuner); + CU_ASSERT_EQUAL(tuner.index, index); + + /* fetch the current frequency setting */ + memset(&orig_freq, 0xff, sizeof(orig_freq)); + orig_freq.tuner = index; + ret_g_freq = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &orig_freq); + errno_g_freq = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret_g_freq=%i, errno_g_freq=%i, orig_freq.frequency=%u\n", + __FILE__, __LINE__, ret_g_freq, errno_g_freq, orig_freq.frequency); + CU_ASSERT_EQUAL(orig_freq.tuner, index); + + if (ret_g_freq == 0) { + CU_ASSERT_EQUAL(orig_freq.tuner, index); + + dprintf("\t%s:%u: tuner.rangelow=%u, tuner.rangehigh=%u\n", + __FILE__, __LINE__, tuner.rangelow, tuner.rangehigh); + + i = tuner.rangelow; + prev_freq.frequency = 0; + do { + /* try to set the frequency */ + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + + freq.frequency = i; + ret_set = + ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + errno_set = errno; + dprintf + ("\t%s:%u: VIDIOC_S_FREQUENCY, ret_set=%i, errno_set=%i, freq.frequency=%u\n", + __FILE__, __LINE__, ret_set, errno_set, i); + + CU_ASSERT_EQUAL(ret_set, 0); + if (ret_set == 0) { + + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret_get = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret_get, errno_get, + new_freq.frequency); + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT(prev_freq.frequency <= + new_freq.frequency); + CU_ASSERT(tuner.rangelow <= + new_freq.frequency); + CU_ASSERT(new_freq.frequency <= + tuner.rangehigh); + prev_freq = new_freq; + } + } else { + printf("\tError %i while setting to %u\n", + errno_set, i); + } + i++; + } while (i <= tuner.rangehigh); + + /* try restore the original frequency settings */ + memset(&freq, 0xff, sizeof(freq)); + freq.tuner = index; + freq.type = orig_freq.type; + freq.frequency = orig_freq.frequency; + ret_set = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_FREQUENCY, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, 0); + if (ret_set == 0) { + + /* check wheteher the frequency has been restored */ + memset(&new_freq, 0xff, sizeof(new_freq)); + new_freq.tuner = index; + ret_get = + ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, + &new_freq); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i, new_freq.frequency=%u\n", + __FILE__, __LINE__, ret_get, errno_get, + new_freq.frequency); + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT_EQUAL(new_freq.frequency, + orig_freq.frequency); + } + } + } + + if (ret_g_freq != 0) { + CU_ASSERT_EQUAL(ret_g_freq, -1); + CU_ASSERT_EQUAL(errno, EINVAL); + } + + if (ret_g_tuner != 0) { + CU_ASSERT_EQUAL(ret_g_tuner, -1); + CU_ASSERT_EQUAL(errno, EINVAL); + } + +} + +void test_VIDIOC_S_FREQUENCY_NULL() +{ + int ret_get, errno_get; + int ret_set, errno_set; + int ret_null, errno_null; + struct v4l2_frequency freq_orig; + struct v4l2_frequency freq; + __u32 tuner; + + tuner = 0; + + memset(&freq_orig, 0, sizeof(freq_orig)); + freq_orig.tuner = tuner; + freq_orig.type = V4L2_TUNER_ANALOG_TV; + ret_get = ioctl(get_video_fd(), VIDIOC_G_FREQUENCY, &freq_orig); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + memset(&freq, 0, sizeof(freq)); + freq.tuner = 0; + freq.type = V4L2_TUNER_ANALOG_TV; + freq.frequency = freq_orig.frequency; + ret_set = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, &freq_orig); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_G_FREQUENCY, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + ret_null = ioctl(get_video_fd(), VIDIOC_S_FREQUENCY, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_S_FREQUENCY, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* Check whether any of VIDIOC_S_FREQUENCY or VIDIOC_G_FREQUENCY + * is supported at all or not + */ + if (ret_get == 0 || ret_set == 0) { + /* VIDIOC_G_FREQUENCY or VIDIOC_S_FREQUENCY is supported, so + * the parameter of VIDIOC_S_FREQUENCY should be checked + */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + /* none of VIDIOC_G_FREQUENCY and VIDIOC_S_FREQUENCY is supported, + * the parameter should not be evaluated + */ + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FREQUENCY.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FREQUENCY.h new file mode 100644 index 0000000000000000000000000000000000000000..b5e4263aacff78e15d7458fd16d8bde1760cd0b6 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_FREQUENCY.h @@ -0,0 +1,21 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 29 Mar 2009 0.3 Test case for VIDIOC_S_FREQUENCY with NULL parameter added + * 1 Feb 2009 0.2 Added test cases for VIDIOC_S_FREQUENCY + * 31 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_FREQUENCY(void); +void test_VIDIOC_G_FREQUENCY_S32_MAX(void); +void test_VIDIOC_G_FREQUENCY_S32_MAX_1(void); +void test_VIDIOC_G_FREQUENCY_U32_MAX(void); +void test_VIDIOC_G_FREQUENCY_NULL(void); + +void test_VIDIOC_S_FREQUENCY(void); +void test_VIDIOC_S_FREQUENCY_boundaries(void); +void test_VIDIOC_S_FREQUENCY_scan(void); +void test_VIDIOC_S_FREQUENCY_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_G_SLICED_VBI_CAP.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_G_SLICED_VBI_CAP.c new file mode 100644 index 0000000000000000000000000000000000000000..40564a08ae4b848ed2ebd0b341587cf873c95c82 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_G_SLICED_VBI_CAP.c @@ -0,0 +1,152 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 22 Mar 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_G_SLICED_VBI_CAP.h" + +void do_get_sliced_vbi_cap(enum v4l2_buf_type type) +{ + int ret_cap, errno_cap; + struct v4l2_sliced_vbi_cap sliced_vbi_cap; + + memset(&sliced_vbi_cap, 0xff, sizeof(sliced_vbi_cap)); + sliced_vbi_cap.type = type; + ret_cap = + ioctl(get_video_fd(), VIDIOC_G_SLICED_VBI_CAP, &sliced_vbi_cap); + errno_cap = errno; + + dprintf + ("\tVIDIOC_G_SLICED_VBI_CAP: type=%i, ret_cap=%i, errno_cap=%i\n", + type, ret_cap, errno_cap); + + if (ret_cap == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + + } else { + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); + } + +} + +void test_VIDIOC_G_SLICED_VBI_CAP() +{ + do_get_sliced_vbi_cap(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_get_sliced_vbi_cap(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); +} + +void do_get_sliced_vbi_cap_invalid(enum v4l2_buf_type type) +{ + int ret_cap, errno_cap; + struct v4l2_sliced_vbi_cap sliced_vbi_cap; + + memset(&sliced_vbi_cap, 0xff, sizeof(sliced_vbi_cap)); + sliced_vbi_cap.type = type; + ret_cap = + ioctl(get_video_fd(), VIDIOC_G_SLICED_VBI_CAP, &sliced_vbi_cap); + errno_cap = errno; + + dprintf + ("\tVIDIOC_G_SLICED_VBI_CAP: type=%i, ret_cap=%i, errno_cap=%i\n", + type, ret_cap, errno_cap); + + CU_ASSERT_EQUAL(ret_cap, -1); + CU_ASSERT_EQUAL(errno_cap, EINVAL); +} + +void test_VIDIOC_G_SLICED_VBI_CAP_invalid() +{ + do_get_sliced_vbi_cap_invalid(0); + do_get_sliced_vbi_cap_invalid(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_get_sliced_vbi_cap_invalid(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_get_sliced_vbi_cap_invalid(V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_get_sliced_vbi_cap_invalid(V4L2_BUF_TYPE_VBI_CAPTURE); + do_get_sliced_vbi_cap_invalid(V4L2_BUF_TYPE_VBI_OUTPUT); + do_get_sliced_vbi_cap_invalid(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_get_sliced_vbi_cap_invalid(V4L2_BUF_TYPE_PRIVATE); + do_get_sliced_vbi_cap_invalid(S32_MAX); + do_get_sliced_vbi_cap_invalid(((__u32) S32_MAX) + 1); + do_get_sliced_vbi_cap_invalid(U32_MAX); +} + +void test_VIDIOC_G_SLICED_VBI_CAP_NULL() +{ + int ret_get, errno_get; + int ret_set_capture, errno_set_capture; + int ret_set_output, errno_set_output; + int ret_null, errno_null; + struct v4l2_sliced_vbi_cap sliced_vbi_cap; + + memset(&sliced_vbi_cap, 0, sizeof(sliced_vbi_cap)); + sliced_vbi_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret_get = + ioctl(get_video_fd(), VIDIOC_G_SLICED_VBI_CAP, &sliced_vbi_cap); + errno_get = errno; + + dprintf("\tVIDIOC_G_SLICED_VBI_CAP ret_get=%i, errno_get=%i\n", ret_get, + errno_get); + + memset(&sliced_vbi_cap, 0, sizeof(sliced_vbi_cap)); + sliced_vbi_cap.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + + ret_set_capture = + ioctl(get_video_fd(), VIDIOC_G_SLICED_VBI_CAP, &sliced_vbi_cap); + errno_set_capture = errno; + + dprintf + ("\tVIDIOC_G_SLICED_VBI_CAP ret_set_capture=%i, errno_set_capture=%i\n", + ret_set_capture, errno_set_capture); + + memset(&sliced_vbi_cap, 0, sizeof(sliced_vbi_cap)); + sliced_vbi_cap.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + + ret_set_output = + ioctl(get_video_fd(), VIDIOC_G_SLICED_VBI_CAP, &sliced_vbi_cap); + errno_set_output = errno; + + dprintf + ("\tVIDIOC_G_SLICED_VBI_CAP ret_set_output=%i, errno_set_output=%i\n", + ret_set_output, errno_set_output); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_SLICED_VBI_CAP, NULL); + errno_null = errno; + + dprintf("\tVIDIOC_G_SLICED_VBI_CAP ret_null=%i, errno_null=%i\n", + ret_null, errno_null); + + if (ret_get == 0 || ret_set_capture == 0 || ret_set_output == 0) { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_set_capture, -1); + CU_ASSERT_EQUAL(errno_set_capture, EINVAL); + CU_ASSERT_EQUAL(ret_set_capture, -1); + CU_ASSERT_EQUAL(errno_set_capture, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_G_SLICED_VBI_CAP.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_G_SLICED_VBI_CAP.h new file mode 100644 index 0000000000000000000000000000000000000000..2850296ca5bb420bee7798ae553a97ba708ac66b --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_G_SLICED_VBI_CAP.h @@ -0,0 +1,12 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 22 Mar 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_SLICED_VBI_CAP(void); +void test_VIDIOC_G_SLICED_VBI_CAP_invalid(void); +void test_VIDIOC_G_SLICED_VBI_CAP_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_INPUT.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_INPUT.c new file mode 100644 index 0000000000000000000000000000000000000000..ed58ce6d1eac1ce7b832533a15c6312cac8ee9dc --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_INPUT.c @@ -0,0 +1,302 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 4 Apr 2009 0.5 Test case for NULL parameter reworked + * 22 Mar 2009 0.4 Cleanup dprintf() outputs and ret and errno names + * 9 Feb 2009 0.3 Modify test cases to support drivers without any inputs + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_INPUT.h" + +int valid_input_index(int f, __u32 index) +{ + __u32 i; + struct v4l2_input input; + int ret_enum, errno_enum; + int valid = 0; + + /* Search for index with VIDIOC_ENUMINPUT. Do not just + * check the given index with VIDIOC_ENUMINPUT because + * we could miss the end of the enumeration. After the + * end of enumeration no more indexes are allowed. + */ + i = 0; + do { + memset(&input, 0xff, sizeof(input)); + input.index = i; + ret_enum = ioctl(f, VIDIOC_ENUMINPUT, &input); + errno_enum = errno; + if (ret_enum == 0 && index == i) { + valid = 1; + break; + } + i++; + } while (ret_enum == 0 && i != 0); + return valid; +} + +void test_VIDIOC_G_INPUT() +{ + int ret_get, errno_get; + __u32 index; + int f; + + f = get_video_fd(); + + memset(&index, 0xff, sizeof(index)); + ret_get = ioctl(f, VIDIOC_G_INPUT, &index); + errno_get = errno; + + dprintf("\tVIDIOC_G_INPUT, ret_get=%i, errno_get=%i\n", ret_get, + errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT(valid_input_index(f, index)); + + dprintf("\tindex=0x%X\n", index); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + +} + +void test_VIDIOC_S_INPUT_from_enum() +{ + int ret_get, errno_get; + int ret_enum, errno_enum; + int ret_set, errno_set; + __u32 input_index_orig; + struct v4l2_input input; + __u32 i; + int f; + + f = get_video_fd(); + + memset(&input_index_orig, 0xff, sizeof(input_index_orig)); + ret_get = ioctl(f, VIDIOC_G_INPUT, &input_index_orig); + errno_get = errno; + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + i = 0; + do { + memset(&input, 0xff, sizeof(input)); + input.index = i; + ret_enum = ioctl(f, VIDIOC_ENUMINPUT, &input); + errno_enum = errno; + + dprintf("\tENUMINPUT: i=%u, ret_enum=%i, errno=%i\n", i, + ret_enum, errno); + + if (ret_enum == 0) { + ret_set = + ioctl(f, VIDIOC_S_INPUT, &input.index); + errno_set = errno; + CU_ASSERT_EQUAL(ret_set, 0); + + dprintf + ("\tinput.index=0x%X, ret_set=%i, errno_set=%i\n", + input.index, ret_set, errno_set); + + } + i++; + } while (ret_enum == 0 && i != 0); + + /* Setting the original input_id should not fail */ + ret_set = ioctl(f, VIDIOC_S_INPUT, &input_index_orig); + CU_ASSERT_EQUAL(ret_set, 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } +} + +static void do_set_input(int f, __u32 first_wrong_input, __u32 index) +{ + struct v4l2_input input; + int ret_set, errno_set; + + if (first_wrong_input <= index) { + + dprintf("\tdo_set_input(f, 0x%X, 0x%X)\n", first_wrong_input, + index); + + memset(&input, 0xff, sizeof(input)); + input.index = index; + ret_set = ioctl(f, VIDIOC_S_INPUT, &input.index); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + dprintf("\t%s:%u: input.index=0x%X, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, input.index, ret_set, errno_set); + + } + +} + +void test_VIDIOC_S_INPUT_invalid_inputs() +{ + int ret_get, errno_get; + int ret_enum, errno_enum; + int ret_set, errno_set; + __u32 input_index_orig; + struct v4l2_input input; + __u32 i, first_wrong_input; + int f; + + f = get_video_fd(); + + memset(&input_index_orig, 0xff, sizeof(input_index_orig)); + ret_get = ioctl(f, VIDIOC_G_INPUT, &input_index_orig); + errno_get = errno; + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + i = 0; + do { + memset(&input, 0xff, sizeof(input)); + input.index = i; + ret_enum = ioctl(f, VIDIOC_ENUMINPUT, &input); + errno_enum = errno; + + dprintf + ("\t%s:%u: ENUMINPUT: i=%u, ret_enum=%i, errno_enum=%i\n", + __FILE__, __LINE__, i, ret_enum, errno_enum); + + i++; + } while (ret_enum == 0 && i != 0); + + if (i != 0) { + first_wrong_input = i; + + /* The input index range 0..(i-1) are valid inputs. */ + /* Try index values from range i..U32_MAX */ + do_set_input(f, first_wrong_input, i); + do_set_input(f, first_wrong_input, i + 1); + + /* Check for signed/unsigned mismatch near S32_MAX */ + for (i = 0; i <= first_wrong_input + 1; i++) { + do_set_input(f, first_wrong_input, + ((__u32) S32_MAX) + i); + } + + i = (U32_MAX - 1) - first_wrong_input; + do { + do_set_input(f, first_wrong_input, i); + i++; + } while (i != 0); + } + + /* Setting the original input_id should not fail */ + ret_set = ioctl(f, VIDIOC_S_INPUT, &input_index_orig); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } +} + +void test_VIDIOC_G_INPUT_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + __u32 index; + + memset(&index, 0xff, sizeof(index)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_INPUT, &index); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_INPUT, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_INPUT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_INPUT: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +void test_VIDIOC_S_INPUT_NULL() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + int ret_null, errno_null; + __u32 index_orig; + __u32 index; + + /* save the original input */ + memset(&index_orig, 0, sizeof(index_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_INPUT, &index_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_INPUT, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + + memset(&index, 0xff, sizeof(index)); + index = index_orig; + ret_set = ioctl(get_video_fd(), VIDIOC_S_INPUT, &index); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_INPUT ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + ret_null = ioctl(get_video_fd(), VIDIOC_S_INPUT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_S_INPUT: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_INPUT.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_INPUT.h new file mode 100644 index 0000000000000000000000000000000000000000..b71199fb415d0171e6dd22ee075ea0d32f6c42b5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_INPUT.h @@ -0,0 +1,15 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 22 Mar 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_INPUT(void); +void test_VIDIOC_S_INPUT_from_enum(void); +void test_VIDIOC_S_INPUT_invalid_inputs(void); + +void test_VIDIOC_G_INPUT_NULL(void); +void test_VIDIOC_S_INPUT_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_JPEGCOMP.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_JPEGCOMP.c new file mode 100644 index 0000000000000000000000000000000000000000..6137f2e7c91d35cf724bb0b485167eda61e7a2bc --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_JPEGCOMP.c @@ -0,0 +1,123 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 16 Jun 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" +#include "v4l2_foreach.h" + +#include "test_VIDIOC_JPEGCOMP.h" + +static int valid_jpeg_markers(__u32 jpeg_markers) +{ + int valid = 0; + + if ((jpeg_markers & ~(V4L2_JPEG_MARKER_DHT | + V4L2_JPEG_MARKER_DQT | + V4L2_JPEG_MARKER_DRI | + V4L2_JPEG_MARKER_COM | V4L2_JPEG_MARKER_APP)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +void test_VIDIOC_G_JPEGCOMP() +{ + struct v4l2_jpegcompression jpegcomp; + int ret_get, errno_get; + + memset(&jpegcomp, 0xff, sizeof(jpegcomp)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_JPEGCOMP, &jpegcomp); + errno_get = errno; + + dprintf("\tVIDIOC_G_JPEGCOMP, ret_get=%i, errno_get=%i\n", ret_get, + errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + //CU_ASSERT_EQUAL(jpegcomp.quality, ???); + //CU_ASSERT_EQUAL(jpegcomp.APPn, ???); + CU_ASSERT(0 <= jpegcomp.APP_len); + CU_ASSERT(jpegcomp.APP_len <= (int)sizeof(jpegcomp.APP_data)); + //CU_ASSERT_EQUAL(jpegcomp.APP_data, ???); + CU_ASSERT(0 <= jpegcomp.COM_len); + CU_ASSERT(jpegcomp.COM_len <= (int)sizeof(jpegcomp.COM_data)); + //CU_ASSERT_EQUAL(jpegcomp.COM_data, ???); + CU_ASSERT(valid_jpeg_markers(jpegcomp.jpeg_markers)); + + dprintf("\tjpegcomp = { .quality=%i, " + ".APPn=%i, " + ".APP_len=%i, " + ".APP_data=..., " + ".COM_len=%i, " + ".COM_data=..., " + ".jpeg_markers=0x%x ", + jpegcomp.quality, jpegcomp.APPn, jpegcomp.APP_len, + //jpegcomp.APP_data, + jpegcomp.COM_len, + //jpegcomp.COM_data, + jpegcomp.jpeg_markers); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + +} + +void test_VIDIOC_G_JPEGCOMP_NULL() +{ + struct v4l2_jpegcompression jpegcomp; + int ret_get, errno_get; + int ret_null, errno_null; + + memset(&jpegcomp, 0, sizeof(jpegcomp)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_JPEGCOMP, &jpegcomp); + errno_get = errno; + + dprintf("\tVIDIOC_G_JPEGCOMP, ret_get=%i, errno_get=%i\n", ret_get, + errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_JPEGCOMP, NULL); + errno_null = errno; + + dprintf("\tVIDIOC_G_JPEGCOMP, ret_null=%i, errno_null=%i\n", ret_null, + errno_null); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_JPEGCOMP.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_JPEGCOMP.h new file mode 100644 index 0000000000000000000000000000000000000000..77e7cc3456df7bd56cc100eaff9fba02034aa3d0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_JPEGCOMP.h @@ -0,0 +1,11 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 16 Jul 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_JPEGCOMP(void); +void test_VIDIOC_G_JPEGCOMP_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_LOG_STATUS.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_LOG_STATUS.c new file mode 100644 index 0000000000000000000000000000000000000000..f98e8bdc84bb6d3510a82ae56c353128480834c7 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_LOG_STATUS.c @@ -0,0 +1,51 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 27 Mar 2009 0.2 Clean up ret and errno variable names and dprintf() output + * 23 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_LOG_STATUS.h" + +void test_VIDIOC_LOG_STATUS() +{ + int ret_log, errno_log; + + ret_log = ioctl(get_video_fd(), VIDIOC_LOG_STATUS); + errno_log = errno; + + dprintf("\t%s:%u: ret_log=%i, errno_log=%i\n", + __FILE__, __LINE__, ret_log, errno_log); + + /* this is an optional ioctl, so two possible return values */ + /* are possible */ + if (ret_log == 0) { + CU_ASSERT_EQUAL(ret_log, 0); + /* TODO: check if something is shown in dmesg */ + + } else { + CU_ASSERT_EQUAL(ret_log, -1); + CU_ASSERT_EQUAL(errno_log, EINVAL); + } +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_LOG_STATUS.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_LOG_STATUS.h new file mode 100644 index 0000000000000000000000000000000000000000..d3f98d337264d8847f069ad7c457321b9741eeeb --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_LOG_STATUS.h @@ -0,0 +1,10 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 23 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_LOG_STATUS(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_MODULATOR.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_MODULATOR.c new file mode 100644 index 0000000000000000000000000000000000000000..d657134c0e9586f51d45ad163f89458549e64aa7 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_MODULATOR.c @@ -0,0 +1,257 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.4 Added string content validation + * 18 Apr 2009 0.3 More strict check for strings + * 28 Mar 2009 0.2 Clean up ret and errno variable names and dprintf() output + * 2 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_MODULATOR.h" + +int valid_modulator_sub(__u32 tuner_sub) +{ + int valid = 0; + + CU_ASSERT_EQUAL(V4L2_TUNER_SUB_SAP, V4L2_TUNER_SUB_LANG2); + + if ((tuner_sub & ~(V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_SAP)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +static int do_get_modulator(int f, __u32 index) +{ + int ret_get, errno_get; + struct v4l2_modulator modulator; + struct v4l2_modulator modulator2; + + memset(&modulator, 0xff, sizeof(modulator)); + modulator.index = index; + ret_get = ioctl(f, VIDIOC_G_MODULATOR, &modulator); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_MODULATOR, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + CU_ASSERT_EQUAL(modulator.index, index); + + CU_ASSERT(0 < strlen((char *)modulator.name)); + CU_ASSERT(valid_string + ((char *)modulator.name, sizeof(modulator.name))); + + CU_ASSERT(valid_modulator_capability(modulator.capability)); + + CU_ASSERT(modulator.rangelow <= modulator.rangehigh); + + CU_ASSERT(valid_modulator_sub(modulator.txsubchans)); + + CU_ASSERT_EQUAL(modulator.reserved[0], 0); + CU_ASSERT_EQUAL(modulator.reserved[1], 0); + CU_ASSERT_EQUAL(modulator.reserved[2], 0); + CU_ASSERT_EQUAL(modulator.reserved[3], 0); + + /* Check if the unused bytes of the name string are also filled + * with zeros. Also check if there is any padding byte between + * any two fields then this padding byte is also filled with + * zeros. + */ + memset(&modulator2, 0, sizeof(modulator2)); + modulator2.index = modulator.index; + strncpy((char *)modulator2.name, (char *)modulator.name, + sizeof(modulator2.name)); + modulator2.capability = modulator.capability; + modulator2.rangelow = modulator.rangelow; + modulator2.rangehigh = modulator.rangehigh; + modulator2.txsubchans = modulator.txsubchans; + CU_ASSERT_EQUAL(memcmp + (&modulator, &modulator2, sizeof(modulator)), + 0); + + dprintf("\tmodulator = { " + ".index = %u, " + ".name = \"%s\", " + ".capability = 0x%X, " + ".rangelow = %u, " + ".rangehigh = %u, " + ".txsubchans = %u, " + ".reserved[]={ 0x%X, 0x%X, 0x%X, 0x%X } }\n", + modulator.index, + modulator.name, + modulator.capability, + modulator.rangelow, + modulator.rangehigh, + modulator.txsubchans, + modulator.reserved[0], + modulator.reserved[1], + modulator.reserved[2], modulator.reserved[3] + ); + + } else { + dprintf("\t%s:%u: ret_get=%d (expected %d)\n", __FILE__, + __LINE__, ret_get, -1); + dprintf("\t%s:%u: errno_get=%d (expected %d)\n", __FILE__, + __LINE__, errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + + return ret_get; +} + +void test_VIDIOC_G_MODULATOR() +{ + int ret; + __u32 index; + int f; + + f = get_video_fd(); + + index = 0; + do { + ret = do_get_modulator(f, index); + index++; + } while (ret == 0); + +} + +void test_VIDIOC_G_MODULATOR_S32_MAX() +{ + int ret_get, errno_get; + __u32 index; + struct v4l2_modulator modulator; + + index = (__u32) S32_MAX; + + memset(&modulator, 0xff, sizeof(modulator)); + modulator.index = index; + ret_get = ioctl(get_video_fd(), VIDIOC_G_MODULATOR, &modulator); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_MODULATOR, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + dprintf("\t%s:%u: ret_get=%d (expected %d)\n", __FILE__, __LINE__, + ret_get, -1); + dprintf("\t%s:%u: errno_get=%d (expected %d)\n", __FILE__, __LINE__, + errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_MODULATOR_S32_MAX_1() +{ + int ret_get, errno_get; + __u32 index; + struct v4l2_modulator modulator; + + index = (__u32) S32_MAX + 1; + + memset(&modulator, 0xff, sizeof(modulator)); + modulator.index = index; + ret_get = ioctl(get_video_fd(), VIDIOC_G_MODULATOR, &modulator); + errno_get = errno; + + dprintf("VIDIOC_G_MODULATOR, ret_get=%i\n", ret_get); + + dprintf("\t%s:%u: ret_get=%d (expected %d)\n", __FILE__, __LINE__, + ret_get, -1); + dprintf("\t%s:%u: errno_get=%d (expected %d)\n", __FILE__, __LINE__, + errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_MODULATOR_U32_MAX() +{ + int ret_get, errno_get; + __u32 index; + struct v4l2_modulator modulator; + + index = U32_MAX; + + memset(&modulator, 0xff, sizeof(modulator)); + modulator.index = index; + ret_get = ioctl(get_video_fd(), VIDIOC_G_MODULATOR, &modulator); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_MODULATOR, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + dprintf("\t%s:%u: ret_get=%d (expected %d)\n", __FILE__, __LINE__, + ret_get, -1); + dprintf("\t%s:%u: errno_get=%d (expected %d)\n", __FILE__, __LINE__, + errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_MODULATOR_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + struct v4l2_modulator modulator; + + memset(&modulator, 0xff, sizeof(modulator)); + modulator.index = 0; + ret_get = ioctl(get_video_fd(), VIDIOC_G_MODULATOR, &modulator); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_MODULATOR, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_MODULATOR, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_MODULATOR, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* check if VIDIOC_G_MODULATOR is supported at all or not */ + if (ret_get == 0) { + /* VIDIOC_G_MODULATOR is supported, the parameter should be checked */ + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + /* VIDIOC_G_MODULATOR not supported at all, the parameter should not be evaluated */ + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +/* TODO: test cases for VIDIOC_S_MODULATOR */ diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_MODULATOR.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_MODULATOR.h new file mode 100644 index 0000000000000000000000000000000000000000..13caca938f202318cbca00fd0e0e01bf9ab07f9f --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_MODULATOR.h @@ -0,0 +1,14 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 2 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_MODULATOR(void); +void test_VIDIOC_G_MODULATOR_S32_MAX(void); +void test_VIDIOC_G_MODULATOR_S32_MAX_1(void); +void test_VIDIOC_G_MODULATOR_U32_MAX(void); +void test_VIDIOC_G_MODULATOR_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_OUTPUT.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_OUTPUT.c new file mode 100644 index 0000000000000000000000000000000000000000..e56cb841ab0d9461431ca95737baa2a3e8eff3f7 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_OUTPUT.c @@ -0,0 +1,297 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 4 Apr 2009 0.3 Test case for NULL parameter reworked + * 29 Mar 2009 0.2 Clean up test case for NULL parameter + * 22 Mar 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_OUTPUT.h" + +int valid_output_index(int f, __u32 index) +{ + __u32 i; + struct v4l2_output output; + int ret_enum, errno_enum; + int valid = 0; + + /* Search for index with VIDIOC_ENUMOUTPUT. Do not just + * check the given index with VIDIOC_ENUMOUTPUT because + * we could miss the end of the enumeration. After the + * end of enumeration no more indexes are allowed. + */ + i = 0; + do { + memset(&output, 0xff, sizeof(output)); + output.index = i; + ret_enum = ioctl(f, VIDIOC_ENUMOUTPUT, &output); + errno_enum = errno; + if (ret_enum == 0 && index == i) { + valid = 1; + break; + } + i++; + } while (ret_enum == 0 && i != 0); + return valid; +} + +void test_VIDIOC_G_OUTPUT() +{ + int ret_get, errno_get; + __u32 index; + int f; + + f = get_video_fd(); + + memset(&index, 0xff, sizeof(index)); + ret_get = ioctl(f, VIDIOC_G_OUTPUT, &index); + errno_get = errno; + + dprintf("\tVIDIOC_G_OUTPUT, ret_get=%i, errno_get=%i\n", ret_get, + errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT(valid_output_index(f, index)); + + dprintf("\tindex=0x%X\n", index); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + +} + +void test_VIDIOC_S_OUTPUT_from_enum() +{ + int ret_get, errno_get; + int ret_set, errno_set; + int ret_enum, errno_enum; + __u32 output_index_orig; + struct v4l2_output output; + __u32 i; + int f; + + f = get_video_fd(); + + memset(&output_index_orig, 0xff, sizeof(output_index_orig)); + ret_get = ioctl(f, VIDIOC_G_OUTPUT, &output_index_orig); + errno_get = errno; + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + i = 0; + do { + memset(&output, 0xff, sizeof(output)); + output.index = i; + ret_enum = ioctl(f, VIDIOC_ENUMOUTPUT, &output); + errno_enum = errno; + + dprintf + ("\tENUMOUTPUT: i=%u, ret_enum=%i, errno_enum=%i\n", + i, ret_enum, errno_enum); + + if (ret_enum == 0) { + ret_set = + ioctl(f, VIDIOC_S_OUTPUT, &output.index); + errno_set = errno; + CU_ASSERT_EQUAL(ret_set, 0); + + dprintf + ("\toutput.index=0x%X, ret_set=%i, errno_set=%i\n", + output.index, ret_set, errno_set); + + } + i++; + } while (ret_enum == 0 && i != 0); + + /* Setting the original output_id should not fail */ + ret_set = ioctl(f, VIDIOC_S_OUTPUT, &output_index_orig); + errno_set = errno; + CU_ASSERT_EQUAL(ret_set, 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } +} + +static void do_set_output(int f, __u32 first_wrong_output, __u32 index) +{ + struct v4l2_output output; + int ret_set, errno_set; + + if (first_wrong_output <= index) { + + dprintf("\tdo_set_output(f, 0x%X, 0x%X)\n", first_wrong_output, + index); + + memset(&output, 0xff, sizeof(output)); + output.index = index; + ret_set = ioctl(f, VIDIOC_S_OUTPUT, &output.index); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + + dprintf("\toutput.index=0x%X, ret_set=%i, errno_set=%i\n", + output.index, ret_set, errno_set); + + } + +} + +void test_VIDIOC_S_OUTPUT_invalid_outputs() +{ + int ret_get, errno_get; + int ret_set, errno_set; + int ret_enum, errno_enum; + __u32 output_index_orig; + struct v4l2_output output; + __u32 i, first_wrong_output; + int f; + + f = get_video_fd(); + + memset(&output_index_orig, 0xff, sizeof(output_index_orig)); + ret_get = ioctl(f, VIDIOC_G_OUTPUT, &output_index_orig); + errno_get = errno; + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + i = 0; + do { + memset(&output, 0xff, sizeof(output)); + output.index = i; + ret_enum = ioctl(f, VIDIOC_ENUMOUTPUT, &output); + errno_enum = errno; + + dprintf + ("\tENUMOUTPUT: i=%u, ret_enum=%i, errno_enum=%i\n", + i, ret_enum, errno_enum); + + i++; + } while (ret_enum == 0 && i != 0); + + if (i != 0) { + first_wrong_output = i; + + /* The output index range 0..(i-1) are valid outputs. */ + /* Try index values from range i..U32_MAX */ + do_set_output(f, first_wrong_output, i); + do_set_output(f, first_wrong_output, i + 1); + + /* Check for signed/unsigned mismatch near S32_MAX */ + for (i = 0; i <= first_wrong_output + 1; i++) { + do_set_output(f, first_wrong_output, + ((__u32) S32_MAX) + i); + } + + i = (U32_MAX - 1) - first_wrong_output; + do { + do_set_output(f, first_wrong_output, i); + i++; + } while (i != 0); + } + + /* Setting the original output_id should not fail */ + ret_set = ioctl(f, VIDIOC_S_OUTPUT, &output_index_orig); + errno_set = errno; + CU_ASSERT_EQUAL(ret_set, 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } +} + +void test_VIDIOC_G_OUTPUT_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + __u32 index; + + memset(&index, 0xff, sizeof(index)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_OUTPUT, &index); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_OUTPUT, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_OUTPUT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_OUTPUT: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +void test_VIDIOC_S_OUTPUT_NULL() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + int ret_null, errno_null; + __u32 index_orig; + __u32 index; + + /* save the original output */ + memset(&index_orig, 0, sizeof(index_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_OUTPUT, &index_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_OUTPUT, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + + memset(&index, 0xff, sizeof(index)); + index = index_orig; + ret_set = ioctl(get_video_fd(), VIDIOC_S_OUTPUT, &index); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_OUTPUT ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + ret_null = ioctl(get_video_fd(), VIDIOC_S_OUTPUT, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_S_OUTPUT: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_OUTPUT.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_OUTPUT.h new file mode 100644 index 0000000000000000000000000000000000000000..02154b70fd119b815dbc344d1cae144aaec46b49 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_OUTPUT.h @@ -0,0 +1,16 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_OUTPUT(void); +void test_VIDIOC_S_OUTPUT_from_enum(void); +void test_VIDIOC_S_OUTPUT_invalid_outputs(void); + +void test_VIDIOC_G_OUTPUT_NULL(void); +void test_VIDIOC_S_OUTPUT_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PARM.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PARM.c new file mode 100644 index 0000000000000000000000000000000000000000..fbf3a670ba29e566afe01b0abaec9b16f19ee272 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PARM.c @@ -0,0 +1,328 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 29 Mar 2009 0.2 Comments updated + * 18 Mar 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_PARM.h" + +int valid_v4l2_captureparm_capability(__u32 capability) +{ + int valid = 0; + + if ((capability & ~(V4L2_CAP_TIMEPERFRAME)) == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +int valid_v4l2_outputparm_capability(__u32 capability) +{ + int valid = 0; + + if ((capability & ~(V4L2_CAP_TIMEPERFRAME)) == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +int valid_v4l2_captureparm_capturemode(__u32 capturemode) +{ + int valid = 0; + + if ((capturemode & ~(V4L2_MODE_HIGHQUALITY)) == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +int valid_v4l2_outputparm_outputpmode(__u32 outputmode) +{ + int valid = 0; + + if ((outputmode & ~(V4L2_MODE_HIGHQUALITY)) == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +static void do_get_param(enum v4l2_buf_type type) +{ + int ret_get, errno_get; + struct v4l2_streamparm parm; + struct v4l2_streamparm parm2; + + memset(&parm, 0xff, sizeof(parm)); + parm.type = type; + ret_get = ioctl(get_video_fd(), VIDIOC_G_PARM, &parm); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_PARM, type=%i, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, type, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(parm.type, type); + + switch (parm.type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + dprintf("\t%s:%u: { .type=%i, parm.capture = { " + ".capability = 0x%X, " + ".capturemode = 0x%X, " + ".timeperframe = { .numerator = %u, .denominator = %u }, " + ".extendedmode = %u, " + ".readbuffers = %u, " + "reserved[] = { 0x%X, 0x%X, 0x%X, 0x%X }}}\n", + __FILE__, __LINE__, + parm.type, + parm.parm.capture.capability, + parm.parm.capture.capturemode, + parm.parm.capture.timeperframe.numerator, + parm.parm.capture.timeperframe.denominator, + parm.parm.capture.extendedmode, + parm.parm.capture.readbuffers, + parm.parm.capture.reserved[0], + parm.parm.capture.reserved[1], + parm.parm.capture.reserved[2], + parm.parm.capture.reserved[3] + ); + + CU_ASSERT(valid_v4l2_captureparm_capability + (parm.parm.capture.capability)); + CU_ASSERT(valid_v4l2_captureparm_capturemode + (parm.parm.capture.capturemode)); + + if (parm.parm.capture. + capability & V4L2_CAP_TIMEPERFRAME) { + //CU_ASSERT_EQUAL(parm.parm.capture.timeperframe.numerator, ???); + //CU_ASSERT_EQUAL(parm.parm.capture.timeperframe.denominator, ???); + CU_ASSERT(parm.parm.capture.timeperframe. + denominator != 0); + // TODO: timerperframe: check struct v4l2_standard frameperiod field + } else { + //CU_ASSERT_EQUAL(parm.parm.capture.timeperframe.numerator, 0); + //CU_ASSERT_EQUAL(parm.parm.capture.timeperframe.denominator, 0); + CU_ASSERT(parm.parm.output.timeperframe. + denominator != 0); + } + + //CU_ASSERT_EQUAL(parm.parm.capture.extendedmode, ???); + //CU_ASSERT_EQUAL(parm.parm.capture.readbuffers, ???); + + CU_ASSERT_EQUAL(parm.parm.capture.reserved[0], 0); + CU_ASSERT_EQUAL(parm.parm.capture.reserved[1], 0); + CU_ASSERT_EQUAL(parm.parm.capture.reserved[2], 0); + CU_ASSERT_EQUAL(parm.parm.capture.reserved[3], 0); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + dprintf("\t%s:%u: { .type=%i, parm.output = { " + ".capability = 0x%X, " + ".outputmode = 0x%X, " + ".timeperframe = { .numerator = %u, .denominator = %u }, " + ".extendedmode = %u, " + ".writebuffers = %u, " + "reserved[] = { 0x%X, 0x%X, 0x%X, 0x%X }}}\n", + __FILE__, __LINE__, + parm.type, + parm.parm.output.capability, + parm.parm.output.outputmode, + parm.parm.output.timeperframe.numerator, + parm.parm.output.timeperframe.denominator, + parm.parm.output.extendedmode, + parm.parm.output.writebuffers, + parm.parm.output.reserved[0], + parm.parm.output.reserved[1], + parm.parm.output.reserved[2], + parm.parm.output.reserved[3] + ); + + CU_ASSERT(valid_v4l2_outputparm_capability + (parm.parm.output.capability)); + CU_ASSERT(valid_v4l2_outputparm_outputpmode + (parm.parm.output.outputmode)); + + if (parm.parm.output.capability & V4L2_CAP_TIMEPERFRAME) { + //CU_ASSERT_EQUAL(parm.parm.output.timeperframe.numerator, ???); + //CU_ASSERT_EQUAL(parm.parm.output.timeperframe.denominator, ???); + CU_ASSERT(parm.parm.output.timeperframe. + denominator != 0); + // TODO: timerperframe: check struct v4l2_standard frameperiod field + } else { + //CU_ASSERT_EQUAL(parm.parm.output.timeperframe.numerator, 0); + //CU_ASSERT_EQUAL(parm.parm.output.timeperframe.denominator, 0); + CU_ASSERT(parm.parm.output.timeperframe. + denominator != 0); + } + + //CU_ASSERT_EQUAL(parm.parm.output.extendedmode, ???); + //CU_ASSERT_EQUAL(parm.parm.output.writebuffers, ???); + + CU_ASSERT_EQUAL(parm.parm.output.reserved[0], 0); + CU_ASSERT_EQUAL(parm.parm.output.reserved[1], 0); + CU_ASSERT_EQUAL(parm.parm.output.reserved[2], 0); + CU_ASSERT_EQUAL(parm.parm.output.reserved[3], 0); + break; + default: + ; + } + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + /* check whether the parm structure is untouched */ + memset(&parm2, 0xff, sizeof(parm2)); + parm2.type = type; + + CU_ASSERT_EQUAL(memcmp(&parm, &parm2, sizeof(parm)), 0); + + } + +} + +void test_VIDIOC_G_PARM() +{ + do_get_param(V4L2_BUF_TYPE_VIDEO_CAPTURE); + do_get_param(V4L2_BUF_TYPE_VIDEO_OUTPUT); + do_get_param(V4L2_BUF_TYPE_PRIVATE); +} + +static void do_get_param_invalid(enum v4l2_buf_type type) +{ + int ret_get, errno_get; + struct v4l2_streamparm parm; + struct v4l2_streamparm parm2; + + memset(&parm, 0xff, sizeof(parm)); + parm.type = type; + ret_get = ioctl(get_video_fd(), VIDIOC_G_PARM, &parm); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_PARM, type=%i, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, type, ret_get, errno_get); + + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + /* check whether the parm structure is untouched */ + memset(&parm2, 0xff, sizeof(parm2)); + parm2.type = type; + + CU_ASSERT_EQUAL(memcmp(&parm, &parm2, sizeof(parm)), 0); +} + +void test_VIDIOC_G_PARM_invalid() +{ + do_get_param_invalid(S32_MIN); + + /* check if 0x80000001 is not treated as 1 (V4L2_BUF_TYPE_VIDEO_CAPTURE) */ + do_get_param_invalid(S32_MIN + 1); + + /* check if 0x80000002 is not treated as 2 (V4L2_BUF_TYPE_VIDEO_OUTPUT) */ + do_get_param_invalid(S32_MIN + 2); + + do_get_param_invalid(S16_MIN); + do_get_param_invalid(0); + do_get_param_invalid(V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_get_param_invalid(V4L2_BUF_TYPE_VBI_CAPTURE); + do_get_param_invalid(V4L2_BUF_TYPE_VBI_OUTPUT); + do_get_param_invalid(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_get_param_invalid(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); + do_get_param_invalid(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_get_param_invalid(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY + 1); + do_get_param_invalid(V4L2_BUF_TYPE_PRIVATE - 1); + do_get_param_invalid(S16_MAX); + do_get_param_invalid(S32_MAX); +} + +void test_VIDIOC_G_PARM_NULL() +{ + int ret_capture, errno_capture; + int ret_output, errno_output; + int ret_private, errno_private; + int ret_null, errno_null; + enum v4l2_buf_type type; + struct v4l2_streamparm parm; + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + memset(&parm, 0, sizeof(parm)); + parm.type = type; + ret_capture = ioctl(get_video_fd(), VIDIOC_G_PARM, &parm); + errno_capture = errno; + dprintf + ("\t%s:%u: VIDIOC_G_PARM, type=%i, ret_capture=%i, errno_capture=%i\n", + __FILE__, __LINE__, type, ret_capture, errno_capture); + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + memset(&parm, 0, sizeof(parm)); + parm.type = type; + ret_output = ioctl(get_video_fd(), VIDIOC_G_PARM, &parm); + errno_output = errno; + dprintf + ("\t%s:%u: VIDIOC_G_PARM, type=%i, ret_output=%i, errno_output=%i\n", + __FILE__, __LINE__, type, ret_output, errno_output); + + type = V4L2_BUF_TYPE_PRIVATE; + memset(&parm, 0, sizeof(parm)); + parm.type = type; + ret_private = ioctl(get_video_fd(), VIDIOC_G_PARM, &parm); + errno_private = errno; + dprintf + ("\t%s:%u: VIDIOC_G_PARM, type=%i, ret_private=%i, errno_private=%i\n", + __FILE__, __LINE__, type, ret_private, errno_private); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_PARM, NULL); + errno_null = errno; + dprintf("\t%s:%u: VIDIOC_G_PARM, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_capture == 0 || ret_output == 0 || ret_private == 0) { + /* if at least one type is supported, then the + * parameter shall be tested and the result shall be EFAULT + */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_capture, -1); + CU_ASSERT_EQUAL(errno_capture, EINVAL); + CU_ASSERT_EQUAL(ret_output, -1); + CU_ASSERT_EQUAL(errno_output, EINVAL); + CU_ASSERT_EQUAL(ret_private, -1); + CU_ASSERT_EQUAL(errno_private, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +/* TODO: test cases for VIDIOC_S_PARM */ diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PARM.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PARM.h new file mode 100644 index 0000000000000000000000000000000000000000..98d58b544ee8d139b046afda4ffce3c1e9e29f86 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PARM.h @@ -0,0 +1,12 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 18 Mar 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_PARM(void); +void test_VIDIOC_G_PARM_invalid(void); +void test_VIDIOC_G_PARM_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PRIORITY.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PRIORITY.c new file mode 100644 index 0000000000000000000000000000000000000000..47947ac94d961f267ed534dc1e5babd5dd213530 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PRIORITY.c @@ -0,0 +1,280 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 4 Apr 2009 0.3 Test case for NULL parameter reworked + * 27 Mar 2009 0.2 Correct VIDIOC_S_PRIORITY test cases + * Clean up ret and errno variable names and dprintf() output + * 2 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_PRIORITY.h" + +int valid_priority(enum v4l2_priority priority) +{ + int valid = 0; + + CU_ASSERT_EQUAL(V4L2_PRIORITY_DEFAULT, V4L2_PRIORITY_INTERACTIVE); + + switch (priority) { + case V4L2_PRIORITY_UNSET: + case V4L2_PRIORITY_BACKGROUND: + case V4L2_PRIORITY_INTERACTIVE: + case V4L2_PRIORITY_RECORD: + valid = 1; + break; + default: + valid = 0; + } + return valid; +} + +static void do_set_priority(enum v4l2_priority priority) +{ + int ret_set, errno_set; + int ret_get, errno_get; + enum v4l2_priority new_priority; + + dprintf("\t%s:%u: set priority to %i\n", __FILE__, __LINE__, priority); + ret_set = ioctl(get_video_fd(), VIDIOC_S_PRIORITY, &priority); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_PRIORITY, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, 0); + if (ret_set == 0) { + memset(&new_priority, 0xff, sizeof(new_priority)); + ret_get = + ioctl(get_video_fd(), VIDIOC_G_PRIORITY, &new_priority); + errno_get = errno; + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT_EQUAL(new_priority, priority); + } + } +} + +static void do_set_invalid_priority(enum v4l2_priority orig_priority, + enum v4l2_priority priority) +{ + int ret_set, errno_set; + int ret_get, errno_get; + enum v4l2_priority new_priority; + + dprintf("\t%s:%u: try to set priority to %i\n", __FILE__, __LINE__, + priority); + ret_set = ioctl(get_video_fd(), VIDIOC_S_PRIORITY, &priority); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_PRIORITY, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + if (ret_set == -1 && errno_set == EINVAL) { + memset(&new_priority, 0xff, sizeof(new_priority)); + ret_get = + ioctl(get_video_fd(), VIDIOC_G_PRIORITY, &new_priority); + errno_get = errno; + + CU_ASSERT_EQUAL(ret_get, 0); + if (ret_get == 0) { + CU_ASSERT_EQUAL(new_priority, orig_priority); + } + } +} + +void test_VIDIOC_G_PRIORITY() +{ + int ret_get, errno_get; + enum v4l2_priority orig_priority; + + memset(&orig_priority, 0xff, sizeof(orig_priority)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_PRIORITY, &orig_priority); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_PRIORITY, ret_get=%i, errno_get=%i, orig_priority=%i\n", + __FILE__, __LINE__, ret_get, errno_get, orig_priority); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT(valid_priority(orig_priority)); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + } + +} + +void test_VIDIOC_G_PRIORITY_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + enum v4l2_priority priority; + + memset(&priority, 0xff, sizeof(priority)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_PRIORITY, &priority); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_PRIORITY: ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_PRIORITY, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_PRIORITY: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* check if VIDIOC_G_PRIORITY is supported at all or not */ + if (ret_get == -1 && errno_get == EINVAL) { + /* VIDIOC_G_PRIORITY not supported at all, the parameter should not be evaluated */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + + } else { + /* VIDIOC_G_PRIORITY is supported, the parameter should be checked */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } +} + +void test_VIDIOC_S_PRIORITY() +{ + int ret_get, errno_get; + enum v4l2_priority orig_priority; + + memset(&orig_priority, 0xff, sizeof(orig_priority)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_PRIORITY, &orig_priority); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_PRIORITY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT(valid_priority(orig_priority)); + + dprintf("\torig_priority = %u\n", orig_priority); + + do_set_priority(V4L2_PRIORITY_UNSET); + do_set_priority(V4L2_PRIORITY_BACKGROUND); + do_set_priority(V4L2_PRIORITY_INTERACTIVE); + do_set_priority(V4L2_PRIORITY_RECORD); + + CU_ASSERT_EQUAL(V4L2_PRIORITY_DEFAULT, + V4L2_PRIORITY_INTERACTIVE); + + do_set_priority(orig_priority); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + } +} + +void test_VIDIOC_S_PRIORITY_invalid() +{ + int ret_get, errno_get; + enum v4l2_priority orig_priority; + + memset(&orig_priority, 0xff, sizeof(orig_priority)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_PRIORITY, &orig_priority); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_PRIORITY, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT(valid_priority(orig_priority)); + + dprintf("\torig_priority = %u\n", orig_priority); + + do_set_invalid_priority(orig_priority, 4); + do_set_invalid_priority(orig_priority, S32_MAX); + do_set_invalid_priority(orig_priority, ((__u32) S32_MAX) + 1); + do_set_invalid_priority(orig_priority, U32_MAX); + + do_set_priority(orig_priority); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + } +} + +void test_VIDIOC_S_PRIORITY_NULL() +{ + int ret_orig, errno_orig; + int ret_set, errno_set; + int ret_null, errno_null; + enum v4l2_priority priority_orig; + enum v4l2_priority priority; + + memset(&priority_orig, 0, sizeof(priority_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_PRIORITY, &priority_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_PRIORITY, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + + if (ret_orig == 0) { + priority = priority_orig; + } else { + priority = V4L2_PRIORITY_DEFAULT; + } + + ret_set = ioctl(get_video_fd(), VIDIOC_S_PRIORITY, &priority); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_PRIORITY, ret_set=%d, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + ret_null = ioctl(get_video_fd(), VIDIOC_S_PRIORITY, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_S_PRIORITY, ret_null=%d, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* check if VIDIOC_S_PRIORITY is supported at all or not */ + if (ret_set == 0) { + /* VIDIOC_S_PRIORITY is supported, the parameter should be checked */ + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + /* VIDIOC_S_PRIORITY not supported at all, the parameter should not be evaluated */ + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PRIORITY.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PRIORITY.h new file mode 100644 index 0000000000000000000000000000000000000000..db933cfb1c4dec72e2c4b1adeee5dcde16d709ca --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_PRIORITY.h @@ -0,0 +1,14 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 2 Feb 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_PRIORITY(void); +void test_VIDIOC_G_PRIORITY_NULL(void); +void test_VIDIOC_S_PRIORITY(void); +void test_VIDIOC_S_PRIORITY_invalid(void); +void test_VIDIOC_S_PRIORITY_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYBUF.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYBUF.c new file mode 100644 index 0000000000000000000000000000000000000000..313f4b728a0660109965c9f8e68df7dd6b42cfc5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYBUF.c @@ -0,0 +1,506 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 5 May 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "v4l2_show.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_REQBUFS.h" + +static void do_VIDIOC_QUERYBUF(enum v4l2_memory memory, + enum v4l2_buf_type type, __u32 count, + int expected_ret_req) +{ + int ret_req, errno_req; + int ret_query, errno_query; + struct v4l2_requestbuffers reqbuf; + struct v4l2_buffer buf; + __u32 i; + unsigned int j; + const enum v4l2_buf_type buffer_types[] = { + 0, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_BUF_TYPE_VIDEO_OVERLAY, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_BUF_TYPE_VBI_OUTPUT, + V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, + V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, + V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + V4L2_BUF_TYPE_PRIVATE - 1, + V4L2_BUF_TYPE_PRIVATE, + V4L2_BUF_TYPE_PRIVATE + 1, + S32_MAX, + (__s32) ((__u32) S32_MAX + 1), + U32_MAX - 1, + U32_MAX + }; + + memset(&reqbuf, 0, sizeof(reqbuf)); + reqbuf.count = count; + reqbuf.type = type; + reqbuf.memory = memory; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + if (expected_ret_req == 0) { + CU_ASSERT_EQUAL(ret_req, 0); + } else { + CU_ASSERT_EQUAL(ret_req, -1); + CU_ASSERT_EQUAL(errno_req, EINVAL); + } + + dprintf + ("\t%s:%u: VIDIOC_REQBUF, count=%u, type=%i, memory=%i, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, count, type, memory, ret_req, errno_req); + + if (ret_req == 0) { + show_v4l2_requestbuffers(&reqbuf); + } + + if (ret_req != 0) { + reqbuf.count = 0; + } + + for (i = 0; i < reqbuf.count; i++) { + memset(&buf, 0xff, sizeof(buf)); + buf.type = type; + buf.index = i; + + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYBUF, &buf); + errno_query = errno; + + CU_ASSERT_EQUAL(buf.index, i); + CU_ASSERT_EQUAL(buf.type, type); + //CU_ASSERT_EQUAL(buf.bytesused, ???); + CU_ASSERT_EQUAL(buf. + flags & ~(V4L2_BUF_FLAG_MAPPED | + V4L2_BUF_FLAG_QUEUED | + V4L2_BUF_FLAG_DONE), 0); + //CU_ASSERT_EQUAL(buf.field, ???); + //CU_ASSERT_EQUAL(buf.timestamp.tv_sec, ???); + //CU_ASSERT_EQUAL(buf.timestamp.tv_usec, ???); + //CU_ASSERT_EQUAL(buf.timecode.type, ???); + //CU_ASSERT_EQUAL(buf.timecode.flags, ???); + //CU_ASSERT_EQUAL(buf.timecode.frames, ???); + //CU_ASSERT_EQUAL(buf.timecode.seconds, ???); + //CU_ASSERT_EQUAL(buf.timecode.minutes, ???); + //CU_ASSERT_EQUAL(buf.timecode.hours, ???); + //CU_ASSERT_EQUAL(buf.timecode.userbits[0], ???); + //CU_ASSERT_EQUAL(buf.timecode.userbits[1], ???); + //CU_ASSERT_EQUAL(buf.timecode.userbits[2], ???); + //CU_ASSERT_EQUAL(buf.timecode.userbits[3], ???); + //CU_ASSERT_EQUAL(buf.sequence, ???); + CU_ASSERT_EQUAL(buf.memory, memory); + //CU_ASSERT_EQUAL(buf.m.userptr, ???); + //CU_ASSERT_EQUAL(buf.m.offset, ???); + CU_ASSERT(0 < buf.length); + //CU_ASSERT_EQUAL(buf.input, ???); + CU_ASSERT_EQUAL(buf.reserved, 0); + + dprintf + ("\t%s:%u: VIDIOC_QUERYBUF, type=%i, index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, buf.type, buf.index, ret_query, + errno_query); + if (ret_query == 0) + show_v4l2_buffer(&buf); + + } + + /* Check for not buffer types which do not match the VIDIOC_REQBUF + * buffer type + */ + for (i = 0; i < reqbuf.count; i++) { + for (j = 0; j < sizeof(buffer_types) / sizeof(*buffer_types); + j++) { + if (buffer_types[j] != type) { + memset(&buf, 0xff, sizeof(buf)); + buf.type = buffer_types[j]; + buf.index = i; + + ret_query = + ioctl(get_video_fd(), VIDIOC_QUERYBUF, + &buf); + errno_query = errno; + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + dprintf + ("\t%s:%u: VIDIOC_QUERYBUF, type=%i, index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, buf.type, buf.index, + ret_query, errno_query); + if (ret_query == 0) + show_v4l2_buffer(&buf); + } + } + } + + memset(&buf, 0xff, sizeof(buf)); + buf.type = type; + buf.index = reqbuf.count; + + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYBUF, &buf); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYBUF, type=%i, index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, buf.type, buf.index, ret_query, errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + if (reqbuf.count < (__u32) S16_MIN) { + memset(&buf, 0xff, sizeof(buf)); + buf.type = type; + buf.index = (__u32) S16_MIN; + + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYBUF, &buf); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYBUF, type=%i, index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, buf.type, buf.index, ret_query, + errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + + if (reqbuf.count < (__u32) S16_MAX) { + memset(&buf, 0xff, sizeof(buf)); + buf.type = type; + buf.index = (__u32) S16_MAX; + + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYBUF, &buf); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYBUF, type=%i, index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, buf.type, buf.index, ret_query, + errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + + if (reqbuf.count < U32_MAX) { + memset(&buf, 0xff, sizeof(buf)); + buf.type = type; + buf.index = U32_MAX; + + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYBUF, &buf); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYBUF, type=%i, index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, buf.type, buf.index, ret_query, + errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + + memset(&reqbuf, 0, sizeof(reqbuf)); + reqbuf.count = 0; + reqbuf.type = type; + reqbuf.memory = V4L2_MEMORY_MMAP; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf("\t%s:%u: VIDIOC_REQBUF, count=%u, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, count, ret_req, errno_req); + + if (expected_ret_req == 0) { + CU_ASSERT_EQUAL(ret_req, 0); + } else { + CU_ASSERT_EQUAL(ret_req, -1); + CU_ASSERT_EQUAL(errno_req, EINVAL); + } + if (ret_req == 0) { + show_v4l2_requestbuffers(&reqbuf); + } +} + +void test_VIDIOC_QUERYBUF_capture_mmap() +{ + int ret_cap, errno_cap; + struct v4l2_capability cap; + int expected_ret_req; + + memset(&cap, 0, sizeof(cap)); + + ret_cap = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + errno_cap = errno; + + if (ret_cap == 0 && + (cap.capabilities & V4L2_CAP_STREAMING) && + (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + expected_ret_req = 0; + } else { + expected_ret_req = -1; + } + + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_CAPTURE, 1, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_CAPTURE, 3, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_CAPTURE, 4, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_CAPTURE, + (__u32) S16_MIN, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_CAPTURE, + (__u32) S16_MAX, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_CAPTURE, + U32_MAX, expected_ret_req); +} + +void test_VIDIOC_QUERYBUF_capture_userptr() +{ + int ret_cap, errno_cap; + int ret_req, errno_req; + struct v4l2_capability cap; + struct v4l2_requestbuffers reqbuf; + int expected_ret_req; + + memset(&cap, 0, sizeof(cap)); + + ret_cap = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + errno_cap = errno; + + memset(&reqbuf, 0, sizeof(reqbuf)); + reqbuf.count = 2; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf.memory = V4L2_MEMORY_USERPTR; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf("\t%s:%u: VIDIOC_REQBUF, count=%u, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, reqbuf.count, ret_req, errno_req); + + if (ret_cap == 0 && + (cap.capabilities & V4L2_CAP_STREAMING) && + (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && ret_req == 0) { + expected_ret_req = 0; + } else { + expected_ret_req = -1; + } + + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, 1, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, 3, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, 4, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, + (__u32) S16_MIN, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, + (__u32) S16_MAX, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, + U32_MAX, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, + expected_ret_req); +} + +void test_VIDIOC_QUERYBUF_output_mmap() +{ + int ret_cap, errno_cap; + struct v4l2_capability cap; + int expected_ret_req; + + memset(&cap, 0, sizeof(cap)); + + ret_cap = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + errno_cap = errno; + + if (ret_cap == 0 && + (cap.capabilities & V4L2_CAP_STREAMING) && + (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { + expected_ret_req = 0; + } else { + expected_ret_req = -1; + } + + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, 1, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, 3, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, 4, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, + (__u32) S16_MIN, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, + (__u32) S16_MAX, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, + U32_MAX, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0, + expected_ret_req); +} + +void test_VIDIOC_QUERYBUF_output_userptr() +{ + int ret_cap, errno_cap; + int ret_req, errno_req; + struct v4l2_capability cap; + struct v4l2_requestbuffers reqbuf; + int expected_ret_req; + + memset(&cap, 0, sizeof(cap)); + + ret_cap = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + errno_cap = errno; + + memset(&reqbuf, 0, sizeof(reqbuf)); + reqbuf.count = 2; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + reqbuf.memory = V4L2_MEMORY_USERPTR; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf("\t%s:%u: VIDIOC_REQBUF, count=%u, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, reqbuf.count, ret_req, errno_req); + + if (ret_cap == 0 && + (cap.capabilities & V4L2_CAP_STREAMING) && + (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) && ret_req == 0) { + expected_ret_req = 0; + } else { + expected_ret_req = -1; + } + + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, 1, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, 3, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, 4, + expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, + (__u32) S16_MIN, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, + (__u32) S16_MAX, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, + U32_MAX, expected_ret_req); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0, + expected_ret_req); +} + +void test_VIDIOC_QUERYBUF_overlay_capture() +{ + do_VIDIOC_QUERYBUF(V4L2_MEMORY_OVERLAY, V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, + -1); +} + +void test_VIDIOC_QUERYBUF_overlay_output() +{ + do_VIDIOC_QUERYBUF(V4L2_MEMORY_OVERLAY, V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, + -1); +} + +void test_VIDIOC_QUERYBUF_invalid_memory_capture() +{ + do_VIDIOC_QUERYBUF(SINT_MIN, V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, -1); + do_VIDIOC_QUERYBUF(0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_OVERLAY + 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, + 2, -1); + do_VIDIOC_QUERYBUF(SINT_MAX, V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, -1); +} + +void test_VIDIOC_QUERYBUF_invalid_memory_output() +{ + do_VIDIOC_QUERYBUF(SINT_MIN, V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, -1); + do_VIDIOC_QUERYBUF(0, V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_OVERLAY + 1, V4L2_BUF_TYPE_VIDEO_OUTPUT, + 2, -1); + do_VIDIOC_QUERYBUF(SINT_MAX, V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, -1); +} + +void test_VIDIOC_QUERYBUF_invalid_type_mmap() +{ + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, 0, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OVERLAY, 2, + -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VBI_CAPTURE, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VBI_OUTPUT, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, + 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, 2, + -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_PRIVATE - 1, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_PRIVATE, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_PRIVATE + 1, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, S32_MAX, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, (__s32) ((__u32) S32_MAX + 1), 2, + -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, U32_MAX - 1, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_MMAP, U32_MAX, 2, -1); +} + +void test_VIDIOC_QUERYBUF_invalid_type_userptr() +{ + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, 0, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VIDEO_OVERLAY, 2, + -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VBI_CAPTURE, 2, + -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_VBI_OUTPUT, 2, + -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, + 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_PRIVATE - 1, 2, + -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_PRIVATE, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, V4L2_BUF_TYPE_PRIVATE + 1, 2, + -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, S32_MAX, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, (__s32) ((__u32) S32_MAX + 1), + 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, U32_MAX - 1, 2, -1); + do_VIDIOC_QUERYBUF(V4L2_MEMORY_USERPTR, U32_MAX, 2, -1); +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYBUF.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYBUF.h new file mode 100644 index 0000000000000000000000000000000000000000..13426a6d7e44346f2b7cbfd4a09108a40546a639 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYBUF.h @@ -0,0 +1,19 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 5 May 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_QUERYBUF_capture_mmap(void); +void test_VIDIOC_QUERYBUF_capture_userptr(void); +void test_VIDIOC_QUERYBUF_output_mmap(void); +void test_VIDIOC_QUERYBUF_output_userptr(void); +void test_VIDIOC_QUERYBUF_overlay_capture(void); +void test_VIDIOC_QUERYBUF_overlay_output(void); +void test_VIDIOC_QUERYBUF_invalid_memory_capture(void); +void test_VIDIOC_QUERYBUF_invalid_memory_output(void); +void test_VIDIOC_QUERYBUF_invalid_type_mmap(void); +void test_VIDIOC_QUERYBUF_invalid_type_userptr(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCAP.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCAP.c new file mode 100644 index 0000000000000000000000000000000000000000..58cac0ce2149d62ba021c4ba7a4846c470dfd8de --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCAP.c @@ -0,0 +1,145 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.5 Added string content validation + * 18 Apr 2009 0.4 More strict check for strings + * 29 Mar 2009 0.3 Clean up ret and errno variable names and dprintf() output + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_QUERYCAP.h" + +int valid_capabilities(__u32 capabilities) +{ + int valid = 1; + + if ((capabilities & ~(V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VBI_OUTPUT | + V4L2_CAP_SLICED_VBI_CAPTURE | + V4L2_CAP_SLICED_VBI_OUTPUT | + V4L2_CAP_RDS_CAPTURE | + V4L2_CAP_VIDEO_OUTPUT_OVERLAY | + V4L2_CAP_TUNER | + V4L2_CAP_AUDIO | + V4L2_CAP_RADIO | + V4L2_CAP_READWRITE | + V4L2_CAP_ASYNCIO | V4L2_CAP_STREAMING)) != 0) { + valid = 0; + } + + return valid; +} + +void test_VIDIOC_QUERYCAP() +{ + int ret; + struct v4l2_capability cap; + struct v4l2_capability cap2; + + memset(&cap, 0xff, sizeof(cap)); + + ret = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + + dprintf("VIDIOC_QUERYCAP, ret=%i\n", ret); + dprintf("\tcap = { .driver = \"%s\", .card = \"%s\", " + ".bus_info = \"%s\", " + ".version = %u.%u.%u, " + ".capabilities = 0x%X, " + ".reserved[]={ 0x%X, 0x%X, 0x%X, 0x%X } }\n", + cap.driver, + cap.card, + cap.bus_info, + (cap.version >> 16) & 0xFF, + (cap.version >> 8) & 0xFF, + cap.version & 0xFF, + cap.capabilities, + cap.reserved[0], + cap.reserved[1], cap.reserved[2], cap.reserved[3] + ); + + /* This ioctl must be implemented by ALL drivers */ + CU_ASSERT_EQUAL(ret, 0); + if (ret == 0) { + CU_ASSERT(0 < strlen((char *)cap.driver)); + CU_ASSERT(valid_string((char *)cap.driver, sizeof(cap.driver))); + + CU_ASSERT(0 < strlen((char *)cap.card)); + CU_ASSERT(valid_string((char *)cap.card, sizeof(cap.card))); + + /* cap.bus_info is allowed to be an empty string ("") if no + * is info available + */ + CU_ASSERT(valid_string + ((char *)cap.bus_info, sizeof(cap.bus_info))); + + //CU_ASSERT_EQUAL(cap.version, ?); + CU_ASSERT(valid_capabilities(cap.capabilities)); + + CU_ASSERT_EQUAL(cap.reserved[0], 0); + CU_ASSERT_EQUAL(cap.reserved[1], 0); + CU_ASSERT_EQUAL(cap.reserved[2], 0); + CU_ASSERT_EQUAL(cap.reserved[3], 0); + + /* Check if the unused bytes of the driver, card and bus_info + * strings are also filled with zeros. Also check if there is + * any padding byte between any two fields then this padding + * byte is also filled with zeros. + */ + memset(&cap2, 0, sizeof(cap2)); + strncpy((char *)cap2.driver, (char *)cap.driver, + sizeof(cap2.driver)); + strncpy((char *)cap2.card, (char *)cap.card, sizeof(cap2.card)); + strncpy((char *)cap2.bus_info, (char *)cap.bus_info, + sizeof(cap2.bus_info)); + cap2.version = cap.version; + cap2.capabilities = cap.capabilities; + CU_ASSERT_EQUAL(memcmp(&cap, &cap2, sizeof(cap)), 0); + + } + +} + +void test_VIDIOC_QUERYCAP_NULL() +{ + int ret_null, errno_null; + + ret_null = ioctl(get_video_fd(), VIDIOC_QUERYCAP, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_QUERYCAP, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* VIDIOC_QUERYCAP is a mandatory command, all drivers shall + * support it. The parameter shall be always tested. + */ + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCAP.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCAP.h new file mode 100644 index 0000000000000000000000000000000000000000..314be04c01752be010806835b63dc39cdd3531c5 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCAP.h @@ -0,0 +1,12 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_QUERYCAP(void); +void test_VIDIOC_QUERYCAP_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCTRL.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCTRL.c new file mode 100644 index 0000000000000000000000000000000000000000..8ee703e67554962977f3ef68e399049b1e809b2e --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCTRL.c @@ -0,0 +1,712 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.4 Added string content validation + * 18 Apr 2009 0.3 More strict check for strings + * 28 Mar 2009 0.2 Clean up ret and errno variable names and dprintf() output + * 2 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +/* + * Note: V4L2_CID_LASTP1 != V4L2_CID_BASE_LASTP1 + */ + +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_QUERYCTRL.h" + +static int valid_control_flag(__u32 flags) +{ + int valid = 0; + + if ((flags & ~(V4L2_CTRL_FLAG_DISABLED | + V4L2_CTRL_FLAG_GRABBED | + V4L2_CTRL_FLAG_READ_ONLY | + V4L2_CTRL_FLAG_UPDATE | + V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_SLIDER)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +static int valid_control_type(__u32 type) +{ + int valid = 0; + + switch (type) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_INTEGER64: + case V4L2_CTRL_TYPE_CTRL_CLASS: + valid = 1; + break; + default: + valid = 0; + } + return valid; +} + +void test_VIDIOC_QUERYCTRL() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + struct v4l2_queryctrl queryctrl2; + __u32 i; + + /* The available controls and their parameters + * may change with different + * - input or output + * - tuner or modulator + * - audio input or audio output + * See V4L API specification rev. 0.24, Chapter 1.8. + * "User Controls" for details + * + * TODO: iterate through the mentioned settings. + * TODO: check for deprecated controls (maybe in a + * separated test case which could fail when a + * deprecated control is supported) + */ + + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_BASE, ret_query, + errno_query); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + CU_ASSERT_EQUAL(queryctrl.id, i); + + CU_ASSERT(0 < strlen((char *)queryctrl.name)); + CU_ASSERT(valid_string + ((char *)queryctrl.name, + sizeof(queryctrl.name))); + + CU_ASSERT(valid_control_type(queryctrl.type)); + + switch (queryctrl.type) { + case V4L2_CTRL_TYPE_INTEGER: + /* min < max, because otherwise this control makes no sense */ + CU_ASSERT(queryctrl.minimum < + queryctrl.maximum); + + CU_ASSERT(0 < queryctrl.step); + + CU_ASSERT(queryctrl.minimum <= + queryctrl.default_value); + CU_ASSERT(queryctrl.default_value <= + queryctrl.maximum); + break; + + case V4L2_CTRL_TYPE_BOOLEAN: + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT_EQUAL(queryctrl.maximum, 1); + CU_ASSERT_EQUAL(queryctrl.step, 1); + CU_ASSERT((queryctrl.default_value == 0) + || (queryctrl.default_value == 1)); + break; + + case V4L2_CTRL_TYPE_MENU: + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT(queryctrl.minimum <= + queryctrl.default_value); + CU_ASSERT_EQUAL(queryctrl.step, 1); + CU_ASSERT(queryctrl.minimum <= + queryctrl.default_value); + CU_ASSERT(queryctrl.default_value <= + queryctrl.maximum); + break; + + case V4L2_CTRL_TYPE_BUTTON: + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT_EQUAL(queryctrl.maximum, 0); + CU_ASSERT_EQUAL(queryctrl.step, 0); + CU_ASSERT_EQUAL(queryctrl.default_value, 0); + break; + + case V4L2_CTRL_TYPE_INTEGER64: /* fallthrough */ + case V4L2_CTRL_TYPE_CTRL_CLASS: + /* These parameters are defined as n/a by V4L2, so + * they should be filled with zeros, the same like + * the reserved fields. + */ + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT_EQUAL(queryctrl.maximum, 0); + CU_ASSERT_EQUAL(queryctrl.step, 0); + CU_ASSERT_EQUAL(queryctrl.default_value, 0); + break; + + default: + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT_EQUAL(queryctrl.maximum, 0); + CU_ASSERT_EQUAL(queryctrl.step, 0); + CU_ASSERT_EQUAL(queryctrl.default_value, 0); + } + + CU_ASSERT(valid_control_flag(queryctrl.flags)); + + CU_ASSERT_EQUAL(queryctrl.reserved[0], 0); + CU_ASSERT_EQUAL(queryctrl.reserved[1], 0); + + /* Check if the unused bytes of the name string are + * also filled with zeros. Also check if there is any + * padding byte between any two fields then this + * padding byte is also filled with zeros. + */ + memset(&queryctrl2, 0, sizeof(queryctrl2)); + queryctrl2.id = queryctrl.id; + queryctrl2.type = queryctrl.type; + strncpy((char *)queryctrl2.name, (char *)queryctrl.name, + sizeof(queryctrl2.name)); + queryctrl2.minimum = queryctrl.minimum; + queryctrl2.maximum = queryctrl.maximum; + queryctrl2.step = queryctrl.step; + queryctrl2.default_value = queryctrl.default_value; + queryctrl2.flags = queryctrl.flags; + CU_ASSERT_EQUAL(memcmp + (&queryctrl, &queryctrl2, + sizeof(queryctrl)), 0); + + dprintf + ("\tqueryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", queryctrl.id, + queryctrl.type, queryctrl.name, queryctrl.minimum, + queryctrl.maximum, queryctrl.step, + queryctrl.default_value, queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + memset(&queryctrl2, 0xff, sizeof(queryctrl2)); + queryctrl2.id = i; + CU_ASSERT_EQUAL(memcmp + (&queryctrl, &queryctrl2, + sizeof(queryctrl)), 0); + + } + } + +} + +void test_VIDIOC_QUERYCTRL_BASE_1() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + struct v4l2_queryctrl queryctrl2; + + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = V4L2_CID_BASE - 1; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE-1), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, V4L2_CID_BASE - 1, ret_query, errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + memset(&queryctrl2, 0xff, sizeof(queryctrl2)); + queryctrl2.id = V4L2_CID_BASE - 1; + CU_ASSERT_EQUAL(memcmp(&queryctrl, &queryctrl2, sizeof(queryctrl)), 0); + +} + +void test_VIDIOC_QUERYCTRL_LASTP1() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + struct v4l2_queryctrl queryctrl2; + + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = V4L2_CID_LASTP1; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_LASTP1), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, V4L2_CID_LASTP1, ret_query, errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + memset(&queryctrl2, 0xff, sizeof(queryctrl2)); + queryctrl2.id = V4L2_CID_LASTP1; + CU_ASSERT_EQUAL(memcmp(&queryctrl, &queryctrl2, sizeof(queryctrl)), 0); + +} + +void test_VIDIOC_QUERYCTRL_LASTP1_1() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + struct v4l2_queryctrl queryctrl2; + + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = V4L2_CID_LASTP1 + 1; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_LASTP1+1), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, V4L2_CID_LASTP1 + 1, ret_query, errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + memset(&queryctrl2, 0xff, sizeof(queryctrl2)); + queryctrl2.id = V4L2_CID_LASTP1 + 1; + CU_ASSERT_EQUAL(memcmp(&queryctrl, &queryctrl2, sizeof(queryctrl)), 0); + +} + +void test_VIDIOC_QUERYCTRL_flag_NEXT_CTRL() +{ + int ret_query, errno_query; + char count_controls1[V4L2_CID_LASTP1 - V4L2_CID_BASE]; + char count_controls2[V4L2_CID_LASTP1 - V4L2_CID_BASE]; + struct v4l2_queryctrl controls[V4L2_CID_LASTP1 - V4L2_CID_BASE]; + struct v4l2_queryctrl queryctrl; + __u32 i; + + /* find out all the possible user controls */ + memset(count_controls1, 0, sizeof(count_controls1)); + memset(controls, 0, sizeof(controls)); + + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + CU_ASSERT_EQUAL(queryctrl.id, i); + count_controls1[i - V4L2_CID_BASE]++; + controls[i - V4L2_CID_BASE] = queryctrl; + + dprintf + ("\tqueryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", queryctrl.id, + queryctrl.type, queryctrl.name, queryctrl.minimum, + queryctrl.maximum, queryctrl.step, + queryctrl.default_value, queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + } + + /* enumerate the controls with V4L2_CTRL_FLAG_NEXT_CTRL */ + dprintf1("\tStarting enumeration with V4L2_CTRL_FLAG_NEXT_CTRL\n"); + memset(count_controls2, 0, sizeof(count_controls2)); + + /* As described at V4L2 Chapter 1.9.3. Enumerating Extended Controls */ + i = 0; + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i | V4L2_CTRL_FLAG_NEXT_CTRL; + dprintf + ("\tasking for id=%i=V4L2_CID_BASE+%i | V4L2_CTRL_FLAG_NEXT_CTRL\n", + i, i - V4L2_CID_BASE); + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf("\tret_query=%i\n", ret_query); + + if (ret_query == 0) { + do { + /* protect the count_controls2[] from overindexing */ + if ((V4L2_CID_BASE <= queryctrl.id) + && (queryctrl.id < V4L2_CID_LASTP1)) { + count_controls2[queryctrl.id - V4L2_CID_BASE]++; + CU_ASSERT_EQUAL(memcmp + (&queryctrl, + &controls[queryctrl.id - + V4L2_CID_BASE], + sizeof(queryctrl)), 0); + } + + /* "The VIDIOC_QUERYCTRL ioctl will return the first + * control with a higher ID than the specified one." + */ + CU_ASSERT(i < queryctrl.id); + + CU_ASSERT(V4L2_CID_BASE <= queryctrl.id); + CU_ASSERT(queryctrl.id < V4L2_CID_LASTP1); + + dprintf + ("\tqueryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", queryctrl.id, + queryctrl.type, queryctrl.name, queryctrl.minimum, + queryctrl.maximum, queryctrl.step, + queryctrl.default_value, queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + + i = queryctrl.id; + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i | V4L2_CTRL_FLAG_NEXT_CTRL; + dprintf + ("\tasking for id=%i=V4L2_CID_BASE+%i | V4L2_CTRL_FLAG_NEXT_CTRL\n", + i, i - V4L2_CID_BASE); + ret_query = + ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf("\tret_query=%i\n", ret_query); + + } while (ret_query == 0 + && V4L2_CTRL_ID2CLASS(queryctrl.id) == + V4L2_CTRL_CLASS_USER); + + if (ret_query == 0) { + /* some other controls also exists, stop for now. */ + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + + /* Check whether the same controls are reported if using + * V4L2_CTRL_FLAG_NEXT_CTRL and without using it. + * This also checks if one control is not reported twice. + */ + CU_ASSERT_EQUAL(memcmp + (count_controls1, count_controls2, + sizeof(count_controls1)), 0); + + dprintf1("count_controls1 = { "); + for (i = 0; + i < sizeof(count_controls1) / sizeof(*count_controls1); + i++) { + dprintf("%i ", count_controls1[i]); + } + dprintf1("}\n"); + + dprintf1("count_controls2 = { "); + for (i = 0; + i < sizeof(count_controls2) / sizeof(*count_controls2); + i++) { + dprintf("%i ", count_controls2[i]); + } + dprintf1("}\n"); + + } else { + dprintf1 + ("V4L2_CTRL_FLAG_NEXT_CTRL is not supported or no control is available\n"); + /* The flag V4L2_CTRL_FLAG_NEXT_CTRL is not supported + * or no control is avaliable at all. Do not continue the + * enumeration. + */ + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + +} + +void test_VIDIOC_QUERYCTRL_private() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + struct v4l2_queryctrl queryctrl2; + __u32 i; + + i = V4L2_CID_PRIVATE_BASE; + do { + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_BASE, ret_query, + errno_query); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + CU_ASSERT_EQUAL(queryctrl.id, i); + + CU_ASSERT(0 < strlen((char *)queryctrl.name)); + CU_ASSERT(valid_string + ((char *)queryctrl.name, + sizeof(queryctrl.name))); + + CU_ASSERT(valid_control_type(queryctrl.type)); + + switch (queryctrl.type) { + case V4L2_CTRL_TYPE_INTEGER: + /* min < max, because otherwise this control makes no sense */ + CU_ASSERT(queryctrl.minimum < + queryctrl.maximum); + + CU_ASSERT(0 < queryctrl.step); + + CU_ASSERT(queryctrl.minimum <= + queryctrl.default_value); + CU_ASSERT(queryctrl.default_value <= + queryctrl.maximum); + break; + + case V4L2_CTRL_TYPE_BOOLEAN: + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT_EQUAL(queryctrl.maximum, 1); + CU_ASSERT_EQUAL(queryctrl.step, 1); + CU_ASSERT((queryctrl.default_value == 0) + || (queryctrl.default_value == 1)); + break; + + case V4L2_CTRL_TYPE_MENU: + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT(queryctrl.minimum <= + queryctrl.default_value); + CU_ASSERT_EQUAL(queryctrl.step, 1); + CU_ASSERT(queryctrl.minimum <= + queryctrl.default_value); + CU_ASSERT(queryctrl.default_value <= + queryctrl.maximum); + break; + + case V4L2_CTRL_TYPE_BUTTON: + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT_EQUAL(queryctrl.maximum, 0); + CU_ASSERT_EQUAL(queryctrl.step, 0); + CU_ASSERT_EQUAL(queryctrl.default_value, 0); + break; + + case V4L2_CTRL_TYPE_INTEGER64: /* fallthrough */ + case V4L2_CTRL_TYPE_CTRL_CLASS: + /* These parameters are defined as n/a by V4L2, so + * they should be filled with zeros, the same like + * the reserved fields. + */ + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT_EQUAL(queryctrl.maximum, 0); + CU_ASSERT_EQUAL(queryctrl.step, 0); + CU_ASSERT_EQUAL(queryctrl.default_value, 0); + break; + + default: + CU_ASSERT_EQUAL(queryctrl.minimum, 0); + CU_ASSERT_EQUAL(queryctrl.maximum, 0); + CU_ASSERT_EQUAL(queryctrl.step, 0); + CU_ASSERT_EQUAL(queryctrl.default_value, 0); + } + + CU_ASSERT(valid_control_flag(queryctrl.flags)); + + CU_ASSERT_EQUAL(queryctrl.reserved[0], 0); + CU_ASSERT_EQUAL(queryctrl.reserved[1], 0); + + /* Check if the unused bytes of the name string are + * also filled with zeros. Also check if there is any + * padding byte between any two fields then this + * padding byte is also filled with zeros. + */ + memset(&queryctrl2, 0, sizeof(queryctrl2)); + queryctrl2.id = queryctrl.id; + queryctrl2.type = queryctrl.type; + strncpy((char *)queryctrl2.name, (char *)queryctrl.name, + sizeof(queryctrl2.name)); + queryctrl2.minimum = queryctrl.minimum; + queryctrl2.maximum = queryctrl.maximum; + queryctrl2.step = queryctrl.step; + queryctrl2.default_value = queryctrl.default_value; + queryctrl2.flags = queryctrl.flags; + CU_ASSERT_EQUAL(memcmp + (&queryctrl, &queryctrl2, + sizeof(queryctrl)), 0); + + dprintf + ("\tqueryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", queryctrl.id, + queryctrl.type, queryctrl.name, queryctrl.minimum, + queryctrl.maximum, queryctrl.step, + queryctrl.default_value, queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + memset(&queryctrl2, 0xff, sizeof(queryctrl2)); + queryctrl2.id = i; + CU_ASSERT_EQUAL(memcmp + (&queryctrl, &queryctrl2, + sizeof(queryctrl)), 0); + + } + } while (ret_query == 0); + +} + +void test_VIDIOC_QUERYCTRL_private_base_1() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + struct v4l2_queryctrl queryctrl2; + + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = V4L2_CID_PRIVATE_BASE - 1; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_PRIVATE_BASE-1), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, V4L2_CID_PRIVATE_BASE - 1, ret_query, + errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + memset(&queryctrl2, 0xff, sizeof(queryctrl2)); + queryctrl2.id = V4L2_CID_PRIVATE_BASE - 1; + CU_ASSERT_EQUAL(memcmp(&queryctrl, &queryctrl2, sizeof(queryctrl)), 0); + +} + +void test_VIDIOC_QUERYCTRL_private_last_1() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + struct v4l2_queryctrl queryctrl2; + __u32 i; + + i = V4L2_CID_PRIVATE_BASE; + do { + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + i++; + } while (ret_query == 0); + + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_PRIVATE_BASE+%u), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_PRIVATE_BASE, ret_query, + errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + memset(&queryctrl2, 0xff, sizeof(queryctrl2)); + queryctrl2.id = i; + CU_ASSERT_EQUAL(memcmp(&queryctrl, &queryctrl2, sizeof(queryctrl)), 0); + +} + +void test_VIDIOC_QUERYCTRL_NULL() +{ + int ret_query, errno_query; + int ret_null, errno_null; + struct v4l2_queryctrl queryctrl; + __u32 i; + unsigned int count_ctrl; + + count_ctrl = 0; + + i = V4L2_CID_BASE; + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_BASE, ret_query, + errno_query); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + count_ctrl++; + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + } + + i = V4L2_CID_PRIVATE_BASE; + do { + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_PRIVATE_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_PRIVATE_BASE, + ret_query, errno_query); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + count_ctrl++; + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + + i++; + } while (ret_query == 0 && V4L2_CID_PRIVATE_BASE <= i); + + ret_null = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_QUERYCTRL, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (0 < count_ctrl) { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCTRL.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCTRL.h new file mode 100644 index 0000000000000000000000000000000000000000..bf9eb02afbcfecf7bf737fd32c346d7eb8a1f6b0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYCTRL.h @@ -0,0 +1,18 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 2 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_QUERYCTRL(void); +void test_VIDIOC_QUERYCTRL_BASE_1(void); +void test_VIDIOC_QUERYCTRL_LASTP1(void); +void test_VIDIOC_QUERYCTRL_LASTP1_1(void); +void test_VIDIOC_QUERYCTRL_flag_NEXT_CTRL(void); +void test_VIDIOC_QUERYCTRL_private(void); +void test_VIDIOC_QUERYCTRL_private_base_1(void); +void test_VIDIOC_QUERYCTRL_private_last_1(void); +void test_VIDIOC_QUERYCTRL_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYMENU.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYMENU.c new file mode 100644 index 0000000000000000000000000000000000000000..e7d35e9e8efcfbf4435a09df524b5ae079aff322 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYMENU.c @@ -0,0 +1,400 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.3 Added string content validation + * 18 Apr 2009 0.2 More strict check for strings + * 5 Apr 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +/* + * Note: V4L2_CID_LASTP1 != V4L2_CID_BASE_LASTP1 + */ + +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_QUERYCTRL.h" + +static void do_check_menu(__u32 id, __u32 index, + int ret_query, int errno_query, + struct v4l2_querymenu *menu) +{ + struct v4l2_querymenu menu2; + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + + dprintf("\tmenu = {.id=%u, .index=%i, .name=\"%s\", " + ".reserved=0x%X }\n", + menu->id, menu->index, menu->name, menu->reserved); + + CU_ASSERT_EQUAL(menu->id, id); + CU_ASSERT_EQUAL(menu->index, index); + + CU_ASSERT(0 < strlen((char *)menu->name)); + CU_ASSERT(valid_string((char *)menu->name, sizeof(menu->name))); + + CU_ASSERT_EQUAL(menu->reserved, 0); + + /* Check if the unused bytes of the name string is also filled + * with zeros. Also check if there is any padding byte between + * any two fields then this padding byte is also filled with + * zeros. + */ + memset(&menu2, 0, sizeof(menu2)); + menu2.id = id; + menu2.index = index; + strncpy((char *)menu2.name, (char *)menu->name, + sizeof(menu2.name)); + CU_ASSERT_EQUAL(memcmp(menu, &menu2, sizeof(*menu)), 0); + + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + memset(&menu2, 0xff, sizeof(menu2)); + menu2.id = id; + menu2.index = index; + CU_ASSERT(memcmp(&menu, &menu2, sizeof(menu))); + } +} + +static void do_query_menu(__u32 id) +{ + int ret_query, errno_query; + __u32 i; + struct v4l2_querymenu menu; + + i = 0; + do { + memset(&menu, 0xff, sizeof(menu)); + menu.id = id; + menu.index = i; + + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYMENU, &menu); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYMENU, id=%u, (V4L2_CID_BASE+%i), index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, i, ret_query, + errno_query); + + do_check_menu(id, i, ret_query, errno_query, &menu); + + i++; + } while (ret_query == 0); + +} + +static void do_query_menu_invalid(__u32 id) +{ + int ret_query, errno_query; + unsigned int i; + struct v4l2_querymenu menu; + const __u32 test_index[] = { + U32_MIN, + U32_MIN + 1, + (__u32) S32_MIN, + (__u32) S32_MAX, + U32_MAX - 1, + U32_MAX + }; + + for (i = 0; i < sizeof(test_index) / sizeof(*test_index); i++) { + memset(&menu, 0xff, sizeof(menu)); + menu.id = id; + menu.index = test_index[i]; + + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYMENU, &menu); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYMENU, id=%u, (V4L2_CID_BASE+%i), index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, id, id - V4L2_CID_BASE, test_index[i], + ret_query, errno_query); + + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + do_check_menu(id, test_index[i], ret_query, errno_query, &menu); + + } + +} + +void test_VIDIOC_QUERYMENU() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + __u32 i; + + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + + memset(&queryctrl, 0, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_BASE, ret_query, + errno_query); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + CU_ASSERT_EQUAL(queryctrl.id, i); + + dprintf + ("\tqueryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", queryctrl.id, + queryctrl.type, queryctrl.name, queryctrl.minimum, + queryctrl.maximum, queryctrl.step, + queryctrl.default_value, queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + + switch (queryctrl.type) { + case V4L2_CTRL_TYPE_MENU: + do_query_menu(i); + break; + + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_INTEGER64: + case V4L2_CTRL_TYPE_CTRL_CLASS: + default: + do_query_menu_invalid(i); + } + + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + do_query_menu_invalid(i); + + } + } + +} + +void test_VIDIOC_QUERYMENU_invalid() +{ + do_query_menu_invalid(0); + do_query_menu_invalid(V4L2_CID_BASE - 1); + do_query_menu_invalid(V4L2_CID_LASTP1); + do_query_menu_invalid(V4L2_CID_LASTP1 + 1); + do_query_menu_invalid(V4L2_CID_PRIVATE_BASE - 1); +} + +void test_VIDIOC_QUERYMENU_private() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + __u32 i; + + i = V4L2_CID_PRIVATE_BASE; + do { + memset(&queryctrl, 0, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_BASE, ret_query, + errno_query); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + CU_ASSERT_EQUAL(queryctrl.id, i); + + dprintf + ("\tqueryctrl = {.id=%u, .type=%i, .name=\"%s\", " + ".minimum=%i, .maximum=%i, .step=%i, " + ".default_value=%i, " ".flags=0x%X, " + ".reserved[]={ 0x%X, 0x%X } }\n", queryctrl.id, + queryctrl.type, queryctrl.name, queryctrl.minimum, + queryctrl.maximum, queryctrl.step, + queryctrl.default_value, queryctrl.flags, + queryctrl.reserved[0], queryctrl.reserved[1] + ); + + switch (queryctrl.type) { + case V4L2_CTRL_TYPE_MENU: + do_query_menu(i); + break; + + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_INTEGER64: /* fallthrough */ + case V4L2_CTRL_TYPE_CTRL_CLASS: + default: + do_query_menu_invalid(i); + + } + + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + + do_query_menu_invalid(i); + + } + } while (ret_query == 0); + +} + +void test_VIDIOC_QUERYMENU_private_last_1() +{ + int ret_query, errno_query; + struct v4l2_queryctrl queryctrl; + __u32 i; + + i = V4L2_CID_PRIVATE_BASE; + do { + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + i++; + } while (ret_query == 0); + + do_query_menu_invalid(i); +} + +void test_VIDIOC_QUERYMENU_NULL() +{ + int ret_query, errno_query; + int ret_menu, errno_menu; + int ret_null, errno_null; + struct v4l2_queryctrl queryctrl; + struct v4l2_querymenu menu; + __u32 i; + unsigned int count_menu; + + count_menu = 0; + + i = V4L2_CID_BASE; + for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) { + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_BASE, ret_query, + errno_query); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + if (queryctrl.type == V4L2_CTRL_TYPE_MENU) { + + memset(&menu, 0, sizeof(menu)); + menu.id = i; + menu.index = 0; + + ret_menu = + ioctl(get_video_fd(), VIDIOC_QUERYMENU, + &menu); + errno_menu = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYMENU, id=%u, (V4L2_CID_BASE+%i), index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_BASE, + 0, ret_query, errno_query); + + if (ret_menu == 0) { + CU_ASSERT_EQUAL(ret_menu, 0); + count_menu++; + } else { + CU_ASSERT_EQUAL(ret_menu, -1); + CU_ASSERT_EQUAL(errno_menu, EINVAL); + } + } + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + } + + i = V4L2_CID_PRIVATE_BASE; + do { + memset(&queryctrl, 0xff, sizeof(queryctrl)); + queryctrl.id = i; + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYCTRL, &queryctrl); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYCTRL, id=%u (V4L2_CID_PRIVATE_BASE+%i), ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_PRIVATE_BASE, + ret_query, errno_query); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + if (queryctrl.type == V4L2_CTRL_TYPE_MENU) { + + memset(&menu, 0, sizeof(menu)); + menu.id = i; + menu.index = 0; + + ret_menu = + ioctl(get_video_fd(), VIDIOC_QUERYMENU, + &menu); + errno_menu = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYMENU, id=%u, (V4L2_CID_BASE+%i), index=%u, ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, i, i - V4L2_CID_BASE, + 0, ret_query, errno_query); + + if (ret_menu == 0) { + CU_ASSERT_EQUAL(ret_menu, 0); + count_menu++; + } else { + CU_ASSERT_EQUAL(ret_menu, -1); + CU_ASSERT_EQUAL(errno_menu, EINVAL); + } + } + } else { + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + + i++; + } while (ret_query == 0 && V4L2_CID_PRIVATE_BASE <= i); + + ret_null = ioctl(get_video_fd(), VIDIOC_QUERYMENU, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_QUERYMENU, ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (0 < count_menu) { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYMENU.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYMENU.h new file mode 100644 index 0000000000000000000000000000000000000000..d3a3e92b1f958178fce85b3deedc340899c26e58 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYMENU.h @@ -0,0 +1,14 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 5 Apr 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_QUERYMENU(void); +void test_VIDIOC_QUERYMENU_invalid(void); +void test_VIDIOC_QUERYMENU_private(void); +void test_VIDIOC_QUERYMENU_private_last_1(void); +void test_VIDIOC_QUERYMENU_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYSTD.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYSTD.c new file mode 100644 index 0000000000000000000000000000000000000000..7c8d4fae8a5be577366bd79ec76cc31bc7a0cc21 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYSTD.c @@ -0,0 +1,95 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 5 Apr 2009 0.3 Test case for NULL parameter reworked + * 28 Mar 2009 0.2 Clean up ret and errno variable names and dprintf() output + * 30 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_QUERYSTD.h" + +void test_VIDIOC_QUERYSTD() +{ + int ret_query, errno_query; + v4l2_std_id id; + + memset(&id, 0xff, sizeof(id)); + + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYSTD, &id); + errno_query = errno; + + dprintf + ("\t%s:%u: VIDIOC_QUERYSTD, ret_query=%i, errno_query=%i, id=0x%llx\n", + __FILE__, __LINE__, ret_query, errno_query, id); + + if (ret_query == 0) { + CU_ASSERT_EQUAL(ret_query, 0); + CU_ASSERT(id != 0); + CU_ASSERT(valid_v4l2_std_id(id)); + + } else { + /* if this ioctl is not supported, then errno shall be EINVAL */ + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + } + +} + +void test_VIDIOC_QUERYSTD_NULL() +{ + int ret_query, errno_query; + int ret_null, errno_null; + v4l2_std_id id; + + memset(&id, 0, sizeof(id)); + ret_query = ioctl(get_video_fd(), VIDIOC_QUERYSTD, &id); + errno_query = errno; + + dprintf("\t%s:%u: VIDIOC_QUERYSTD: ret_query=%i, errno_query=%i\n", + __FILE__, __LINE__, ret_query, errno_query); + + ret_null = ioctl(get_video_fd(), VIDIOC_QUERYSTD, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* check if VIDIOC_QUERYSTD is supported at all or not */ + if (ret_query == 0) { + /* VIDIOC_QUERYSTD is supported, the parameter should be checked */ + CU_ASSERT_EQUAL(ret_query, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + /* VIDIOC_QUERYSTD not supported at all, the parameter should not be evaluated */ + CU_ASSERT_EQUAL(ret_query, -1); + CU_ASSERT_EQUAL(errno_query, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + + } +} + +/* TODO: check for different input settings */ diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYSTD.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYSTD.h new file mode 100644 index 0000000000000000000000000000000000000000..aa4e137912c45c2fc5e2b31dff87ca673deaab60 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_QUERYSTD.h @@ -0,0 +1,11 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 30 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_QUERYSTD(void); +void test_VIDIOC_QUERYSTD_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_REQBUFS.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_REQBUFS.c new file mode 100644 index 0000000000000000000000000000000000000000..40b8a21a38bc9b0c06adff2868c0392edff5ad4e --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_REQBUFS.c @@ -0,0 +1,448 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 7 May 2009 0.2 show_v4l2_*() function extracted to v4l2_show.c + * 29 Apr 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "v4l2_show.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_REQBUFS.h" + +static void do_VIDIOC_REQBUFS_capture_mmap(__u32 count) +{ + int ret_cap, errno_cap; + int ret_req, errno_req; + struct v4l2_capability cap; + struct v4l2_requestbuffers reqbuf; + struct v4l2_requestbuffers reqbuf2; + + memset(&cap, 0, sizeof(cap)); + + ret_cap = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + errno_cap = errno; + + memset(&reqbuf, 0xff, sizeof(reqbuf)); + reqbuf.count = count; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf.memory = V4L2_MEMORY_MMAP; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf("\t%s:%u: VIDIOC_REQBUF, count=%u, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, count, ret_req, errno_req); + + if (ret_cap == 0 && + (cap.capabilities & V4L2_CAP_STREAMING) && + (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT(cap.capabilities & V4L2_CAP_STREAMING); + + CU_ASSERT_EQUAL(ret_req, 0); + //CU_ASSERT_EQUAL(reqbuf.count, ???); + CU_ASSERT_EQUAL(reqbuf.type, V4L2_BUF_TYPE_VIDEO_CAPTURE); + CU_ASSERT_EQUAL(reqbuf.memory, V4L2_MEMORY_MMAP); + CU_ASSERT_EQUAL(reqbuf.reserved[0], 0); + CU_ASSERT_EQUAL(reqbuf.reserved[1], 0); + + } else { + CU_ASSERT_EQUAL(ret_req, -1); + CU_ASSERT_EQUAL(errno_req, EINVAL); + + memset(&reqbuf2, 0xff, sizeof(reqbuf2)); + reqbuf2.count = count; + reqbuf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf2.memory = V4L2_MEMORY_MMAP; + + CU_ASSERT_EQUAL(memcmp(&reqbuf, &reqbuf2, sizeof(reqbuf)), 0); + } + + if (ret_req == 0) { + show_v4l2_requestbuffers(&reqbuf); + } + +} + +void test_VIDIOC_REQBUFS_capture_mmap() +{ + do_VIDIOC_REQBUFS_capture_mmap(0); + do_VIDIOC_REQBUFS_capture_mmap(1); + do_VIDIOC_REQBUFS_capture_mmap(2); + do_VIDIOC_REQBUFS_capture_mmap(3); + do_VIDIOC_REQBUFS_capture_mmap(4); + do_VIDIOC_REQBUFS_capture_mmap((__u32) S16_MIN); + do_VIDIOC_REQBUFS_capture_mmap((__u32) S16_MAX); + do_VIDIOC_REQBUFS_capture_mmap(U32_MAX); + do_VIDIOC_REQBUFS_capture_mmap(0); +} + +static void do_VIDIOC_REQBUFS_capture_userptr(__u32 count) +{ + int ret_cap, errno_cap; + int ret_req, errno_req; + struct v4l2_capability cap; + struct v4l2_requestbuffers reqbuf; + struct v4l2_requestbuffers reqbuf2; + + memset(&cap, 0, sizeof(cap)); + + ret_cap = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + errno_cap = errno; + + memset(&reqbuf, 0xff, sizeof(reqbuf)); + reqbuf.count = count; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf.memory = V4L2_MEMORY_USERPTR; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf("\t%s:%u: VIDIOC_REQBUF, count=%u, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, count, ret_req, errno_req); + + if (ret_cap == 0 && + (cap.capabilities & V4L2_CAP_STREAMING) && + (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && ret_req == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT(cap.capabilities & V4L2_CAP_STREAMING); + + CU_ASSERT_EQUAL(ret_req, 0); + //CU_ASSERT_EQUAL(reqbuf.count, ???); + CU_ASSERT_EQUAL(reqbuf.type, V4L2_BUF_TYPE_VIDEO_CAPTURE); + CU_ASSERT_EQUAL(reqbuf.memory, V4L2_MEMORY_USERPTR); + CU_ASSERT_EQUAL(reqbuf.reserved[0], 0); + CU_ASSERT_EQUAL(reqbuf.reserved[1], 0); + + } else { + CU_ASSERT_EQUAL(ret_req, -1); + CU_ASSERT_EQUAL(errno_req, EINVAL); + + memset(&reqbuf2, 0xff, sizeof(reqbuf2)); + reqbuf2.count = count; + reqbuf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf2.memory = V4L2_MEMORY_USERPTR; + + CU_ASSERT_EQUAL(memcmp(&reqbuf, &reqbuf2, sizeof(reqbuf)), 0); + } + + if (ret_req == 0) { + show_v4l2_requestbuffers(&reqbuf); + } + +} + +void test_VIDIOC_REQBUFS_capture_userptr() +{ + do_VIDIOC_REQBUFS_capture_userptr(0); + do_VIDIOC_REQBUFS_capture_userptr(1); + do_VIDIOC_REQBUFS_capture_userptr((__u32) S16_MIN); + do_VIDIOC_REQBUFS_capture_userptr((__u32) S16_MAX); + do_VIDIOC_REQBUFS_capture_userptr(U32_MAX); + do_VIDIOC_REQBUFS_capture_userptr(0); +} + +static void do_VIDIOC_REQBUFS_output_mmap(__u32 count) +{ + int ret_cap, errno_cap; + int ret_req, errno_req; + struct v4l2_capability cap; + struct v4l2_requestbuffers reqbuf; + struct v4l2_requestbuffers reqbuf2; + + memset(&cap, 0, sizeof(cap)); + + ret_cap = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + errno_cap = errno; + + memset(&reqbuf, 0xff, sizeof(reqbuf)); + reqbuf.count = count; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + reqbuf.memory = V4L2_MEMORY_MMAP; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf("\t%s:%u: VIDIOC_REQBUF, count=%u, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, count, ret_req, errno_req); + + if (ret_cap == 0 && + (cap.capabilities & V4L2_CAP_STREAMING) && + (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { + + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT(cap.capabilities & V4L2_CAP_STREAMING); + + CU_ASSERT_EQUAL(ret_req, 0); + //CU_ASSERT_EQUAL(reqbuf.count, ???); + CU_ASSERT_EQUAL(reqbuf.type, V4L2_BUF_TYPE_VIDEO_OUTPUT); + CU_ASSERT_EQUAL(reqbuf.memory, V4L2_MEMORY_MMAP); + CU_ASSERT_EQUAL(reqbuf.reserved[0], 0); + CU_ASSERT_EQUAL(reqbuf.reserved[1], 0); + + } else { + CU_ASSERT_EQUAL(ret_req, -1); + CU_ASSERT_EQUAL(errno_req, EINVAL); + + memset(&reqbuf2, 0xff, sizeof(reqbuf2)); + reqbuf2.count = count; + reqbuf2.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + reqbuf2.memory = V4L2_MEMORY_MMAP; + + CU_ASSERT_EQUAL(memcmp(&reqbuf, &reqbuf2, sizeof(reqbuf)), 0); + } + + if (ret_req == 0) { + show_v4l2_requestbuffers(&reqbuf); + } + +} + +void test_VIDIOC_REQBUFS_output_mmap() +{ + do_VIDIOC_REQBUFS_output_mmap(0); + do_VIDIOC_REQBUFS_output_mmap(1); + do_VIDIOC_REQBUFS_output_mmap(2); + do_VIDIOC_REQBUFS_output_mmap(3); + do_VIDIOC_REQBUFS_output_mmap(4); + do_VIDIOC_REQBUFS_output_mmap((__u32) S16_MIN); + do_VIDIOC_REQBUFS_output_mmap((__u32) S16_MAX); + do_VIDIOC_REQBUFS_output_mmap(U32_MAX); + do_VIDIOC_REQBUFS_output_mmap(0); +} + +static void do_VIDIOC_REQBUFS_output_userptr(__u32 count) +{ + int ret_cap, errno_cap; + int ret_req, errno_req; + struct v4l2_capability cap; + struct v4l2_requestbuffers reqbuf; + struct v4l2_requestbuffers reqbuf2; + + memset(&cap, 0, sizeof(cap)); + + ret_cap = ioctl(get_video_fd(), VIDIOC_QUERYCAP, &cap); + errno_cap = errno; + + memset(&reqbuf, 0xff, sizeof(reqbuf)); + reqbuf.count = count; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + reqbuf.memory = V4L2_MEMORY_USERPTR; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf("\t%s:%u: VIDIOC_REQBUF, count=%u, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, count, ret_req, errno_req); + + if (ret_cap == 0 && + (cap.capabilities & V4L2_CAP_STREAMING) && + (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) && ret_req == 0) { + CU_ASSERT_EQUAL(ret_cap, 0); + CU_ASSERT(cap.capabilities & V4L2_CAP_STREAMING); + + CU_ASSERT_EQUAL(ret_req, 0); + //CU_ASSERT_EQUAL(reqbuf.count, ???); + CU_ASSERT_EQUAL(reqbuf.type, V4L2_BUF_TYPE_VIDEO_OUTPUT); + CU_ASSERT_EQUAL(reqbuf.memory, V4L2_MEMORY_USERPTR); + CU_ASSERT_EQUAL(reqbuf.reserved[0], 0); + CU_ASSERT_EQUAL(reqbuf.reserved[1], 0); + + } else { + CU_ASSERT_EQUAL(ret_req, -1); + CU_ASSERT_EQUAL(errno_req, EINVAL); + + memset(&reqbuf2, 0xff, sizeof(reqbuf2)); + reqbuf2.count = count; + reqbuf2.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + reqbuf2.memory = V4L2_MEMORY_USERPTR; + + CU_ASSERT_EQUAL(memcmp(&reqbuf, &reqbuf2, sizeof(reqbuf)), 0); + } + + if (ret_req == 0) { + show_v4l2_requestbuffers(&reqbuf); + } + +} + +void test_VIDIOC_REQBUFS_output_userptr() +{ + do_VIDIOC_REQBUFS_output_userptr(0); + do_VIDIOC_REQBUFS_output_userptr(1); + do_VIDIOC_REQBUFS_output_userptr((__u32) S16_MIN); + do_VIDIOC_REQBUFS_output_userptr((__u32) S16_MAX); + do_VIDIOC_REQBUFS_output_userptr(U32_MAX); + do_VIDIOC_REQBUFS_output_userptr(0); +} + +static void do_VIDIOC_REQBUFS_invalid_memory(enum v4l2_buf_type type, + enum v4l2_memory memory) +{ + int ret_req, errno_req; + struct v4l2_requestbuffers reqbuf; + struct v4l2_requestbuffers reqbuf2; + + memset(&reqbuf, 0xff, sizeof(reqbuf)); + reqbuf.count = 0; + reqbuf.type = type; + reqbuf.memory = memory; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf("\t%s:%u: VIDIOC_REQBUF, type=0%x, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, type, ret_req, errno_req); + + CU_ASSERT_EQUAL(ret_req, -1); + CU_ASSERT_EQUAL(errno_req, EINVAL); + + memset(&reqbuf2, 0xff, sizeof(reqbuf2)); + reqbuf2.count = 0; + reqbuf2.type = type; + reqbuf2.memory = memory; + + CU_ASSERT_EQUAL(memcmp(&reqbuf, &reqbuf2, sizeof(reqbuf)), 0); + + if (ret_req == 0) { + show_v4l2_requestbuffers(&reqbuf); + } + +} + +void test_VIDIOC_REQBUFS_invalid_memory_capture() +{ + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_CAPTURE, SINT_MIN); + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_CAPTURE, 0); + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_MEMORY_OVERLAY); + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_MEMORY_OVERLAY + 1); + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_CAPTURE, SINT_MAX); +} + +void test_VIDIOC_REQBUFS_invalid_memory_output() +{ + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_OUTPUT, SINT_MIN); + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_OUTPUT, 0); + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_MEMORY_OVERLAY); + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_MEMORY_OVERLAY + 1); + do_VIDIOC_REQBUFS_invalid_memory(V4L2_BUF_TYPE_VIDEO_OUTPUT, SINT_MAX); +} + +static void do_VIDIOC_REQBUFS_invalid_type(enum v4l2_memory memory, + enum v4l2_buf_type type) +{ + int ret_req, errno_req; + struct v4l2_requestbuffers reqbuf; + struct v4l2_requestbuffers reqbuf2; + __u32 count; + + count = 1; + + memset(&reqbuf, 0xff, sizeof(reqbuf)); + reqbuf.count = count; + reqbuf.type = type; + reqbuf.memory = memory; + + ret_req = ioctl(get_video_fd(), VIDIOC_REQBUFS, &reqbuf); + errno_req = errno; + + dprintf + ("\t%s:%u: VIDIOC_REQBUF, type=0x%x, memory=%i, ret_req=%i, errno_req=%i\n", + __FILE__, __LINE__, type, memory, ret_req, errno_req); + + CU_ASSERT_EQUAL(ret_req, -1); + CU_ASSERT_EQUAL(errno_req, EINVAL); + + memset(&reqbuf2, 0xff, sizeof(reqbuf2)); + reqbuf2.count = count; + reqbuf2.type = type; + reqbuf2.memory = memory; + + CU_ASSERT_EQUAL(memcmp(&reqbuf, &reqbuf2, sizeof(reqbuf)), 0); + + if (ret_req == 0) { + show_v4l2_requestbuffers(&reqbuf); + } +} + +void test_VIDIOC_REQUBUFS_invalid_type_mmap() +{ + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, 0); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + V4L2_BUF_TYPE_VBI_CAPTURE); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + V4L2_BUF_TYPE_VBI_OUTPUT); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + V4L2_BUF_TYPE_PRIVATE - 1); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, V4L2_BUF_TYPE_PRIVATE); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + V4L2_BUF_TYPE_PRIVATE + 1); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, S32_MAX); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, + (__s32) ((__u32) S32_MAX + 1)); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, U32_MAX - 1); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_MMAP, U32_MAX); + +} + +void test_VIDIOC_REQUBUFS_invalid_type_userptr() +{ + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, 0); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_VIDEO_OVERLAY); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_VBI_CAPTURE); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_VBI_OUTPUT); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_SLICED_VBI_CAPTURE); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_PRIVATE - 1); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_PRIVATE); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + V4L2_BUF_TYPE_PRIVATE + 1); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, S32_MAX); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, + (__s32) ((__u32) S32_MAX + 1)); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, U32_MAX - 1); + do_VIDIOC_REQBUFS_invalid_type(V4L2_MEMORY_USERPTR, U32_MAX); + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_REQBUFS.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_REQBUFS.h new file mode 100644 index 0000000000000000000000000000000000000000..bc3d716f5f70a68813d2b0dad5669597ff1a8a7f --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_REQBUFS.h @@ -0,0 +1,20 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 29 Apr 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_REQBUFS_capture_mmap(void); +void test_VIDIOC_REQBUFS_capture_userptr(void); + +void test_VIDIOC_REQBUFS_output_mmap(void); +void test_VIDIOC_REQBUFS_output_userptr(void); + +void test_VIDIOC_REQBUFS_invalid_memory_capture(void); +void test_VIDIOC_REQBUFS_invalid_memory_output(void); + +void test_VIDIOC_REQUBUFS_invalid_type_mmap(void); +void test_VIDIOC_REQUBUFS_invalid_type_userptr(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_STD.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_STD.c new file mode 100644 index 0000000000000000000000000000000000000000..e0800d7b7dc5f1ec817f5dc644dd95cbcae6e2c0 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_STD.c @@ -0,0 +1,531 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 5 Jul 2009 0.9 Iterate through all possible inputs + * 18 Apr 2009 0.8 Typo corrected + * 27 Mar 2009 0.7 Cleanup ret and errno variable names and dprintf() outputs; + * Make VIDIOC_S_STD tests independent from VIDIOC_G_STD + * 9 Feb 2009 0.6 Modify test cases to support drivers without any inputs; + * cleanup debug printouts + * 30 Jan 2009 0.5 valid_v4l2_std_id() moved to v4l2_validator.c + * 18 Jan 2009 0.4 Typo corrected + * 23 Dec 2008 0.3 Debug messages added + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" +#include "v4l2_foreach.h" + +#include "test_VIDIOC_STD.h" + +static void do_test_VIDIOC_G_STD(int ret_input_enum, int errno_input_enum, + struct v4l2_input *input) +{ + v4l2_std_id std_id; + int ret_std_get, errno_std_get; + int f; + + /* Iterate trough all inputs with VIDIOC_ENUMINPUT. + * Also ensure tahat VIDIC_G_STD is called at least + * once even if VIDIOC_ENUMINPUT always return EINVAL. + * + * V4L2 API specification rev. 0.24, Chapter 1.7. + * "Video Standards" specifies if the std field + * of v4l2_input or v4l2_output is zero when + * executing VIDIOC_ENUMINPUT or VIDIOC_ENUMOUTPUT, + * respectively, then VIDIOC_G_STD shall always + * return EINVAL. + */ + + /* TODO: Iterate trough all outputs VIDIOC_ENUMOUTPUT. + * Also ensure tahat VIDIC_G_STD is called at least + * once even if VIDIOC_ENUMOUTPUT always return EINVAL. + * + * TODO: What shall happen when changing output? The + * VIDIOC_G_STD only deals with current input. + */ + + f = get_video_fd(); + + memset(&std_id, 0xff, sizeof(std_id)); + ret_std_get = ioctl(f, VIDIOC_G_STD, &std_id); + errno_std_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_STD, ret_std_get=%i, errno_std_get=%i, std_id=0x%llX\n", + __FILE__, __LINE__, ret_std_get, errno_std_get, std_id); + + if (ret_input_enum == 0) { + CU_ASSERT_EQUAL(ret_input_enum, 0); + if (input->std == 0) { + CU_ASSERT_EQUAL(ret_std_get, -1); + CU_ASSERT_EQUAL(errno_std_get, EINVAL); + } else { + if (ret_std_get == 0) { + CU_ASSERT_EQUAL(ret_std_get, 0); + CU_ASSERT(valid_v4l2_std_id(std_id)); + } else { + CU_ASSERT_EQUAL(ret_std_get, -1); + CU_ASSERT_EQUAL(errno_std_get, EINVAL); + } + } + } else { + CU_ASSERT_EQUAL(ret_input_enum, -1); + CU_ASSERT_EQUAL(errno_input_enum, EINVAL); + if (ret_std_get == 0) { + CU_ASSERT_EQUAL(ret_std_get, 0); + CU_ASSERT(valid_v4l2_std_id(std_id)); + } else { + CU_ASSERT_EQUAL(ret_std_get, -1); + CU_ASSERT_EQUAL(errno_std_get, EINVAL); + } + } +} + +void test_VIDIOC_G_STD() +{ + + /* Iterate trough all inputs with VIDIOC_ENUMINPUT. + * Also ensure tahat VIDIC_G_STD is called at least + * once even if VIDIOC_ENUMINPUT always return EINVAL. + * + * V4L2 API specification rev. 0.24, Chapter 1.7. + * "Video Standards" specifies if the std field + * of v4l2_input or v4l2_output is zero when + * executing VIDIOC_ENUMINPUT or VIDIOC_ENUMOUTPUT, + * respectively, then VIDIOC_G_STD shall always + * return EINVAL. + */ + + foreach_input(do_test_VIDIOC_G_STD); + + /* TODO: Iterate trough all outputs VIDIOC_ENUMOUTPUT. + * Also ensure tahat VIDIC_G_STD is called at least + * once even if VIDIOC_ENUMOUTPUT always return EINVAL. + * + * TODO: What shall happen when changing output? The + * VIDIOC_G_STD only deals with current input. + */ + +} + +static int do_set_video_standard(int f, v4l2_std_id id, + int ret_input_enum, int errno_input_enum, + struct v4l2_input *input) +{ + int ret_std_set, errno_std_set; + int ret_std_get, errno_std_get; + v4l2_std_id std_id; + + std_id = id; + ret_std_set = ioctl(f, VIDIOC_S_STD, &std_id); + errno_std_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_STD: ret_std_set=%i, errno_std_set=%i, std_id=0x%llX, id=0x%llX\n", + __FILE__, __LINE__, ret_std_set, errno_std_set, std_id, id); + + memset(&std_id, 0xff, sizeof(std_id)); + ret_std_get = ioctl(f, VIDIOC_G_STD, &std_id); + errno_std_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_STD: ret_std_get=%i, errno_std_get=%i, std_id=0x%llX\n", + __FILE__, __LINE__, ret_std_get, errno_std_get, std_id); + + if (ret_input_enum == 0) { + CU_ASSERT_EQUAL(ret_input_enum, 0); + if (input->std == 0) { + CU_ASSERT_EQUAL(ret_std_get, -1); + CU_ASSERT_EQUAL(errno_std_get, EINVAL); + CU_ASSERT_EQUAL(ret_std_set, -1); + CU_ASSERT_EQUAL(errno_std_set, EINVAL); + } else { + if (ret_std_set == 0) { + CU_ASSERT_EQUAL(ret_std_set, 0); + CU_ASSERT_EQUAL(ret_std_get, 0); + CU_ASSERT(valid_v4l2_std_id(std_id)); + } else { + CU_ASSERT_EQUAL(ret_std_set, -1); + CU_ASSERT_EQUAL(errno_std_set, EINVAL); + } + } + } else { + CU_ASSERT_EQUAL(ret_input_enum, -1); + CU_ASSERT_EQUAL(errno_input_enum, EINVAL); + if (ret_std_set == 0) { + CU_ASSERT_EQUAL(ret_std_set, 0); + CU_ASSERT_EQUAL(ret_std_get, 0); + CU_ASSERT(valid_v4l2_std_id(std_id)); + } else { + CU_ASSERT_EQUAL(ret_std_set, -1); + CU_ASSERT_EQUAL(errno_std_set, EINVAL); + } + } + + return ret_std_set; +} + +static void do_test_VIDIOC_S_STD(int ret_input_enum, int errno_input_enum, + struct v4l2_input *input) +{ + int ret_get, errno_get; + int ret_set, errno_set; + v4l2_std_id std_id_orig; + int f; + + f = get_video_fd(); + + memset(&std_id_orig, 0xff, sizeof(std_id_orig)); + ret_get = ioctl(f, VIDIOC_G_STD, &std_id_orig); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_STD: ret_get=%i, errno_get=%i, std_id_orig=0x%llX\n", + __FILE__, __LINE__, ret_get, errno_get, std_id_orig); + + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_B, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_B1, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_G, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_H, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_I, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_D, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_D1, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_K, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_M, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_N, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_Nc, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_PAL_60, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_NTSC_M, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_NTSC_M_JP, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_NTSC_443, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_NTSC_M_KR, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_SECAM_B, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_SECAM_D, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_SECAM_G, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_SECAM_H, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_SECAM_K, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_SECAM_K1, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_SECAM_L, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_SECAM_LC, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_ATSC_8_VSB, ret_input_enum, + errno_input_enum, input); + ret_set = + do_set_video_standard(f, V4L2_STD_ATSC_16_VSB, ret_input_enum, + errno_input_enum, input); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + /* Setting the original std_id should not fail */ + ret_set = + do_set_video_standard(f, std_id_orig, ret_input_enum, + errno_input_enum, input); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + +} + +void test_VIDIOC_S_STD() +{ + foreach_input(do_test_VIDIOC_S_STD); +} + +static void do_test_VIDIOC_S_STD_from_enum(int ret_input_enum, + int errno_input_enum, + struct v4l2_input *input) +{ + int ret_get, errno_get; + int ret_enum, errno_enum; + int ret_set, errno_set; + v4l2_std_id std_id_orig; + struct v4l2_standard std; + __u32 i; + int f; + + f = get_video_fd(); + + memset(&std_id_orig, 0xff, sizeof(std_id_orig)); + ret_get = ioctl(f, VIDIOC_G_STD, &std_id_orig); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_STD: ret_get=%i, errno_get=%i, std_id_orig=0x%llX\n", + __FILE__, __LINE__, ret_get, errno_get, std_id_orig); + + /* Try to continue even if VIDIOC_G_STD returned error */ + i = 0; + do { + memset(&std, 0xff, sizeof(std)); + std.index = i; + ret_enum = ioctl(f, VIDIOC_ENUMSTD, &std); + errno_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUMSTD: i=%u, ret_enum=%i, errno_enum=%i, std.id=0x%llX\n", + __FILE__, __LINE__, i, ret_enum, errno_enum, std.id); + + if (ret_enum == 0) { + ret_set = + do_set_video_standard(f, std.id, ret_input_enum, + errno_input_enum, input); + CU_ASSERT_EQUAL(ret_set, 0); + } + i++; + } while (ret_enum == 0 && i != 0); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + /* Setting the original std_id should not fail */ + ret_set = + do_set_video_standard(f, std_id_orig, ret_input_enum, + errno_input_enum, input); + errno_set = errno; + dprintf + ("\t%s:%u: VIDIOC_S_STD: ret_set=%i (expected %i), errno=%i\n", + __FILE__, __LINE__, ret_set, 0, errno); + CU_ASSERT_EQUAL(ret_set, 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + +} + +void test_VIDIOC_S_STD_from_enum() +{ + foreach_input(do_test_VIDIOC_S_STD_from_enum); +} + +static void do_test_VIDIOC_S_STD_invalid_standard(int ret_input_enum, + int errno_input_enum, + struct v4l2_input *input) +{ + int ret_get, errno_get; + int ret_set, errno_set; + v4l2_std_id std_id_orig; + v4l2_std_id std_id; + int f; + + f = get_video_fd(); + + memset(&std_id_orig, 0xff, sizeof(std_id_orig)); + ret_get = ioctl(f, VIDIOC_G_STD, &std_id_orig); + errno_get = errno; + + dprintf + ("\t%s:%u: VIDIOC_G_STD: ret_get=%i, errno_get=%i, std_id_orig=0x%llX\n", + __FILE__, __LINE__, ret_get, errno_get, std_id_orig); + + /* Try to continue even if VIDIOC_G_STD retunred with error */ + std_id = 1; + while (std_id != 0) { + if (!valid_v4l2_std_id(std_id)) { + ret_set = + do_set_video_standard(f, std_id, ret_input_enum, + errno_input_enum, input); + errno_set = errno; + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + dprintf + ("\t%s:%u: VIDIOC_S_STD: ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + } + std_id = std_id << 1; + } + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + /* Setting the original std_id should not fail */ + ret_set = + do_set_video_standard(f, std_id_orig, ret_input_enum, + errno_input_enum, input); + errno_set = errno; + + dprintf + ("\t%s:%u: VIDIOC_S_STD: ret_set=%i (expected 0), errno=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + CU_ASSERT_EQUAL(ret_set, 0); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } +} + +void test_VIDIOC_S_STD_invalid_standard() +{ + foreach_input(do_test_VIDIOC_S_STD_invalid_standard); +} + +static void do_test_VIDIOC_G_STD_NULL(int ret_input_enum, int errno_input_enum, + struct v4l2_input *input) +{ + int ret_get, errno_get; + int ret_null, errno_null; + v4l2_std_id std_id; + + memset(&std_id, 0, sizeof(std_id)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_STD, &std_id); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_STD, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_STD, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_STD: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_input_enum == 0) { + CU_ASSERT_EQUAL(ret_input_enum, 0); + if (input->std == 0) { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } else { + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + } + } else { + CU_ASSERT_EQUAL(ret_input_enum, -1); + CU_ASSERT_EQUAL(errno_input_enum, EINVAL); + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + } + +} + +void test_VIDIOC_G_STD_NULL() +{ + foreach_input(do_test_VIDIOC_G_STD_NULL); +} + +static void do_test_VIDIOC_S_STD_NULL(int ret_input_enum, int errno_input_enum, + struct v4l2_input *input) +{ + int ret_null, errno_null; + + /* TODO: check whether VIDIOC_S_STD is supported at all or not */ + + ret_null = ioctl(get_video_fd(), VIDIOC_S_STD, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_S_STD: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + if (ret_input_enum == 0) { + CU_ASSERT_EQUAL(ret_input_enum, 0); + if (input->std == 0) { + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } else { + } + } else { + CU_ASSERT_EQUAL(ret_input_enum, -1); + CU_ASSERT_EQUAL(errno_input_enum, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } +} + +void test_VIDIOC_S_STD_NULL() +{ + foreach_input(do_test_VIDIOC_S_STD_NULL); +} + +/* TODO: VIDIOC_S_STD while STREAM_ON */ diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_STD.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_STD.h new file mode 100644 index 0000000000000000000000000000000000000000..000f6030867116adc802b38e893e047640238980 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_STD.h @@ -0,0 +1,16 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 22 Dec 2008 0.2 Test case with NULL parameter added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_STD(void); +void test_VIDIOC_S_STD(void); +void test_VIDIOC_S_STD_from_enum(void); +void test_VIDIOC_S_STD_invalid_standard(void); +void test_VIDIOC_G_STD_NULL(void); +void test_VIDIOC_S_STD_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_TUNER.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_TUNER.c new file mode 100644 index 0000000000000000000000000000000000000000..29b3dc1f2b9dd63578d57bde33321d5ce5a78c02 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_TUNER.c @@ -0,0 +1,567 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.5 Added string content validation + * 18 Apr 2009 0.4 More strict check for strings + * 28 Mar 2009 0.3 Clean up ret and errno variable names and dprintf() output + * 9 Feb 2009 0.2 Added test cases for VIDIOC_S_TUNER; + * Some typos corrected; + * Add some debug messages + * 31 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +#include "test_VIDIOC_TUNER.h" + +int valid_tuner_type(enum v4l2_tuner_type type) +{ + int valid = 0; + + switch (type) { + case V4L2_TUNER_RADIO: + case V4L2_TUNER_ANALOG_TV: + valid = 1; + break; + default: + valid = 0; + } + + return valid; +} + +int valid_tuner_sub(__u32 tuner_sub) +{ + int valid = 0; + + CU_ASSERT_EQUAL(V4L2_TUNER_SUB_SAP, V4L2_TUNER_SUB_LANG2); + + if ((tuner_sub & ~(V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_SAP)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +int valid_tuner_audmode(__u32 audmode) +{ + int valid = 0; + + CU_ASSERT_EQUAL(V4L2_TUNER_MODE_SAP, V4L2_TUNER_MODE_LANG2); + + switch (audmode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + case V4L2_TUNER_MODE_LANG2: + case V4L2_TUNER_MODE_LANG1_LANG2: + valid = 1; + break; + default: + valid = 0; + } + + return valid; +} + +static int do_get_tuner(int f, __u32 index) +{ + int ret_get, errno_get; + struct v4l2_tuner tuner; + struct v4l2_tuner tuner2; + + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = index; + ret_get = ioctl(f, VIDIOC_G_TUNER, &tuner); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + CU_ASSERT_EQUAL(tuner.index, index); + + CU_ASSERT(0 < strlen((char *)tuner.name)); + CU_ASSERT(valid_string((char *)tuner.name, sizeof(tuner.name))); + + CU_ASSERT(valid_tuner_type(tuner.type)); + CU_ASSERT(valid_tuner_capability(tuner.capability)); + + CU_ASSERT(tuner.rangelow <= tuner.rangehigh); + CU_ASSERT(valid_tuner_sub(tuner.rxsubchans)); + CU_ASSERT(valid_tuner_audmode(tuner.audmode)); + + /* tuner.signal can have any value */ + //CU_ASSERT_EQUAL(tuner.signal, ???); + + /* tuner.afc can have any value */ + //CU_ASSERT_EQUAL(tuner.afc, ???); + + CU_ASSERT_EQUAL(tuner.reserved[0], 0); + CU_ASSERT_EQUAL(tuner.reserved[1], 0); + CU_ASSERT_EQUAL(tuner.reserved[2], 0); + CU_ASSERT_EQUAL(tuner.reserved[3], 0); + + /* Check if the unused bytes of the name string are also filled + * with zeros. Also check if there is any padding byte between + * any two fields then this padding byte is also filled with + * zeros. + */ + memset(&tuner2, 0, sizeof(tuner2)); + tuner2.index = tuner.index; + strncpy((char *)tuner2.name, (char *)tuner.name, + sizeof(tuner2.name)); + tuner2.type = tuner.type; + tuner2.capability = tuner.capability; + tuner2.rangelow = tuner.rangelow; + tuner2.rangehigh = tuner.rangehigh; + tuner2.rxsubchans = tuner.rxsubchans; + tuner2.audmode = tuner.audmode; + tuner2.signal = tuner.signal; + tuner2.afc = tuner.afc; + CU_ASSERT_EQUAL(memcmp(&tuner, &tuner2, sizeof(tuner)), 0); + + dprintf("\ttuner = { " + ".index = %u, " + ".name = \"%s\", " + ".type = %i, " + ".capability = %u, " + ".rangelow = %u, " + ".rangehigh = %u, " + ".rxsubchans = %u, " + ".audmode = %u, " + ".signal = %u, " + ".afc = %i, " + ".reserved[]={ 0x%X, 0x%X, 0x%X, 0x%X } }\n", + tuner.index, + tuner.name, + tuner.type, + tuner.capability, + tuner.rangelow, + tuner.rangehigh, + tuner.rxsubchans, + tuner.audmode, + tuner.signal, + tuner.afc, + tuner.reserved[0], + tuner.reserved[1], tuner.reserved[2], tuner.reserved[3] + ); + + } else { + dprintf("\t%s:%u: ret_get=%d (expected %d)\n", __FILE__, + __LINE__, ret_get, -1); + dprintf("\t%s:%u: errno_get=%d (expected %d)\n", __FILE__, + __LINE__, errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + } + + return ret_get; +} + +void test_VIDIOC_G_TUNER() +{ + int ret; + __u32 index; + int f; + + f = get_video_fd(); + + index = 0; + do { + ret = do_get_tuner(f, index); + index++; + } while (ret == 0); + +} + +void test_VIDIOC_G_TUNER_S32_MAX() +{ + int ret_get, errno_get; + __u32 index; + struct v4l2_tuner tuner; + + index = (__u32) S32_MAX; + + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = index; + ret_get = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + dprintf("\t%s:%u: ret_get=%d (expected %d)\n", __FILE__, __LINE__, + ret_get, -1); + dprintf("\t%s:%u: errno_get=%d (expected %d)\n", __FILE__, __LINE__, + errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_TUNER_S32_MAX_1() +{ + int ret_get, errno_get; + __u32 index; + struct v4l2_tuner tuner; + + index = (__u32) S32_MAX + 1; + + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = index; + ret_get = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER, ret_get=%i\n", + __FILE__, __LINE__, ret_get); + + dprintf("\t%s:%u: ret_get=%d (expected %d)\n", __FILE__, __LINE__, + ret_get, -1); + dprintf("\t%s:%u: errno_get=%d (expected %d)\n", __FILE__, __LINE__, + errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_TUNER_U32_MAX() +{ + int ret_get, errno_get; + __u32 index; + struct v4l2_tuner tuner; + + index = U32_MAX; + + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = index; + ret_get = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + dprintf("\t%s:%u: ret_get=%d (expected %d)\n", __FILE__, __LINE__, + ret_get, -1); + dprintf("\t%s:%u: errno_get=%d (expected %d)\n", __FILE__, __LINE__, + errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); +} + +void test_VIDIOC_G_TUNER_NULL() +{ + int ret_get, errno_get; + int ret_null, errno_null; + struct v4l2_tuner tuner; + + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = 0; + ret_get = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner); + errno_get = errno; + dprintf("\t%s:%u: VIDIOC_G_TUNER: ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + ret_null = ioctl(get_video_fd(), VIDIOC_G_TUNER, NULL); + errno_null = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_null, errno_null); + + /* check if VIDIOC_G_TUNER is supported at all or not */ + if (ret_get == 0) { + /* VIDIOC_G_TUNER is supported, the parameter should be checked */ + CU_ASSERT_EQUAL(ret_get, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + /* VIDIOC_G_TUNER not supported at all, the parameter should not be evaluated */ + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} + +void do_set_tuner_audmode(__u32 index, __u32 audmode) +{ + int ret_set, errno_set; + struct v4l2_tuner tuner; + + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = index; + tuner.audmode = audmode; + ret_set = ioctl(get_video_fd(), VIDIOC_S_TUNER, &tuner); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_TUNER: index=%u, audmode=%u, " + "ret_set=%i (expected %i), errno_set=%i\n", + __FILE__, __LINE__, index, audmode, ret_set, 0, errno_set); + + CU_ASSERT_EQUAL(ret_set, 0); + +} + +void do_set_tuner_audmode_invalid(__u32 index, __u32 audmode) +{ + int ret_set, errno_set; + struct v4l2_tuner tuner; + + memset(&tuner, 0xff, sizeof(tuner)); + tuner.index = index; + tuner.audmode = audmode; + ret_set = ioctl(get_video_fd(), VIDIOC_S_TUNER, &tuner); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_TUNER: index=%u, audmode=%u, " + "ret_set=%i (expected %i), errno_set=%i (expected %i)\n", + __FILE__, __LINE__, + index, audmode, ret_set, -1, errno_set, EINVAL); + + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); +} + +void test_VIDIOC_S_TUNER() +{ + int ret_get, errno_get; + int ret_set, errno_set; + struct v4l2_tuner tuner_orig; + struct v4l2_tuner tuner_set; + + /* remember the tuner settings */ + memset(&tuner_orig, 0, sizeof(tuner_orig)); + ret_get = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner_orig); + errno_get = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER, ret_get=%i, errno_get=%i\n", + __FILE__, __LINE__, ret_get, errno_get); + + if (ret_get == 0) { + CU_ASSERT_EQUAL(ret_get, 0); + + do_set_tuner_audmode(tuner_orig.index, V4L2_TUNER_MODE_MONO); + do_set_tuner_audmode(tuner_orig.index, V4L2_TUNER_MODE_STEREO); + do_set_tuner_audmode(tuner_orig.index, V4L2_TUNER_MODE_LANG1); + do_set_tuner_audmode(tuner_orig.index, V4L2_TUNER_MODE_LANG2); + do_set_tuner_audmode(tuner_orig.index, V4L2_TUNER_MODE_SAP); + do_set_tuner_audmode(tuner_orig.index, + V4L2_TUNER_MODE_LANG1_LANG2); + + } else { + CU_ASSERT_EQUAL(ret_get, -1); + CU_ASSERT_EQUAL(errno_get, EINVAL); + + /* if VIDIOC_G_TUNER is not supported then VIDIOC_S_TUNER shall also + * not supported. + */ + do_set_tuner_audmode_invalid(tuner_orig.index, + V4L2_TUNER_MODE_MONO); + do_set_tuner_audmode_invalid(tuner_orig.index, + V4L2_TUNER_MODE_STEREO); + do_set_tuner_audmode_invalid(tuner_orig.index, + V4L2_TUNER_MODE_LANG1); + do_set_tuner_audmode_invalid(tuner_orig.index, + V4L2_TUNER_MODE_LANG2); + do_set_tuner_audmode_invalid(tuner_orig.index, + V4L2_TUNER_MODE_SAP); + do_set_tuner_audmode_invalid(tuner_orig.index, + V4L2_TUNER_MODE_LANG1_LANG2); + + } + + if (ret_get == 0) { + + /* restore the tuner settings */ + memset(&tuner_set, 0xff, sizeof(tuner_set)); + tuner_set.index = tuner_orig.index; + tuner_set.audmode = tuner_orig.audmode; + ret_set = ioctl(get_video_fd(), VIDIOC_S_TUNER, &tuner_orig); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_TUNER, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, 0); + } + +} + +void test_VIDIOC_S_TUNER_invalid() +{ + int ret1, errno1; + int ret_set, errno_set; + struct v4l2_tuner tuner_orig; + struct v4l2_tuner tuner_set; + + /* remember the tuner settings */ + memset(&tuner_orig, 0, sizeof(tuner_orig)); + ret1 = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner_orig); + errno1 = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER, ret1=%i, errno1=%i\n", + __FILE__, __LINE__, ret1, errno1); + + if (ret1 == 0) { + CU_ASSERT_EQUAL(ret1, 0); + + /* try with invalid index */ + do_set_tuner_audmode_invalid(tuner_orig.index + 1, + V4L2_TUNER_MODE_MONO); + do_set_tuner_audmode_invalid(tuner_orig.index - 1, + V4L2_TUNER_MODE_MONO); + do_set_tuner_audmode_invalid((__u32) S32_MAX, + V4L2_TUNER_MODE_MONO); + do_set_tuner_audmode_invalid(((__u32) S32_MAX) + 1, + V4L2_TUNER_MODE_MONO); + do_set_tuner_audmode_invalid(U32_MAX, V4L2_TUNER_MODE_MONO); + + do_set_tuner_audmode_invalid(tuner_orig.index + 1, + V4L2_TUNER_MODE_STEREO); + do_set_tuner_audmode_invalid(tuner_orig.index - 1, + V4L2_TUNER_MODE_STEREO); + do_set_tuner_audmode_invalid((__u32) S32_MAX, + V4L2_TUNER_MODE_STEREO); + do_set_tuner_audmode_invalid(((__u32) S32_MAX) + 1, + V4L2_TUNER_MODE_STEREO); + do_set_tuner_audmode_invalid(U32_MAX, V4L2_TUNER_MODE_STEREO); + + do_set_tuner_audmode_invalid(tuner_orig.index + 1, + V4L2_TUNER_MODE_LANG1); + do_set_tuner_audmode_invalid(tuner_orig.index - 1, + V4L2_TUNER_MODE_LANG1); + do_set_tuner_audmode_invalid((__u32) S32_MAX, + V4L2_TUNER_MODE_LANG1); + do_set_tuner_audmode_invalid(((__u32) S32_MAX) + 1, + V4L2_TUNER_MODE_LANG1); + do_set_tuner_audmode_invalid(U32_MAX, V4L2_TUNER_MODE_LANG1); + + do_set_tuner_audmode_invalid(tuner_orig.index + 1, + V4L2_TUNER_MODE_LANG2); + do_set_tuner_audmode_invalid(tuner_orig.index - 1, + V4L2_TUNER_MODE_LANG2); + do_set_tuner_audmode_invalid((__u32) S32_MAX, + V4L2_TUNER_MODE_LANG2); + do_set_tuner_audmode_invalid(((__u32) S32_MAX) + 1, + V4L2_TUNER_MODE_LANG2); + do_set_tuner_audmode_invalid(U32_MAX, V4L2_TUNER_MODE_LANG2); + + do_set_tuner_audmode_invalid(tuner_orig.index + 1, + V4L2_TUNER_MODE_SAP); + do_set_tuner_audmode_invalid(tuner_orig.index - 1, + V4L2_TUNER_MODE_SAP); + do_set_tuner_audmode_invalid((__u32) S32_MAX, + V4L2_TUNER_MODE_SAP); + do_set_tuner_audmode_invalid(((__u32) S32_MAX) + 1, + V4L2_TUNER_MODE_SAP); + do_set_tuner_audmode_invalid(U32_MAX, V4L2_TUNER_MODE_SAP); + + do_set_tuner_audmode_invalid(tuner_orig.index + 1, + V4L2_TUNER_MODE_LANG1_LANG2); + do_set_tuner_audmode_invalid(tuner_orig.index - 1, + V4L2_TUNER_MODE_LANG1_LANG2); + do_set_tuner_audmode_invalid((__u32) S32_MAX, + V4L2_TUNER_MODE_LANG1_LANG2); + do_set_tuner_audmode_invalid(((__u32) S32_MAX) + 1, + V4L2_TUNER_MODE_LANG1_LANG2); + do_set_tuner_audmode_invalid(U32_MAX, + V4L2_TUNER_MODE_LANG1_LANG2); + + } else { + CU_ASSERT_EQUAL(ret1, -1); + CU_ASSERT_EQUAL(errno1, EINVAL); + + } + + /* try with invalid audmode */ + do_set_tuner_audmode_invalid(tuner_orig.index, 5); + do_set_tuner_audmode_invalid(tuner_orig.index, (__u32) S32_MAX); + do_set_tuner_audmode_invalid(tuner_orig.index, ((__u32) S32_MAX) + 1); + do_set_tuner_audmode_invalid(tuner_orig.index, U32_MAX); + + if (ret1 == 0) { + + /* restore the tuner settings */ + memset(&tuner_set, 0xff, sizeof(tuner_set)); + tuner_set.index = tuner_orig.index; + tuner_set.audmode = tuner_orig.audmode; + ret_set = ioctl(get_video_fd(), VIDIOC_S_TUNER, &tuner_orig); + errno_set = errno; + + dprintf("\t%s:%u: VIDIOC_S_TUNER, ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + CU_ASSERT_EQUAL(ret_set, 0); + } + +} + +void test_VIDIOC_S_TUNER_NULL() +{ + int ret_orig, errno_orig; + int ret_null, errno_null; + int ret_set, errno_set; + struct v4l2_tuner tuner_orig; + struct v4l2_tuner tuner; + + /* remember the tuner settings */ + memset(&tuner_orig, 0, sizeof(tuner_orig)); + ret_orig = ioctl(get_video_fd(), VIDIOC_G_TUNER, &tuner_orig); + errno_orig = errno; + + dprintf("\t%s:%u: VIDIOC_G_TUNER, ret_orig=%i, errno_orig=%i\n", + __FILE__, __LINE__, ret_orig, errno_orig); + + memset(&tuner, 0, sizeof(tuner)); + tuner.index = tuner_orig.index; + tuner.audmode = tuner_orig.audmode; + ret_set = ioctl(get_video_fd(), VIDIOC_S_TUNER, &tuner); + errno_set = errno; + + dprintf("\t%s:%u:VIDIOC_S_TUNER: ret_set=%i, errno_set=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + ret_null = ioctl(get_video_fd(), VIDIOC_S_TUNER, NULL); + errno_null = errno; + + dprintf("\t%s:%u:VIDIOC_S_TUNER: ret_null=%i, errno_null=%i\n", + __FILE__, __LINE__, ret_set, errno_set); + + if (ret_set == 0) { + CU_ASSERT_EQUAL(ret_set, 0); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EFAULT); + } else { + CU_ASSERT_EQUAL(ret_set, -1); + CU_ASSERT_EQUAL(errno_set, EINVAL); + CU_ASSERT_EQUAL(ret_null, -1); + CU_ASSERT_EQUAL(errno_null, EINVAL); + } + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_TUNER.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_TUNER.h new file mode 100644 index 0000000000000000000000000000000000000000..1e11477d7b83d9aa7a8ecf63355f5d373b7b80c7 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_VIDIOC_TUNER.h @@ -0,0 +1,18 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 31 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_VIDIOC_G_TUNER(void); +void test_VIDIOC_G_TUNER_S32_MAX(void); +void test_VIDIOC_G_TUNER_S32_MAX_1(void); +void test_VIDIOC_G_TUNER_U32_MAX(void); +void test_VIDIOC_G_TUNER_NULL(void); + +void test_VIDIOC_S_TUNER(void); +void test_VIDIOC_S_TUNER_invalid(void); +void test_VIDIOC_S_TUNER_NULL(void); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_invalid_ioctl.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_invalid_ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..0ea948674a59b619845aac4b40092fb0592637de --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_invalid_ioctl.c @@ -0,0 +1,63 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 28 Mar 2009 0.2 Clean up ret and errno variable names + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_invalid_ioctl.h" + +/* invalid ioctls */ + +static void do_invalid_ioctl(int f, int request) +{ + int ret_invalid, errno_invalid; + + ret_invalid = ioctl(f, request, NULL); + errno_invalid = errno; + + CU_ASSERT_EQUAL(ret_invalid, -1); + CU_ASSERT_EQUAL(errno_invalid, EINVAL); +} + +void test_invalid_ioctl_1() +{ + do_invalid_ioctl(get_video_fd(), _IO(0, 0)); +} + +void test_invalid_ioctl_2() +{ + do_invalid_ioctl(get_video_fd(), _IO(0xFF, 0xFF)); +} + +void test_invalid_ioctl_3() +{ + do_invalid_ioctl(get_video_fd(), _IO('v', 0xFF)); +} + +void test_invalid_ioctl_4() +{ + do_invalid_ioctl(get_video_fd(), _IO('V', 0xFF)); +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/test_invalid_ioctl.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_invalid_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..ce5895142ca70e055baeed946463a765a46ff695 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/test_invalid_ioctl.h @@ -0,0 +1,14 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +void test_invalid_ioctl_1(void); +void test_invalid_ioctl_2(void); +void test_invalid_ioctl_3(void); +void test_invalid_ioctl_4(void); + diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_foreach.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_foreach.c new file mode 100644 index 0000000000000000000000000000000000000000..ce6f41618fed2a4c9e46beafefbdaf06acf5c7e3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_foreach.c @@ -0,0 +1,89 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 5 Jul 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "v4l2_show.h" +#include "v4l2_foreach.h" + +void foreach_input(V4L2InputTestFunc pFunc) +{ + __u32 input_index_orig; + struct v4l2_input input; + int ret_input_get, errno_input_get; + int ret_input_enum, errno_input_enum; + int ret_input_set, errno_input_set; + __u32 i; + int f; + char not_yet_called = 1; + + f = get_video_fd(); + + memset(&input_index_orig, 0xff, sizeof(input_index_orig)); + ret_input_get = ioctl(f, VIDIOC_G_INPUT, &input_index_orig); + errno_input_get = errno; + dprintf + ("\t%s:%u: VIDIOC_G_INPUT, ret_input_get=%i, errno_input_get=%i, input_index_orig=0x%X\n", + __FILE__, __LINE__, ret_input_get, errno_input_get, + input_index_orig); + + i = 0; + do { + memset(&input, 0xff, sizeof(input)); + input.index = i; + ret_input_enum = ioctl(f, VIDIOC_ENUMINPUT, &input); + errno_input_enum = errno; + + dprintf + ("\t%s:%u: VIDIOC_ENUMINPUT: i=%u, ret_input_enum=%i, errno_input_enum=%i\n", + __FILE__, __LINE__, i, ret_input_enum, errno_input_enum); + + if (ret_input_enum == 0) { + show_v4l2_input(&input); + ret_input_set = ioctl(f, VIDIOC_S_INPUT, &input.index); + errno_input_set = errno; + dprintf + ("\t%s:%u: VIDIOC_S_INPUT: input.index=0x%X, ret_input_set=%i, errno_input_set=%i\n", + __FILE__, __LINE__, input.index, ret_input_set, + errno_input_set); + CU_ASSERT_EQUAL(ret_input_set, 0); + } + + /* Ensure that pFunc() is called at least once even if + * everything else returned error before. + */ + if (not_yet_called || ret_input_enum == 0) { + pFunc(ret_input_enum, errno_input_enum, &input); + not_yet_called = 0; + } + + i++; + } while (ret_input_enum == 0 && i != 0); + + if (ret_input_get == 0) { + /* Setting the original input_id should not fail */ + ret_input_set = ioctl(f, VIDIOC_S_INPUT, &input_index_orig); + errno_input_set = errno; + CU_ASSERT_EQUAL(ret_input_set, 0); + } +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_foreach.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_foreach.h new file mode 100644 index 0000000000000000000000000000000000000000..74530b0dbd206b453fb7d4d8ae571d8f1f7c1a6e --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_foreach.h @@ -0,0 +1,14 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 5 Jul 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include + +typedef void (*V4L2InputTestFunc)(int ret_input_enum, int errno_input_enum, struct v4l2_input* input); + +void foreach_input(V4L2InputTestFunc pFunc); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_show.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_show.c new file mode 100644 index 0000000000000000000000000000000000000000..663dfcc83054a5909114d58230916ae64ce33599 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_show.c @@ -0,0 +1,165 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 17 Jul 2009 0.3 show_v4l2_frmsizeenum() added + * 5 Jul 2009 0.2 show_v4l2_input() introduced + * 7 May 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_REQBUFS.h" + +void show_v4l2_requestbuffers(struct v4l2_requestbuffers *reqbuf) +{ + dprintf("\treqbuf = { " + ".count=%u, " + ".type=%i, " + ".memory=%i, " + ".reserved = { 0x%X, 0x%X } " + "}\n", + reqbuf->count, + reqbuf->type, + reqbuf->memory, reqbuf->reserved[0], reqbuf->reserved[1] + ); +} + +void show_v4l2_buffer(struct v4l2_buffer *buf) +{ + unsigned int i; + + dprintf("\tbuf = { " + ".index=%u, " + ".type=%i, " + ".bytesused=%u, " + ".flags=0x%x, " + ".field=%i, " + ".timestamp = { tv_sec=%lu, tv_usec=%lu }, " + ".timecode = { " + ".type=%u, " + ".flags=0x%x, " + ".frames=%u, " + ".seconds=%u, " + ".minutes=%u, " + ".hours=%u, " + ".userbits = { 0x%x, 0x%x, 0x%x, 0x%x } " + " }, " + ".sequence=%u, " + ".memory=%i, ", + buf->index, + buf->type, + buf->bytesused, + buf->flags, + buf->field, + buf->timestamp.tv_sec, + buf->timestamp.tv_usec, + buf->timecode.type, + buf->timecode.flags, + buf->timecode.frames, + buf->timecode.seconds, + buf->timecode.minutes, + buf->timecode.hours, + buf->timecode.userbits[0], + buf->timecode.userbits[1], + buf->timecode.userbits[2], + buf->timecode.userbits[3], buf->sequence, buf->memory); + + switch (buf->memory) { + case V4L2_MEMORY_USERPTR: + dprintf(".m.userptr=0x%lx, ", buf->m.userptr); + for (i = sizeof(buf->m.userptr); i < sizeof(buf->m); i++) { + dprintf("((__u8*)&.m)[%u]=0x%x, ", + i, ((__u8 *) & buf->m)[i]); + } + break; + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + default: + dprintf(".m.offset=%u, ", buf->m.offset); + for (i = sizeof(buf->m.offset); i < sizeof(buf->m); i++) { + dprintf("((__u8*)&.m)[%u]=0x%x, ", + i, ((__u8 *) & buf->m)[i]); + } + } + + dprintf(".length=%u, " + ".input=%u, " + ".reserved=0x%x " + "}\n", buf->length, buf->input, buf->reserved); + +} + +void show_v4l2_input(struct v4l2_input *input) +{ + dprintf("\tinput = {.index=%u, .name=\"%s\", " + ".type=0x%X, .audioset=0x%X, .tuner=0x%X, " + ".std=%llX, " + ".status=0x%X, " + ".reserved[]={ 0x%X, 0x%X, 0x%X, 0x%X } }\n", + input->index, + input->name, + input->type, + input->audioset, + input->tuner, + input->std, + input->status, + input->reserved[0], + input->reserved[1], input->reserved[2], input->reserved[3] + ); +} + +void show_v4l2_frmsizeenum(struct v4l2_frmsizeenum *framesize) +{ + dprintf("\tframesize = { .index=%u, " + ".pixel_format=0x%x, " + ".type=%u, ", + framesize->index, framesize->pixel_format, framesize->type); + + switch (framesize->type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + dprintf(".discrete = { .width=%u, heigth=%u }, ", + framesize->discrete.width, framesize->discrete.height); + break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + case V4L2_FRMSIZE_TYPE_STEPWISE: + dprintf(".stepwise = { .min_width=%u, " + ".max_width=%u, " + ".step_width=%u, " + ".min_height=%u, " + ".max_height=%u, " + ".step_height=%u }, ", + framesize->stepwise.min_width, + framesize->stepwise.max_width, + framesize->stepwise.step_width, + framesize->stepwise.min_height, + framesize->stepwise.max_height, + framesize->stepwise.step_height); + break; + default: + ; + } + + dprintf(".reserved = { 0x%x, 0x%x } }\n", + framesize->reserved[0], framesize->reserved[1] + ); + +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_show.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_show.h new file mode 100644 index 0000000000000000000000000000000000000000..1ab8b3b382987320c917986027846e2f3bda00a3 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_show.h @@ -0,0 +1,17 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 17 Jul 2009 0.3 show_v4l2_frmsizeenum() added + * 5 Jul 2009 0.2 show_v4l2_input() introduced + * 7 May 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include + +void show_v4l2_requestbuffers(struct v4l2_requestbuffers *reqbuf); +void show_v4l2_buffer(struct v4l2_buffer *buf); +void show_v4l2_input(struct v4l2_input *input); +void show_v4l2_frmsizeenum(struct v4l2_frmsizeenum* framesize); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_test.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_test.c new file mode 100644 index 0000000000000000000000000000000000000000..1e4b4bae693e564361f780528711002d59ee3f21 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_test.c @@ -0,0 +1,487 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 16 Jul 2009 0.24 Test cases added for VIDIOC_G_JPEGCOMP and VIDIOC_ENUM_FRAMESIZES + * 23 May 2009 0.23 Test cases added for VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS + * 5 May 2009 0.22 Test cases added for VIDIOC_QUERYBUF + * 29 Apr 2009 0.21 Test cases added for VIDIOC_REQBUFS + * 18 Apr 2009 0.20 NULL parameter test suite split to read only, write only + * and write/read ioctl suite + * 16 Apr 2009 0.19 Test cases added for VIDIOC_S_FMT + * 5 Apr 2009 0.18 Test cases for VIDIOC_QUERYMENU added + * 4 Apr 2009 0.17 Test cases for VIDIOC_G_FMT added + * 29 Mar 2009 0.16 Test case for VIDIOC_S_FREQUENCY with NULL parameter added + * 22 Mar 2009 0.15 Test cases added for VIDIOC_G_OUTPUT and VIDIOC_S_OUTPUT + * 18 Mar 2009 0.14 Test cases added for VIDIOC_G_PARM + * 7 Mar 2009 0.13 Test cases added for VIDIOC_S_CROP + * 22 Feb 2009 0.12 Test cases added for VIDIOC_S_CTRL + * 19 Feb 2009 0.11 Test cases added for VIDIOC_G_CTRL + * 7 Feb 2009 0.10 Test cases added for VIDIOC_G_AUDIO, VIDIOC_G_AUDOUT, + * VIDIOC_S_AUDIO and VIDIOC_G_CROP + * 3 Feb 2009 0.9 Test cases for VIDIOC_G_AUDIO and VIDIOC_G_AUDOUT added + * 2 Feb 2009 0.8 Test cases for VIDIOC_G_MODULATOR, VIDIOC_G_PRIORITY + * and VIDIOC_S_PRIORITY added + * 1 Feb 2009 0.7 Test cases for VIDIOC_S_FREQUENCY added + * 31 Jan 2009 0.6 Test cases for VIDIOC_G_TUNER added + * 18 Jan 2009 0.5 Test cases for MAX_EM28XX_INPUT and MAX_EM28XX_TVNORMS + * removed + * 1 Jan 2009 0.4 Test cases for VIDIOC_ENUMOUTPUT, VIDIOC_ENUMAUDOUT, + * VIDIOC_QUERYCTRL added; + * New test cases for VIDIOC_ENUMAUDIO, VIDIOC_ENUM_FMT, + * VIDIOC_ENUM_STD + * 23 Dec 2008 0.3 Test cases for VIDIOC_LOG_STATUS added + * 22 Dec 2008 0.2 Test cases with NULL parameter added; + * Test cases for VIDIOC_CROPCAP added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" + +#include "test_VIDIOC_QUERYCAP.h" +#include "test_VIDIOC_QUERYSTD.h" +#include "test_VIDIOC_QUERYCTRL.h" +#include "test_VIDIOC_QUERYMENU.h" +#include "test_VIDIOC_CROPCAP.h" +#include "test_VIDIOC_G_SLICED_VBI_CAP.h" + +#include "test_VIDIOC_ENUMAUDIO.h" +#include "test_VIDIOC_ENUMAUDOUT.h" +#include "test_VIDIOC_ENUMSTD.h" +#include "test_VIDIOC_ENUM_FMT.h" +#include "test_VIDIOC_ENUMINPUT.h" +#include "test_VIDIOC_ENUMOUTPUT.h" +#include "test_VIDIOC_ENUM_FRAMESIZES.h" + +#include "test_VIDIOC_STD.h" +#include "test_VIDIOC_INPUT.h" +#include "test_VIDIOC_OUTPUT.h" +#include "test_VIDIOC_TUNER.h" +#include "test_VIDIOC_MODULATOR.h" +#include "test_VIDIOC_FREQUENCY.h" +#include "test_VIDIOC_PRIORITY.h" +#include "test_VIDIOC_AUDIO.h" +#include "test_VIDIOC_AUDOUT.h" +#include "test_VIDIOC_CROP.h" +#include "test_VIDIOC_CTRL.h" +#include "test_VIDIOC_EXT_CTRLS.h" +#include "test_VIDIOC_PARM.h" +#include "test_VIDIOC_FMT.h" +#include "test_VIDIOC_JPEGCOMP.h" + +#include "test_VIDIOC_REQBUFS.h" +#include "test_VIDIOC_QUERYBUF.h" + +#include "test_VIDIOC_LOG_STATUS.h" +#include "test_invalid_ioctl.h" + +static CU_TestInfo suite_querycap[] = { + {"VIDIOC_QUERYCAP", test_VIDIOC_QUERYCAP}, + + {"VIDIOC_CROPCAP", test_VIDIOC_CROPCAP}, + {"VIDIOC_CROPCAP with different inputs", + test_VIDIOC_CROPCAP_enum_INPUT}, + + {"VIDIOC_G_SLICED_VBI_CAP", test_VIDIOC_G_SLICED_VBI_CAP}, + {"VIDIOC_G_SLICED_VBI_CAP with invalid types", + test_VIDIOC_G_SLICED_VBI_CAP_invalid}, + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_enums[] = { + {"VIDIOC_ENUMAUDIO", test_VIDIOC_ENUMAUDIO}, + {"VIDIOC_ENUMAUDIO, index=S32_MAX", test_VIDIOC_ENUMAUDIO_S32_MAX}, + {"VIDIOC_ENUMAUDIO, index=S32_MAX+1", test_VIDIOC_ENUMAUDIO_S32_MAX_1}, + {"VIDIOC_ENUMAUDIO, index=U32_MAX", test_VIDIOC_ENUMAUDIO_U32_MAX}, + + {"VIDIOC_ENUMAUDOUT", test_VIDIOC_ENUMAUDOUT}, + {"VIDIOC_ENUMAUDOUT, index=S32_MAX", test_VIDIOC_ENUMAUDOUT_S32_MAX}, + {"VIDIOC_ENUMAUDOUT, index=S32_MAX+1", + test_VIDIOC_ENUMAUDOUT_S32_MAX_1}, + {"VIDIOC_ENUMAUDOUT, index=U32_MAX", test_VIDIOC_ENUMAUDOUT_U32_MAX}, + + {"VIDIOC_ENUM_FMT", test_VIDIOC_ENUM_FMT}, + {"VIDIOC_ENUM_FMT, index=S32_MAX", test_VIDIOC_ENUM_FMT_S32_MAX}, + {"VIDIOC_ENUM_FMT, index=S32_MAX+1", test_VIDIOC_ENUM_FMT_S32_MAX_1}, + {"VIDIOC_ENUM_FMT, index=U32_MAX", test_VIDIOC_ENUM_FMT_U32_MAX}, + {"VIDIOC_ENUM_FMT, invalid type", test_VIDIOC_ENUM_FMT_invalid_type}, + + {"VIDIOC_ENUMINPUT", test_VIDIOC_ENUMINPUT}, + {"VIDIOC_ENUMINPUT, index=S32_MAX", test_VIDIOC_ENUMINPUT_S32_MAX}, + {"VIDIOC_ENUMINPUT, index=S32_MAX+1", test_VIDIOC_ENUMINPUT_S32_MAX_1}, + {"VIDIOC_ENUMINPUT, index=U32_MAX", test_VIDIOC_ENUMINPUT_U32_MAX}, + + {"VIDIOC_ENUMOUTPUT", test_VIDIOC_ENUMOUTPUT}, + {"VIDIOC_ENUMOUTPUT, index=S32_MAX", test_VIDIOC_ENUMOUTPUT_S32_MAX}, + {"VIDIOC_ENUMOUTPUT, index=S32_MAX+1", + test_VIDIOC_ENUMOUTPUT_S32_MAX_1}, + {"VIDIOC_ENUMOUTPUT, index=U32_MAX", test_VIDIOC_ENUMOUTPUT_U32_MAX}, + + {"VIDIOC_ENUMSTD", test_VIDIOC_ENUMSTD}, + {"VIDIOC_ENUMSTD, index=S32_MAX", test_VIDIOC_ENUMSTD_S32_MAX}, + {"VIDIOC_ENUMSTD, index=S32_MAX+1", test_VIDIOC_ENUMSTD_S32_MAX_1}, + {"VIDIOC_ENUMSTD, index=U32_MAX", test_VIDIOC_ENUMSTD_U32_MAX}, + + {"VIDIOC_QUERYCTRL", test_VIDIOC_QUERYCTRL}, + {"VIDIOC_QUERYCTRL, id=V4L2_CID_BASE-1", test_VIDIOC_QUERYCTRL_BASE_1}, + {"VIDIOC_QUERYCTRL, id=V4L2_CID_LASTP1", test_VIDIOC_QUERYCTRL_LASTP1}, + {"VIDIOC_QUERYCTRL, id=V4L2_CID_LASTP1+1", + test_VIDIOC_QUERYCTRL_LASTP1_1}, + {"VIDIOC_QUERYCTRL with V4L2_CTRL_FLAG_NEXT_CTRL", + test_VIDIOC_QUERYCTRL_flag_NEXT_CTRL}, + {"VIDIOC_QUERYCTRL, enumerate private controls", + test_VIDIOC_QUERYCTRL_private}, + {"VIDIOC_QUERYCTRL, V4L2_CID_PRIVATE_BASE-1", + test_VIDIOC_QUERYCTRL_private_base_1}, + {"VIDIOC_QUERYCTRL, last private control+1", + test_VIDIOC_QUERYCTRL_private_last_1}, + + {"VIDIOC_QUERYMENU", test_VIDIOC_QUERYMENU}, + {"VIDIOC_QUERYMENU with invalid id", test_VIDIOC_QUERYMENU_invalid}, + {"VIDIOC_QUERYMENU with private controls", + test_VIDIOC_QUERYMENU_private}, + {"VIDIOC_QUERYMENU, last private control+1", + test_VIDIOC_QUERYMENU_private_last_1}, + + {"VIDIOC_ENUM_FRAMESIZES", test_VIDIOC_ENUM_FRAMESIZES}, + {"VIDIOC_ENUM_FRAMESIZES with invalid index", + test_VIDIOC_ENUM_FRAMESIZES_invalid_index}, + {"VIDIOC_ENUM_FRAMESIZES with invalid pixel_format", + test_VIDIOC_ENUM_FRAMESIZES_invalid_pixel_format}, + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_get_set_try[] = { + {"VIDIOC_G_STD", test_VIDIOC_G_STD}, + {"VIDIOC_S_STD with the enumerated values", + test_VIDIOC_S_STD_from_enum}, + {"VIDIOC_S_STD", test_VIDIOC_S_STD}, + {"VIDIOC_S_STD with invalid standard", + test_VIDIOC_S_STD_invalid_standard}, + + {"VIDIOC_G_INPUT", test_VIDIOC_G_INPUT}, + {"VIDIOC_S_INPUT from enum", test_VIDIOC_S_INPUT_from_enum}, + {"VIDIOC_S_INPUT with invalid inputs", + test_VIDIOC_S_INPUT_invalid_inputs}, + + {"VIDIOC_G_OUTPUT", test_VIDIOC_G_OUTPUT}, + {"VIDIOC_S_OUTPUT from enum", test_VIDIOC_S_OUTPUT_from_enum}, + {"VIDIOC_S_OUTPUT with invalid outputs", + test_VIDIOC_S_OUTPUT_invalid_outputs}, + + {"VIDIOC_G_TUNER", test_VIDIOC_G_TUNER}, + {"VIDIOC_G_TUNER, index=S32_MAX", test_VIDIOC_G_TUNER_S32_MAX}, + {"VIDIOC_G_TUNER, index=S32_MAX+1", test_VIDIOC_G_TUNER_S32_MAX_1}, + {"VIDIOC_G_TUNER, index=U32_MAX", test_VIDIOC_G_TUNER_U32_MAX}, + + {"VIDIOC_S_TUNER", test_VIDIOC_S_TUNER}, + {"VIDIOC_S_TUNER with invalid index and audmode parameters", + test_VIDIOC_S_TUNER_invalid}, + + {"VIDIOC_G_MODULATOR", test_VIDIOC_G_MODULATOR}, + {"VIDIOC_G_MODULATOR, index=S32_MAX", test_VIDIOC_G_MODULATOR_S32_MAX}, + {"VIDIOC_G_MODULATOR, index=S32_MAX+1", + test_VIDIOC_G_MODULATOR_S32_MAX_1}, + {"VIDIOC_G_MODULATOR, index=U32_MAX", test_VIDIOC_G_MODULATOR_U32_MAX}, + + {"VIDIOC_G_FREQUENCY", test_VIDIOC_G_FREQUENCY}, + {"VIDIOC_G_FREQUENCY, tuner=S32_MAX", test_VIDIOC_G_FREQUENCY_S32_MAX}, + {"VIDIOC_G_FREQUENCY, tuner=S32_MAX+1", + test_VIDIOC_G_FREQUENCY_S32_MAX_1}, + {"VIDIOC_G_FREQUENCY, tuner=U32_MAX", test_VIDIOC_G_FREQUENCY_U32_MAX}, + + {"VIDIOC_S_FREQUENCY", test_VIDIOC_S_FREQUENCY}, + {"VIDIOC_S_FREQUENCY with boundary values", + test_VIDIOC_S_FREQUENCY_boundaries}, + {"VIDIOC_S_FREQUENCY scan all possbile values", + test_VIDIOC_S_FREQUENCY_scan}, + + {"VIDIOC_G_PRIORITY", test_VIDIOC_G_PRIORITY}, + {"VIDIOC_S_PRIORITY", test_VIDIOC_S_PRIORITY}, + {"VIDIOC_S_PRIORITY with invalid values", + test_VIDIOC_S_PRIORITY_invalid}, + + {"VIDIOC_G_AUDIO", test_VIDIOC_G_AUDIO}, + {"VIDIOC_G_AUDIO, ignore index value", + test_VIDIOC_G_AUDIO_ignore_index}, + + {"VIDIOC_S_AUDIO", test_VIDIOC_S_AUDIO}, + {"VIDIOC_S_AUDIO, index=S32_MAX", test_VIDIOC_S_AUDIO_S32_MAX}, + {"VIDIOC_S_AUDIO, index=S32_MAX+1", test_VIDIOC_S_AUDIO_S32_MAX_1}, + {"VIDIOC_S_AUDIO, index=U32_MAX", test_VIDIOC_S_AUDIO_U32_MAX}, + + {"VIDIOC_G_AUDOUT", test_VIDIOC_G_AUDOUT}, + {"VIDIOC_G_AUDOUT, ignore index value", + test_VIDIOC_G_AUDOUT_ignore_index}, + + {"VIDIOC_S_AUDOUT", test_VIDIOC_S_AUDOUT}, + {"VIDIOC_S_AUDOUT, index=S32_MAX", test_VIDIOC_S_AUDOUT_S32_MAX}, + {"VIDIOC_S_AUDOUT, index=S32_MAX+1", test_VIDIOC_S_AUDOUT_S32_MAX_1}, + {"VIDIOC_S_AUDOUT, index=U32_MAX", test_VIDIOC_S_AUDOUT_U32_MAX}, + + {"VIDIOC_G_CROP", test_VIDIOC_G_CROP}, + {"VIDIOC_G_CROP with invalid type", test_VIDIOC_G_CROP_invalid}, + {"VIDIOC_S_CROP", test_VIDIOC_S_CROP}, + {"VIDIOC_S_CROP with invalid type", test_VIDIOC_S_CROP_invalid}, + + {"VIDIOC_G_CTRL", test_VIDIOC_G_CTRL}, + + {"VIDIOC_S_CTRL", test_VIDIOC_S_CTRL}, + {"VIDIOC_S_CTRL with invalid value parameter", + test_VIDIOC_S_CTRL_invalid}, + {"VIDIOC_S_CTRL, withe balance", test_VIDIOC_S_CTRL_white_balance}, + {"VIDIOC_S_CTRL, white balance with invalid value parameter", + test_VIDIOC_S_CTRL_white_balance_invalid}, + {"VIDIOC_S_CTRL, gain control", test_VIDIOC_S_CTRL_gain}, + {"VIDIOC_S_CTRL, gain control with invalid value parameter", + test_VIDIOC_S_CTRL_gain_invalid}, + + {"VIDIOC_G_EXT_CTRLS with zero items to get", + test_VIDIOC_G_EXT_CTRLS_zero}, + {"VIDIOC_G_EXT_CTRLS with zero items to get, but with invalid count values", + test_VIDIOC_G_EXT_CTRLS_zero_invalid_count}, + {"VIDIOC_G_EXT_CTRLS with only one item to get", + test_VIDIOC_G_EXT_CTRLS_one}, + + {"VIDIOC_S_EXT_CTRLS with zero items to set", + test_VIDIOC_S_EXT_CTRLS_zero}, + {"VIDIOC_S_EXT_CTRLS with zero items to set, but with invalid count values", + test_VIDIOC_S_EXT_CTRLS_zero_invalid_count}, + + {"VIDIOC_TRY_EXT_CTRLS with zero items to try", + test_VIDIOC_TRY_EXT_CTRLS_zero}, + {"VIDIOC_TRY_EXT_CTRLS with zero items to try, but with invalid count values", + test_VIDIOC_TRY_EXT_CTRLS_zero_invalid_count}, + + {"VIDIOC_G_PARM", test_VIDIOC_G_PARM}, + {"VIDIOC_G_PARM with invalid type parameter", + test_VIDIOC_G_PARM_invalid}, + + {"VIDIOC_G_FMT", test_VIDIOC_G_FMT}, + {"VIDIOC_G_FMT with invalid type parameter", + test_VIDIOC_G_FMT_invalid_type}, + + {"VIDIOC_S_FMT with enumerated values", test_VIDIOC_S_FMT_enum}, + {"VIDIOC_S_FMT with invalid type parameter", test_VIDIOC_S_FMT_type}, + + {"VIDIOC_G_JPEGCOMP", test_VIDIOC_G_JPEGCOMP}, + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_querystd[] = { + {"VIDIOC_QUERYSTD", test_VIDIOC_QUERYSTD}, + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_buffs[] = { + {"VIDIOC_REQBUFS with memory map capture streaming i/o", + test_VIDIOC_REQBUFS_capture_mmap}, + {"VIDIOC_REQBUFS with user pointer capture streaming i/o", + test_VIDIOC_REQBUFS_capture_userptr}, + {"VIDIOC_REQBUFS with memory map output streaming i/o", + test_VIDIOC_REQBUFS_output_mmap}, + {"VIDIOC_REQBUFS with user pointer output streaming i/o", + test_VIDIOC_REQBUFS_output_userptr}, + {"VIDIOC_REQBUFS with invalid memory parameter, capture", + test_VIDIOC_REQBUFS_invalid_memory_capture}, + {"VIDIOC_REQBUFS with invalid memory parameter, output", + test_VIDIOC_REQBUFS_invalid_memory_output}, + {"VIDIOC_REQBUFS with invalid type parameter, memory mapped i/o", + test_VIDIOC_REQUBUFS_invalid_type_mmap}, + {"VIDIOC_REQBUFS with invalid type parameter, user pointer i/o", + test_VIDIOC_REQUBUFS_invalid_type_userptr}, + + {"VIDIOC_QUERYBUF with memory map capture streaming i/o", + test_VIDIOC_QUERYBUF_capture_mmap}, + {"VIDIOC_QUERYBUF with user pointer capture streaming i/o", + test_VIDIOC_QUERYBUF_capture_userptr}, + {"VIDIOC_QUERYBUF with memory map output streaming i/o", + test_VIDIOC_QUERYBUF_output_mmap}, + {"VIDIOC_QUERYBUF with user pointer output streaming i/o", + test_VIDIOC_QUERYBUF_output_userptr}, + {"VIDIOC_QUERYBUF with overlay capture (invalid)", + test_VIDIOC_QUERYBUF_overlay_capture}, + {"VIDIOC_QUERYBUF with overlay output (invalid)", + test_VIDIOC_QUERYBUF_overlay_output}, + {"VIDIOC_QUERYBUF with invalid memory parameter, capture", + test_VIDIOC_QUERYBUF_invalid_memory_capture}, + {"VIDIOC_QUERYBUF with invalid memory parameter, output", + test_VIDIOC_QUERYBUF_invalid_memory_output}, + {"VIDIOC_QUERYBUF with invalid type parameter, memory mapped i/o", + test_VIDIOC_QUERYBUF_invalid_type_mmap}, + {"VIDIOC_QUERYBUF with invalid type parameter, user pointer i/o", + test_VIDIOC_QUERYBUF_invalid_type_userptr}, + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_null_readonly[] = { + {"VIDIOC_QUERYCAP with NULL parameter", test_VIDIOC_QUERYCAP_NULL}, + /* { "VIDIOC_G_FBUF with NULL parameter", }, */ + {"VIDIOC_G_STD with NULL parameter", test_VIDIOC_G_STD_NULL}, + {"VIDIOC_G_AUDIO with NULL parameter", test_VIDIOC_G_AUDIO_NULL}, + {"VIDIOC_G_INPUT with NULL parameter", test_VIDIOC_G_INPUT_NULL}, + {"VIDIOC_G_OUTPUT with NULL parameter", test_VIDIOC_G_OUTPUT_NULL}, + {"VIDIOC_G_AUDOUT with NULL parameter", test_VIDIOC_G_AUDOUT_NULL}, + {"VIDIOC_G_JPEGCOMP with NULL parameter", test_VIDIOC_G_JPEGCOMP_NULL}, + {"VIDIOC_QUERYSTD with NULL parameter", test_VIDIOC_QUERYSTD_NULL}, + {"VIDIOC_G_PRIORITY with NULL parameter", test_VIDIOC_G_PRIORITY_NULL}, + /* { "VIDIOC_G_ENC_INDEX with NULL parameter", }, */ + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_null_writeonly[] = { + /* { "VIDIOC_S_FBUF with NULL parameter", }, */ + /* { "VIDIOC_OVERLAY with NULL parameter", }, */ + /* { "VIDIOC_STREAMON with NULL parameter", }, */ + /* { "VIDIOC_STREAMOFF with NULL parameter", }, */ + {"VIDIOC_S_STD with NULL parameter", test_VIDIOC_S_STD_NULL}, + {"VIDIOC_S_TUNER with NULL parameter", test_VIDIOC_S_TUNER_NULL}, + {"VIDIOC_S_AUDIO with NULL parameter", test_VIDIOC_S_AUDIO_NULL}, + {"VIDIOC_S_AUDOUT with NULL parameter", test_VIDIOC_S_AUDOUT_NULL}, + /* { "VIDIOC_S_MODULATOR with NULL parameter", }, */ + {"VIDIOC_S_FREQUENCY with NULL parameter", + test_VIDIOC_S_FREQUENCY_NULL}, + {"VIDIOC_S_CROP with NULL parameter", test_VIDIOC_S_CROP_NULL}, + /* { "VIDIOC_S_JPEGCOMP with NULL parameter", }, */ + {"VIDIOC_S_PRIORITY with NULL parameter", test_VIDIOC_S_PRIORITY_NULL}, + /* { "VIDIOC_DBG_S_REGISTER with NULL parameter", }, */ + /* { "VIDIOC_S_HW_FREQ_SEEK with NULL parameter", }, */ + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_null_writeread[] = { + {"VIDIOC_ENUM_FMT with NULL parameter", test_VIDIOC_ENUM_FMT_NULL}, + {"VIDIOC_G_FMT with NULL parameter", test_VIDIOC_G_FMT_NULL}, + /* { "VIDIOC_S_FMT with NULL parameter", }, */ + /* { "VIDIOC_REQBUFS with NULL parameter", } */ + /* { "VIDIOC_QUERYBUF with NULL parameter", } */ + /* { "VIDIOC_QBUF with NULL parameter", }, */ + /* { "VIDIOC_DQBUF with NULL parameter", }, */ + {"VIDIOC_G_PARM with NULL parameter", test_VIDIOC_G_PARM_NULL}, + /* { "VIDIOC_S_PARM with NULL parameter", }, */ + {"VIDIOC_ENUMSTD with NULL parameter", test_VIDIOC_ENUMSTD_NULL}, + {"VIDIOC_ENUMINPUT with NULL parameter", test_VIDIOC_ENUMINPUT_NULL}, + {"VIDIOC_G_CTRL with NULL parameter", test_VIDIOC_G_CTRL_NULL}, + {"VIDIOC_S_CTRL with NULL parameter", test_VIDIOC_S_CTRL_NULL}, + {"VIDIOC_G_TUNER with NULL parameter", test_VIDIOC_G_TUNER_NULL}, + {"VIDIOC_QUERYCTRL with NULL parameter", test_VIDIOC_QUERYCTRL_NULL}, + {"VIDIOC_QUERYMENU with NULL parameter", test_VIDIOC_QUERYMENU_NULL}, + {"VIDIOC_S_INPUT with NULL parameter", test_VIDIOC_S_INPUT_NULL}, + {"VIDIOC_S_OUTPUT with NULL parameter", test_VIDIOC_S_OUTPUT_NULL}, + {"VIDIOC_ENUMOUTPUT with NULL parameter", test_VIDIOC_ENUMOUTPUT_NULL}, + {"VIDIOC_G_MODULATOR with NULL parameter", + test_VIDIOC_G_MODULATOR_NULL}, + {"VIDIOC_G_FREQUENCY with NULL parameter", + test_VIDIOC_G_FREQUENCY_NULL}, + {"VIDIOC_CROPCAP with NULL parameter", test_VIDIOC_CROPCAP_NULL}, + {"VIDIOC_G_CROP with NULL parameter", test_VIDIOC_G_CROP_NULL}, + /* { "VIDIOC_TRY_FMT with NULL parameter", }, */ + {"VIDIOC_ENUMAUDIO with NULL parameter", test_VIDIOC_ENUMAUDIO_NULL}, + {"VIDIOC_ENUMAUDOUT with NULL parameter", test_VIDIOC_ENUMAUDOUT_NULL}, + {"VIDIOC_G_SLICED_VBI_CAP with NULL parameter", + test_VIDIOC_G_SLICED_VBI_CAP_NULL}, + {"VIDIOC_G_EXT_CTRLS with NULL parameter", + test_VIDIOC_G_EXT_CTRLS_NULL}, + {"VIDIOC_S_EXT_CTRLS with NULL parameter", + test_VIDIOC_S_EXT_CTRLS_NULL}, + {"VIDIOC_TRY_EXT_CTRLS with NULL parameter", + test_VIDIOC_TRY_EXT_CTRLS_NULL}, + {"VIDIOC_ENUM_FRAMESIZES with NULL parameter", + test_VIDIOC_ENUM_FRAMESIZES_NULL}, + /* { "VIDIOC_ENUM_FRAMEINTERVALS with NULL parameter", }, */ + /* { "VIDIOC_ENCODER_CMD with NULL parameter", }, */ + /* { "VIDIOC_TRY_ENCODER_CMD with NULL parameter", }, */ + /* { "VIDIOC_DBG_G_REGISTER with NULL parameter", }, */ + /* { "VIDIOC_DBG_G_CHIP_IDENT with NULL parameter", }, */ + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_invalid_ioctl[] = { + {"invalid ioctl _IO(0, 0)", test_invalid_ioctl_1}, + {"invalid ioctl _IO(0xFF, 0xFF)", test_invalid_ioctl_2}, + {"invalid v4l1 ioctl _IO('v', 0xFF)", test_invalid_ioctl_3}, + {"invalid v4l2 ioctl _IO('V', 0xFF)", test_invalid_ioctl_4}, + + CU_TEST_INFO_NULL, +}; + +static CU_TestInfo suite_debug_ioctl[] = { + {"test_VIDIOC_LOG_STATUS", test_VIDIOC_LOG_STATUS}, + + CU_TEST_INFO_NULL, +}; + +static CU_SuiteInfo suites[] = { + {"VIDIOC_QUERYCAP", open_video, close_video, suite_querycap}, + {"VIDIOC_ENUM* ioctl calls", open_video, close_video, suite_enums}, + {"VIDIOC_G_*, VIDIOC_S_* and VIDIOC_TRY_* ioctl calls", open_video, + close_video, suite_get_set_try}, + {"VIDIOC_QUERYSTD", open_video, close_video, suite_querystd}, + {"buffer i/o", open_video, close_video, suite_buffs}, + {"read only IOCTLs with NULL parameter", open_video, close_video, + suite_null_readonly}, + {"write only IOCTLs with NULL parameter", open_video, close_video, + suite_null_writeonly}, + {"write and read IOCTLs with NULL parameter", open_video, close_video, + suite_null_writeread}, + {"debug ioctl calls", open_video, close_video, suite_debug_ioctl}, + {"invalid ioctl calls", open_video, close_video, suite_invalid_ioctl}, + CU_SUITE_INFO_NULL, +}; + +int main() +{ + CU_ErrorCode err; + + err = CU_initialize_registry(); + if (err != CUE_SUCCESS) { + printf("ERROR: cannot initialize CUNIT registry, giving up.\n"); + return 1; + } + + err = CU_register_suites(suites); + if (err == CUE_SUCCESS) { + + //CU_basic_set_mode(CU_BRM_NORMAL); + //CU_basic_set_mode(CU_BRM_SILENT); + CU_basic_set_mode(CU_BRM_VERBOSE); + err = CU_basic_run_tests(); + if (err != CUE_SUCCESS) { + printf("CU_basic_run_tests returned %i\n", err); + } + + } else { + printf("ERROR: cannot add test suites\n"); + } + + CU_cleanup_registry(); + + tst_exit(); +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_test.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_test.h new file mode 100644 index 0000000000000000000000000000000000000000..6e5b3b608ac437b5a456f0d084e5e68a4132ed22 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_test.h @@ -0,0 +1,21 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 1 Jan 2008 0.2 Include stdio.h if needed; + * dprintf1() added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +//#define DEBUG 1 + +#ifdef DEBUG +#include +#define dprintf1(fmt) printf(fmt) +#define dprintf(fmt, ...) printf(fmt, __VA_ARGS__) +#else +#define dprintf1(fmt) +#define dprintf(fmt, ...) +#endif diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_validator.c b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_validator.c new file mode 100644 index 0000000000000000000000000000000000000000..b51901217f5f0dd3d2642d789f2ef2d3e567fb5d --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_validator.c @@ -0,0 +1,109 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 30 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "v4l2_test.h" +#include "dev_video.h" +#include "video_limits.h" +#include "v4l2_validator.h" + +int valid_v4l2_std_id(v4l2_std_id std_id) +{ + int valid = 0; + + if ((std_id & ~(V4L2_STD_PAL_B | + V4L2_STD_PAL_B1 | + V4L2_STD_PAL_G | + V4L2_STD_PAL_H | + V4L2_STD_PAL_I | + V4L2_STD_PAL_D | + V4L2_STD_PAL_D1 | + V4L2_STD_PAL_K | + V4L2_STD_PAL_M | + V4L2_STD_PAL_N | + V4L2_STD_PAL_Nc | + V4L2_STD_PAL_60 | + V4L2_STD_NTSC_M | + V4L2_STD_NTSC_M_JP | + V4L2_STD_NTSC_443 | + V4L2_STD_NTSC_M_KR | + V4L2_STD_SECAM_B | + V4L2_STD_SECAM_D | + V4L2_STD_SECAM_G | + V4L2_STD_SECAM_H | + V4L2_STD_SECAM_K | + V4L2_STD_SECAM_K1 | + V4L2_STD_SECAM_L | + V4L2_STD_SECAM_LC | + V4L2_STD_ATSC_8_VSB | V4L2_STD_ATSC_16_VSB)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +int valid_tuner_capability(__u32 capability) +{ + int valid = 0; + + if ((capability & ~(V4L2_TUNER_CAP_LOW | + V4L2_TUNER_CAP_NORM | + V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP)) + == 0) { + valid = 1; + } else { + valid = 0; + } + return valid; +} + +int valid_modulator_capability(__u32 capability) +{ + return valid_tuner_capability(capability); +} + +int valid_string(char *str, unsigned int max_length) +{ + int valid = 1; + unsigned int i; + + i = 0; + while (i < max_length && str[i] != 0) { + /* Printable characters start with SPACE (32) and + * ends with '~' (126) inclusively. + */ + if (str[i] < 32 || 126 < str[i]) { + valid = 0; + break; + } + i++; + } + + /* check if the string was closed with zero byte properly */ + if (i == max_length) { + valid = 0; + } + + return valid; +} diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_validator.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_validator.h new file mode 100644 index 0000000000000000000000000000000000000000..9da7fbe525b0f922cd5c685d772bc393caa85fe6 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/v4l2_validator.h @@ -0,0 +1,16 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 20 Apr 2009 0.2 Printable string validator added + * 30 Jan 2009 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include + +int valid_v4l2_std_id(v4l2_std_id std_id); +int valid_tuner_capability(__u32 capability); +int valid_modulator_capability(__u32 capability); +int valid_string(char* str, unsigned int max_length); diff --git a/ltp/testcases/kernel/device-drivers/v4l/user_space/video_limits.h b/ltp/testcases/kernel/device-drivers/v4l/user_space/video_limits.h new file mode 100644 index 0000000000000000000000000000000000000000..d8687fb8d0a9068108dec71c76019827b7561410 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/v4l/user_space/video_limits.h @@ -0,0 +1,28 @@ +/* + * v4l-test: Test environment for Video For Linux Two API + * + * 12 Mar 2009 0.4 S16_MIN, S16_MAX, U16_MIN and U16_MAX added + * 22 Feb 2009 0.3 S32_MIN and U32_MIN added + * 1 Jan 2009 0.2 SINT_MAX and SINT_MIN added + * 18 Dec 2008 0.1 First release + * + * Written by Mrton Nmeth + * Released under GPL + */ + +#include + +#define S32_MIN ((__s32)0x80000000) +#define S32_MAX 0x7FFFFFFF + +#define U32_MIN 0 +#define U32_MAX 0xFFFFFFFFU + +#define S16_MIN -32768 +#define S16_MAX 32767 + +#define U16_MIN 0 +#define U16_MAX 0xFFFFU + +#define SINT_MIN INT_MIN +#define SINT_MAX INT_MAX diff --git a/ltp/testcases/kernel/device-drivers/zram/.gitignore b/ltp/testcases/kernel/device-drivers/zram/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7d54f60414b8af4709fc08631daa263433644366 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/zram/.gitignore @@ -0,0 +1 @@ +/zram03 diff --git a/ltp/testcases/kernel/device-drivers/zram/Makefile b/ltp/testcases/kernel/device-drivers/zram/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0d73f6635d7eb0a52e5ce7353b420ff7b583bf28 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/zram/Makefile @@ -0,0 +1,22 @@ +# Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. +# +# 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 would 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 the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +top_srcdir ?= ../../../.. +include $(top_srcdir)/include/mk/testcases.mk + +INSTALL_TARGETS := *.sh + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/testcases/kernel/device-drivers/zram/zram01.sh b/ltp/testcases/kernel/device-drivers/zram/zram01.sh new file mode 100755 index 0000000000000000000000000000000000000000..793f6603c903555db099ba4a1d0f17ac19f47287 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/zram/zram01.sh @@ -0,0 +1,187 @@ +#!/bin/sh +# Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. +# Copyright (c) 2019-2022 Petr Vorel +# Author: Alexey Kodanev +# +# Test creates several zram devices with different filesystems on them. +# It fills each device with zeros and checks that compression works. + +TST_CNT=7 +TST_TESTFUNC="do_test" +TST_NEEDS_CMDS="awk bc dd" +TST_SETUP="setup" + +check_space_for_fs() +{ + local fs="$1" + local ram_size + + ram_size=$(awk '/MemTotal:/ {print $2}' /proc/meminfo) + if [ "$ram_size" -lt 1048576 ]; then + tst_res TINFO "not enough space for $fs" + return 1 + fi + return 0 +} + +# List of parameters for zram devices. +# For each number the test creates own zram device. +# NOTE about size: +# The zram sysfs node 'disksize' value can be either in bytes, +# or you can use mem suffixes. But in some old kernels, mem +# suffixes are not supported, for example, in RHEL6.6GA's kernel +# layer, it uses strict_strtoull() to parse disksize which does +# not support mem suffixes, in some newer kernels, they use +# memparse() which supports mem suffixes. So here we just use +# bytes to make sure everything works correctly. +initialize_vars() +{ + local fs limit size stream=-1 + dev_num=0 + + for fs in $(tst_supported_fs -s tmpfs); do + size="26214400" + limit="25M" + + if [ "$fs" = "btrfs" -o "$fs" = "xfs" ]; then + check_space_for_fs "$fs" || continue + + if [ "$fs" = "btrfs" ]; then + size="402653184" + elif [ "$fs" = "xfs" ]; then + size=314572800 + fi + limit="$((size/1024/1024))M" + fi + + stream=$((stream+3)) + dev_num=$((dev_num+1)) + zram_filesystems="$zram_filesystems $fs" + zram_mem_limits="$zram_mem_limits $limit" + zram_sizes="$zram_sizes $size" + zram_max_streams="$zram_max_streams $stream" + done + + [ $dev_num -eq 0 ] && \ + tst_brk TCONF "no suitable filesystem" +} + +setup() +{ + initialize_vars + zram_load +} + +zram_makefs() +{ + local i=$dev_start + local fs + + for fs in $zram_filesystems; do + tst_res TINFO "make $fs filesystem on /dev/zram$i" + mkfs.$fs /dev/zram$i > err.log 2>&1 + if [ $? -ne 0 ]; then + cat err.log + tst_res TFAIL "Failed to make $fs on /dev/zram$i" + tst_brk TBROK "Can't continue with mounting the FS" + fi + + i=$(($i + 1)) + done + + tst_res TPASS "zram_makefs succeeded" +} + +zram_mount() +{ + local i + + for i in $(seq $dev_start $dev_end); do + tst_res TINFO "mount /dev/zram$i" + mkdir zram$i + ROD mount /dev/zram$i zram$i + dev_mounted=$i + done + + tst_res TPASS "mount of zram device(s) succeeded" +} + +read_mem_used_total() +{ + echo $(awk '{print $3}' $1) +} + +# Reads /sys/block/zram*/mm_stat until mem_used_total is not 0. +check_read_mem_used_total() +{ + local file="$1" + local mem_used_total + + tst_res TINFO "$file" + cat $file >&2 + + mem_used_total=$(read_mem_used_total $file) + [ "$mem_used_total" -eq 0 ] && return 1 + + return 0 +} + +zram_fill_fs() +{ + local mem_used_total + local b i r v + + for i in $(seq $dev_start $dev_end); do + tst_res TINFO "filling zram$i (it can take long time)" + b=0 + while true; do + dd conv=notrunc if=/dev/zero of=zram${i}/file \ + oflag=append count=1 bs=1024 status=none \ + >/dev/null 2>err.txt || break + b=$(($b + 1)) + done + if [ $b -eq 0 ]; then + [ -s err.txt ] && tst_res TWARN "dd error: $(cat err.txt)" + tst_brk TBROK "cannot fill zram $i" + fi + tst_res TPASS "zram$i was filled with '$b' KB" + + if [ ! -f "/sys/block/zram$i/mm_stat" ]; then + if [ $i -eq 0 ]; then + tst_res TCONF "zram compression ratio test requires zram mm_stat sysfs file" + fi + + continue + fi + + TST_RETRY_FN_EXP_BACKOFF "check_read_mem_used_total /sys/block/zram$i/mm_stat" 0 10 + mem_used_total=$(read_mem_used_total /sys/block/zram$i/mm_stat) + tst_res TINFO "mem_used_total: $mem_used_total" + + v=$((100 * 1024 * $b / $mem_used_total)) + r=$(echo "scale=2; $v / 100 " | bc) + + if [ "$v" -lt 100 ]; then + tst_res TFAIL "compression ratio: $r:1" + break + fi + + tst_res TPASS "compression ratio: $r:1" + done +} + +do_test() +{ + case $1 in + 1) zram_max_streams;; + 2) zram_compress_alg;; + 3) zram_set_disksizes;; + 4) zram_set_memlimit;; + 5) zram_makefs;; + 6) zram_mount;; + 7) zram_fill_fs;; + esac +} + +. zram_lib.sh +tst_run diff --git a/ltp/testcases/kernel/device-drivers/zram/zram02.sh b/ltp/testcases/kernel/device-drivers/zram/zram02.sh new file mode 100755 index 0000000000000000000000000000000000000000..bb6e9a5f0e8e77827f0a068c768bcc3d34310e6c --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/zram/zram02.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. +# Copyright (c) 2019-2021 Petr Vorel +# Author: Alexey Kodanev +# +# Test checks that we can create swap zram device. + +TST_CNT=6 +TST_TESTFUNC="do_test" + +# List of parameters for zram devices. +# For each number the test creates own zram device. +zram_max_streams="2" + +# The zram sysfs node 'disksize' value can be either in bytes, +# or you can use mem suffixes. But in some old kernels, mem +# suffixes are not supported, for example, in RHEL6.6GA's kernel +# layer, it uses strict_strtoull() to parse disksize which does +# not support mem suffixes, in some newer kernels, they use +# memparse() which supports mem suffixes. So here we just use +# bytes to make sure everything works correctly. +zram_sizes="107374182400" # 100GB +zram_mem_limits="1M" + +zram_makeswap() +{ + tst_res TINFO "make swap with zram device(s)" + tst_require_cmds mkswap swapon swapoff + local i=0 + + for i in $(seq $dev_start $dev_end); do + ROD mkswap /dev/zram$i + ROD swapon /dev/zram$i + tst_res TINFO "done with /dev/zram$i" + dev_makeswap=$i + done + + tst_res TPASS "making zram swap succeeded" +} + +zram_swapoff() +{ + tst_require_cmds swapoff + local i + + for i in $(seq $dev_start $dev_end); do + ROD swapoff /dev/zram$i + done + dev_makeswap=-1 + + tst_res TPASS "swapoff completed" +} + +do_test() +{ + case $1 in + 1) zram_max_streams;; + 2) zram_compress_alg;; + 3) zram_set_disksizes;; + 4) zram_set_memlimit;; + 5) zram_makeswap;; + 6) zram_swapoff;; + esac +} + +. zram_lib.sh +tst_run diff --git a/ltp/testcases/kernel/device-drivers/zram/zram03.c b/ltp/testcases/kernel/device-drivers/zram/zram03.c new file mode 100644 index 0000000000000000000000000000000000000000..8cf26de4c6eef470e94710a0f539c0dc27adc202 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/zram/zram03.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2010 Red Hat, Inc. + */ + +/*\ + * zram: generic RAM based compressed R/W block devices + * http://lkml.org/lkml/2010/8/9/227 + * + * This case check whether data read from zram device is consistent with + * thoese are written. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "tst_safe_stdio.h" +#include "tst_test.h" + +#define ZRAM_CONTROL_PATH "/sys/class/zram-control" +#define HOT_ADD_PATH ZRAM_CONTROL_PATH"/hot_add" +#define HOT_REMOVE_PATH ZRAM_CONTROL_PATH"/hot_remove" +#define SIZE (512 * 1024 * 1024L) + +static char zram_block_path[100], zram_dev_path[100]; +static int modprobe, dev_num, hot_add_flag; +static const char *const cmd_rmmod[] = {"rmmod", "zram", NULL}; + +static void set_disksize(void) +{ + char disksize_path[200]; + + tst_res(TINFO, "create a zram device with %ld bytes in size", SIZE); + sprintf(disksize_path, "%s/disksize", zram_block_path); + SAFE_FILE_PRINTF(disksize_path, "%ld", SIZE); +} + +static void write_device(void) +{ + int fd; + char *s; + + tst_res(TINFO, "map this zram device into memory"); + fd = SAFE_OPEN(zram_dev_path, O_RDWR); + s = SAFE_MMAP(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + tst_res(TINFO, "write all the memory"); + memset(s, 'a', SIZE - 1); + s[SIZE - 1] = '\0'; + + SAFE_MUNMAP(s, SIZE); + SAFE_CLOSE(fd); +} + +static void verify_device(void) +{ + int fd; + long i = 0, fail = 0; + char *s; + + tst_res(TINFO, "verify contents from device"); + fd = SAFE_OPEN(zram_dev_path, O_RDONLY); + s = SAFE_MMAP(NULL, SIZE, PROT_READ, MAP_PRIVATE, fd, 0); + + while (s[i] && i < SIZE - 1) { + if (s[i] != 'a') + fail++; + i++; + } + if (i != SIZE - 1) { + tst_res(TFAIL, "expect size: %ld, actual size: %ld.", + SIZE - 1, i); + } else if (s[i] != '\0') { + tst_res(TFAIL, "zram device seems not null terminated"); + } else if (fail) { + tst_res(TFAIL, "%ld failed bytes found", fail); + } else { + tst_res(TPASS, "data read from zram device is consistent with those are written"); + } + + SAFE_MUNMAP(s, SIZE); + SAFE_CLOSE(fd); +} + +static void reset_zram(void) +{ + char reset_path[200]; + + tst_res(TINFO, "Reset zram"); + sprintf(reset_path, "%s/reset", zram_block_path); + SAFE_FILE_PRINTF(reset_path, "1"); +} + +static void print(char *string) +{ + char filename[BUFSIZ], value[BUFSIZ]; + + tst_res(TINFO, "%s", zram_block_path); + sprintf(filename, "%s/%s", zram_block_path, string); + SAFE_FILE_SCANF(filename, "%s", value); + tst_res(TINFO, "%s is %s", filename, value); +} + +static void print_stat(char *nread, char *nwrite) +{ + char nread_val[BUFSIZ], nwrite_val[BUFSIZ]; + char zram_stat_path[100]; + + sprintf(zram_stat_path, "/sys/block/zram%d/stat", dev_num); + SAFE_FILE_SCANF(zram_stat_path, "%s %*s %*s %*s %s", nread_val, nwrite_val); + tst_res(TINFO, "%s from %s is %s", nread, zram_stat_path, nread_val); + tst_res(TINFO, "%s from %s is %s", nwrite, zram_stat_path, nwrite_val); +} + +static void print_mm_stat(char *orig, char *compr, char *mem, char *zero) +{ + char orig_val[BUFSIZ], compr_val[BUFSIZ]; + char mem_val[BUFSIZ], zero_val[BUFSIZ]; + char zram_mm_stat_path[100]; + + sprintf(zram_mm_stat_path, "/sys/block/zram%d/mm_stat", dev_num); + SAFE_FILE_SCANF(zram_mm_stat_path, "%s %s %s %*s %*s %s", + orig_val, compr_val, mem_val, zero_val); + tst_res(TINFO, "%s from %s is %s", orig, zram_mm_stat_path, orig_val); + tst_res(TINFO, "%s from %s is %s", compr, zram_mm_stat_path, compr_val); + tst_res(TINFO, "%s from %s is %s", mem, zram_mm_stat_path, mem_val); + tst_res(TINFO, "%s from %s is %s", zero, zram_mm_stat_path, zero_val); +} + +static void dump_info(void) +{ + char zram_obsolete_file_path[100]; + + sprintf(zram_obsolete_file_path, "/sys/block/zram%d/num_reads", dev_num); + print("initstate"); + print("disksize"); + if (!access(zram_obsolete_file_path, F_OK)) { + print("orig_data_size"); + print("compr_data_size"); + print("mem_used_total"); + print("zero_pages"); + print("num_reads"); + print("num_writes"); + } else { + print_mm_stat("orig_data_size", "compr_data_size", + "mem_used_total", "zero/same_pages"); + print_stat("num_reads", "num_writes"); + } +} + +static void run(void) +{ + set_disksize(); + + write_device(); + dump_info(); + verify_device(); + + reset_zram(); + dump_info(); +} + +static void setup(void) +{ + const char *const cmd_modprobe[] = {"modprobe", "zram", NULL}; + const char *const cmd_zramctl[] = {"zramctl", "-f", NULL}; + const char *zramctl_log_path = "zramctl.log"; + FILE *file; + char line[PATH_MAX]; + int fd; + + /* zram module was built in or loaded on new kernel */ + if (!access(ZRAM_CONTROL_PATH, F_OK)) { + tst_res(TINFO, + "zram module already loaded, kernel supports zram-control interface"); + SAFE_FILE_SCANF(HOT_ADD_PATH, "%d", &dev_num); + hot_add_flag = 1; + goto fill_path; + } + + /* zram module was built in or being used on old kernel */ + SAFE_CMD(cmd_modprobe, NULL, NULL); + file = SAFE_FOPEN("/proc/modules", "r"); + while (fgets(line, sizeof(line), file)) { + if (strstr(line, "zram")) { + modprobe = 1; + break; + } + } + SAFE_FCLOSE(file); + if (access(ZRAM_CONTROL_PATH, F_OK)) { + if (modprobe) { + tst_res(TINFO, + "rmmod zram before test on old kernel without zram-control interface"); + if (!tst_cmd(cmd_rmmod, NULL, NULL, TST_CMD_PASS_RETVAL)) { + SAFE_CMD(cmd_modprobe, NULL, NULL); + goto fill_path; + } + } else { + tst_res(TINFO, + "zram module is built in old kernel without zram-control interface"); + } + + modprobe = 0; + tst_res(TINFO, "use zramctl -f to find free zram device"); + fd = SAFE_OPEN(zramctl_log_path, O_CREAT | O_RDWR, 0644); + SAFE_CLOSE(fd); + if (tst_cmd(cmd_zramctl, zramctl_log_path, NULL, TST_CMD_PASS_RETVAL)) + tst_brk(TCONF | TERRNO, "zramctl -f failed"); + else + SAFE_FILE_SCANF(zramctl_log_path, "/dev/zram%d", &dev_num); + } + +fill_path: + sprintf(zram_block_path, "/sys/block/zram%d", dev_num); + sprintf(zram_dev_path, "/dev/zram%d", dev_num); +} + +static void cleanup(void) +{ + if (hot_add_flag) + SAFE_FILE_PRINTF(HOT_REMOVE_PATH, "%d", dev_num); + + if (modprobe) + SAFE_CMD(cmd_rmmod, NULL, NULL); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .needs_tmpdir = 1, + .needs_drivers = (const char *const []) { + "zram", + NULL + }, + .needs_cmds = (const char *[]) { + "modprobe", + "rmmod", + NULL + } +}; diff --git a/ltp/testcases/kernel/device-drivers/zram/zram_lib.sh b/ltp/testcases/kernel/device-drivers/zram/zram_lib.sh new file mode 100755 index 0000000000000000000000000000000000000000..e94f9244d81d915dd6ac058c128d9da202ab5fb4 --- /dev/null +++ b/ltp/testcases/kernel/device-drivers/zram/zram_lib.sh @@ -0,0 +1,206 @@ +#!/bin/sh +# Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. +# Copyright (c) 2019-2022 Petr Vorel +# Author: Alexey Kodanev + +dev_makeswap=-1 +dev_mounted=-1 +dev_start=0 +dev_end=-1 +module_load=-1 +sys_control=-1 + +TST_NEEDS_TMPDIR=1 +TST_NEEDS_ROOT=1 +TST_SETUP="${TST_SETUP:-zram_load}" +TST_CLEANUP="${TST_CLEANUP:-zram_cleanup}" +TST_NEEDS_DRIVERS="zram" + +zram_cleanup() +{ + local i + + for i in $(seq $dev_start $dev_makeswap); do + swapoff /dev/zram$i + done + + for i in $(seq $dev_start $dev_mounted); do + umount /dev/zram$i + done + + for i in $(seq $dev_start $dev_end); do + echo 1 > /sys/block/zram${i}/reset + done + + if [ $sys_control -eq 1 ]; then + for i in $(seq $dev_start $dev_end); do + echo $i > /sys/class/zram-control/hot_remove + done + fi + + if [ $module_load -eq 1 ]; then + rmmod zram > /dev/null 2>&1 + fi +} + +zram_load() +{ + local tmp + + if [ -z "$dev_num" ]; then + dev_num=0 + for tmp in $zram_max_streams; do + dev_num=$((dev_num+1)) + done + fi + + if [ $dev_num -le 0 ]; then + tst_brk TBROK "dev_num must be > 0" + fi + + tst_set_timeout $((dev_num*450)) + + tst_res TINFO "create '$dev_num' zram device(s)" + + # zram module loaded, new kernel + if [ -d "/sys/class/zram-control" ]; then + tst_res TINFO "zram module already loaded, kernel supports zram-control interface" + dev_start=$(ls /dev/zram* | wc -w) + dev_end=$(($dev_start + $dev_num - 1)) + sys_control=1 + + for i in $(seq $dev_start $dev_end); do + cat /sys/class/zram-control/hot_add > /dev/null + done + + tst_res TPASS "all zram devices (/dev/zram$dev_start~$dev_end) successfully created" + return + fi + + # detect old kernel or built-in + modprobe zram num_devices=$dev_num + if [ ! -d "/sys/class/zram-control" ]; then + if grep -q '^zram' /proc/modules; then + rmmod zram > /dev/null 2>&1 || \ + tst_brk TCONF "zram module is being used on old kernel without zram-control interface" + else + tst_brk TCONF "test needs CONFIG_ZRAM=m on old kernel without zram-control interface" + fi + modprobe zram num_devices=$dev_num + fi + + module_load=1 + dev_end=$(($dev_num - 1)) + tst_res TPASS "all zram devices (/dev/zram0~$dev_end) successfully created" +} + +zram_max_streams() +{ + if tst_kvcmp -lt "3.15" -o -ge "4.7"; then + tst_res TCONF "The device attribute max_comp_streams was"\ + "introduced in kernel 3.15 and deprecated in 4.7" + return + fi + + tst_res TINFO "set max_comp_streams to zram device(s)" + + local i=$dev_start + + for max_s in $zram_max_streams; do + local sys_path="/sys/block/zram${i}/max_comp_streams" + if ! echo $max_s > $sys_path; then + tst_res TFAIL "failed to set '$max_s' to $sys_path" + return + fi + local max_streams=$(cat $sys_path) + + if [ "$max_s" -ne "$max_streams" ]; then + tst_res TFAIL "can't set max_streams '$max_s', get $max_stream" + return + fi + + i=$(($i + 1)) + tst_res TINFO "$sys_path = '$max_streams'" + done + + tst_res TPASS "test succeeded" +} + +zram_compress_alg() +{ + if tst_kvcmp -lt "3.15"; then + tst_res TCONF "device attribute comp_algorithm is"\ + "introduced since kernel v3.15, the running kernel"\ + "does not support it" + return + fi + + local i=$dev_start + + tst_res TINFO "test that we can set compression algorithm" + local algs="$(sed 's/[][]//g' /sys/block/zram${i}/comp_algorithm)" + tst_res TINFO "supported algs: $algs" + + for i in $(seq $dev_start $dev_end); do + for alg in $algs; do + local sys_path="/sys/block/zram${i}/comp_algorithm" + if ! echo "$alg" > $sys_path; then + tst_res TFAIL "can't set '$alg' to $sys_path" + return + fi + tst_res TINFO "$sys_path = '$alg'" + done + done + + tst_res TPASS "test succeeded" +} + +zram_set_disksizes() +{ + local i=$dev_start + local ds + + tst_res TINFO "set disk size to zram device(s)" + for ds in $zram_sizes; do + local sys_path="/sys/block/zram${i}/disksize" + if ! echo "$ds" > $sys_path; then + tst_res TFAIL "can't set '$ds' to $sys_path" + return + fi + + i=$(($i + 1)) + tst_res TINFO "$sys_path = '$ds'" + done + + tst_res TPASS "test succeeded" +} + +zram_set_memlimit() +{ + if tst_kvcmp -lt "3.18"; then + tst_res TCONF "device attribute mem_limit is"\ + "introduced since kernel v3.18, the running kernel"\ + "does not support it" + return + fi + + local i=$dev_start + local ds + + tst_res TINFO "set memory limit to zram device(s)" + + for ds in $zram_mem_limits; do + local sys_path="/sys/block/zram${i}/mem_limit" + if ! echo "$ds" > $sys_path; then + tst_res TFAIL "can't set '$ds' to $sys_path" + return + fi + + i=$(($i + 1)) + tst_res TINFO "$sys_path = '$ds'" + done + + tst_res TPASS "test succeeded" +} + +. tst_test.sh diff --git a/ltp/testcases/kernel/firmware/Makefile b/ltp/testcases/kernel/firmware/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..57b598db842bd52fd297d5de80201a4d7b2a9c30 --- /dev/null +++ b/ltp/testcases/kernel/firmware/Makefile @@ -0,0 +1,20 @@ +# Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. +# +# 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 would 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 the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +top_srcdir ?= ../../.. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/generic_trunk_target.mk diff --git a/ltp/testcases/kernel/firmware/fw_load_kernel/.gitignore b/ltp/testcases/kernel/firmware/fw_load_kernel/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6fc82952c7f5406c04195e1064375d0c2bd53909 --- /dev/null +++ b/ltp/testcases/kernel/firmware/fw_load_kernel/.gitignore @@ -0,0 +1,7 @@ +/ltp_fw_load.ko +/*.cmd +/modules.order +/Module.symvers +/ltp_fw_load.mod.c +/.tmp_versions/ +modules.livepatch diff --git a/ltp/testcases/kernel/firmware/fw_load_kernel/Makefile b/ltp/testcases/kernel/firmware/fw_load_kernel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..73996996f3397fb0a7f4616457168213587e654f --- /dev/null +++ b/ltp/testcases/kernel/firmware/fw_load_kernel/Makefile @@ -0,0 +1,35 @@ +# Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. +# +# 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 would 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 the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +ifneq ($(KERNELRELEASE),) + +ifdef CONFIG_FW_LOADER +obj-m := ltp_fw_load.o +endif + +else + +top_srcdir ?= ../../../.. +include $(top_srcdir)/include/mk/env_pre.mk + +REQ_VERSION_MAJOR := 3 +REQ_VERSION_PATCH := 7 +MAKE_TARGETS := ltp_fw_load.ko + +include $(top_srcdir)/include/mk/module.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk + +endif diff --git a/ltp/testcases/kernel/firmware/fw_load_kernel/README b/ltp/testcases/kernel/firmware/fw_load_kernel/README new file mode 100644 index 0000000000000000000000000000000000000000..97507fd99aa3bead708cd4bf599f4abf9ec6e2da --- /dev/null +++ b/ltp/testcases/kernel/firmware/fw_load_kernel/README @@ -0,0 +1,16 @@ +The aim of the test is to check device firmware loading. Since kernel 3.7 +firmware loading changed to direct loading (by-pass udev). The test consists +of the two parts: + - userspace part + - kernelspace part + +This is a kernel module, which is a part of the device firmware loading test. +It allows to call request_firmware kernel function with specified parameters. +Template firmware file name and expected firmware file's data size are passed +as the insmod command line parameters. Then, the number of firmware test files +should be written to sysfs file 'fwnum' (the maximum number is 32). This write +will initiate request firmware procedure. In the end, results can be read from +'result' device sysfs file. Also, some information regarding module loading, +can be obtained by looking at kernel log file. + +It is automatically used by userspace part of the test. diff --git a/ltp/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c b/ltp/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c new file mode 100644 index 0000000000000000000000000000000000000000..b7397e8f13154a16c2626517545c3c14d153a043 --- /dev/null +++ b/ltp/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * + * 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 would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Alexey Kodanev + * + * This module is trying to load external test firmware files (n#_load_tst.fw). + * In the end, it writes results to /sys/devices/ltp_fw_load/result file. + */ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexey Kodanev "); +MODULE_DESCRIPTION("This module is checking device firmware loading"); + +#define TCID "ltp_fw_load" + +static char *fw_name = "load_tst.fw"; +static int fw_size = 0x1000; +static int max_name = 64; +static int fw; + +module_param(fw_name, charp, 0444); +MODULE_PARM_DESC(fw_name, "Template firmware file name: n#_name"); + +module_param(fw_size, int, 0444); +MODULE_PARM_DESC(fw_size, "Firmware file size"); + +/* + * bit mask for each test-case, + * if test is passed, bit will be set to 1 + */ +static int test_result; + +static void device_release(struct device *dev) +{ + pr_info(TCID ": device released\n"); +} + +static struct device tdev = { + .init_name = TCID, + .release = device_release, +}; + +/* read and print firmware data */ +static int fw_read(const u8 *data, size_t size) +{ + size_t i; + pr_info(TCID ": Firmware has size '%zu'\n", size); + if (size != fw_size) { + pr_err(TCID ": Expected firmware size '%d'\n", fw_size); + return -1; + } + for (i = 0; i < size; ++i) { + if (data[i] != (u8)fw) { + pr_err(TCID ": Unexpected firmware data\n"); + return -1; + } + } + return 0; +} + +static int try_request_fw(const char *name) +{ + int err; + const struct firmware *fw_entry = NULL; + err = request_firmware(&fw_entry, name, &tdev); + if (!err) { + pr_info(TCID ": firmware '%s' requested\n", name); + err = fw_read(fw_entry->data, fw_entry->size); + } else + pr_err(TCID ": Can't request firmware '%s'\n", name); + release_firmware(fw_entry); + return err; +} + +/* print test result to sysfs file */ +static ssize_t sys_result(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", test_result); +} +static DEVICE_ATTR(result, S_IRUSR, sys_result, NULL); + +/* + * get the number of firmware files and + * perform firmware requests + */ +static ssize_t sys_fwnum(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err, fw_num = 0; + + sscanf(buf, "%d", &fw_num); + if (fw_num <= 0 || fw_num > 32) { + pr_err(TCID ": Unexpected number of firmwares '%d'", fw_num); + return count; + } + for (fw = 0; fw < fw_num; ++fw) { + char name[max_name]; + snprintf(name, max_name, "n%d_%s", fw, fw_name); + err = try_request_fw(name); + test_result |= (err == 0) << fw; + } + return count; +} +static DEVICE_ATTR(fwnum, S_IWUSR, NULL, sys_fwnum); + +static int test_init(void) +{ + int err; + + err = device_register(&tdev); + if (err) { + pr_err(TCID ": Unable to register device\n"); + return err; + } + pr_info(TCID ": device registered\n"); + + err = device_create_file(&tdev, &dev_attr_result); + if (err) { + pr_err(TCID ": Can't create sysfs file 'result'\n"); + device_unregister(&tdev); + return err; + } + err = device_create_file(&tdev, &dev_attr_fwnum); + if (err) { + pr_err(TCID ": Can't create sysfs file 'fwnum'\n"); + device_remove_file(&tdev, &dev_attr_result); + device_unregister(&tdev); + } + return err; +} +module_init(test_init); + +static void test_exit(void) +{ + device_remove_file(&tdev, &dev_attr_result); + device_remove_file(&tdev, &dev_attr_fwnum); + + device_unregister(&tdev); + pr_info(TCID ": module exited\n"); +} +module_exit(test_exit); diff --git a/ltp/testcases/kernel/firmware/fw_load_user/.gitignore b/ltp/testcases/kernel/firmware/fw_load_user/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1d0814980660f34b64bd49ba16c25dc1d99e9d07 --- /dev/null +++ b/ltp/testcases/kernel/firmware/fw_load_user/.gitignore @@ -0,0 +1 @@ +/fw_load diff --git a/ltp/testcases/kernel/firmware/fw_load_user/Makefile b/ltp/testcases/kernel/firmware/fw_load_user/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..effd5dae5c05e9115c391093af523ab36ebfc8d6 --- /dev/null +++ b/ltp/testcases/kernel/firmware/fw_load_user/Makefile @@ -0,0 +1,20 @@ +# Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. +# +# 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 would 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 the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/testcases/kernel/firmware/fw_load_user/README b/ltp/testcases/kernel/firmware/fw_load_user/README new file mode 100644 index 0000000000000000000000000000000000000000..702fac90a2ccb41612ea8dc1010b468588cd3446 --- /dev/null +++ b/ltp/testcases/kernel/firmware/fw_load_user/README @@ -0,0 +1,11 @@ +The aim of the test is to check device firmware loading. Since kernel 3.7 +firmware loading changed to direct loading (by-pass udev). The test consists +of the two parts: + - userspace part + - kernelspace part + +This is the userspace part, its tasks are: + - create firmware files in the standard firmware paths + - load the module and initiate firmware request procedure + - read device's result file and print final results + - unload the module. diff --git a/ltp/testcases/kernel/firmware/fw_load_user/fw_load.c b/ltp/testcases/kernel/firmware/fw_load_user/fw_load.c new file mode 100644 index 0000000000000000000000000000000000000000..b2ed09e6f356d26df111df9d98bce34e441f99a1 --- /dev/null +++ b/ltp/testcases/kernel/firmware/fw_load_user/fw_load.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * + * 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 would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Alexey Kodanev + * + * Test checks device firmware loading. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "test.h" +#include "safe_macros.h" +#include "old_module.h" + +/* number of test firmware files */ +#define FW_FILES 5 + +char *TCID = "fw_load"; +int TST_TOTAL = FW_FILES; + +static int fw_size = 0x1000; + +static const char fw_name[] = "load_tst.fw"; +static const char module_name[] = "ltp_fw_load.ko"; + +/* paths to module's sysfs files */ +static const char dev_fwnum[] = "/sys/devices/ltp_fw_load/fwnum"; +static const char dev_result[] = "/sys/devices/ltp_fw_load/result"; + +struct fw_file_info { + char *file; + char *dir; + int fake; + int remove_dir; + int remove_file; +}; + +static struct fw_file_info fw[FW_FILES]; +static int fw_num; + +/* test options */ +static char *narg; +static int nflag; +static int skip_cleanup; +static int verbose; +static const option_t options[] = { + {"n:", &nflag, &narg}, + {"s", &skip_cleanup, NULL}, + {"v", &verbose, NULL}, + {NULL, NULL, NULL} +}; + +static void help(void); +static void setup(int argc, char *argv[]); +static void test_run(void); +static void cleanup(void); + +/* + * create firmware files in the fw_paths + * @fw_paths: it must be termintated by a NULL pointer + */ +static void create_firmware(char *const fw_paths[]); + +int main(int argc, char *argv[]) +{ + setup(argc, argv); + + test_run(); + + cleanup(); + + tst_exit(); +} + +static void help(void) +{ + printf(" -n x Write x bytes to firmware file, default is %d\n", + fw_size); + printf(" -s Skip cleanup\n"); + printf(" -v Verbose\n"); +} + +void setup(int argc, char *argv[]) +{ + tst_parse_opts(argc, argv, options, help); + + if (nflag) { + if (sscanf(narg, "%i", &fw_size) != 1) + tst_brkm(TBROK, NULL, "-n option arg is not a number"); + if (fw_size < 0) + tst_brkm(TBROK, NULL, "-n option arg is less than 0"); + } + + tst_require_root(); + tst_requires_module_signature_disabled(); + + char fw_size_param[19]; + snprintf(fw_size_param, 19, "fw_size=%d", fw_size); + char *const mod_params[2] = { fw_size_param, NULL }; + tst_module_load(NULL, module_name, mod_params); + + tst_sig(FORK, DEF_HANDLER, cleanup); + + /* get current Linux version and make firmware paths */ + struct utsname uts_name; + uname(&uts_name); + + /* 4 firmware paths + NULL */ + char *fw_paths[5] = { "/lib/firmware", "/lib/firmware/updates" }; + SAFE_ASPRINTF(cleanup, &fw_paths[2], "%s/%s", fw_paths[0], uts_name.release); + SAFE_ASPRINTF(cleanup, &fw_paths[3], "%s/%s", fw_paths[1], uts_name.release); + + /* create firmware in the hard coded firmware search paths */ + create_firmware(fw_paths); + + free(fw_paths[2]); + free(fw_paths[3]); + + /* make non-existent firmware file */ + SAFE_ASPRINTF(cleanup, &fw[fw_num].file, "/n%d_%s", fw_num, fw_name); + fw[fw_num].fake = 1; + ++fw_num; +} + +static void test_run(void) +{ + /* initiate firmware requests */ + SAFE_FILE_PRINTF(cleanup, dev_fwnum, "%d", fw_num); + + /* get module results by reading result bit mask */ + int result = 0; + SAFE_FILE_SCANF(cleanup, dev_result, "%d", &result); + + int i, fail, offset; + for (i = 0; i < fw_num; ++i) { + fail = (result & (1 << i)) == 0 && !fw[i].fake; + offset = (fw[i].dir) ? strlen(fw[i].dir) : 0; + tst_resm((fail) ? TFAIL : TPASS, + "Expect: %s load firmware '...%s'", + (fw[i].fake) ? "can't" : "can", + fw[i].file + offset); + } +} + +static void cleanup(void) +{ + if (skip_cleanup) + return; + + int i; + /* remove subdirs first and then upper level dirs */ + for (i = fw_num - 1; i >= 0; --i) { + if (fw[i].remove_file && remove(fw[i].file) == -1) + tst_resm(TWARN, "Can't remove: %s", fw[i].file); + free(fw[i].file); + + if (fw[i].remove_dir && remove(fw[i].dir) == -1) + tst_resm(TWARN, "Can't remove %s", fw[i].dir); + free(fw[i].dir); + } + + tst_module_unload(NULL, module_name); +} + +static void create_firmware(char *const fw_paths[]) +{ + int i = 0; + while (fw_paths[i] != NULL) { + struct fw_file_info *fi = &fw[fw_num]; + fi->dir = strdup(fw_paths[i]); + if (access(fi->dir, X_OK) == -1) { + /* create dir */ + SAFE_MKDIR(cleanup, fi->dir, 0755); + fi->remove_dir = 1; + } + + /* create test firmware file */ + SAFE_ASPRINTF(cleanup, &fi->file, "%s/n%d_%s", fi->dir, fw_num, fw_name); + + FILE *f = SAFE_FOPEN(cleanup, fi->file, "w"); + fi->remove_file = 1; + int k, byte = fw_num; + ++fw_num; + for (k = 0; k < fw_size; ++k) + fputc(byte, f); + SAFE_FCLOSE(cleanup, f); + ++i; + } +} diff --git a/ltp/testcases/kernel/fs/Makefile b/ltp/testcases/kernel/fs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6e9a471865c47f954d2b5f3507da4096d2494fb7 --- /dev/null +++ b/ltp/testcases/kernel/fs/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +top_srcdir ?= ../../.. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/generic_trunk_target.mk diff --git a/ltp/testcases/kernel/fs/acl/tacl_xattr.sh b/ltp/testcases/kernel/fs/acl/tacl_xattr.sh new file mode 100755 index 0000000000000000000000000000000000000000..c2383fdd9567f2cbc282d086a31d7abd79cb531b --- /dev/null +++ b/ltp/testcases/kernel/fs/acl/tacl_xattr.sh @@ -0,0 +1,807 @@ +#!/bin/bash +############################################################## +# +# Copyright (c) International Business Machines Corp., 2003 +# +# 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, +# +# FILE : tacl_xattr.sh +# USAGE : ./tacl_xattr.sh +# +# DESCRIPTION : A script that will test ACL and Extend Attribute on Linux system. +# REQUIREMENTS: +# 1) Kernel with loop device support +# 2) A spare (scratch) disk partition of 100MB or larger. +# 3) Kernel with ACL and Extend Attribute function support +# +# HISTORY : +# 10/23/2003 Kai Zhao (ltcd3@cn.ibm.com) +# 07/06/2004 Jacky Malcles enable ext3 & clean users home dir. +# +# CODE COVERAGE: +# 76.3% - fs/posix_acl.c +# 80.9% - xattr_acl.c +# 73.0% - xattr.c +# +############################################################## + +CUR_PATH="" +CONTENT="" +RES="" +USER_PERMISSION="" +GROUP_PERMISSION="" +OTHER_PERMISSION="" +ITEM_OWNER="" +ITEM_GROUP="" + +################################################################ +# +# Make sure that uid=root is running this script. +# Make sure that loop device is built into the kernel +# Make sure that ACL(Access Control List) and Extended Attribute are +# built into the kernel +# +################################################################ + +if [ $UID != 0 ] +then + echo "FAILED: Must have root access to execute this script" + exit 1 +fi + +################################################################# +# +# Prepare Ext2 file system for ACL and Extended Attribute test +# Make some directory , file and symlink for the test +# Add three users for the test +# +################################################################# + +if [ ! -e tacl ] +then + mkdir -m 777 tacl +else + echo "FAILED: Directory tacl are exist" + exit 1 +fi + +dd if=/dev/zero of=tacl/blkext2 bs=1k count=10240 +chmod 777 tacl/blkext2 + +losetup /dev/loop0 tacl/blkext2 >/dev/null 2>&1 +if [ $? != 0 ] +then + printf "\nFAILED: [ losetup ] Must have loop device support by kernel\n" + printf "\t to execute this script\n" + exit 1 +fi + +mount | grep ext2 +if [ $? != 0 ] +then + mkfs -t ext3 /dev/loop0 + mkdir -m 777 tacl/mount-ext2 + mount -t ext3 -o defaults,acl,user_xattr /dev/loop0 tacl/mount-ext2 + if [ $? != 0 ] + then + printf "\nFAILED: [ mount ] Make sure that ACL (Access Control List)\n" + printf "\t and Extended Attribute are built into the kernel\n" + printf "\t Can not mount ext2 file system with acl and user_xattr options\n" + exit 1 + fi + +else + mkfs -t ext2 /dev/loop0 + mkdir -m 777 tacl/mount-ext2 + mount -t ext2 -o defaults,acl,user_xattr /dev/loop0 tacl/mount-ext2 + if [ $? != 0 ] + then + printf "\nFAILED: [ mount ] Make sure that ACL (Access Control List)\n" + printf "\t and Extended Attribute are built into the kernel\n" + printf "\t Can not mount ext2 file system with acl and user_xattr options\n" + exit 1 + fi +fi + +chmod 777 tacl/mount-ext2 + +useradd -d `pwd`/tacl/tacluser1 tacluser1 +useradd -d `pwd`/tacl/tacluser2 tacluser2 +useradd -d `pwd`/tacl/tacluser3 tacluser3 +useradd -d `pwd`/tacl/tacluser4 tacluser4 + +if [ ! -e tacl/mount-ext2/shared ] +then + mkdir -p -m 777 tacl/mount-ext2/shared +fi + +CUR_PATH=`pwd` + +su - tacluser1 << TACL_USER1 + + mkdir $CUR_PATH/tacl/mount-ext2/shared/team1 + touch $CUR_PATH/tacl/mount-ext2/shared/team1/file1 + + cd $CUR_PATH/tacl/mount-ext2/shared/team1 + ln -sf file1 symlinkfile1 + cd $CUR_PATH + + cd $CUR_PATH/tacl/mount-ext2/shared + ln -sf team1 symlinkdir1 + cd $CUR_PATH + +TACL_USER1 + +su - tacluser2 << TACL_USER2 + + mkdir $CUR_PATH/tacl/mount-ext2/shared/team2 + touch $CUR_PATH/tacl/mount-ext2/shared/team2/file1 + + cd $CUR_PATH/tacl/mount-ext2/shared/team2 + ln -sf file1 symlinkfile1 + cd $CUR_PATH + + cd $CUR_PATH/tacl/mount-ext2/shared + ln -sf team2 symlinkdir2 + cd $CUR_PATH + +TACL_USER2 + +############################################################################################# +# +# The permissions bit limit user's act +# lrwxrwxrwx 1 tacluser1 tacluser1 5 Jun 23 13:39 symlinkdir1 -> team1 +# lrwxrwxrwx 1 tacluser2 tacluser2 5 Jun 23 13:39 symlinkdir2 -> team2 +# dr-x------ 2 tacluser1 tacluser1 1024 Jun 23 13:39 team1 +# drwxrwxr-x 2 tacluser2 tacluser2 1024 Jun 23 13:39 team2 +# +############################################################################################# + +chmod 500 tacl/mount-ext2/shared/team1 + +su - tacluser1 << TACL_USER1 + + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfil1 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile1 ] + then + printf "\nFAILED: [ touch ] Create file must be denied by file permission bits\n" + printf "\t [ Physical Directory ]\n" + else + printf "\nSUCCESS: Create file denied by file permission bits [ Physical directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfil2 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile2 ] + then + printf "\nFAILED: [ touch ] Create file must be denied by file permission bits\n" + printf "\t [ Symlink Directory ]\n" + else + printf "\nSUCCESS: Create file denied by file permission bits [ Symlink directory ]\n" + fi + +TACL_USER1 + +################################################################# +# +# ACL_USER_OBJ are a superset of the permissions specified +# by the file permission bits. +# The effective user ID of the process matches the user ID of +# the file object owner. +# Owner's act are based ACL_USER_OBJ +# +################################################################# + +setfacl -m u::rx tacl/mount-ext2/shared/team1 +su - tacluser1 << TACL_USER1 + + cd $CUR_PATH/tacl/mount-ext2/shared/team1/ 2> /dev/null + if [ $? != 0 ] + then + printf "\nFAILED: [ touch ] ACL_USER_OBJ entry already contains the owner execute\n" + printf "\t permissions, but operation failed [ Physical Directory ]\n" + else + printf "\nSUCCESS: ACL_USER_OBJ entry contains the owner execute permissions,\n" + printf "\t operation success [ Physical Directory ]\n" + fi + + cd $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/ 2> /dev/null + if [ $? != 0 ] + then + printf "\nFAILED: [ touch ] ACL_USER_OBJ entry already contains the owner execute\n" + printf "\t permissions, but operation failed [ Symlink Directory ]\n" + else + printf "\nSUCCESS: ACL_USER_OBJ entry contains the owner execute permissions,\n" + printf "\t operation success [ Symlink Directory ]\n" + fi + +TACL_USER1 + +setfacl -m u::rwx tacl/mount-ext2/shared/team1 + +su - tacluser1 << TACL_USER1 + + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfil1 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile1 ] + then + printf "\nFAILED: [ touch ] ACL_USER_OBJ entry already contains the owner write \n" + printf "\t permissions, but operation failed [ Physical Directory ]\n" + else + printf "\nSUCCESS: ACL_USER_OBJ entry contains the owner write permissions,\n" + printf "\t operation success [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfil2 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile2 ] + then + printf "\nFAILED: [ touch ] ACL_USER_OBJ entry already contains the owner write \n" + printf "\t permissions, but operation failed [ Symlink Directory ]\n" + else + printf "\nSUCCESS: ACL_USER_OBJ entry contains the owner write permissions,\n" + printf "\t operation success [ Symlink Directory ]\n" + fi + +TACL_USER1 + +################################################################# +# +# The effective user ID of the process matches the qualifier of +# any entry of type ACL_USER +# IF the matching ACL_USER entry and the ACL_MASK +# entry contain the requested permissions,# access is granted, +# ELSE access is denied. +# +################################################################# + +setfacl -m u:tacluser3:rwx tacl/mount-ext2/shared/team1 + +su - tacluser3 << TACL_USER3 + + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile3 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile3 ] + then + printf "\nSUCCESS: ACL_USER entry contains the user permissions,\n" + printf "\t operation success [ Physical Directory ]\n" + else + printf "\nFAILED: ACL_USER entry contains the user permissions,\n" + printf "\t but operation denied [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile4 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile4 ] + then + printf "\nSUCCESS: ACL_USER entry contains the user permissions,\n" + printf "\t operation success [ Symlink Directory ]\n" + else + printf "\nFAILED: ACL_USER entry contains the user permissions,\n" + printf "\t but operation denied [ Symlink Directory ]\n" + fi + +TACL_USER3 + +setfacl -m mask:--- tacl/mount-ext2/shared/team1 + +su - tacluser3 << TACL_USER3 + + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile5 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile5 ] + then + printf "\nFAILED: [ touch ] ACL_USER entry contains the user permissions\n" + printf "\t but ACL_MASK are set --- ,\n" + printf "\t operation must be denied [ Physical Directory ]\n" + else + printf "\nSUCCESS: ACL_USER entry contains the user permissions,\n" + printf "\t but ACL_MASK are set ___ ,\n" + printf "\t operation success [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile6 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile6 ] + then + printf "\nFAILED: [ touch ] ACL_USER entry contains the user permissions\n" + printf "\t but ACL_MASK are set --- ,\n" + printf "\t operation must be denied [ Symlink Directory ]\n" + else + printf "\nSUCCESS: ACL_USER entry contains the user permissions,\n" + printf "\t but ACL_MASK are set ___ ,\n" + printf "\t operation success [ Symlink Directory ]\n" + fi + +TACL_USER3 + +########################################################################################### +# +# The effective group ID or any of the supplementary group IDs of the process match the +# qualifier of the entry of type ACL_GROUP_OBJ, or the qualifier of any entry of type +# ACL_GROUP +# +# IF the ACL contains an ACL_MASK entry, THEN +# if the ACL_MASK entry and any of the matching ACL_GROUP_OBJ +# or ACL_GROUP entries contain the requested permissions, +# access is granted, +# +# else access is denied. +# +# ELSE (note that there can be no ACL_GROUP entries without an ACL_MASK entry) +# if the ACL_GROUP_OBJ entry contains the requested permis- +# sions, access is granted, +# +# else access is denied. +# +########################################################################################### + +setfacl -m g:tacluser2:rwx tacl/mount-ext2/shared/team1 + +su - tacluser2 << TACL_USER2 + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile7 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile7 ] + then + printf "\nSUCCESS: ACL_GROUP entry contains the group permissions,\n" + printf "\t option success [ Physical Directory ]\n" + else + printf "\nFAILED: [ touch ] ACL_GROUP entry already contains the group permissions,\n" + printf "\t but option success [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile8 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile8 ] + then + printf "\nSUCCESS: ACL_GROUP entry contains the group permissions,\n" + printf "\t option success [ Symlink Directory ]\n" + else + printf "\nFAILED: [ touch ] ACL_GROUP entry already contains the group permissions,\n" + printf "\t but option success [ Symlink Directory ]\n" + fi + +TACL_USER2 + +setfacl -m mask:--- tacl/mount-ext2/shared/team1 + +su - tacluser2 << TACL_USER2 + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile9 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile9 ] + then + printf "\nFAILED: [ touch ] ACL_GROUP entry contains the group permissions\n" + printf "\t and ACL_MASK entry are set ---,\n" + printf "\t option must no be success [ Physical Directory ]\n" + else + printf "\nSUCCESS: ACL_GROUP entry already contains the group permissions\n" + printf "\t and ACL_MASK entry are set ---,\n" + printf "\t option success [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile10 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile10 ] + then + printf "\nFAILED: [ touch ] ACL_GROUP entry contains the group permissions\n" + printf "\t and ACL_MASK entry are set ---,\n" + printf "\t option must no be success [ Symlink Directory ]\n" + else + printf "\nSUCCESS: ACL_GROUP entry already contains the group permissions\n" + printf "\t and ACL_MASK entry are set ---,\n" + printf "\t option success [ Symlink Directory ]\n" + fi + +TACL_USER2 + +setfacl -m g::rwx tacl/mount-ext2/shared/team1 +usermod -g tacluser1 tacluser2 + +su - tacluser2 << TACL_USER2 + + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile11 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile11 ] + then + printf "\nSUCCESS: ACL_GROUP_OBJ entry contains the group owner permissions,\n" + printf "\t option success [ Physical Directory ]\n" + else + printf "\nFAILED: [ touch ] ACL_GROUP_OBJ entry already contains the group owner,\n" + printf "\t but option denied [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile12 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile12 ] + then + printf "\nSUCCESS: ACL_GROUP_OBJ entry contains the group owner permissions,\n" + printf "\t option success [ Symlink Directory ]\n" + else + printf "\nFAILED: [ touch ] ACL_GROUP_OBJ entry already contains the group owner,\n" + printf "\t but option denied [ Symlink Directory ]\n" + fi + +TACL_USER2 + +setfacl -m mask:--- tacl/mount-ext2/shared/team1 + +su - tacluser2 << TACL_USER2 + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile13 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile13 ] + then + printf "\nFAILED: [ touch ] ACL_GROUP_OBJ entry contains the group owner permissions\n" + printf "\t and ACL_MASK entry are set ---,\n" + printf "\t option must no be success [ Physical Directory ]\n" + else + printf "\nSUCCESS: ACL_GROUP_OBJ entry already contains the group owner permissions\n" + printf "\t and ACL_MASK entry are set ---,\n" + printf "\t option success [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile14 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile14 ] + then + printf "\nFAILED: [ touch ] ACL_GROUP_OBJ entry contains the group owner permissions\n" + printf "\t and ACL_MASK entry are set ---,\n" + printf "\t option must no be success [ Symlink Directory ]\n" + else + printf "\nSUCCESS: ACL_GROUP_OBJ entry already contains the group owner permissions\n" + printf "\t and ACL_MASK entry are set ---,\n" + printf "\t option success [ Symlink Directory ]\n" + fi + +TACL_USER2 + +usermod -g tacluser2 tacluser2 + +################################################################################### +# +# IF the ACL_OTHER entry contains the requested permissions, access is granted +# +################################################################################### + +setfacl -m o::rwx tacl/mount-ext2/shared/team1 + +su - tacluser4 << TACL_USER4 + + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile15 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile15 ] + then + printf "\nSUCCESS: ACL_OTHER entry contains the user permissions,\n" + printf "\t operation success [ Physical Directory ]\n" + else + printf "\nFAILED: ACL_OTHER entry contains the user permissions,\n" + printf "\t but operation denied [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile16 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile16 ] + then + printf "\nSUCCESS: ACL_OTHER entry contains the user permissions,\n" + printf "\t operation success [ Symlink Directory ]\n" + else + printf "\nFAILED: ACL_OTHER entry contains the user permissions,\n" + printf "\t but operation denied [ Symlink Directory ]\n" + fi + +TACL_USER4 + +setfacl -m mask:--- tacl/mount-ext2/shared/team1 + +su - tacluser4 << TACL_USER4 + + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile17 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile17 ] + then + printf "\nSUCCESS: [ touch ] ACL_OTHER do not strick by ACL_MASK [ Physical Directory ]\n" + else + printf "\nFAILED: ACL_OTHER do not strick by ACL_MASK [ Physical Directory ]\n" + fi + + touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile18 2> /dev/null + if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile18 ] + then + printf "\nSUCCESS: [ touch ] ACL_OTHER do not strick by ACL_MASK [ Symlink Directory ]\n" + else + printf "\nFAILED: ACL_OTHER do not strick by ACL_MASK [ Symlink Directory ]\n" + fi + +TACL_USER4 + +############################################################################ +# +# OBJECT CREATION AND DEFAULT ACLs +# The new object inherits the default ACL of the containing directory as its access ACL. +# +############################################################################ + +rm -f tacl/mount-ext2/shared/team1/newfil* + +# +# Test ACL_USER_OBJ default ACLs +# +setfacl -m d:u::r -m d:g::r -m d:o::r tacl/mount-ext2/shared/team1 + +su - tacluser1 << TACL_USER1 + + MASK=`umask` + umask 0 + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile1 + umask $MASK > /dev/null + +TACL_USER1 + +CONTENT="" +CONTENT=`ls -l tacl/mount-ext2/shared/team1/newfile1` +RES=`echo $CONTENT | grep ".r--r--r--" | awk '{print $1}'` + +if [ $RES != "" ] +then + printf "\nSUCCESS: With default ACLs set, new file permission set correct.\n" +else + printf "\nFAILED: With default ACLs set, new file permission set not correct\n" +fi + + + +# +# Test ACL_USER and ACL_GROUP defaults ACLs +# +setfacl -m d:u:tacluser3:rw -m d:g:tacluser3:rw tacl/mount-ext2/shared/team1 +su - tacluser3 << TACL_USER3 + + MASK=`umask` + umask 0 + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile2 + umask $MASK > /dev/null + +TACL_USER3 + +CONTENT="" +CONTENT=`ls -l tacl/mount-ext2/shared/team1/newfile2` +RES=`echo $CONTENT | grep ".r--rw-r--" | awk '{print $1}'` + +if [ $RES != "" ] +then + printf "\nSUCCESS: With default ACLs set, new file permission set correct.\n" +else + printf "\nFAILED: With default ACLs set, new file permission set not correct\n" +fi + +# +# Test ACL_GROUP default ACLs +# + +setfacl -m d:u::rwx -m d:g::rwx -m d:o::rwx tacl/mount-ext2/shared/team1 +su - tacluser3 << TACL_USER3 + + MASK=`umask` + umask 0 + touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile3 + umask $MASK > /dev/null + +TACL_USER3 + +CONTENT="" +CONTENT=`ls -l tacl/mount-ext2/shared/team1/newfile3` +RES=`echo $CONTENT | grep ".rw-rw-rw-" | awk '{print \$1}'` + +if [ $RES != "" ] +then + printf "\nSUCCESS: With default ACLs set, new file permission set correct.\n" +else + printf "\nFAILED: With default ACLs set, new file permission set not correct\n" +fi + + +################################################################################# +# +# Chmod also change ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER permissions +# +################################################################################# +su - tacluser3 << TACL_USER3 + MASK=`umask` + umask 0 + + chmod 777 $CUR_PATH/tacl/mount-ext2/shared/team1/newfile3 + umask $MASK > /dev/null +TACL_USER3 + +CONTENT="" +CONTENT=`getfacl tacl/mount-ext2/shared/team1/newfile3` + +USER_PERMISSION=`echo $CONTENT | awk '{print \$10}'` + +GROUP_PERMISSION=`echo $CONTENT | awk '{print \$12}'` +OTHER_PERMISSION=`echo $CONTENT | awk '{print \$15}'` + +if [ $USER_PERMISSION = "user::rwx" ] +then + if [ $GROUP_PERMISSION = "group::rwx" ] + then + if [ $OTHER_PERMISSION = "other::rwx" ] + then + printf "\nSUCCESS: Chmod with ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER are correct\n" + else + printf "\nFAILED: Chmod with ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER are not correct\n" + fi + else + printf "\nFAILED: Chmod with ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER are not correct\n" + fi +else + printf "\nFAILED: Chmod with ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER are not correct\n" +fi + + +##################################################################################### +# +# Chown only change object owner and group +# +##################################################################################### + +chown tacluser2.tacluser2 tacl/mount-ext2/shared/team1/newfile2 +CONTENT="" +CONTENT=`getfacl tacl/mount-ext2/shared/team1/newfile2` + +ITEM_OWNER=`echo $CONTENT | awk '{print \$6}'` +ITEM_GROUP=`echo $CONTENT | awk '{print \$9}'` + +if [ $ITEM_OWNER = "tacluser2" ] +then + if [ $ITEM_GROUP = "tacluser2" ] + then + printf "\nSUCCESS: Chown correct\n" + else + printf "\nFAILED: Chown are not correct\n" + fi +else + echo "FAILED: Chown are not correct" +fi + +##################################################### +# +# Test ACLs backup and restore +# +##################################################### + +getfacl -RL tacl/mount-ext2/ > tacl/tmp1 +setfacl -m u::--- -m g::--- -m o::--- tacl/mount-ext2/shared/team1 +setfacl --restore tacl/tmp1 +getfacl -RL tacl/mount-ext2/ > tacl/tmp2 + +if [ `diff tacl/tmp1 tacl/tmp2` ] +then + printf "\nFAILED: ACLs backup and restore are not correct\n" +else + printf "\nSUCCESS: ACLs backup and restore are correct\n" +fi + +printf "\n\tEnd ACLs Test\n" + +##################################################### +# +# Now begin Extend Attribute test +# +##################################################### + +printf "\nNow begin Extend Attribute Test\n" + +# dir +printf "\nAttach name:value pair to object dir\n\n" +attr -s attrname1 -V attrvalue1 tacl/mount-ext2/shared/team2 +if [ $? != 0 ] +then + echo "FAILED: Attach name:value pair to object dir" +fi + +#file +echo +echo "Attach name:value pair to object file " +echo "" +attr -s attrname2 -V attrvalue2 tacl/mount-ext2/shared/team2/file1 +if [ $? != 0 ] +then + echo "FAILED: Attach name:value pair to object file" +fi + +#symlink file +echo +echo "Attach name:value pair to object symlink file" +echo "" +attr -s attrname3 -V attrvalue3 tacl/mount-ext2/shared/team2/symlinkfile1 +if [ $? != 0 ] +then + echo "INFO: Can't attach name:value pair to object symlink file" +fi + +echo "" +ls -lRt tacl/mount-ext2/shared/team2 + +echo +echo "get extended attributes of filesystem objects" +echo "" + +echo "Dump the values" +getfattr -d tacl/mount-ext2/shared/team2 +if [ $? != 0 ] +then + echo "FAILED: getfattr: Dump the values" +fi + +echo "Recursively dump the values" +getfattr -dR tacl/mount-ext2/* +if [ $? != 0 ] +then + echo "FAILED: getfattr: Recursively Dump the values" +fi + +echo "Do not follow symlinks." +echo "but extended user attributes are disallowed for symbolic links" +getfattr -h --no-dereference tacl/mount-ext2/shared/team2/symlinkfile1 +if [ $? != 0 ] +then + echo "FAILED: getfattr: Do not follow symlinks." +fi +echo + +echo "Logical walk, follow symbolic links" +getfattr -L tacl/mount-ext2/shared/team2/* +if [ $? != 0 ] +then + echo "FAILED: getfattr: Logical walk" +fi + +echo "Physical walk, skip all symbolic links" +getfattr -P tacl/mount-ext2/shared/team2/* +if [ $? != 0 ] +then + echo "FAILED: getfattr: Physical walk" +fi + +echo "attr -g to search the named object" +attr -g attrname1 tacl/mount-ext2/shared/team2 +if [ $? != 0 ] +then + echo "FAILED: attr: to search the named object" +fi +echo + +echo "attr -r to remove the named object" +attr -r attrname2 tacl/mount-ext2/shared/team2/file1 +if [ $? != 0 ] +then + echo "FAILED: attr: to remove the named object" +fi + + +################################# +# +# Backup and Restore +# +################################# +getfattr -dhR -m- -e hex tacl/mount-ext2 > tacl/backup.ea +setfattr -h --restore=tacl/backup.ea + +getfattr -dhR -m- -e hex tacl/mount-ext2 > tacl/backup.ea1 +if [ `diff tacl/backup.ea1 tacl/backup.ea` ] +then + printf "\nFAILED: EAs backup and restore are not correct\n" +else + printf "\nSUCCESS: EAs backup and restore are correct\n" +fi + +printf "\n\tEnd EAs Test\n" + + + +##################################################### +# +# Clean up +# +##################################################### + +userdel tacluser1 +userdel tacluser2 +userdel tacluser3 +userdel tacluser4 +umount -d tacl/mount-ext2 +rm -rf tacl diff --git a/ltp/testcases/kernel/fs/binfmt_misc/Makefile b/ltp/testcases/kernel/fs/binfmt_misc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..14437b50dae0dea323085dbaf9f1e039f2707a6b --- /dev/null +++ b/ltp/testcases/kernel/fs/binfmt_misc/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. +# Author: Xiao Yang + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INSTALL_TARGETS := binfmt_misc01.sh binfmt_misc02.sh binfmt_misc_lib.sh + +include $(top_srcdir)/include/mk/generic_trunk_target.mk diff --git a/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc01.sh b/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc01.sh new file mode 100755 index 0000000000000000000000000000000000000000..beb803084f9ab26851475db31439e0de5afb6d13 --- /dev/null +++ b/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc01.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. +# Author: Xiao Yang +# +# Description: +# Use various invalid inputs to register a new binary type. +# 1) Invalid format of string fails to register a new binary type. +# 2) Invalid type fails to register a new binary type. +# 3) Invalid name containing slashes fails to register a new +# binary type. +# 4) If extension matching is chosen, invalid magic containing +# slashes fails to register a new binary type. +# 5) If magic matching is chosen, invalid offset(e.g. -1 and +# 2500000000) fails to register a new binary type. +# 6) Invalid flag fails to register a new binary type. +# +# Note: +# This is also a regression test for the following kernel bug: +# '5cc41e099504 ("fs/binfmt_misc.c: do not allow offset overflow")' + + +TST_CNT=9 +TST_TESTFUNC=do_test +TST_NEEDS_CMDS="cat" + + +verify_binfmt_misc() +{ + local name=$(echo "$1" | awk -F ':' '{print $2}') + local mntpoint=$(get_binfmt_misc_mntpoint) + + (echo "$1" >"$mntpoint/register") 2>/dev/null + if [ $? -ne 0 -a ! -f "$mntpoint/$name" ]; then + tst_res TPASS "Failed to register a binary type" + return + fi + + # Trigger kernel crash reliably by cat command. + cat "$mntpoint/$name" >/dev/null 2>&1 + tst_res TFAIL "Register a binary type successfully" + + [ -f "$mntpoint/$name" ] && \ + remove_binary_type "$mntpoint/$name" +} + +do_test() +{ + case $1 in + 1) verify_binfmt_misc ".textension,E,,ltp,,$(which cat),";; + 2) verify_binfmt_misc ":tnone:X::ltp::$(which cat):";; + 3) verify_binfmt_misc ":textension/:E::ltp::$(which cat):";; + 4) verify_binfmt_misc ":tmagic/:M::ltp::$(which cat):";; + 5) verify_binfmt_misc ":textension:E::ltp/::$(which cat):";; + 6) verify_binfmt_misc ":tmagic:M:-1:ltp::$(which cat):";; + 7) verify_binfmt_misc ":tmagic:M:2500000000:ltp::$(which cat):";; + 8) verify_binfmt_misc ":textension:E::ltp::$(which cat):A";; + 9) verify_binfmt_misc ":tmagic:M::ltp::$(which cat):A";; + esac +} + +. binfmt_misc_lib.sh +tst_run diff --git a/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc02.sh b/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc02.sh new file mode 100755 index 0000000000000000000000000000000000000000..37c9b9e0f4e2b5afe51d4ba32c99030418111c9a --- /dev/null +++ b/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc02.sh @@ -0,0 +1,109 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. +# Author: Xiao Yang +# +# Description: +# Register a new binary type and then check if binfmt_misc +# recognises the binary type in some conditions. +# 1) binfmt_misc should recognise the binary type when extension +# or magic is matched. +# 2) binfmt_misc should not recognise the binary type when extension +# or magic is mismatched. +# 3) binfmt_misc should not recognise the binary type when it is +# disabled. +# +# Note: +# We use various delimiteris to register a new binary type. + +TST_CNT=6 +TST_TESTFUNC=do_test +TST_NEEDS_CMDS="cat head" + + +recognised_unrecognised() +{ + local file=$1 + local string="$2" + + eval $file >temp 2>&1 + if [ $? -ne 0 ] || ! grep -q "$string" temp; then + tst_res TFAIL "Fail to recognise a binary type" + return + fi + + (echo 0 >"$mntpoint/$name") 2>/dev/null + if [ $? -ne 0 ] || grep -q enable "$mntpoint/$name"; then + tst_res TFAIL "Fail to disable a binary type" + return + fi + + eval $file >temp 2>&1 + if [ $? -eq 0 ] || grep -q "$string" temp; then + tst_res TFAIL "Recognise a disabled binary type successfully" + return + fi + + tst_res TPASS "Recognise and unrecognise a binary type as expected" +} + +unrecognised() +{ + local file=$1 + local string="$2" + + eval $file >temp 2>&1 + if [ $? -eq 0 ] || grep -q "$string" temp; then + tst_res TFAIL "Recognise a binary type successfully" + else + tst_res TPASS "Fail to recognise a binary type" + fi +} + +verify_binfmt_misc() +{ + local delimiter=$(echo "$1" | head -c1) + local name=$(echo "$1" | awk -F $delimiter '{print $2}') + local ttype=$(echo "$1" | awk -F $delimiter '{print $3}') + local tfile=$2 + local valid=$3 + local mntpoint=$(get_binfmt_misc_mntpoint) + + (echo "$1" >"$mntpoint/register") 2>/dev/null + if [ $? -ne 0 -o ! -f "$mntpoint/$name" ]; then + tst_res TFAIL "Fail to register a binary type" + return + fi + + [ "$ttype" = "E" ] && local tstring="This is test for extension" + [ "$ttype" = "M" ] && local tstring="This is test for magic" + + [ "$valid" = "1" ] && recognised_unrecognised "$tfile" "$tstring" + [ "$valid" = "0" ] && unrecognised "$tfile" "$tstring" + + remove_binary_type "$mntpoint/$name" +} + +do_test() +{ + local cat="$(command -v cat)" + + case $1 in + 1) verify_binfmt_misc ":textension:E::extension::$cat:" \ + "$TST_DATAROOT/file.extension" "1";; + 2) verify_binfmt_misc ":tmagic:M:1:This::$cat:" \ + "$TST_DATAROOT/file.magic" "1";; + 3) verify_binfmt_misc ".textension.E..extension..$cat." \ + "$TST_DATAROOT/file.extension" "1";; + 4) verify_binfmt_misc ",tmagic,M,1,This,,$cat," \ + "$TST_DATAROOT/file.magic" "1";; + 5) verify_binfmt_misc ":textension:E::ltp::$cat:" \ + "$TST_DATAROOT/file.extension" "0";; + 6) verify_binfmt_misc ":tmagic:M:0:This::$cat:" \ + "$TST_DATAROOT/file.magic" "0";; + esac +} + +. binfmt_misc_lib.sh +tst_run diff --git a/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc_lib.sh b/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc_lib.sh new file mode 100755 index 0000000000000000000000000000000000000000..7fcf12388e0b4f6db6f813218037a64baf0485a3 --- /dev/null +++ b/ltp/testcases/kernel/fs/binfmt_misc/binfmt_misc_lib.sh @@ -0,0 +1,74 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. +# Author: Xiao Yang + +TST_SETUP="${TST_SETUP:-binfmt_misc_setup}" +TST_CLEANUP="${TST_CLEANUP:-binfmt_misc_cleanup}" +TST_NEEDS_DRIVERS="binfmt_misc" +TST_NEEDS_TMPDIR=1 +TST_NEEDS_ROOT=1 +TST_NEEDS_CMDS="${TST_NEEDS_CMDS} modprobe mount umount mkdir rm" + +rmod_binfmt_misc=0 +umount_binfmt_misc=0 +binfmt_misc_mntpoint="ltp_binfmt_misc" + +remove_binary_type() +{ + local name=$1 + + (echo -1 >"$name") 2>/dev/null + [ $? -ne 0 -o -f "$name" ] && \ + tst_res TWARN "Fail to remove a binary type" +} + +get_binfmt_misc_mntpoint() +{ + local mntpoint + + mntpoint=$(awk '/ binfmt_misc / { print $2 }' /proc/mounts) + [ -z "$mntpoint" ] && tst_brk TBROK "Can't get binfmt_misc mntpoint" + + echo "$mntpoint" +} + +binfmt_misc_setup() +{ + local mntpoint + + if ! grep -q "binfmt_misc" /proc/filesystems; then + ROD modprobe binfmt_misc + rmod_binfmt_misc=1 + fi + + # Match fs type accurately, because autofs is also mounted on + # /proc/sys/fs/binfmt_misc on some distros, as below: + # cat /proc/mounts | grep binfmt_misc + # systemd-1 /proc/sys/fs/binfmt_misc autofs ... + # binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc ... + mntpoint=$(awk '/ binfmt_misc / { print $2 }' /proc/mounts) + [ -n "$mntpoint" ] && return + + ROD mkdir ${binfmt_misc_mntpoint} + ROD mount -t binfmt_misc none ${binfmt_misc_mntpoint} + umount_binfmt_misc=1 +} + +binfmt_misc_cleanup() +{ + if [ ${umount_binfmt_misc} -ne 0 ]; then + umount ${binfmt_misc_mntpoint} + umount_binfmt_misc=0 + fi + + [ -d ${binfmt_misc_mntpoint} ] && rm -rf ${binfmt_misc_mntpoint} + + if [ ${rmod_binfmt_misc} -ne 0 ]; then + modprobe -r binfmt_misc + rmod_binfmt_misc=0 + fi +} + +. tst_test.sh diff --git a/ltp/testcases/kernel/fs/binfmt_misc/datafiles/Makefile b/ltp/testcases/kernel/fs/binfmt_misc/datafiles/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e6d1487c975adf570a6d7e6a77c2512106c72909 --- /dev/null +++ b/ltp/testcases/kernel/fs/binfmt_misc/datafiles/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. +# Author: Xiao Yang + +top_srcdir ?= ../../../../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INSTALL_DIR := testcases/data/binfmt_misc02 +INSTALL_TARGETS := file.extension file.magic + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/testcases/kernel/fs/binfmt_misc/datafiles/file.extension b/ltp/testcases/kernel/fs/binfmt_misc/datafiles/file.extension new file mode 100755 index 0000000000000000000000000000000000000000..8468a8fa1273cd83e22318820f9ed492494861b9 --- /dev/null +++ b/ltp/testcases/kernel/fs/binfmt_misc/datafiles/file.extension @@ -0,0 +1 @@ +This is test for extension diff --git a/ltp/testcases/kernel/fs/binfmt_misc/datafiles/file.magic b/ltp/testcases/kernel/fs/binfmt_misc/datafiles/file.magic new file mode 100755 index 0000000000000000000000000000000000000000..f2823b67b1aff1f715ca4b569daa04c5c6c1b295 --- /dev/null +++ b/ltp/testcases/kernel/fs/binfmt_misc/datafiles/file.magic @@ -0,0 +1 @@ + This is test for magic diff --git a/ltp/testcases/kernel/fs/doio/.gitignore b/ltp/testcases/kernel/fs/doio/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..debfce8acf5b877e95abb663002f6f8ba626ac9a --- /dev/null +++ b/ltp/testcases/kernel/fs/doio/.gitignore @@ -0,0 +1,3 @@ +/doio +/growfiles +/iogen diff --git a/ltp/testcases/kernel/fs/doio/Makefile b/ltp/testcases/kernel/fs/doio/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..449e100a5b5bcf99db8dcbeb4a32a7f33c7a0e78 --- /dev/null +++ b/ltp/testcases/kernel/fs/doio/Makefile @@ -0,0 +1,41 @@ +# +# kernel/fs/doio testcases 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. +# +# Ngie Cooper, July 2009 +# + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +CFLAGS += -D_LARGEFILE64_SOURCE -Wall \ + -I$(abs_top_srcdir)/testcases/kernel/fs/doio/include/ +LDLIBS += -lrt -lpthread + +MAKE_TARGETS := growfiles doio iogen +INSTALL_TARGETS := rwtest + + +$(MAKE_TARGETS): dataascii.o databin.o file_lock.o forker.o open_flags.o \ + datapid.o write_log.o pattern.o string_to_tokens.o \ + bytes_by_prefix.o + +%.o: $(abs_top_srcdir)/testcases/kernel/fs/doio/%.c + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/ltp/testcases/kernel/fs/doio/README b/ltp/testcases/kernel/fs/doio/README new file mode 100644 index 0000000000000000000000000000000000000000..f62bf309ec40d8864d636e27a3f97f2a8f5f3b38 --- /dev/null +++ b/ltp/testcases/kernel/fs/doio/README @@ -0,0 +1,79 @@ + +$Id: README,v 1.1 2001/08/27 22:15:12 plars Exp $ + +This file contains some very basic information on: + iogen/doio and rwtest + growfiles + +All tools use the -h flag for printing some form of help (sometimes voluminous). +They are extremely configurable; the examples below are some common uses. +Read the help and experiment! This testing tools were originally written +to test UNICOS's NC1 and IRIX XFS filesystems. + + +IOGEN & DOIO +============= + +This is a pair of programs that does basic I/O operations on a set of files. +The file offset, I/O length, I/O operation, and what open(2) flags are +selected randomly from a pre-defined or commandline given set. All data +written can be verified (this is the usual method). + +rwtest is a shell script that is a wrapper of iogen and doio. + +Examples: +--------- +# run forever: 8 process - using record locks +iogen -i 0 100000b:doio_1 | doio -av -n 8 -m 1000 + +# run forever: 8 process - using record locks +iogen -i 0 100000b:doio_2 | doio -akv -n 8 -m 1000 + +# run forever: max i/o 64b, to /tmp/rwtest01%f, which 500b in size +rwtest -c -i 0 -T 64b 500b:/tmp/rwtest01%f + + + +GROWFILES +============= + +Growfiles will create and truncate files in gradual steps using write, and +lseek. All system calls are checked for proper returns. The writes or the +whole file content can be verified. It can cause disk fragmentation. + + +Examples: +--------- +growfiles -E output: +# run forever: writes of 4090 bytes then on every 100 iterval +# truncate file by 408990 bytes. Done to 200 files in dir1. +growfiles -i 0 -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -d dir1 -S 200 + +# same as above with writes of 5000 bytes and truncs of 499990 +growfiles -i 0 -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -d dir2 -S 200 + +# runs forever: beats on opens and closes of file ocfile - no io +growfiles -i 0 -g 0 -c 0 -C 0 ocfile + +# writes 4096 to files until 50 blocks are written +growfiles -i 0 -g 4096 -B 50b file1 file2 + +# write one byte to 750 files in gdir then unlinks them +growfiles -g 1 -C 0 -d gdir -u -S 750 + +# run 30 secs: random iosize, random lseek up to eof +# Only valid for one growfile process per file. +growfiles -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand1 g_rand2 + +# run 30 secs: grow by lseek then write single byte, trunc every 10 itervals +growfiles -g 5000 -wlu -i 0 -L 30 -C 1 -T 10 g_sleek1 g_lseek2 + +# run forever: 5 copies of random iosize, random lseek to beyond eof, +# rand io types doing a trunc every 5 iterations, with unlinks. +growfiles -i0 -r 1-50000 -R 0--2 -I r -C1 -l -n5 -u -U 100-200 gf_rana gf_ranb + +# run forever: 5 copies of random iosize, random lseek to beyond eof, +# random open flags, rand io types doing a trunc every 10 iterations. +growfiles -i0 -r 1-50000 -R 0--2 -o random -I r -C0 -l -T 20 -uU100-200 -n 5 gf_rand1 gf_rand2 + + diff --git a/ltp/testcases/kernel/fs/doio/bytes_by_prefix.c b/ltp/testcases/kernel/fs/doio/bytes_by_prefix.c new file mode 100644 index 0000000000000000000000000000000000000000..797442c6d4d17c385d0aac534a0cd07f52ce4bc7 --- /dev/null +++ b/ltp/testcases/kernel/fs/doio/bytes_by_prefix.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +#include +#include + +#include "bytes_by_prefix.h" + +/**************************************************************************** + * bytes_by_prefix(s) + * + * Computes the number of bytes described by string s. s is assumed to be + * a base 10 positive (ie. >= 0) number followed by an optional single + * character multiplier. The following multipliers are supported: + * + * char mult + * ----------------- + * b BSIZE or BBSIZE + * k 1024 bytes + * K 1024 * sizeof(long) + * m 2^20 (1048576) + * M 2^20 (1048576 * sizeof(long) + * g 2^30 (1073741824) + * G 2^30 (1073741824) * sizeof(long) + * + * for instance, "1k" and "1024" would both cause bytes_by_prefix to return 1024 + * + * Returns -1 if mult is an invalid character, or if the integer portion of + * s is not a positive integer. + * + ****************************************************************************/ + +#ifdef DEV_BSIZE +#define B_MULT DEV_BSIZE /* block size */ +#else +#warning DEV_BSIZE is not defined, defaulting to 512 +#define B_MULT 512 +#endif + +#define K_MULT 1024 /* Kilo or 2^10 */ +#define M_MULT 1048576 /* Mega or 2^20 */ +#define G_MULT 1073741824 /* Giga or 2^30 */ +#define T_MULT 1099511627776 /* tera or 2^40 */ + +int bytes_by_prefix(char *s) +{ + char mult, junk; + int nconv; + float num; + int result; + + nconv = sscanf(s, "%f%c%c", &num, &mult, &junk); + if (nconv == 0 || nconv == 3) + return -1; + + if (nconv == 1) { + result = num; + return result < 0 ? -1 : result; + } + + switch (mult) { + case 'b': + result = (int)(num * (float)B_MULT); + break; + case 'k': + result = (int)(num * (float)K_MULT); + break; + case 'K': + result = (int)((num * (float)K_MULT) * sizeof(long)); + break; + case 'm': + result = (int)(num * (float)M_MULT); + break; + case 'M': + result = (int)((num * (float)M_MULT) * sizeof(long)); + break; + case 'g': + result = (int)(num * (float)G_MULT); + break; + case 'G': + result = (int)((num * (float)G_MULT) * sizeof(long)); + break; + default: + return -1; + } + + if (result < 0) + return -1; + + return result; +} + +long lbytes_by_prefix(char *s) +{ + char mult, junk; + int nconv; + float num; + long result; + + nconv = sscanf(s, "%f%c%c", &num, &mult, &junk); + if (nconv == 0 || nconv == 3) + return -1; + + if (nconv == 1) { + result = (long)num; + return result < 0 ? -1 : result; + } + + switch (mult) { + case 'b': + result = (long)(num * (float)B_MULT); + break; + case 'k': + result = (long)(num * (float)K_MULT); + break; + case 'K': + result = (long)((num * (float)K_MULT) * sizeof(long)); + break; + case 'm': + result = (long)(num * (float)M_MULT); + break; + case 'M': + result = (long)((num * (float)M_MULT) * sizeof(long)); + break; + case 'g': + result = (long)(num * (float)G_MULT); + break; + case 'G': + result = (long)((num * (float)G_MULT) * sizeof(long)); + break; + default: + return -1; + } + + if (result < 0) + return -1; + + return result; +} + +/* + * Force 64 bits number when compiled as 32 IRIX binary. + * This allows for a number bigger than 2G. + */ +long long llbytes_by_prefix(char *s) +{ + char mult, junk; + int nconv; + double num; + long long result; + + nconv = sscanf(s, "%lf%c%c", &num, &mult, &junk); + if (nconv == 0 || nconv == 3) + return -1; + if (nconv == 1) { + result = (long long)num; + return result < 0 ? -1 : result; + } + + switch (mult) { + case 'b': + result = (long long)(num * (float)B_MULT); + break; + case 'k': + result = (long long)(num * (float)K_MULT); + break; + case 'K': + result = (long long)((num * (float)K_MULT) * sizeof(long long)); + break; + case 'm': + result = (long long)(num * (float)M_MULT); + break; + case 'M': + result = (long long)((num * (float)M_MULT) * sizeof(long long)); + break; + case 'g': + result = (long long)(num * (float)G_MULT); + break; + case 'G': + result = (long long)((num * (float)G_MULT) * sizeof(long long)); + break; + default: + return -1; + } + + if (result < 0) + return -1; + + return result; +} diff --git a/ltp/testcases/kernel/fs/doio/dataascii.c b/ltp/testcases/kernel/fs/doio/dataascii.c new file mode 100644 index 0000000000000000000000000000000000000000..da7e2a3feb1b1921cce0c257d217a7728b71de77 --- /dev/null +++ b/ltp/testcases/kernel/fs/doio/dataascii.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +#include +#include +#include "dataascii.h" + +#define CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjiklmnopqrstuvwxyz\n" +#define CHARS_SIZE sizeof(CHARS) + +#ifdef UNIT_TEST +#include +#endif + +static char Errmsg[80]; + +int dataasciigen(char *listofchars, char *buffer, int bsize, int offset) +{ + int cnt; + int total; + int ind; + char *chr; + int chars_size; + char *charlist; + + chr = buffer; + total = offset + bsize; + + if (listofchars == NULL) { + charlist = CHARS; + chars_size = CHARS_SIZE; + } else { + charlist = listofchars; + chars_size = strlen(listofchars); + } + + for (cnt = offset; cnt < total; cnt++) { + ind = cnt % chars_size; + *chr++ = charlist[ind]; + } + + return bsize; +} + +int dataasciichk(char *listofchars, char *buffer, int bsize, + int offset, char **errmsg) +{ + int cnt; + int total; + int ind; + char *chr; + int chars_size; + char *charlist; + + chr = buffer; + total = offset + bsize; + + if (listofchars == NULL) { + charlist = CHARS; + chars_size = CHARS_SIZE; + } else { + charlist = listofchars; + chars_size = strlen(listofchars); + } + + if (errmsg != NULL) + *errmsg = Errmsg; + + for (cnt = offset; cnt < total; chr++, cnt++) { + ind = cnt % chars_size; + if (*chr != charlist[ind]) { + sprintf(Errmsg, + "data mismatch at offset %d, exp:%#o, act:%#o", + cnt, charlist[ind], *chr); + return cnt; + } + } + + sprintf(Errmsg, "all %d bytes match desired pattern", bsize); + return -1; +} + +#if UNIT_TEST + +int main(int ac, char **ag) +{ + + int size = 1023; + char *buffer; + int ret; + char *errmsg; + + buffer = malloc(size); + if (buffer == NULL) { + perror("malloc"); + exit(2); + } + + dataasciigen(NULL, buffer, size, 0); + printf("dataasciigen(NULL, buffer, %d, 0)\n", size); + + ret = dataasciichk(NULL, buffer, size, 0, &errmsg); + printf("dataasciichk(NULL, buffer, %d, 0, &errmsg) returned %d %s\n", + size, ret, errmsg); + + if (ret == -1) + printf("\tPASS return value is -1 as expected\n"); + else + printf("\tFAIL return value is %d, expected -1\n", ret); + + ret = dataasciichk(NULL, &buffer[1], size - 1, 1, &errmsg); + printf("dataasciichk(NULL, &buffer[1], %d, 1, &errmsg) returned %d %s\n", + size - 1, ret, errmsg); + + if (ret == -1) + printf("\tPASS return value is -1 as expected\n"); + else + printf("\tFAIL return value is %d, expected -1\n", ret); + + buffer[25] = 0x0; + printf("changing char 25\n"); + + ret = dataasciichk(NULL, &buffer[1], size - 1, 1, &errmsg); + printf("dataasciichk(NULL, &buffer[1], %d, 1, &errmsg) returned %d %s\n", + size - 1, ret, errmsg); + + if (ret == 25) + printf("\tPASS return value is 25 as expected\n"); + else + printf("\tFAIL return value is %d, expected 25\n", ret); + + dataasciigen("this is a test of the my string", buffer, size, 0); + printf("dataasciigen(\"this is a test of the my string\", buffer, %d, 0)\n", + size); + + ret = dataasciichk("this is a test of the my string", + buffer, size, 0, &errmsg); + printf("dataasciichk(\"this is a test of the my string\", buffer, %d, 0, &errmsg) returned %d %s\n", + size, ret, errmsg); + + if (ret == -1) + printf("\tPASS return value is -1 as expected\n"); + else + printf("\tFAIL return value is %d, expected -1\n", ret); + + ret = + dataasciichk("this is a test of the my string", &buffer[1], + size - 1, 1, &errmsg); + printf("dataasciichk(\"this is a test of the my string\", &buffer[1], %d, 1, &errmsg) returned %d %s\n", + size - 1, ret, errmsg); + + if (ret == -1) + printf("\tPASS return value is -1 as expected\n"); + else + printf("\tFAIL return value is %d, expected -1\n", ret); + + buffer[25] = 0x0; + printf("changing char 25\n"); + + ret = dataasciichk("this is a test of the my string", &buffer[1], + size - 1, 1, &errmsg); + printf("dataasciichk(\"this is a test of the my string\", &buffer[1], %d, 1, &errmsg) returned %d %s\n", + size - 1, ret, errmsg); + + if (ret == 25) + printf("\tPASS return value is 25 as expected\n"); + else + printf("\tFAIL return value is %d, expected 25\n", ret); + + exit(0); +} + +#endif diff --git a/ltp/testcases/kernel/fs/doio/databin.c b/ltp/testcases/kernel/fs/doio/databin.c new file mode 100644 index 0000000000000000000000000000000000000000..702485b85a4501f2c2004271259ac5be40f756bf --- /dev/null +++ b/ltp/testcases/kernel/fs/doio/databin.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +#include +#include +#include /* memset */ +#include /* rand */ +#include "databin.h" + +#if UNIT_TEST +#include +#endif + +static char Errmsg[80]; + +void databingen(int mode, char *buffer, int bsize, int offset) +{ + int ind; + + switch (mode) { + default: + case 'a': /* alternating bit pattern */ + memset(buffer, 0x55, bsize); + break; + + case 'c': /* checkerboard pattern */ + memset(buffer, 0xf0, bsize); + break; + + case 'C': /* */ + for (ind = 0; ind < bsize; ind++) + buffer[ind] = ((offset + ind) % 8 & 0177); + + break; + + case 'o': + memset(buffer, 0xff, bsize); + break; + + case 'z': + memset(buffer, 0x0, bsize); + break; + + case 'r': /* random */ + for (ind = 0; ind < bsize; ind++) + buffer[ind] = (rand() & 0177) | 0100; + } +} + +/* + * return values: + * >= 0 : error at byte offset into the file, offset+buffer[0-(bsize-1)] + * < 0 : no error + */ +int databinchk(int mode, char *buffer, int bsize, int offset, char **errmsg) +{ + int cnt; + unsigned char *chr; + long expbits; + long actbits; + + chr = (unsigned char *)buffer; + + if (errmsg != NULL) + *errmsg = Errmsg; + + switch (mode) { + default: + case 'a': /* alternating bit pattern */ + expbits = 0x55; + break; + + case 'c': /* checkerboard pattern */ + expbits = 0xf0; + break; + + case 'C': /* counting pattern */ + for (cnt = 0; cnt < bsize; cnt++) { + expbits = ((offset + cnt) % 8 & 0177); + + if (buffer[cnt] != expbits) { + sprintf(Errmsg, + "data mismatch at offset %d, exp:%#lo, act:%#o", + offset + cnt, expbits, buffer[cnt]); + return offset + cnt; + } + } + sprintf(Errmsg, "all %d bytes match desired pattern", bsize); + return -1; + + case 'o': + expbits = 0xff; + break; + + case 'z': + expbits = 0; + break; + + case 'r': + return -1; /* no check can be done for random */ + } + + for (cnt = 0; cnt < bsize; chr++, cnt++) { + actbits = (long)*chr; + + if (actbits != expbits) { + sprintf(Errmsg, + "data mismatch at offset %d, exp:%#lo, act:%#lo", + offset + cnt, expbits, actbits); + return offset + cnt; + } + } + + sprintf(Errmsg, "all %d bytes match desired pattern", bsize); + return -1; +} + +#if UNIT_TEST + +int main(int ac, char **ag) +{ + int size = 1023; + int offset; + int number; + unsigned char *buffer; + int ret; + char *errmsg; + + buffer = malloc(size); + if (buffer == NULL) { + perror("malloc"); + exit(2); + } + + printf("***** for a ****************************\n"); + databingen('a', buffer, size, 0); + printf("databingen('a', buffer, %d, 0)\n", size); + + ret = databinchk('a', buffer, size, 0, &errmsg); + printf("databinchk('a', buffer, %d, 0, &errmsg) returned %d: %s\n", + size, ret, errmsg); + if (ret == -1) + printf("\tPASS return value of -1 as expected\n"); + else + printf("\tFAIL return value %d, expected -1\n", ret); + + offset = 232400; + ret = databinchk('a', &buffer[1], size - 1, offset, &errmsg); + printf("databinchk('a', &buffer[1], %d, %d, &errmsg) returned %d: %s\n", + size, offset, ret, errmsg); + if (ret == -1) + printf("\tPASS return value of -1 as expected\n"); + else + printf("\tFAIL return value %d, expected -1\n", ret); + + buffer[15] = 0x0; + printf("changing char 15 (offset (%d+15) = %d) to 0x0\n", offset, + offset + 15); + number = offset + 15; + + ret = databinchk('a', &buffer[1], size - 1, offset + 1, &errmsg); + printf("databinchk('a', &buffer[1], %d, %d, &errmsg) returned %d: %s\n", + size - 1, offset + 1, ret, errmsg); + if (ret == number) + printf("\tPASS return value of %d as expected\n", number); + else + printf("\tFAIL return value %d, expected %d\n", ret, number); + + printf("***** for c ****************************\n"); + databingen('c', buffer, size, 0); + printf("databingen('c', buffer, %d, 0)\n", size); + + ret = databinchk('c', buffer, size, 0, &errmsg); + printf("databinchk('c', buffer, %d, 0, &errmsg) returned %d: %s\n", + size, ret, errmsg); + if (ret == -1) + printf("\tPASS return value of -1 as expected\n"); + else + printf("\tFAIL return value %d, expected -1\n", ret); + + offset = 232400; + ret = databinchk('c', &buffer[1], size - 1, offset, &errmsg); + printf("databinchk('c', &buffer[1], %d, %d, &errmsg) returned %d: %s\n", + size, offset, ret, errmsg); + if (ret == -1) + printf("\tPASS return value of -1 as expected\n"); + else + printf("\tFAIL return value %d, expected -1\n", ret); + + buffer[15] = 0x0; + printf("changing char 15 (offset (%d+15) = %d) to 0x0\n", offset, + offset + 15); + number = offset + 15; + + ret = databinchk('c', &buffer[1], size - 1, offset + 1, &errmsg); + printf("databinchk('c', &buffer[1], %d, %d, &errmsg) returned %d: %s\n", + size - 1, offset + 1, ret, errmsg); + if (ret == number) + printf("\tPASS return value of %d as expected\n", number); + else + printf("\tFAIL return value %d, expected %d\n", ret, number); + + printf("***** for C ****************************\n"); + + databingen('C', buffer, size, 0); + printf("databingen('C', buffer, %d, 0)\n", size); + + ret = databinchk('C', buffer, size, 0, &errmsg); + printf("databinchk('C', buffer, %d, 0, &errmsg) returned %d: %s\n", + size, ret, errmsg); + if (ret == -1) + printf("\tPASS return value of -1 as expected\n"); + else + printf("\tFAIL return value %d, expected -1\n", ret); + + offset = 18; + ret = databinchk('C', &buffer[18], size - 18, 18, &errmsg); + printf + ("databinchk('C', &buffer[18], %d, 18, &errmsg) returned %d: %s\n", + size - 18, ret, errmsg); + if (ret == -1) + printf("\tPASS return value of -1 as expected\n"); + else + printf("\tFAIL return value %d, expected -1\n", ret); + + buffer[20] = 0x0; + buffer[21] = 0x0; + printf("changing char 20 and 21 to 0x0 (offset %d and %d)\n", 20, 21); + + ret = databinchk('C', &buffer[18], size - 18, 18, &errmsg); + printf("databinchk('C', &buffer[18], %d, 18, &errmsg) returned %d: %s\n", + size - 18, ret, errmsg); + + if (ret == 20 || ret == 21) + printf("\tPASS return value of %d or %d as expected\n", 20, 21); + else + printf("\tFAIL return value %d, expected %d or %d\n", ret, + 20, 21); + + exit(0); + +} + +#endif diff --git a/ltp/testcases/kernel/fs/doio/datapid.c b/ltp/testcases/kernel/fs/doio/datapid.c new file mode 100644 index 0000000000000000000000000000000000000000..dad1a12b68e564bbfd4f2c6115b057570ceb6c88 --- /dev/null +++ b/ltp/testcases/kernel/fs/doio/datapid.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +/************ + +64 bits in a Cray word + + 12345678901234567890123456789012 +1234567890123456789012345678901234567890123456789012345678901234 +________________________________________________________________ +< pid >< word-offset in file (same #) >< pid > + +1234567890123456789012345678901234567890123456789012345678901234 +________________________________________________________________ +< pid >< offset in file of this word >< pid > + +8 bits to a bytes == character + NBPW 8 +************/ + +#include +#include +#ifdef UNIT_TEST +#include +#include +#endif + +static char Errmsg[80]; + +#define LOWER16BITS(X) (X & 0177777) +#define LOWER32BITS(X) (X & 0xffffffff) + +/*** +#define HIGHBITS(WRD, bits) ( (-1 << (64-bits)) & WRD) +#define LOWBITS(WRD, bits) ( (-1 >> (64-bits)) & WRD) +****/ + +#define NBPBYTE 8 /* number bits per byte */ + +#ifndef DEBUG +#define DEBUG 0 +#endif + +/*********************************************************************** + * + * + * 1 2 3 4 5 6 7 8 9 10 11 12 13 14 14 15 bytes + * 1234567890123456789012345678901234567890123456789012345678901234 bits + * ________________________________________________________________ 1 word + * < pid >< offset in file of this word >< pid > + * + * the words are put together where offset zero is the start. + * thus, offset 16 is the start of the second full word + * Thus, offset 8 is in middle of word 1 + ***********************************************************************/ +int datapidgen(int pid, char *buffer, int bsize, int offset) +{ +#if CRAY + + int cnt; + int tmp; + char *chr; + long *wptr; + long word; + int woff; /* file offset for the word */ + int boff; /* buffer offset or index */ + int num_full_words; + + num_full_words = bsize / NBPW; + boff = 0; + + if (cnt = (offset % NBPW)) { /* partial word */ + + woff = offset - cnt; +#if DEBUG + printf("partial at beginning, cnt = %d, woff = %d\n", cnt, + woff); +#endif + + word = + ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | + LOWER16BITS(pid)); + + chr = (char *)&word; + + for (tmp = 0; tmp < cnt; tmp++) { /* skip unused bytes */ + chr++; + } + + for (; boff < (NBPW - cnt) && boff < bsize; boff++, chr++) { + buffer[boff] = *chr; + } + } + + /* + * full words + */ + + num_full_words = (bsize - boff) / NBPW; + + woff = offset + boff; + + for (cnt = 0; cnt < num_full_words; woff += NBPW, cnt++) { + + word = + ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | + LOWER16BITS(pid)); + + chr = (char *)&word; + for (tmp = 0; tmp < NBPW; tmp++, chr++) { + buffer[boff++] = *chr; + } +/****** Only if wptr is a word ellined + wptr = (long *)&buffer[boff]; + *wptr = word; + boff += NBPW; +*****/ + + } + + /* + * partial word at end of buffer + */ + + if (cnt = ((bsize - boff) % NBPW)) { +#if DEBUG + printf("partial at end\n"); +#endif + word = + ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | + LOWER16BITS(pid)); + + chr = (char *)&word; + + for (tmp = 0; tmp < cnt && boff < bsize; tmp++, chr++) { + buffer[boff++] = *chr; + } + } + + return bsize; + +#else + return -1; /* not support on non-64 bits word machines */ + +#endif + +} + +/*********************************************************************** + * + * + ***********************************************************************/ +int datapidchk(int pid, char *buffer, int bsize, int offset, char **errmsg) +{ +#if CRAY + + int cnt; + int tmp; + char *chr; + long *wptr; + long word; + int woff; /* file offset for the word */ + int boff; /* buffer offset or index */ + int num_full_words; + + if (errmsg != NULL) { + *errmsg = Errmsg; + } + + num_full_words = bsize / NBPW; + boff = 0; + + if (cnt = (offset % NBPW)) { /* partial word */ + woff = offset - cnt; + word = + ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | + LOWER16BITS(pid)); + + chr = (char *)&word; + + for (tmp = 0; tmp < cnt; tmp++) { /* skip unused bytes */ + chr++; + } + + for (; boff < (NBPW - cnt) && boff < bsize; boff++, chr++) { + if (buffer[boff] != *chr) { + sprintf(Errmsg, + "Data mismatch at offset %d, exp:%#o, act:%#o", + offset + boff, *chr, buffer[boff]); + return offset + boff; + } + } + } + + /* + * full words + */ + + num_full_words = (bsize - boff) / NBPW; + + woff = offset + boff; + + for (cnt = 0; cnt < num_full_words; woff += NBPW, cnt++) { + word = + ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | + LOWER16BITS(pid)); + + chr = (char *)&word; + for (tmp = 0; tmp < NBPW; tmp++, boff++, chr++) { + if (buffer[boff] != *chr) { + sprintf(Errmsg, + "Data mismatch at offset %d, exp:%#o, act:%#o", + woff, *chr, buffer[boff]); + return woff; + } + } + +/****** only if a word elined + wptr = (long *)&buffer[boff]; + if (*wptr != word) { + sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o", + woff, word, *wptr); + return woff; + } + boff += NBPW; +******/ + } + + /* + * partial word at end of buffer + */ + + if (cnt = ((bsize - boff) % NBPW)) { +#if DEBUG + printf("partial at end\n"); +#endif + word = + ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | + LOWER16BITS(pid)); + + chr = (char *)&word; + + for (tmp = 0; tmp < cnt && boff < bsize; boff++, tmp++, chr++) { + if (buffer[boff] != *chr) { + sprintf(Errmsg, + "Data mismatch at offset %d, exp:%#o, act:%#o", + offset + boff, *chr, buffer[boff]); + return offset + boff; + } + } + } + + sprintf(Errmsg, "all %d bytes match desired pattern", bsize); + return -1; /* buffer is ok */ + +#else + + if (errmsg != NULL) { + *errmsg = Errmsg; + } + sprintf(Errmsg, "Not supported on this OS."); + return 0; + +#endif + +} /* end of datapidchk */ + +#if UNIT_TEST + +/*********************************************************************** + * main for doing unit testing + ***********************************************************************/ +int main(ac, ag) +int ac; +char **ag; +{ + + int size = 1234; + char *buffer; + int ret; + char *errmsg; + + if ((buffer = (char *)malloc(size)) == NULL) { + perror("malloc"); + exit(2); + } + + datapidgen(-1, buffer, size, 3); + +/*** +fwrite(buffer, size, 1, stdout); +fwrite("\n", 1, 1, stdout); +****/ + + printf("datapidgen(-1, buffer, size, 3)\n"); + + ret = datapidchk(-1, buffer, size, 3, &errmsg); + printf("datapidchk(-1, buffer, %d, 3, &errmsg) returned %d %s\n", + size, ret, errmsg); + ret = datapidchk(-1, &buffer[1], size - 1, 4, &errmsg); + printf("datapidchk(-1, &buffer[1], %d, 4, &errmsg) returned %d %s\n", + size - 1, ret, errmsg); + + buffer[25] = 0x0; + buffer[26] = 0x0; + buffer[27] = 0x0; + buffer[28] = 0x0; + printf("changing char 25-28\n"); + + ret = datapidchk(-1, &buffer[1], size - 1, 4, &errmsg); + printf("datapidchk(-1, &buffer[1], %d, 4, &errmsg) returned %d %s\n", + size - 1, ret, errmsg); + + printf("------------------------------------------\n"); + + datapidgen(getpid(), buffer, size, 5); + +/******* +fwrite(buffer, size, 1, stdout); +fwrite("\n", 1, 1, stdout); +******/ + + printf("\ndatapidgen(getpid(), buffer, size, 5)\n"); + + ret = datapidchk(getpid(), buffer, size, 5, &errmsg); + printf("datapidchk(getpid(), buffer, %d, 5, &errmsg) returned %d %s\n", + size, ret, errmsg); + + ret = datapidchk(getpid(), &buffer[1], size - 1, 6, &errmsg); + printf + ("datapidchk(getpid(), &buffer[1], %d, 6, &errmsg) returned %d %s\n", + size - 1, ret, errmsg); + + buffer[25] = 0x0; + printf("changing char 25\n"); + + ret = datapidchk(getpid(), &buffer[1], size - 1, 6, &errmsg); + printf + ("datapidchk(getpid(), &buffer[1], %d, 6, &errmsg) returned %d %s\n", + size - 1, ret, errmsg); + + exit(0); +} + +#endif diff --git a/ltp/testcases/kernel/fs/doio/doio.c b/ltp/testcases/kernel/fs/doio/doio.c new file mode 100644 index 0000000000000000000000000000000000000000..b170f667089d7abf0acc788535855bd506b7c34c --- /dev/null +++ b/ltp/testcases/kernel/fs/doio/doio.c @@ -0,0 +1,5587 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + */ +/* + * doio - a general purpose io initiator with system call and + * write logging. See doio.h for the structure which defines + * what doio requests should look like. + * + * Currently doio can handle read,write,reada,writea,ssread, + * sswrite, and many varieties of listio requests. + * For disk io, if the O_SSD flag is set doio will allocate + * the appropriate amount of ssd and do the transfer - thus, doio + * can handle all of the primitive types of file io. + * + * programming + * notes: + * ----------- + * messages should generally be printed using doio_fprintf(). + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CRAY +#include +#endif +#ifdef sgi +#include /* for aio_read,write */ +#include /* for uint64_t type */ +#include /* signal handlers & SA_SIGINFO */ +#endif +#ifndef CRAY +#include /* for struct iovec (readv) */ +#include /* for mmap(2) */ +#include /* for i/o buffer in shared memory */ +#include /* for i/o buffer in shared memory */ +#endif +#include +#ifdef CRAY +#include +#include +#endif +#include /* for delays */ + +#include "doio.h" +#include "write_log.h" +#include "random_range.h" +#include "string_to_tokens.h" +#include "pattern.h" + +#define NMEMALLOC 32 +#define MEM_DATA 1 /* data space */ +#define MEM_SHMEM 2 /* System V shared memory */ +#define MEM_T3ESHMEM 3 /* T3E Shared Memory */ +#define MEM_MMAP 4 /* mmap(2) */ + +#define MEMF_PRIVATE 0001 +#define MEMF_AUTORESRV 0002 +#define MEMF_LOCAL 0004 +#define MEMF_SHARED 0010 + +#define MEMF_FIXADDR 0100 +#define MEMF_ADDR 0200 +#define MEMF_AUTOGROW 0400 +#define MEMF_FILE 01000 /* regular file -- unlink on close */ +#define MEMF_MPIN 010000 /* use mpin(2) to lock pages in memory */ + +struct memalloc { + int memtype; + int flags; + int nblks; + char *name; + void *space; /* memory address of allocated space */ + int fd; /* FD open for mmaping */ + int size; +} Memalloc[NMEMALLOC]; + +/* + * Structure for maintaining open file test descriptors. Used by + * alloc_fd(). + */ + +struct fd_cache { + char c_file[MAX_FNAME_LENGTH + 1]; + int c_oflags; + int c_fd; + long c_rtc; +#ifdef sgi + int c_memalign; /* from F_DIOINFO */ + int c_miniosz; + int c_maxiosz; +#endif +#ifndef CRAY + void *c_memaddr; /* mmapped address */ + int c_memlen; /* length of above region */ +#endif +}; + +/* + * Name-To-Value map + * Used to map cmdline arguments to values + */ +struct smap { + char *string; + int value; +}; + +struct aio_info { + int busy; + int id; + int fd; + int strategy; + volatile int done; +#ifdef CRAY + struct iosw iosw; +#endif +#ifdef sgi + aiocb_t aiocb; + int aio_ret; /* from aio_return */ + int aio_errno; /* from aio_error */ +#endif + int sig; + int signalled; + struct sigaction osa; +}; + +/* --------------------------------------------------------------------------- + * + * A new paradigm of doing the r/w system call where there is a "stub" + * function that builds the info for the system call, then does the system + * call; this is called by code that is common to all system calls and does + * the syscall return checking, async I/O wait, iosw check, etc. + * + * Flags: + * WRITE, ASYNC, SSD/SDS, + * FILE_LOCK, WRITE_LOG, VERIFY_DATA, + */ + +struct status { + int rval; /* syscall return */ + int err; /* errno */ + int *aioid; /* list of async I/O structures */ +}; + +struct syscall_info { + char *sy_name; + int sy_type; + struct status *(*sy_syscall) (); + int (*sy_buffer) (); + char *(*sy_format) (); + int sy_flags; + int sy_bits; +}; + +#define SY_WRITE 00001 +#define SY_ASYNC 00010 +#define SY_IOSW 00020 +#define SY_SDS 00100 + +#ifndef O_SSD +#define O_SSD 0 /* so code compiles on a CRAY2 */ +#endif + +#ifdef sgi +#define UINT64_T uint64_t +#else +#define UINT64_T unsigned long +#endif + +#ifndef O_PARALLEL +#define O_PARALLEL 0 /* so O_PARALLEL may be used in expressions */ +#endif + +#define PPID_CHECK_INTERVAL 5 /* check ppid every <-- iterations */ +#define MAX_AIO 256 /* maximum number of async I/O ops */ +#ifdef _CRAYMPP +#define MPP_BUMP 16 /* page un-alignment for MPP */ +#else +#define MPP_BUMP 0 +#endif + +#define SYSERR strerror(errno) + +/* + * getopt() string of supported cmdline arguments. + */ + +#define OPTS "aC:d:ehm:n:kr:w:vU:V:M:N:" + +#define DEF_RELEASE_INTERVAL 0 + +/* + * Flags set in parse_cmdline() to indicate which options were selected + * on the cmdline. + */ + +int a_opt = 0; /* abort on data compare errors */ +int e_opt = 0; /* exec() after fork()'ing */ +int C_opt = 0; /* Data Check Type */ +int d_opt = 0; /* delay between operations */ +int k_opt = 0; /* lock file regions during writes */ +int m_opt = 0; /* generate periodic messages */ +int n_opt = 0; /* nprocs */ +int r_opt = 0; /* resource release interval */ +int w_opt = 0; /* file write log file */ +int v_opt = 0; /* verify writes if set */ +int U_opt = 0; /* upanic() on varios conditions */ +int V_opt = 0; /* over-ride default validation fd type */ +int M_opt = 0; /* data buffer allocation types */ +char TagName[40]; /* name of this doio (see Monster) */ + +/* + * Misc globals initialized in parse_cmdline() + */ + +char *Prog = NULL; /* set up in parse_cmdline() */ +int Upanic_Conditions; /* set by args to -U */ +int Release_Interval; /* arg to -r */ +int Nprocs; /* arg to -n */ +char *Write_Log; /* arg to -w */ +char *Infile; /* input file (defaults to stdin) */ +int *Children; /* pids of child procs */ +int Nchildren = 0; +int Nsiblings = 0; /* tfork'ed siblings */ +int Execd = 0; +int Message_Interval = 0; +int Npes = 0; /* non-zero if built as an mpp multi-pe app */ +int Vpe = -1; /* Virtual pe number if Npes >= 0 */ +int Reqno = 1; /* request # - used in some error messages */ +int Reqskipcnt = 0; /* count of I/O requests that are skipped */ +int Validation_Flags; +char *(*Data_Check) (); /* function to call for data checking */ +int (*Data_Fill) (); /* function to call for data filling */ +int Nmemalloc = 0; /* number of memory allocation strategies */ +int delayop = 0; /* delay between operations - type of delay */ +int delaytime = 0; /* delay between operations - how long */ + +struct wlog_file Wlog; + +int active_mmap_rw = 0; /* Indicates that mmapped I/O is occurring. */ + /* Used by sigbus_action() in the child doio. */ +int havesigint = 0; + +#define SKIP_REQ -2 /* skip I/O request */ + +/* + * Global file descriptors + */ + +int Wfd_Append; /* for appending to the write-log */ +int Wfd_Random; /* for overlaying write-log entries */ + +#define FD_ALLOC_INCR 32 /* allocate this many fd_map structs */ + /* at a time */ + +/* + * Globals for tracking Sds and Core usage + */ + +char *Memptr; /* ptr to core buffer space */ +int Memsize; /* # bytes pointed to by Memptr */ + /* maintained by alloc_mem() */ + +int Sdsptr; /* sds offset (always 0) */ +int Sdssize; /* # bytes of allocated sds space */ + /* Maintained by alloc_sds() */ +char Host[16]; +char Pattern[128]; +int Pattern_Length; + +/* + * Signal handlers, and related globals + */ + +char *syserrno(int err); +void doio(void); +void doio_delay(void); +char *format_oflags(int oflags); +char *format_strat(int strategy); +char *format_rw(struct io_req *ioreq, int fd, void *buffer, + int signo, char *pattern, void *iosw); +#ifdef CRAY +char *format_sds(struct io_req *ioreq, void *buffer, int sds char *pattern); +#endif /* CRAY */ + +int do_read(struct io_req *req); +int do_write(struct io_req *req); +int lock_file_region(char *fname, int fd, int type, int start, int nbytes); + +#ifdef CRAY +char *format_listio(struct io_req *ioreq, int lcmd, + struct listreq *list, int nent, int fd, char *pattern); +#endif /* CRAY */ + +int do_listio(struct io_req *req); + +#if defined(_CRAY1) || defined(CRAY) +int do_ssdio(struct io_req *req); +#endif /* defined(_CRAY1) || defined(CRAY) */ + +char *fmt_ioreq(struct io_req *ioreq, struct syscall_info *sy, int fd); + +#ifdef CRAY +struct status *sy_listio(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr); +int listio_mem(struct io_req *req, int offset, int fmstride, + int *min, int *max); +char *fmt_listio(struct io_req *req, struct syscall_info *sy, + int fd, char *addr); +#endif /* CRAY */ + +#ifdef sgi +struct status *sy_pread(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr); +struct status *sy_pwrite(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr); +char *fmt_pread(struct io_req *req, struct syscall_info *sy, + int fd, char *addr); +#endif /* sgi */ + +#ifndef CRAY +struct status *sy_readv(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr); +struct status *sy_writev(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr); +struct status *sy_rwv(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr, int rw); +char *fmt_readv(struct io_req *req, struct syscall_info *sy, + int fd, char *addr); +#endif /* !CRAY */ + +#ifdef sgi +struct status *sy_aread(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr); +struct status *sy_awrite(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr) +struct status *sy_arw(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr, int rw); +char *fmt_aread(struct io_req *req, struct syscall_info *sy, + int fd, char *addr); +#endif /* sgi */ + +#ifndef CRAY +struct status *sy_mmread(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr); +struct status *sy_mmwrite(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr); +struct status *sy_mmrw(struct io_req *req, struct syscall_info *sysc, + int fd, char *addr, int rw); +char *fmt_mmrw(struct io_req *req, struct syscall_info *sy, int fd, char *addr); +#endif /* !CRAY */ + +int do_rw(struct io_req *req); + +#ifdef sgi +int do_fcntl(struct io_req *req); +#endif /* sgi */ + +#ifndef CRAY +int do_sync(struct io_req *req); +#endif /* !CRAY */ + +int doio_pat_fill(char *addr, int mem_needed, char *Pattern, + int Pattern_Length, int shift); +char *doio_pat_check(char *buf, int offset, int length, + char *pattern, int pattern_length, int patshift); +char *check_file(char *file, int offset, int length, char *pattern, + int pattern_length, int patshift, int fsa); +int doio_fprintf(FILE * stream, char *format, ...); +int alloc_mem(int nbytes); + +#if defined(_CRAY1) || defined(CRAY) +int alloc_sds(int nbytes); +#endif /* defined(_CRAY1) || defined(CRAY) */ + +int alloc_fd(char *file, int oflags); +struct fd_cache *alloc_fdcache(char *file, int oflags); + +#ifdef sgi +void signal_info(int sig, siginfo_t * info, void *v); +void cleanup_handler(int sig, siginfo_t * info, void *v); +void die_handler(int sig, siginfo_t * info, void *v); +void sigbus_handler(int sig, siginfo_t * info, void *v); +#else /* !sgi */ +void cleanup_handler(int sig); +void die_handler(int sig); + +#ifndef CRAY +void sigbus_handler(int sig); +#endif /* !CRAY */ +#endif /* sgi */ + +void noop_handler(int sig); +void sigint_handler(int sig); +void aio_handler(int sig); +void dump_aio(void); + +#ifdef sgi +void cb_handler(sigval_t val); +#endif /* sgi */ + +struct aio_info *aio_slot(int aio_id); +int aio_register(int fd, int strategy, int sig); +int aio_unregister(int aio_id); + +#ifndef __linux__ +int aio_wait(int aio_id); +#endif /* !__linux__ */ + +char *hms(time_t t); +int aio_done(struct aio_info *ainfo); +void doio_upanic(int mask); +int parse_cmdline(int argc, char **argv, char *opts); + +#ifndef CRAY +void parse_memalloc(char *arg); +void dump_memalloc(void); +#endif /* !CRAY */ + +void parse_delay(char *arg); +int usage(FILE * stream); +void help(FILE * stream); + +/* + * Upanic conditions, and a map from symbolics to values + */ + +#define U_CORRUPTION 0001 /* upanic on data corruption */ +#define U_IOSW 0002 /* upanic on bad iosw */ +#define U_RVAL 0004 /* upanic on bad rval */ + +#define U_ALL (U_CORRUPTION | U_IOSW | U_RVAL) + +struct smap Upanic_Args[] = { + {"corruption", U_CORRUPTION}, + {"iosw", U_IOSW}, + {"rval", U_RVAL}, + {"all", U_ALL}, + {NULL, 0} +}; + +struct aio_info Aio_Info[MAX_AIO]; + +/* -C data-fill/check type */ +#define C_DEFAULT 1 +struct smap checkmap[] = { + {"default", C_DEFAULT}, + {NULL, 0}, +}; + +/* -d option delay types */ +#define DELAY_SELECT 1 +#define DELAY_SLEEP 2 +#define DELAY_SGINAP 3 +#define DELAY_ALARM 4 +#define DELAY_ITIMER 5 /* POSIX timer */ + +struct smap delaymap[] = { + {"select", DELAY_SELECT}, + {"sleep", DELAY_SLEEP}, +#ifdef sgi + {"sginap", DELAY_SGINAP}, +#endif + {"alarm", DELAY_ALARM}, + {NULL, 0}, +}; + +/****** +* +* strerror() does similar actions. + +char * +syserrno(int err) +{ + static char sys_errno[10]; + sprintf(sys_errno, "%d", errno); + return(sys_errno); +} + +******/ + +int main(int argc, char **argv) +{ + int i, pid, stat, ex_stat; +#ifdef CRAY + sigset_t omask; +#elif defined(linux) + sigset_t omask, block_mask; +#else + int omask; +#endif + struct sigaction sa; + + umask(0); /* force new file modes to known values */ +#if _CRAYMPP + Npes = sysconf(_SC_CRAY_NPES); /* must do this before parse_cmdline */ + Vpe = sysconf(_SC_CRAY_VPE); +#endif + + TagName[0] = '\0'; + parse_cmdline(argc, argv, OPTS); + + random_range_seed(getpid()); /* initialize random number generator */ + + /* + * If this is a re-exec of doio, jump directly into the doio function. + */ + + if (Execd) { + doio(); + exit(E_SETUP); + } + + /* + * Stop on all but a few signals... + */ + sigemptyset(&sa.sa_mask); + sa.sa_handler = sigint_handler; + sa.sa_flags = SA_RESETHAND; /* sigint is ignored after the */ + /* first time */ + for (i = 1; i <= NSIG; i++) { + switch (i) { +#ifdef SIGRECOVERY + case SIGRECOVERY: + break; +#endif +#ifdef SIGCKPT + case SIGCKPT: +#endif +#ifdef SIGRESTART + case SIGRESTART: +#endif + case SIGTSTP: + case SIGSTOP: + case SIGCONT: + case SIGCHLD: + case SIGBUS: + case SIGSEGV: + case SIGQUIT: + break; + default: + sigaction(i, &sa, NULL); + } + } + + /* + * If we're logging write operations, make a dummy call to wlog_open + * to initialize the write history file. This call must be done in + * the parent, to ensure that the history file exists and/or has + * been truncated before any children attempt to open it, as the doio + * children are not allowed to truncate the file. + */ + + if (w_opt) { + strcpy(Wlog.w_file, Write_Log); + + if (wlog_open(&Wlog, 1, 0666) < 0) { + doio_fprintf(stderr, + "Could not create/truncate write log %s\n", + Write_Log); + exit(2); + } + + wlog_close(&Wlog); + } + + /* + * Malloc space for the children pid array. Initialize all entries + * to -1. + */ + + Children = malloc(sizeof(int) * Nprocs); + for (i = 0; i < Nprocs; i++) { + Children[i] = -1; + } + + sigemptyset(&block_mask); + sigaddset(&block_mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &block_mask, &omask); + + /* + * Fork Nprocs. This [parent] process is a watchdog, to notify the + * invoker of procs which exit abnormally, and to make sure that all + * child procs get cleaned up. If the -e option was used, we will also + * re-exec. This is mostly for unicos/mk on mpp's, to ensure that not + * all of the doio's don't end up in the same pe. + * + * Note - if Nprocs is 1, or this doio is a multi-pe app (Npes > 1), + * jump directly to doio(). multi-pe apps can't fork(), and there is + * no reason to fork() for 1 proc. + */ + + if (Nprocs == 1 || Npes > 1) { + doio(); + exit(0); + } else { + for (i = 0; i < Nprocs; i++) { + if ((pid = fork()) == -1) { + doio_fprintf(stderr, + "(parent) Could not fork %d children: %s (%d)\n", + i + 1, SYSERR, errno); + exit(E_SETUP); + } + + Children[Nchildren] = pid; + Nchildren++; + + if (pid == 0) { + if (e_opt) { + char *exec_path; + + exec_path = argv[0]; + argv[0] = malloc(strlen(exec_path) + 2); + sprintf(argv[0], "-%s", exec_path); + + execvp(exec_path, argv); + doio_fprintf(stderr, + "(parent) Could not execvp %s: %s (%d)\n", + exec_path, SYSERR, errno); + exit(E_SETUP); + } else { + doio(); + exit(E_SETUP); + } + } + } + + /* + * Parent spins on wait(), until all children exit. + */ + + ex_stat = E_NORMAL; + + while (Nprocs) { + if ((pid = wait(&stat)) == -1) { + if (errno == EINTR) + continue; + } + + for (i = 0; i < Nchildren; i++) + if (Children[i] == pid) + Children[i] = -1; + + Nprocs--; + + if (WIFEXITED(stat)) { + switch (WEXITSTATUS(stat)) { + case E_NORMAL: + /* noop */ + break; + + case E_INTERNAL: + doio_fprintf(stderr, + "(parent) pid %d exited because of an internal error\n", + pid); + ex_stat |= E_INTERNAL; + break; + + case E_SETUP: + doio_fprintf(stderr, + "(parent) pid %d exited because of a setup error\n", + pid); + ex_stat |= E_SETUP; + break; + + case E_COMPARE: + doio_fprintf(stderr, + "(parent) pid %d exited because of data compare errors\n", + pid); + + ex_stat |= E_COMPARE; + + if (a_opt) + kill(0, SIGINT); + + break; + + case E_USAGE: + doio_fprintf(stderr, + "(parent) pid %d exited because of a usage error\n", + pid); + + ex_stat |= E_USAGE; + break; + + default: + doio_fprintf(stderr, + "(parent) pid %d exited with unknown status %d\n", + pid, WEXITSTATUS(stat)); + ex_stat |= E_INTERNAL; + break; + } + } else if (WIFSIGNALED(stat) + && WTERMSIG(stat) != SIGINT) { + doio_fprintf(stderr, + "(parent) pid %d terminated by signal %d\n", + pid, WTERMSIG(stat)); + + ex_stat |= E_SIGNAL; + } + + fflush(NULL); + } + } + + exit(ex_stat); + +} /* main */ + +/* + * main doio function. Each doio child starts here, and never returns. + */ + +void doio(void) +{ + int rval, i, infd, nbytes; + char *cp; + struct io_req ioreq; + struct sigaction sa, def_action, ignore_action, exit_action; +#ifndef CRAY + struct sigaction sigbus_action; +#endif + + Memsize = Sdssize = 0; + + /* + * Initialize the Pattern - write-type syscalls will replace Pattern[1] + * with the pattern passed in the request. Make sure that + * strlen(Pattern) is not mod 16 so that out of order words will be + * detected. + */ + + gethostname(Host, sizeof(Host)); + if ((cp = strchr(Host, '.')) != NULL) + *cp = '\0'; + + Pattern_Length = sprintf(Pattern, "-:%d:%s:%s*", getpid(), Host, Prog); + + if (!(Pattern_Length % 16)) { + Pattern_Length = sprintf(Pattern, "-:%d:%s:%s**", + getpid(), Host, Prog); + } + + /* + * Open a couple of descriptors for the write-log file. One descriptor + * is for appending, one for random access. Write logging is done for + * file corruption detection. The program doio_check is capable of + * doing corruption detection based on a doio write-log. + */ + + if (w_opt) { + + strcpy(Wlog.w_file, Write_Log); + + if (wlog_open(&Wlog, 0, 0666) == -1) { + doio_fprintf(stderr, + "Could not open write log file (%s): wlog_open() failed\n", + Write_Log); + exit(E_SETUP); + } + } + + /* + * Open the input stream - either a file or stdin + */ + + if (Infile == NULL) { + infd = 0; + } else { + if ((infd = open(Infile, O_RDWR)) == -1) { + doio_fprintf(stderr, + "Could not open input file (%s): %s (%d)\n", + Infile, SYSERR, errno); + exit(E_SETUP); + } + } + + /* + * Define a set of signals that should never be masked. Receipt of + * these signals generally indicates a programming error, and we want + * a corefile at the point of error. We put SIGQUIT in this list so + * that ^\ will force a user core dump. + * + * Note: the handler for these should be SIG_DFL, all of them + * produce a corefile as the default action. + */ + + ignore_action.sa_handler = SIG_IGN; + ignore_action.sa_flags = 0; + sigemptyset(&ignore_action.sa_mask); + + def_action.sa_handler = SIG_DFL; + def_action.sa_flags = 0; + sigemptyset(&def_action.sa_mask); + +#ifdef sgi + exit_action.sa_sigaction = cleanup_handler; + exit_action.sa_flags = SA_SIGINFO; + sigemptyset(&exit_action.sa_mask); + + sa.sa_sigaction = die_handler; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + + sigbus_action.sa_sigaction = sigbus_handler; + sigbus_action.sa_flags = SA_SIGINFO; + sigemptyset(&sigbus_action.sa_mask); +#else + exit_action.sa_handler = cleanup_handler; + exit_action.sa_flags = 0; + sigemptyset(&exit_action.sa_mask); + + sa.sa_handler = die_handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + +#ifndef CRAY + sigbus_action.sa_handler = sigbus_handler; + sigbus_action.sa_flags = 0; + sigemptyset(&sigbus_action.sa_mask); +#endif +#endif + + for (i = 1; i <= NSIG; i++) { + switch (i) { + /* Signals to terminate program on */ + case SIGINT: + sigaction(i, &exit_action, NULL); + break; + +#ifndef CRAY + /* This depends on active_mmap_rw */ + case SIGBUS: + sigaction(i, &sigbus_action, NULL); + break; +#endif + + /* Signals to Ignore... */ + case SIGSTOP: + case SIGCONT: +#ifdef SIGRECOVERY + case SIGRECOVERY: +#endif + sigaction(i, &ignore_action, NULL); + break; + + /* Signals to trap & report & die */ + /*case SIGTRAP: */ + /*case SIGABRT: */ +#ifdef SIGERR /* cray only signals */ + case SIGERR: + case SIGBUFIO: + case SIGINFO: +#endif + /*case SIGFPE: */ + case SIGURG: + case SIGHUP: + case SIGTERM: + case SIGPIPE: + case SIGIO: + case SIGUSR1: + case SIGUSR2: + sigaction(i, &sa, NULL); + break; + + /* Default Action for all other signals */ + default: + sigaction(i, &def_action, NULL); + break; + } + } + + /* + * Main loop - each doio proc does this until the read returns eof (0). + * Call the appropriate io function based on the request type. + */ + + while ((nbytes = read(infd, (char *)&ioreq, sizeof(ioreq)))) { + + /* + * Periodically check our ppid. If it is 1, the child exits to + * help clean up in the case that the main doio process was + * killed. + */ + + if (Reqno && ((Reqno % PPID_CHECK_INTERVAL) == 0)) { + if (getppid() == 1) { + doio_fprintf(stderr, + "Parent doio process has exited\n"); + alloc_mem(-1); + exit(E_SETUP); + } + } + + if (nbytes == -1) { + doio_fprintf(stderr, + "read of %d bytes from input failed: %s (%d)\n", + sizeof(ioreq), SYSERR, errno); + alloc_mem(-1); + exit(E_SETUP); + } + + if (nbytes != sizeof(ioreq)) { + doio_fprintf(stderr, + "read wrong # bytes from input stream, expected %d, got %d\n", + sizeof(ioreq), nbytes); + alloc_mem(-1); + exit(E_SETUP); + } + + if (ioreq.r_magic != DOIO_MAGIC) { + doio_fprintf(stderr, + "got a bad magic # from input stream. Expected 0%o, got 0%o\n", + DOIO_MAGIC, ioreq.r_magic); + alloc_mem(-1); + exit(E_SETUP); + } + + /* + * If we're on a Release_Interval multiple, relase all ssd and + * core space, and close all fd's in Fd_Map[]. + */ + + if (Reqno && Release_Interval && !(Reqno % Release_Interval)) { + if (Memsize) { +#ifdef NOTDEF + sbrk(-1 * Memsize); +#else + alloc_mem(-1); +#endif + } +#ifdef _CRAY1 + if (Sdssize) { + ssbreak(-1 * btoc(Sdssize)); + Sdsptr = 0; + Sdssize = 0; + } +#endif /* _CRAY1 */ + + alloc_fd(NULL, 0); + } + + switch (ioreq.r_type) { + case READ: + case READA: + rval = do_read(&ioreq); + break; + + case WRITE: + case WRITEA: + rval = do_write(&ioreq); + break; + + case READV: + case AREAD: + case PREAD: + case LREAD: + case LREADA: + case LSREAD: + case LSREADA: + case WRITEV: + case AWRITE: + case PWRITE: + case MMAPR: + case MMAPW: + case LWRITE: + case LWRITEA: + case LSWRITE: + case LSWRITEA: + case LEREAD: + case LEREADA: + case LEWRITE: + case LEWRITEA: + rval = do_rw(&ioreq); + break; + +#ifdef CRAY + case SSREAD: + case SSWRITE: + rval = do_ssdio(&ioreq); + break; + + case LISTIO: + rval = do_listio(&ioreq); + break; +#endif + +#ifdef sgi + case RESVSP: + case UNRESVSP: +#ifdef F_FSYNC + case DFFSYNC: +#endif + rval = do_fcntl(&ioreq); + break; +#endif /* sgi */ + +#ifndef CRAY + case FSYNC2: + case FDATASYNC: + rval = do_sync(&ioreq); + break; +#endif + default: + doio_fprintf(stderr, + "Don't know how to handle io request type %d\n", + ioreq.r_type); + alloc_mem(-1); + exit(E_SETUP); + } + + if (rval == SKIP_REQ) { + Reqskipcnt++; + } else if (rval != 0) { + alloc_mem(-1); + doio_fprintf(stderr, + "doio(): operation %d returned != 0\n", + ioreq.r_type); + exit(E_SETUP); + } + + if (Message_Interval && Reqno % Message_Interval == 0) { + doio_fprintf(stderr, + "Info: %d requests done (%d skipped) by this process\n", + Reqno, Reqskipcnt); + } + + Reqno++; + + if (delayop != 0) + doio_delay(); + } + + /* + * Child exits normally + */ + alloc_mem(-1); + exit(E_NORMAL); + +} /* doio */ + +void doio_delay(void) +{ + struct timeval tv_delay; + struct sigaction sa_al, sa_old; + sigset_t al_mask; + + switch (delayop) { + case DELAY_SELECT: + tv_delay.tv_sec = delaytime / 1000000; + tv_delay.tv_usec = delaytime % 1000000; + /*doio_fprintf(stdout, "delay_select: %d %d\n", + tv_delay.tv_sec, tv_delay.tv_usec); */ + select(0, NULL, NULL, NULL, &tv_delay); + break; + + case DELAY_SLEEP: + sleep(delaytime); + break; + +#ifdef sgi + case DELAY_SGINAP: + sginap(delaytime); + break; +#endif + + case DELAY_ALARM: + sa_al.sa_flags = 0; + sa_al.sa_handler = noop_handler; + sigemptyset(&sa_al.sa_mask); + sigaction(SIGALRM, &sa_al, &sa_old); + sigemptyset(&al_mask); + alarm(delaytime); + sigsuspend(&al_mask); + sigaction(SIGALRM, &sa_old, 0); + break; + } +} + +/* + * Format IO requests, returning a pointer to the formatted text. + * + * format_strat - formats the async i/o completion strategy + * format_rw - formats a read[a]/write[a] request + * format_sds - formats a ssread/sswrite request + * format_listio- formats a listio request + * + * ioreq is the doio io request structure. + */ + +struct smap sysnames[] = { + {"READ", READ}, + {"WRITE", WRITE}, + {"READA", READA}, + {"WRITEA", WRITEA}, + {"SSREAD", SSREAD}, + {"SSWRITE", SSWRITE}, + {"LISTIO", LISTIO}, + {"LREAD", LREAD}, + {"LREADA", LREADA}, + {"LWRITE", LWRITE}, + {"LWRITEA", LWRITEA}, + {"LSREAD", LSREAD}, + {"LSREADA", LSREADA}, + {"LSWRITE", LSWRITE}, + {"LSWRITEA", LSWRITEA}, + + /* Irix System Calls */ + {"PREAD", PREAD}, + {"PWRITE", PWRITE}, + {"AREAD", AREAD}, + {"AWRITE", AWRITE}, + {"LLREAD", LLREAD}, + {"LLAREAD", LLAREAD}, + {"LLWRITE", LLWRITE}, + {"LLAWRITE", LLAWRITE}, + {"RESVSP", RESVSP}, + {"UNRESVSP", UNRESVSP}, + {"DFFSYNC", DFFSYNC}, + + /* Irix and Linux System Calls */ + {"READV", READV}, + {"WRITEV", WRITEV}, + {"MMAPR", MMAPR}, + {"MMAPW", MMAPW}, + {"FSYNC2", FSYNC2}, + {"FDATASYNC", FDATASYNC}, + + {"unknown", -1}, +}; + +struct smap aionames[] = { + {"poll", A_POLL}, + {"signal", A_SIGNAL}, + {"recall", A_RECALL}, + {"recalla", A_RECALLA}, + {"recalls", A_RECALLS}, + {"suspend", A_SUSPEND}, + {"callback", A_CALLBACK}, + {"synch", 0}, + {"unknown", -1}, +}; + +char *format_oflags(int oflags) +{ + char flags[255]; + + flags[0] = '\0'; + switch (oflags & 03) { + case O_RDONLY: + strcat(flags, "O_RDONLY,"); + break; + case O_WRONLY: + strcat(flags, "O_WRONLY,"); + break; + case O_RDWR: + strcat(flags, "O_RDWR,"); + break; + default: + strcat(flags, "O_weird"); + break; + } + + if (oflags & O_EXCL) + strcat(flags, "O_EXCL,"); + + if (oflags & O_SYNC) + strcat(flags, "O_SYNC,"); +#ifdef CRAY + if (oflags & O_RAW) + strcat(flags, "O_RAW,"); + if (oflags & O_WELLFORMED) + strcat(flags, "O_WELLFORMED,"); +#ifdef O_SSD + if (oflags & O_SSD) + strcat(flags, "O_SSD,"); +#endif + if (oflags & O_LDRAW) + strcat(flags, "O_LDRAW,"); + if (oflags & O_PARALLEL) + strcat(flags, "O_PARALLEL,"); + if (oflags & O_BIG) + strcat(flags, "O_BIG,"); + if (oflags & O_PLACE) + strcat(flags, "O_PLACE,"); + if (oflags & O_ASYNC) + strcat(flags, "O_ASYNC,"); +#endif + +#ifdef sgi + if (oflags & O_DIRECT) + strcat(flags, "O_DIRECT,"); + if (oflags & O_DSYNC) + strcat(flags, "O_DSYNC,"); + if (oflags & O_RSYNC) + strcat(flags, "O_RSYNC,"); +#endif + + return (strdup(flags)); +} + +char *format_strat(int strategy) +{ + char msg[64]; + char *aio_strat; + + switch (strategy) { + case A_POLL: + aio_strat = "POLL"; + break; + case A_SIGNAL: + aio_strat = "SIGNAL"; + break; + case A_RECALL: + aio_strat = "RECALL"; + break; + case A_RECALLA: + aio_strat = "RECALLA"; + break; + case A_RECALLS: + aio_strat = "RECALLS"; + break; + case A_SUSPEND: + aio_strat = "SUSPEND"; + break; + case A_CALLBACK: + aio_strat = "CALLBACK"; + break; + case 0: + aio_strat = ""; + break; + default: + sprintf(msg, "", strategy); + aio_strat = strdup(msg); + break; + } + + return (aio_strat); +} + +char *format_rw(struct io_req *ioreq, int fd, void *buffer, int signo, + char *pattern, void *iosw) +{ + static char *errbuf = NULL; + char *aio_strat, *cp; + struct read_req *readp = &ioreq->r_data.read; + struct write_req *writep = &ioreq->r_data.write; + struct read_req *readap = &ioreq->r_data.read; + struct write_req *writeap = &ioreq->r_data.write; + + if (errbuf == NULL) + errbuf = malloc(32768); + + cp = errbuf; + cp += sprintf(cp, "Request number %d\n", Reqno); + + switch (ioreq->r_type) { + case READ: + cp += sprintf(cp, "syscall: read(%d, %#lo, %d)\n", + fd, (unsigned long)buffer, readp->r_nbytes); + cp += + sprintf(cp, + " fd %d is file %s - open flags are %#o\n", + fd, readp->r_file, readp->r_oflags); + cp += + sprintf(cp, " read done at file offset %d\n", + readp->r_offset); + break; + + case WRITE: + cp += sprintf(cp, "syscall: write(%d, %#lo, %d)\n", + fd, (unsigned long)buffer, writep->r_nbytes); + cp += + sprintf(cp, + " fd %d is file %s - open flags are %#o\n", + fd, writep->r_file, writep->r_oflags); + cp += + sprintf(cp, + " write done at file offset %d - pattern is %s\n", + writep->r_offset, pattern); + break; + + case READA: + aio_strat = format_strat(readap->r_aio_strat); + + cp += sprintf(cp, "syscall: reada(%d, %#lo, %d, %#lo, %d)\n", + fd, (unsigned long)buffer, readap->r_nbytes, + (unsigned long)iosw, signo); + cp += + sprintf(cp, + " fd %d is file %s - open flags are %#o\n", + fd, readap->r_file, readp->r_oflags); + cp += + sprintf(cp, " reada done at file offset %d\n", + readap->r_offset); + cp += + sprintf(cp, + " async io completion strategy is %s\n", + aio_strat); + break; + + case WRITEA: + aio_strat = format_strat(writeap->r_aio_strat); + + cp += sprintf(cp, "syscall: writea(%d, %#lo, %d, %#lo, %d)\n", + fd, (unsigned long)buffer, writeap->r_nbytes, + (unsigned long)iosw, signo); + cp += + sprintf(cp, + " fd %d is file %s - open flags are %#o\n", + fd, writeap->r_file, writeap->r_oflags); + cp += + sprintf(cp, + " writea done at file offset %d - pattern is %s\n", + writeap->r_offset, pattern); + cp += + sprintf(cp, + " async io completion strategy is %s\n", + aio_strat); + break; + + } + + return errbuf; +} + +#ifdef CRAY +char *format_sds(struct io_req *ioreq, void *buffer, int sds, char *pattern) +{ + int i; + static char *errbuf = NULL; + char *cp; + + struct ssread_req *ssreadp = &ioreq->r_data.ssread; + struct sswrite_req *sswritep = &ioreq->r_data.sswrite; + + if (errbuf == NULL) + errbuf = malloc(32768); + + cp = errbuf; + cp += sprintf(cp, "Request number %d\n", Reqno); + + switch (ioreq->r_type) { + case SSREAD: + cp += sprintf(cp, "syscall: ssread(%#o, %#o, %d)\n", + buffer, sds, ssreadp->r_nbytes); + break; + + case SSWRITE: + cp += + sprintf(cp, + "syscall: sswrite(%#o, %#o, %d) - pattern was %s\n", + buffer, sds, sswritep->r_nbytes, pattern); + break; + } + return errbuf; +} +#endif /* CRAY */ + +/* + * Perform the various sorts of disk reads + */ + +int do_read(struct io_req *req) +{ + int fd, offset, nbytes, oflags, rval; + char *addr, *file; +#ifdef CRAY + struct aio_info *aiop; + int aio_id, aio_strat, signo; +#endif +#ifdef sgi + struct fd_cache *fdc; +#endif + + /* + * Initialize common fields - assumes r_oflags, r_file, r_offset, and + * r_nbytes are at the same offset in the read_req and reada_req + * structures. + */ + + file = req->r_data.read.r_file; + oflags = req->r_data.read.r_oflags; + offset = req->r_data.read.r_offset; + nbytes = req->r_data.read.r_nbytes; + + /*printf("read: %s, %#o, %d %d\n", file, oflags, offset, nbytes); */ + + /* + * Grab an open file descriptor + * Note: must be done before memory allocation so that the direct i/o + * information is available in mem. allocate + */ + + if ((fd = alloc_fd(file, oflags)) == -1) + return -1; + + /* + * Allocate core or sds - based on the O_SSD flag + */ + +#ifndef wtob +#define wtob(x) (x * sizeof(UINT64_T)) +#endif + +#ifdef CRAY + if (oflags & O_SSD) { + if (alloc_sds(nbytes) == -1) + return -1; + + addr = (char *)Sdsptr; + } else { + if ((rval = + alloc_mem(nbytes + wtob(1) * 2 + + MPP_BUMP * sizeof(UINT64_T))) < 0) { + return rval; + } + + addr = Memptr; + + /* + * if io is not raw, bump the offset by a random amount + * to generate non-word-aligned io. + */ + if (!(req->r_data.read.r_uflags & F_WORD_ALIGNED)) { + addr += random_range(0, wtob(1) - 1, 1, NULL); + } + } +#else +#ifdef sgi + /* get memory alignment for using DIRECT I/O */ + fdc = alloc_fdcache(file, oflags); + + if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) { + return rval; + } + + addr = Memptr; + + if ((req->r_data.read.r_uflags & F_WORD_ALIGNED)) { + /* + * Force memory alignment for Direct I/O + */ + if ((oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0)) { + addr += + fdc->c_memalign - ((long)addr % fdc->c_memalign); + } + } else { + addr += random_range(0, wtob(1) - 1, 1, NULL); + } +#else + /* what is !CRAY && !sgi ? */ + if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) { + return rval; + } + + addr = Memptr; +#endif /* !CRAY && sgi */ +#endif /* CRAY */ + + switch (req->r_type) { + case READ: + /* move to the desired file position. */ + if (lseek(fd, offset, SEEK_SET) == -1) { + doio_fprintf(stderr, + "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n", + fd, offset, SYSERR, errno); + return -1; + } + + if ((rval = read(fd, addr, nbytes)) == -1) { + doio_fprintf(stderr, + "read() request failed: %s (%d)\n%s\n", + SYSERR, errno, + format_rw(req, fd, addr, -1, NULL, NULL)); + doio_upanic(U_RVAL); + return -1; + } else if (rval != nbytes) { + doio_fprintf(stderr, + "read() request returned wrong # of bytes - expected %d, got %d\n%s\n", + nbytes, rval, + format_rw(req, fd, addr, -1, NULL, NULL)); + doio_upanic(U_RVAL); + return -1; + } + break; + +#ifdef CRAY + case READA: + /* + * Async read + */ + + /* move to the desired file position. */ + if (lseek(fd, offset, SEEK_SET) == -1) { + doio_fprintf(stderr, + "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n", + fd, offset, SYSERR, errno); + return -1; + } + + aio_strat = req->r_data.read.r_aio_strat; + signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0; + + aio_id = aio_register(fd, aio_strat, signo); + aiop = aio_slot(aio_id); + + if (reada(fd, addr, nbytes, &aiop->iosw, signo) == -1) { + doio_fprintf(stderr, "reada() failed: %s (%d)\n%s\n", + SYSERR, errno, + format_rw(req, fd, addr, signo, NULL, + &aiop->iosw)); + aio_unregister(aio_id); + doio_upanic(U_RVAL); + rval = -1; + } else { + /* + * Wait for io to complete + */ + + aio_wait(aio_id); + + /* + * make sure the io completed without error + */ + + if (aiop->iosw.sw_count != nbytes) { + doio_fprintf(stderr, + "Bad iosw from reada()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n", + 1, 0, nbytes, + aiop->iosw.sw_flag, + aiop->iosw.sw_error, + aiop->iosw.sw_count, + format_rw(req, fd, addr, signo, + NULL, &aiop->iosw)); + aio_unregister(aio_id); + doio_upanic(U_IOSW); + rval = -1; + } else { + aio_unregister(aio_id); + rval = 0; + } + } + + if (rval == -1) + return rval; + break; +#endif /* CRAY */ + } + + return 0; /* if we get here, everything went ok */ +} + +/* + * Perform the verious types of disk writes. + */ + +int do_write(struct io_req *req) +{ + static int pid = -1; + int fd, nbytes, oflags, signo; + int logged_write, rval, got_lock; + off_t offset, woffset; + char *addr, pattern, *file, *msg; + struct wlog_rec wrec; +#ifdef CRAY + int aio_strat, aio_id; + struct aio_info *aiop; +#endif +#ifdef sgi + struct fd_cache *fdc; +#endif + + woffset = 0; + + /* + * Misc variable setup + */ + + signo = 0; + nbytes = req->r_data.write.r_nbytes; + offset = req->r_data.write.r_offset; + pattern = req->r_data.write.r_pattern; + file = req->r_data.write.r_file; + oflags = req->r_data.write.r_oflags; + + /*printf("pwrite: %s, %#o, %d %d\n", file, oflags, offset, nbytes); */ + + /* + * Allocate core memory and possibly sds space. Initialize the data + * to be written. + */ + + Pattern[0] = pattern; + + /* + * Get a descriptor to do the io on + */ + + if ((fd = alloc_fd(file, oflags)) == -1) + return -1; + + /*printf("write: %d, %s, %#o, %d %d\n", + fd, file, oflags, offset, nbytes); */ + + /* + * Allocate SDS space for backdoor write if desired + */ + +#ifdef CRAY + if (oflags & O_SSD) { +#ifndef _CRAYMPP + if ((rval = alloc_mem(nbytes + wtob(1))) < 0) { + return rval; + } + + (*Data_Fill) (Memptr, nbytes, Pattern, Pattern_Length, 0); + /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0); */ + + if (alloc_sds(nbytes) == -1) + return -1; + + if (sswrite((long)Memptr, Sdsptr, btoc(nbytes)) == -1) { + doio_fprintf(stderr, + "sswrite(%d, %d, %d) failed: %s (%d)\n", + (long)Memptr, Sdsptr, btoc(nbytes), SYSERR, + errno); + fflush(stderr); + return -1; + } + + addr = (char *)Sdsptr; +#else + doio_fprintf(stderr, + "Invalid O_SSD flag was generated for MPP system\n"); + fflush(stderr); + return -1; +#endif /* !CRAYMPP */ + } else { + if ((rval = alloc_mem(nbytes + wtob(1)) < 0)) { + return rval; + } + + addr = Memptr; + + /* + * if io is not raw, bump the offset by a random amount + * to generate non-word-aligned io. + */ + + if (!(req->r_data.write.r_uflags & F_WORD_ALIGNED)) { + addr += random_range(0, wtob(1) - 1, 1, NULL); + } + + (*Data_Fill) (Memptr, nbytes, Pattern, Pattern_Length, 0); + if (addr != Memptr) + memmove(addr, Memptr, nbytes); + } +#else /* CRAY */ +#ifdef sgi + /* get memory alignment for using DIRECT I/O */ + fdc = alloc_fdcache(file, oflags); + + if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) { + return rval; + } + + addr = Memptr; + + if ((req->r_data.write.r_uflags & F_WORD_ALIGNED)) { + /* + * Force memory alignment for Direct I/O + */ + if ((oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0)) { + addr += + fdc->c_memalign - ((long)addr % fdc->c_memalign); + } + } else { + addr += random_range(0, wtob(1) - 1, 1, NULL); + } + + (*Data_Fill) (Memptr, nbytes, Pattern, Pattern_Length, 0); + if (addr != Memptr) + memmove(addr, Memptr, nbytes); + +#else /* sgi */ + if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) { + return rval; + } + + addr = Memptr; + + (*Data_Fill) (Memptr, nbytes, Pattern, Pattern_Length, 0); + if (addr != Memptr) + memmove(addr, Memptr, nbytes); +#endif /* sgi */ +#endif /* CRAY */ + + rval = -1; + got_lock = 0; + logged_write = 0; + + if (k_opt) { + if (lock_file_region(file, fd, F_WRLCK, offset, nbytes) < 0) { + alloc_mem(-1); + exit(E_INTERNAL); + } + + got_lock = 1; + } + + /* + * Write a preliminary write-log entry. This is done so that + * doio_check can do corruption detection across an interrupt/crash. + * Note that w_done is set to 0. If doio_check sees this, it + * re-creates the file extents as if the write completed, but does not + * do any checking - see comments in doio_check for more details. + */ + + if (w_opt) { + if (pid == -1) { + pid = getpid(); + } + wrec.w_async = (req->r_type == WRITEA) ? 1 : 0; + wrec.w_oflags = oflags; + wrec.w_pid = pid; + wrec.w_offset = offset; + wrec.w_nbytes = nbytes; + + wrec.w_pathlen = strlen(file); + memcpy(wrec.w_path, file, wrec.w_pathlen); + wrec.w_hostlen = strlen(Host); + memcpy(wrec.w_host, Host, wrec.w_hostlen); + wrec.w_patternlen = Pattern_Length; + memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen); + + wrec.w_done = 0; + + if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) { + doio_fprintf(stderr, + "Could not append to write-log: %s (%d)\n", + SYSERR, errno); + } else { + logged_write = 1; + } + } + + switch (req->r_type) { + case WRITE: + /* + * sync write + */ + + if (lseek(fd, offset, SEEK_SET) == -1) { + doio_fprintf(stderr, + "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n", + fd, offset, SYSERR, errno); + return -1; + } + + rval = write(fd, addr, nbytes); + + if (rval == -1) { + doio_fprintf(stderr, + "write() failed: %s (%d)\n%s\n", + SYSERR, errno, + format_rw(req, fd, addr, -1, Pattern, + NULL)); +#ifdef sgi + doio_fprintf(stderr, + "write() failed: %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%miniou(%d)=%d, oflags=%#o memalign=%d, addr%%memalign=%d\n", + strerror(errno), + fd, addr, nbytes, + offset, + fdc->c_miniosz, nbytes % fdc->c_miniosz, + oflags, fdc->c_memalign, + (long)addr % fdc->c_memalign); +#else + doio_fprintf(stderr, + "write() failed: %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%1B=%d, oflags=%#o\n", + strerror(errno), + fd, addr, nbytes, + offset, nbytes % 4096, oflags); +#endif + doio_upanic(U_RVAL); + } else if (rval != nbytes) { + doio_fprintf(stderr, + "write() returned wrong # bytes - expected %d, got %d\n%s\n", + nbytes, rval, + format_rw(req, fd, addr, -1, Pattern, + NULL)); + doio_upanic(U_RVAL); + rval = -1; + } + + break; + +#ifdef CRAY + case WRITEA: + /* + * async write + */ + if (lseek(fd, offset, SEEK_SET) == -1) { + doio_fprintf(stderr, + "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n", + fd, offset, SYSERR, errno); + return -1; + } + + aio_strat = req->r_data.write.r_aio_strat; + signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0; + + aio_id = aio_register(fd, aio_strat, signo); + aiop = aio_slot(aio_id); + + /* + * init iosw and do the async write + */ + + if (writea(fd, addr, nbytes, &aiop->iosw, signo) == -1) { + doio_fprintf(stderr, + "writea() failed: %s (%d)\n%s\n", + SYSERR, errno, + format_rw(req, fd, addr, -1, Pattern, + NULL)); + doio_upanic(U_RVAL); + aio_unregister(aio_id); + rval = -1; + } else { + + /* + * Wait for io to complete + */ + + aio_wait(aio_id); + + /* + * check that iosw is ok + */ + + if (aiop->iosw.sw_count != nbytes) { + doio_fprintf(stderr, + "Bad iosw from writea()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n", + 1, 0, nbytes, + aiop->iosw.sw_flag, + aiop->iosw.sw_error, + aiop->iosw.sw_count, + format_rw(req, fd, addr, -1, + Pattern, &aiop->iosw)); + aio_unregister(aio_id); + doio_upanic(U_IOSW); + rval = -1; + } else { + aio_unregister(aio_id); + rval = 0; + } + } + break; + +#endif /* CRAY */ + } + + /* + * Verify that the data was written correctly - check_file() returns + * a non-null pointer which contains an error message if there are + * problems. + */ + + if (v_opt) { + msg = check_file(file, offset, nbytes, Pattern, Pattern_Length, + 0, oflags & O_PARALLEL); + if (msg != NULL) { + doio_fprintf(stderr, "%s%s\n", msg, +#ifdef CRAY + format_rw(req, fd, addr, -1, Pattern, + &aiop->iosw) +#else + format_rw(req, fd, addr, -1, Pattern, NULL) +#endif + ); + doio_upanic(U_CORRUPTION); + exit(E_COMPARE); + + } + } + + /* + * General cleanup ... + * + * Write extent information to the write-log, so that doio_check can do + * corruption detection. Note that w_done is set to 1, indicating that + * the write has been verified as complete. We don't need to write the + * filename on the second logging. + */ + + if (w_opt && logged_write) { + wrec.w_done = 1; + wlog_record_write(&Wlog, &wrec, woffset); + } + + /* + * Unlock file region if necessary + */ + + if (got_lock) { + if (lock_file_region(file, fd, F_UNLCK, offset, nbytes) < 0) { + alloc_mem(-1); + exit(E_INTERNAL); + } + } + + return ((rval == -1) ? -1 : 0); +} + +/* + * Simple routine to lock/unlock a file using fcntl() + */ + +int lock_file_region(char *fname, int fd, int type, int start, int nbytes) +{ + struct flock flk; + + flk.l_type = type; + flk.l_whence = 0; + flk.l_start = start; + flk.l_len = nbytes; + + if (fcntl(fd, F_SETLKW, &flk) < 0) { + doio_fprintf(stderr, + "fcntl(%d, %d, %#o) failed for file %s, lock type %d, offset %d, length %d: %s (%d), open flags: %#o\n", + fd, F_SETLKW, &flk, fname, type, + start, nbytes, SYSERR, errno, + fcntl(fd, F_GETFL, 0)); + return -1; + } + + return 0; +} + +/* + * Perform a listio request. + */ + +#ifdef CRAY +char *format_listio(struct io_req *ioreq, int lcmd, struct listreq *list, + int nent, int fd, char *pattern) +{ + static char *errbuf = NULL; + struct listio_req *liop = &ioreq->r_data.listio; + struct listreq *listreq; + char *cp, *cmd, *opcode, *aio_strat; + int i; + + switch (lcmd) { + case LC_START: + cmd = "LC_START"; + break; + case LC_WAIT: + cmd = "LC_WAIT"; + break; + default: + cmd = "???"; + break; + } + + if (errbuf == NULL) + errbuf = malloc(32768); + + cp = errbuf; + cp += sprintf(cp, "Request number %d\n", Reqno); + + cp += sprintf(cp, "syscall: listio(%s, %#o, %d)\n\n", cmd, list, nent); + + aio_strat = format_strat(liop->r_aio_strat); + + for (i = 0; i < nent; i++) { + cp += sprintf(cp, "struct lioreq for request element %d\n", i); + cp += sprintf(cp, "----------------------------------------\n"); + + listreq = list + i; + + switch (listreq->li_opcode) { + case LO_READ: + opcode = "LO_READ"; + break; + case LO_WRITE: + opcode = "LO_WRITE"; + break; + default: + opcode = "???"; + break; + } + + cp += sprintf(cp, " li_opcode = %s\n", opcode); + cp += + sprintf(cp, " li_drvr = %#o\n", + listreq->li_drvr); + cp += + sprintf(cp, " li_flags = %#o\n", + listreq->li_flags); + cp += + sprintf(cp, " li_offset = %d\n", + listreq->li_offset); + cp += + sprintf(cp, " li_fildes = %d\n", + listreq->li_fildes); + cp += + sprintf(cp, " li_buf = %#o\n", + listreq->li_buf); + cp += + sprintf(cp, " li_nbyte = %d\n", + listreq->li_nbyte); + cp += + sprintf(cp, " li_status = %#o (%d, %d, %d)\n", + listreq->li_status, listreq->li_status->sw_flag, + listreq->li_status->sw_error, + listreq->li_status->sw_count); + cp += + sprintf(cp, " li_signo = %d\n", + listreq->li_signo); + cp += + sprintf(cp, " li_nstride = %d\n", + listreq->li_nstride); + cp += + sprintf(cp, " li_filstride = %d\n", + listreq->li_filstride); + cp += + sprintf(cp, " li_memstride = %d\n", + listreq->li_memstride); + cp += + sprintf(cp, " io completion strategy is %s\n", + aio_strat); + } + return errbuf; +} +#endif /* CRAY */ + +int do_listio(struct io_req *req) +{ +#ifdef CRAY + struct listio_req *lio; + int fd, oflags, signo, nb, i; + int logged_write, rval, got_lock; + int aio_strat, aio_id; + int min_byte, max_byte; + int mem_needed; + int foffset, fstride, mstride, nstrides; + char *moffset; + long offset, woffset; + char *addr, *msg; + sigset_t block_mask, omask; + struct wlog_rec wrec; + struct aio_info *aiop; + struct listreq lio_req; + + lio = &req->r_data.listio; + + /* + * If bytes per stride is less than the stride size, drop the request + * since it will cause overlapping strides, and we cannot predict + * the order they will complete in. + */ + + if (lio->r_filestride && abs(lio->r_filestride) < lio->r_nbytes) { + doio_fprintf(stderr, + "do_listio(): Bogus listio request - abs(filestride) [%d] < nbytes [%d]\n", + abs(lio->r_filestride), lio->r_nbytes); + return -1; + } + + /* + * Allocate core memory. Initialize the data to be written. Make + * sure we get enough, based on the memstride. + */ + + mem_needed = + stride_bounds(0, lio->r_memstride, lio->r_nstrides, + lio->r_nbytes, NULL, NULL); + + if ((rval = alloc_mem(mem_needed + wtob(1))) < 0) { + return rval; + } + + /* + * Set the memory address pointer. If the io is not raw, adjust + * addr by a random amount, so that non-raw io is not necessarily + * word aligned. + */ + + addr = Memptr; + + if (!(lio->r_uflags & F_WORD_ALIGNED)) { + addr += random_range(0, wtob(1) - 1, 1, NULL); + } + + if (lio->r_opcode == LO_WRITE) { + Pattern[0] = lio->r_pattern; + (*Data_Fill) (Memptr, mem_needed, Pattern, Pattern_Length, 0); + if (addr != Memptr) + memmove(addr, Memptr, mem_needed); + } + + /* + * Get a descriptor to do the io on. No need to do an lseek, as this + * is encoded in the listio request. + */ + + if ((fd = alloc_fd(lio->r_file, lio->r_oflags)) == -1) { + return -1; + } + + rval = -1; + got_lock = 0; + logged_write = 0; + + /* + * If the opcode is LO_WRITE, lock all regions of the file that + * are touched by this listio request. Currently, we use + * stride_bounds() to figure out the min and max bytes affected, and + * lock the entire region, regardless of the file stride. + */ + + if (lio->r_opcode == LO_WRITE && k_opt) { + stride_bounds(lio->r_offset, + lio->r_filestride, lio->r_nstrides, + lio->r_nbytes, &min_byte, &max_byte); + + if (lock_file_region(lio->r_file, fd, F_WRLCK, + min_byte, (max_byte - min_byte + 1)) < 0) { + doio_fprintf(stderr, + "stride_bounds(%d, %d, %d, %d, ..., ...) set min_byte to %d, max_byte to %d\n", + lio->r_offset, lio->r_filestride, + lio->r_nstrides, lio->r_nbytes, min_byte, + max_byte); + return -1; + } else { + got_lock = 1; + } + } + + /* + * async write + */ + + aio_strat = lio->r_aio_strat; + signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0; + + aio_id = aio_register(fd, aio_strat, signo); + aiop = aio_slot(aio_id); + + /* + * Form the listio request, and make the call. + */ + + lio_req.li_opcode = lio->r_opcode; + lio_req.li_drvr = 0; + lio_req.li_flags = LF_LSEEK; + lio_req.li_offset = lio->r_offset; + lio_req.li_fildes = fd; + + if (lio->r_memstride >= 0 || lio->r_nstrides <= 1) { + lio_req.li_buf = addr; + } else { + lio_req.li_buf = addr + mem_needed - lio->r_nbytes; + } + + lio_req.li_nbyte = lio->r_nbytes; + lio_req.li_status = &aiop->iosw; + lio_req.li_signo = signo; + lio_req.li_nstride = lio->r_nstrides; + lio_req.li_filstride = lio->r_filestride; + lio_req.li_memstride = lio->r_memstride; + + /* + * If signo != 0, block signo while we're in the system call, so that + * we don't get interrupted syscall failures. + */ + + if (signo) { + sigemptyset(&block_mask); + sigaddset(&block_mask, signo); + sigprocmask(SIG_BLOCK, &block_mask, &omask); + } + + if (listio(lio->r_cmd, &lio_req, 1) < 0) { + doio_fprintf(stderr, + "listio() failed: %s (%d)\n%s\n", + SYSERR, errno, + format_listio(req, lio->r_cmd, &lio_req, 1, fd, + Pattern)); + aio_unregister(aio_id); + doio_upanic(U_RVAL); + goto lio_done; + } + + if (signo) { + sigprocmask(SIG_SETMASK, &omask, NULL); + } + + /* + * Wait for io to complete + */ + + aio_wait(aio_id); + + nstrides = lio->r_nstrides ? lio->r_nstrides : 1; + if (aiop->iosw.sw_count != lio->r_nbytes * nstrides) { + doio_fprintf(stderr, + "Bad iosw from listio()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n", + 1, 0, lio->r_nbytes * lio->r_nstrides, + aiop->iosw.sw_flag, + aiop->iosw.sw_error, aiop->iosw.sw_count, + format_listio(req, lio->r_cmd, &lio_req, 1, fd, + Pattern)); + aio_unregister(aio_id); + doio_upanic(U_IOSW); + goto lio_done; + } + + aio_unregister(aio_id); + + /* + * Verify that the data was written correctly - check_file() returns + * a non-null pointer which contains an error message if there are + * problems. + * + * For listio, we basically have to make 1 call to check_file for each + * stride. + */ + + if (v_opt && lio_req.li_opcode == LO_WRITE) { + fstride = lio->r_filestride ? lio->r_filestride : lio->r_nbytes; + mstride = lio->r_memstride ? lio->r_memstride : lio->r_nbytes; + foffset = lio->r_offset; + + if (mstride > 0 || lio->r_nstrides <= 1) { + moffset = addr; + } else { + moffset = addr + mem_needed - lio->r_nbytes; + } + + for (i = 0; i < lio_req.li_nstride; i++) { + msg = check_file(lio->r_file, + foffset, lio->r_nbytes, + Pattern, Pattern_Length, + moffset - addr, + lio->r_oflags & O_PARALLEL); + + if (msg != NULL) { + doio_fprintf(stderr, "%s\n%s\n", + msg, + format_listio(req, lio->r_cmd, + &lio_req, 1, fd, + Pattern)); + doio_upanic(U_CORRUPTION); + exit(E_COMPARE); + } + + moffset += mstride; + foffset += fstride; + } + + } + + rval = 0; + +lio_done: + + /* + * General cleanup ... + * + */ + + /* + * Release file locks if necessary + */ + + if (got_lock) { + if (lock_file_region(lio->r_file, fd, F_UNLCK, + min_byte, (max_byte - min_byte + 1)) < 0) { + return -1; + } + } + + return rval; +#else + return -1; +#endif +} + +/* + * perform ssread/sswrite operations + */ + +#ifdef _CRAY1 + +int do_ssdio(struct io_req *req) +{ + int nbytes, nb; + char errbuf[BSIZE]; + + nbytes = req->r_data.ssread.r_nbytes; + + /* + * Grab core and sds space + */ + + if ((nb = alloc_mem(nbytes)) < 0) + return nb; + + if (alloc_sds(nbytes) == -1) + return -1; + + if (req->r_type == SSWRITE) { + + /* + * Init data and ship it to the ssd + */ + + Pattern[0] = req->r_data.sswrite.r_pattern; + /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0); */ + (*Data_Fill) (Memptr, nbytes, Pattern, Pattern_Length, 0); + + if (sswrite((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) { + doio_fprintf(stderr, "sswrite() failed: %s (%d)\n%s\n", + SYSERR, errno, + format_sds(req, Memptr, Sdsptr, Pattern)); + doio_upanic(U_RVAL); + return -1; + } + } else { + /* + * read from sds + */ + + if (ssread((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) { + doio_fprintf(stderr, "ssread() failed: %s (%d)\n%s\n", + SYSERR, errno, + format_sds(req, Memptr, Sdsptr, Pattern)); + + doio_upanic(U_RVAL); + return -1; + } + } + + /* + * Verify data if SSWRITE and v_opt + */ + + if (v_opt && req->r_type == SSWRITE) { + ssread((long)Memptr, (long)Sdsptr, btoc(nbytes)); + + if (pattern_check(Memptr, nbytes, Pattern, Pattern_Length, 0) == + -1) { + doio_fprintf(stderr, + "sds DATA COMPARE ERROR - ABORTING\n%s\n", + format_sds(req, Memptr, Sdsptr, Pattern)); + + doio_upanic(U_CORRUPTION); + exit(E_COMPARE); + } + } +} + +#else + +#ifdef CRAY + +int do_ssdio(struct io_req *req) +{ + doio_fprintf(stderr, + "Internal Error - do_ssdio() called on a non-cray1 system\n"); + alloc_mem(-1); + exit(E_INTERNAL); +} + +#endif /* CRAY */ + +#endif /* _CRAY1 */ + +char *fmt_ioreq(struct io_req *ioreq, struct syscall_info *sy, int fd) +{ + static char *errbuf = NULL; + char *cp; + struct rw_req *io; + struct smap *aname; +#ifdef CRAY + struct stat sbuf; +#endif +#ifdef sgi + struct dioattr finfo; +#endif + + if (errbuf == NULL) + errbuf = malloc(32768); + + io = &ioreq->r_data.io; + + /* + * Look up async I/O completion strategy + */ + for (aname = aionames; + aname->value != -1 && aname->value != io->r_aio_strat; aname++) ; + + cp = errbuf; + cp += sprintf(cp, "Request number %d\n", Reqno); + + cp += + sprintf(cp, " fd %d is file %s - open flags are %#o %s\n", + fd, io->r_file, io->r_oflags, format_oflags(io->r_oflags)); + + if (sy->sy_flags & SY_WRITE) { + cp += + sprintf(cp, + " write done at file offset %d - pattern is %c (%#o)\n", + io->r_offset, + (io->r_pattern == '\0') ? '?' : io->r_pattern, + io->r_pattern); + } else { + cp += sprintf(cp, " read done at file offset %d\n", + io->r_offset); + } + + if (sy->sy_flags & SY_ASYNC) { + cp += + sprintf(cp, + " async io completion strategy is %s\n", + aname->string); + } + + cp += + sprintf(cp, + " number of requests is %d, strides per request is %d\n", + io->r_nent, io->r_nstrides); + + cp += sprintf(cp, " i/o byte count = %d\n", io->r_nbytes); + + cp += sprintf(cp, " memory alignment is %s\n", + (io-> + r_uflags & F_WORD_ALIGNED) ? "aligned" : "unaligned"); + +#ifdef CRAY + if (io->r_oflags & O_RAW) { + cp += + sprintf(cp, + " RAW I/O: offset %% 4096 = %d length %% 4096 = %d\n", + io->r_offset % 4096, io->r_nbytes % 4096); + fstat(fd, &sbuf); + cp += + sprintf(cp, + " optimal file xfer size: small: %d large: %d\n", + sbuf.st_blksize, sbuf.st_oblksize); + cp += + sprintf(cp, " cblks %d cbits %#o\n", sbuf.st_cblks, + sbuf.st_cbits); + } +#endif +#ifdef sgi + if (io->r_oflags & O_DIRECT) { + + if (fcntl(fd, F_DIOINFO, &finfo) == -1) { + cp += + sprintf(cp, + " Error %s (%d) getting direct I/O info\n", + strerror(errno), errno); + finfo.d_mem = 1; + finfo.d_miniosz = 1; + finfo.d_maxiosz = 1; + } + + cp += + sprintf(cp, + " DIRECT I/O: offset %% %d = %d length %% %d = %d\n", + finfo.d_miniosz, io->r_offset % finfo.d_miniosz, + io->r_nbytes, io->r_nbytes % finfo.d_miniosz); + cp += + sprintf(cp, + " mem alignment 0x%x xfer size: small: %d large: %d\n", + finfo.d_mem, finfo.d_miniosz, finfo.d_maxiosz); + } +#endif + + return (errbuf); +} + +/* + * Issue listio requests + */ +#ifdef CRAY +struct status *sy_listio(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + int offset, nbytes, nstrides, nents, aio_strat; + int aio_id, signo, o, i, lc; + char *a; + struct listreq *lio_req, *l; + struct aio_info *aiop; + struct status *status; + + /* + * Initialize common fields - assumes r_oflags, r_file, r_offset, and + * r_nbytes are at the same offset in the read_req and reada_req + * structures. + */ + offset = req->r_data.io.r_offset; + nbytes = req->r_data.io.r_nbytes; + nstrides = req->r_data.io.r_nstrides; + nents = req->r_data.io.r_nent; + aio_strat = req->r_data.io.r_aio_strat; + + lc = (sysc->sy_flags & SY_ASYNC) ? LC_START : LC_WAIT; + + status = malloc(sizeof(struct status)); + if (status == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + status->aioid = malloc((nents + 1) * sizeof(int)); + if (status->aioid == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + + signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0; + + lio_req = malloc(nents * sizeof(struct listreq)); + if (lio_req == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + for (l = lio_req, a = addr, o = offset, i = 0; + i < nents; l++, a += nbytes, o += nbytes, i++) { + + aio_id = aio_register(fd, aio_strat, signo); + aiop = aio_slot(aio_id); + status->aioid[i] = aio_id; + + l->li_opcode = (sysc->sy_flags & SY_WRITE) ? LO_WRITE : LO_READ; + l->li_offset = o; + l->li_fildes = fd; + l->li_buf = a; + l->li_nbyte = nbytes; + l->li_status = &aiop->iosw; + l->li_signo = signo; + l->li_nstride = nstrides; + l->li_filstride = 0; + l->li_memstride = 0; + l->li_drvr = 0; + l->li_flags = LF_LSEEK; + } + + status->aioid[nents] = -1; /* end sentinel */ + + if ((status->rval = listio(lc, lio_req, nents)) == -1) { + status->err = errno; + } + + free(lio_req); + return (status); +} + +/* + * Calculate the size of a request in bytes and min/max boundaries + * + * This assumes filestride & memstride = 0. + */ +int listio_mem(struct io_req *req, int offset, int fmstride, int *min, int *max) +{ + int i, size; + + size = stride_bounds(offset, fmstride, + req->r_data.io.r_nstrides * req->r_data.io.r_nent, + req->r_data.io.r_nbytes, min, max); + return (size); +} + +char *fmt_listio(struct io_req *req, struct syscall_info *sy, int fd, + char *addr) +{ + static char *errbuf = NULL; + char *cp; + char *c, *opcode; + int i; + + if (errbuf == NULL) { + errbuf = malloc(32768); + if (errbuf == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + } + + c = (sy->sy_flags & SY_ASYNC) ? "lc_wait" : "lc_start"; + + cp = errbuf; + cp += sprintf(cp, "syscall: listio(%s, (?), %d)\n", + c, req->r_data.io.r_nent); + + cp += sprintf(cp, " data buffer at %#o\n", addr); + + return (errbuf); +} +#endif /* CRAY */ + +#ifdef sgi +struct status *sy_pread(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + int rc; + struct status *status; + + rc = pread(fd, addr, req->r_data.io.r_nbytes, req->r_data.io.r_offset); + + status = malloc(sizeof(struct status)); + if (status == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + status->aioid = NULL; + status->rval = rc; + status->err = errno; + + return (status); +} + +struct status *sy_pwrite(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + int rc; + struct status *status; + + rc = pwrite(fd, addr, req->r_data.io.r_nbytes, req->r_data.io.r_offset); + + status = malloc(sizeof(struct status)); + if (status == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + status->aioid = NULL; + status->rval = rc; + status->err = errno; + + return (status); +} + +char *fmt_pread(struct io_req *req, struct syscall_info *sy, int fd, char *addr) +{ + static char *errbuf = NULL; + char *cp; + + if (errbuf == NULL) { + errbuf = malloc(32768); + if (errbuf == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + } + + cp = errbuf; + cp += sprintf(cp, "syscall: %s(%d, 0x%lx, %d)\n", + sy->sy_name, fd, addr, req->r_data.io.r_nbytes); + return (errbuf); +} +#endif /* sgi */ + +#ifndef CRAY +struct status *sy_readv(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + struct status *sy_rwv(); + return sy_rwv(req, sysc, fd, addr, 0); +} + +struct status *sy_writev(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + struct status *sy_rwv(); + return sy_rwv(req, sysc, fd, addr, 1); +} + +struct status *sy_rwv(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr, int rw) +{ + int rc; + struct status *status; + struct iovec iov[2]; + + status = malloc(sizeof(struct status)); + if (status == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + status->aioid = NULL; + + /* move to the desired file position. */ + if ((rc = lseek(fd, req->r_data.io.r_offset, SEEK_SET)) == -1) { + status->rval = rc; + status->err = errno; + return (status); + } + + iov[0].iov_base = addr; + iov[0].iov_len = req->r_data.io.r_nbytes; + + if (rw) + rc = writev(fd, iov, 1); + else + rc = readv(fd, iov, 1); + status->aioid = NULL; + status->rval = rc; + status->err = errno; + return (status); +} + +char *fmt_readv(struct io_req *req, struct syscall_info *sy, int fd, char *addr) +{ + static char errbuf[32768]; + char *cp; + + cp = errbuf; + cp += sprintf(cp, "syscall: %s(%d, (iov on stack), 1)\n", + sy->sy_name, fd); + return (errbuf); +} +#endif /* !CRAY */ + +#ifdef sgi +struct status *sy_aread(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + struct status *sy_arw(); + return sy_arw(req, sysc, fd, addr, 0); +} + +struct status *sy_awrite(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + struct status *sy_arw(); + return sy_arw(req, sysc, fd, addr, 1); +} + +/* + #define sy_aread(A, B, C, D) sy_arw(A, B, C, D, 0) + #define sy_awrite(A, B, C, D) sy_arw(A, B, C, D, 1) + */ + +struct status *sy_arw(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr, int rw) +{ + /* POSIX 1003.1b-1993 Async read */ + struct status *status; + int rc; + int aio_id, aio_strat, signo; + struct aio_info *aiop; + + status = malloc(sizeof(struct status)); + if (status == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + aio_strat = req->r_data.io.r_aio_strat; + signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0; + + aio_id = aio_register(fd, aio_strat, signo); + aiop = aio_slot(aio_id); + + memset((void *)&aiop->aiocb, 0, sizeof(aiocb_t)); + + aiop->aiocb.aio_fildes = fd; + aiop->aiocb.aio_nbytes = req->r_data.io.r_nbytes; + aiop->aiocb.aio_offset = req->r_data.io.r_offset; + aiop->aiocb.aio_buf = addr; + aiop->aiocb.aio_reqprio = 0; /* must be 0 */ + aiop->aiocb.aio_lio_opcode = 0; + + if (aio_strat == A_SIGNAL) { /* siginfo(2) stuff */ + aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiop->aiocb.aio_sigevent.sigev_signo = signo; + } else if (aio_strat == A_CALLBACK) { + aiop->aiocb.aio_sigevent.sigev_signo = 0; + aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_CALLBACK; + aiop->aiocb.aio_sigevent.sigev_func = cb_handler; + aiop->aiocb.aio_sigevent.sigev_value.sival_int = aio_id; + } else { + aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_NONE; + aiop->aiocb.aio_sigevent.sigev_signo = 0; + } + + if (rw) + rc = aio_write(&aiop->aiocb); + else + rc = aio_read(&aiop->aiocb); + + status->aioid = malloc(2 * sizeof(int)); + if (status->aioid == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + status->aioid[0] = aio_id; + status->aioid[1] = -1; + status->rval = rc; + status->err = errno; + return (status); +} + +char *fmt_aread(struct io_req *req, struct syscall_info *sy, int fd, char *addr) +{ + static char errbuf[32768]; + char *cp; + + cp = errbuf; + cp += sprintf(cp, "syscall: %s(&aiop->aiocb)\n", sy->sy_name); + return (errbuf); +} +#endif /* sgi */ + +#ifndef CRAY + +struct status *sy_mmread(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + struct status *sy_mmrw(); + return sy_mmrw(req, sysc, fd, addr, 0); +} + +struct status *sy_mmwrite(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr) +{ + struct status *sy_mmrw(); + return sy_mmrw(req, sysc, fd, addr, 1); +} + +struct status *sy_mmrw(struct io_req *req, struct syscall_info *sysc, int fd, + char *addr, int rw) +{ + /* + * mmap read/write + * This version is oriented towards mmaping the file to memory + * ONCE and keeping it mapped. + */ + struct status *status; + void *mrc = NULL, *memaddr = NULL; + struct fd_cache *fdc; + struct stat sbuf; + int rc; + + status = malloc(sizeof(struct status)); + if (status == NULL) { + doio_fprintf(stderr, "malloc failed, %s/%d\n", + __FILE__, __LINE__); + return NULL; + } + status->aioid = NULL; + status->rval = -1; + + fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags); + + if (v_opt || fdc->c_memaddr == NULL) { + if (fstat(fd, &sbuf) < 0) { + doio_fprintf(stderr, "fstat failed, errno=%d\n", errno); + status->err = errno; + return (status); + } + + fdc->c_memlen = (int)sbuf.st_size; + mrc = mmap(NULL, (int)sbuf.st_size, + rw ? PROT_WRITE | PROT_READ : PROT_READ, + MAP_SHARED, fd, 0); + + if (mrc == MAP_FAILED) { + doio_fprintf(stderr, "mmap() failed - 0x%lx %d\n", + mrc, errno); + status->err = errno; + return (status); + } + + fdc->c_memaddr = mrc; + } + + memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset); + + active_mmap_rw = 1; + if (rw) + memcpy(memaddr, addr, req->r_data.io.r_nbytes); + else + memcpy(addr, memaddr, req->r_data.io.r_nbytes); + if (v_opt) + msync(fdc->c_memaddr, (int)sbuf.st_size, MS_SYNC); + active_mmap_rw = 0; + + status->rval = req->r_data.io.r_nbytes; + status->err = 0; + + if (v_opt) { + rc = munmap(mrc, (int)sbuf.st_size); + } + + return (status); +} + +char *fmt_mmrw(struct io_req *req, struct syscall_info *sy, int fd, char *addr) +{ + static char errbuf[32768]; + char *cp; + struct fd_cache *fdc; + void *memaddr; + + fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags); + + cp = errbuf; + cp += sprintf(cp, "syscall: %s(NULL, %d, %s, MAP_SHARED, %d, 0)\n", + sy->sy_name, + fdc->c_memlen, + (sy->sy_flags & SY_WRITE) ? "PROT_WRITE" : "PROT_READ", + fd); + + cp += sprintf(cp, "\tfile is mmaped to: 0x%lx\n", + (unsigned long)fdc->c_memaddr); + + memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset); + + cp += sprintf(cp, "\tfile-mem=0x%lx, length=%d, buffer=0x%lx\n", + (unsigned long)memaddr, req->r_data.io.r_nbytes, + (unsigned long)addr); + + return (errbuf); +} +#endif /* !CRAY */ + +struct syscall_info syscalls[] = { +#ifdef CRAY + {"listio-read-sync", LREAD, + sy_listio, NULL, fmt_listio, + SY_IOSW}, + {"listio-read-strides-sync", LSREAD, + sy_listio, listio_mem, fmt_listio, + SY_IOSW}, + {"listio-read-reqs-sync", LEREAD, + sy_listio, listio_mem, fmt_listio, + SY_IOSW}, + {"listio-read-async", LREADA, + sy_listio, NULL, fmt_listio, + SY_IOSW | SY_ASYNC}, + {"listio-read-strides-async", LSREADA, + sy_listio, listio_mem, fmt_listio, + SY_IOSW | SY_ASYNC}, + {"listio-read-reqs-async", LEREADA, + sy_listio, listio_mem, fmt_listio, + SY_IOSW | SY_ASYNC}, + {"listio-write-sync", LWRITE, + sy_listio, listio_mem, fmt_listio, + SY_IOSW | SY_WRITE}, + {"listio-write-strides-sync", LSWRITE, + sy_listio, listio_mem, fmt_listio, + SY_IOSW | SY_WRITE}, + {"listio-write-reqs-sync", LEWRITE, + sy_listio, listio_mem, fmt_listio, + SY_IOSW | SY_WRITE}, + {"listio-write-async", LWRITEA, + sy_listio, listio_mem, fmt_listio, + SY_IOSW | SY_WRITE | SY_ASYNC}, + {"listio-write-strides-async", LSWRITEA, + sy_listio, listio_mem, fmt_listio, + SY_IOSW | SY_WRITE | SY_ASYNC}, + {"listio-write-reqs-async", LEWRITEA, + sy_listio, listio_mem, fmt_listio, + SY_IOSW | SY_WRITE | SY_ASYNC}, +#endif + +#ifdef sgi + {"aread", AREAD, + sy_aread, NULL, fmt_aread, + SY_IOSW | SY_ASYNC}, + {"awrite", AWRITE, + sy_awrite, NULL, fmt_aread, + SY_IOSW | SY_WRITE | SY_ASYNC}, + {"pread", PREAD, + sy_pread, NULL, fmt_pread, + 0}, + {"pwrite", PWRITE, + sy_pwrite, NULL, fmt_pread, + SY_WRITE}, +#endif + +#ifndef CRAY + {"readv", READV, + sy_readv, NULL, fmt_readv, + 0}, + {"writev", WRITEV, + sy_writev, NULL, fmt_readv, + SY_WRITE}, + {"mmap-read", MMAPR, + sy_mmread, NULL, fmt_mmrw, + 0}, + {"mmap-write", MMAPW, + sy_mmwrite, NULL, fmt_mmrw, + SY_WRITE}, +#endif + + {NULL, 0, + 0, 0, 0, + 0}, +}; + +int do_rw(struct io_req *req) +{ + static int pid = -1; + int fd, offset, nbytes, nstrides, nents, oflags; + int rval, mem_needed, i; + int logged_write, got_lock, pattern; + off_t woffset; + int min_byte, max_byte; + char *addr, *file, *msg; + struct status *s; + struct wlog_rec wrec; + struct syscall_info *sy; +#if defined(CRAY) || defined(sgi) + struct aio_info *aiop; + struct iosw *iosw; +#endif +#ifdef sgi + struct fd_cache *fdc; +#endif + + woffset = 0; + + /* + * Initialize common fields - assumes r_oflags, r_file, r_offset, and + * r_nbytes are at the same offset in the read_req and reada_req + * structures. + */ + file = req->r_data.io.r_file; + oflags = req->r_data.io.r_oflags; + offset = req->r_data.io.r_offset; + nbytes = req->r_data.io.r_nbytes; + nstrides = req->r_data.io.r_nstrides; + nents = req->r_data.io.r_nent; + pattern = req->r_data.io.r_pattern; + + if (nents >= MAX_AIO) { + doio_fprintf(stderr, + "do_rw: too many list requests, %d. Maximum is %d\n", + nents, MAX_AIO); + return (-1); + } + + /* + * look up system call info + */ + for (sy = syscalls; sy->sy_name != NULL && sy->sy_type != req->r_type; + sy++) ; + + if (sy->sy_name == NULL) { + doio_fprintf(stderr, "do_rw: unknown r_type %d.\n", + req->r_type); + return (-1); + } + + /* + * Get an open file descriptor + * Note: must be done before memory allocation so that the direct i/o + * information is available in mem. allocate + */ + + if ((fd = alloc_fd(file, oflags)) == -1) + return -1; + + /* + * Allocate core memory and possibly sds space. Initialize the + * data to be written. Make sure we get enough, based on the + * memstride. + * + * need: + * 1 extra word for possible partial-word address "bump" + * 1 extra word for dynamic pattern overrun + * MPP_BUMP extra words for T3E non-hw-aligned memory address. + */ + + if (sy->sy_buffer != NULL) { + mem_needed = (*sy->sy_buffer) (req, 0, 0, NULL, NULL); + } else { + mem_needed = nbytes; + } + +#ifdef CRAY + if ((rval = + alloc_mem(mem_needed + wtob(1) * 2 + + MPP_BUMP * sizeof(UINT64_T))) < 0) { + return rval; + } +#else +#ifdef sgi + /* get memory alignment for using DIRECT I/O */ + fdc = alloc_fdcache(file, oflags); + + if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + fdc->c_memalign)) < 0) { + return rval; + } +#else + /* what is !CRAY && !sgi ? */ + if ((rval = alloc_mem(mem_needed + wtob(1) * 2)) < 0) { + return rval; + } +#endif /* sgi */ +#endif /* CRAY */ + + Pattern[0] = pattern; + + /* + * Allocate SDS space for backdoor write if desired + */ + + if (oflags & O_SSD) { +#ifdef CRAY +#ifndef _CRAYMPP + if (alloc_sds(nbytes) == -1) + return -1; + + if (sy->sy_flags & SY_WRITE) { + /*pattern_fill(Memptr, mem_needed, Pattern, Pattern_Length, 0); */ + (*Data_Fill) (Memptr, nbytes, Pattern, Pattern_Length, + 0); + + if (sswrite((long)Memptr, Sdsptr, btoc(mem_needed)) == + -1) { + doio_fprintf(stderr, + "sswrite(%d, %d, %d) failed: %s (%d)\n", + (long)Memptr, Sdsptr, + btoc(mem_needed), SYSERR, errno); + fflush(stderr); + return -1; + } + } + + addr = (char *)Sdsptr; +#else + doio_fprintf(stderr, + "Invalid O_SSD flag was generated for MPP system\n"); + fflush(stderr); + return -1; +#endif /* _CRAYMPP */ +#else /* CRAY */ + doio_fprintf(stderr, + "Invalid O_SSD flag was generated for non-Cray system\n"); + fflush(stderr); + return -1; +#endif /* CRAY */ + } else { + addr = Memptr; + + /* + * if io is not raw, bump the offset by a random amount + * to generate non-word-aligned io. + * + * On MPP systems, raw I/O must start on an 0x80 byte boundary. + * For non-aligned I/O, bump the address from 1 to 8 words. + */ + + if (!(req->r_data.io.r_uflags & F_WORD_ALIGNED)) { +#ifdef _CRAYMPP + addr += + random_range(0, MPP_BUMP, 1, NULL) * sizeof(int); +#endif + addr += random_range(0, wtob(1) - 1, 1, NULL); + } +#ifdef sgi + /* + * Force memory alignment for Direct I/O + */ + if ((oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0)) { + addr += + fdc->c_memalign - ((long)addr % fdc->c_memalign); + } +#endif + + /* + * FILL must be done on a word-aligned buffer. + * Call the fill function with Memptr which is aligned, + * then memmove it to the right place. + */ + if (sy->sy_flags & SY_WRITE) { + (*Data_Fill) (Memptr, mem_needed, Pattern, + Pattern_Length, 0); + if (addr != Memptr) + memmove(addr, Memptr, mem_needed); + } + } + + rval = 0; + got_lock = 0; + logged_write = 0; + + /* + * Lock data if this is a write and locking option is set + */ + if (sy->sy_flags & SY_WRITE && k_opt) { + if (sy->sy_buffer != NULL) { + (*sy->sy_buffer) (req, offset, 0, &min_byte, &max_byte); + } else { + min_byte = offset; + max_byte = offset + (nbytes * nstrides * nents); + } + + if (lock_file_region(file, fd, F_WRLCK, + min_byte, (max_byte - min_byte + 1)) < 0) { + doio_fprintf(stderr, + "file lock failed:\n%s\n", + fmt_ioreq(req, sy, fd)); + doio_fprintf(stderr, + " buffer(req, %d, 0, 0x%x, 0x%x)\n", + offset, min_byte, max_byte); + alloc_mem(-1); + exit(E_INTERNAL); + } + + got_lock = 1; + } + + /* + * Write a preliminary write-log entry. This is done so that + * doio_check can do corruption detection across an interrupt/crash. + * Note that w_done is set to 0. If doio_check sees this, it + * re-creates the file extents as if the write completed, but does not + * do any checking - see comments in doio_check for more details. + */ + + if (sy->sy_flags & SY_WRITE && w_opt) { + if (pid == -1) { + pid = getpid(); + } + + wrec.w_async = (sy->sy_flags & SY_ASYNC) ? 1 : 0; + wrec.w_oflags = oflags; + wrec.w_pid = pid; + wrec.w_offset = offset; + wrec.w_nbytes = nbytes; /* mem_needed -- total length */ + + wrec.w_pathlen = strlen(file); + memcpy(wrec.w_path, file, wrec.w_pathlen); + wrec.w_hostlen = strlen(Host); + memcpy(wrec.w_host, Host, wrec.w_hostlen); + wrec.w_patternlen = Pattern_Length; + memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen); + + wrec.w_done = 0; + + if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) { + doio_fprintf(stderr, + "Could not append to write-log: %s (%d)\n", + SYSERR, errno); + } else { + logged_write = 1; + } + } + + s = (*sy->sy_syscall) (req, sy, fd, addr); + + if (s->rval == -1) { + doio_fprintf(stderr, + "%s() request failed: %s (%d)\n%s\n%s\n", + sy->sy_name, SYSERR, errno, + fmt_ioreq(req, sy, fd), + (*sy->sy_format) (req, sy, fd, addr)); + + doio_upanic(U_RVAL); + + for (i = 0; i < nents; i++) { + if (s->aioid == NULL) + break; + aio_unregister(s->aioid[i]); + } + rval = -1; + } else { + /* + * If the syscall was async, wait for I/O to complete + */ +#ifndef __linux__ + if (sy->sy_flags & SY_ASYNC) { + for (i = 0; i < nents; i++) { + aio_wait(s->aioid[i]); + } + } +#endif + + /* + * Check the syscall how-much-data-written return. Look + * for this in either the return value or the 'iosw' + * structure. + */ + + if (sy->sy_flags & SY_IOSW) { +#ifdef CRAY + for (i = 0; i < nents; i++) { + if (s->aioid == NULL) + break; /* >>> error condition? */ + aiop = aio_slot(s->aioid[i]); + iosw = &aiop->iosw; + if (iosw->sw_error != 0) { + doio_fprintf(stderr, + "%s() iosw error set: %s\n%s\n%s\n", + sy->sy_name, + strerror(iosw->sw_error), + fmt_ioreq(req, sy, fd), + (*sy->sy_format) (req, sy, + fd, + addr)); + doio_upanic(U_IOSW); + rval = -1; + } else if (iosw->sw_count != nbytes * nstrides) { + doio_fprintf(stderr, + "Bad iosw from %s() #%d\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n%s\n", + sy->sy_name, i, + 1, 0, nbytes * nstrides, + iosw->sw_flag, + iosw->sw_error, + iosw->sw_count, + fmt_ioreq(req, sy, fd), + (*sy->sy_format) (req, sy, + fd, + addr)); + doio_upanic(U_IOSW); + rval = -1; + } + + aio_unregister(s->aioid[i]); + } +#endif /* CRAY */ +#ifdef sgi + for (i = 0; s->aioid[i] != -1; i++) { + if (s->aioid == NULL) { + doio_fprintf(stderr, + "aioid == NULL!\n"); + break; + } + aiop = aio_slot(s->aioid[i]); + + /* + * make sure the io completed without error + */ + if (aiop->aio_errno != 0) { + doio_fprintf(stderr, + "%s() aio error set: %s (%d)\n%s\n%s\n", + sy->sy_name, + strerror(aiop->aio_errno), + aiop->aio_errno, + fmt_ioreq(req, sy, fd), + (*sy->sy_format) (req, sy, + fd, + addr)); + doio_upanic(U_IOSW); + rval = -1; + } else if (aiop->aio_ret != nbytes) { + doio_fprintf(stderr, + "Bad aio return from %s() #%d\nExpected (%d,%d), got (%d,%d)\n%s\n%s\n", + sy->sy_name, i, + 0, nbytes, + aiop->aio_errno, + aiop->aio_ret, + fmt_ioreq(req, sy, fd), + (*sy->sy_format) (req, sy, + fd, + addr)); + aio_unregister(s->aioid[i]); + doio_upanic(U_IOSW); + return -1; + } else { + aio_unregister(s->aioid[i]); + rval = 0; + } + } +#endif /* sgi */ + } else { + + if (s->rval != mem_needed) { + doio_fprintf(stderr, + "%s() request returned wrong # of bytes - expected %d, got %d\n%s\n%s\n", + sy->sy_name, nbytes, s->rval, + fmt_ioreq(req, sy, fd), + (*sy->sy_format) (req, sy, fd, + addr)); + rval = -1; + doio_upanic(U_RVAL); + } + } + } + + /* + * Verify that the data was written correctly - check_file() returns + * a non-null pointer which contains an error message if there are + * problems. + */ + + if (rval == 0 && sy->sy_flags & SY_WRITE && v_opt) { + msg = check_file(file, offset, nbytes * nstrides * nents, + Pattern, Pattern_Length, 0, + oflags & O_PARALLEL); + if (msg != NULL) { + doio_fprintf(stderr, "%s\n%s\n%s\n", + msg, + fmt_ioreq(req, sy, fd), + (*sy->sy_format) (req, sy, fd, addr)); + doio_upanic(U_CORRUPTION); + exit(E_COMPARE); + } + } + + /* + * General cleanup ... + * + * Write extent information to the write-log, so that doio_check can do + * corruption detection. Note that w_done is set to 1, indicating that + * the write has been verified as complete. We don't need to write the + * filename on the second logging. + */ + + if (w_opt && logged_write) { + wrec.w_done = 1; + wlog_record_write(&Wlog, &wrec, woffset); + } + + /* + * Unlock file region if necessary + */ + + if (got_lock) { + if (lock_file_region(file, fd, F_UNLCK, + min_byte, (max_byte - min_byte + 1)) < 0) { + alloc_mem(-1); + exit(E_INTERNAL); + } + } + + if (s->aioid != NULL) + free(s->aioid); + free(s); + return (rval == -1) ? -1 : 0; +} + +/* + * fcntl-based requests + * - F_FRESVSP + * - F_UNRESVSP + * - F_FSYNC + */ +#ifdef sgi +int do_fcntl(struct io_req *req) +{ + int fd, oflags, offset, nbytes; + int rval, op; + int got_lock; + int min_byte, max_byte; + char *file, *msg; + struct flock flk; + + /* + * Initialize common fields - assumes r_oflags, r_file, r_offset, and + * r_nbytes are at the same offset in the read_req and reada_req + * structures. + */ + file = req->r_data.io.r_file; + oflags = req->r_data.io.r_oflags; + offset = req->r_data.io.r_offset; + nbytes = req->r_data.io.r_nbytes; + + flk.l_type = 0; + flk.l_whence = SEEK_SET; + flk.l_start = offset; + flk.l_len = nbytes; + + /* + * Get an open file descriptor + */ + + if ((fd = alloc_fd(file, oflags)) == -1) + return -1; + + rval = 0; + got_lock = 0; + + /* + * Lock data if this is locking option is set + */ + if (k_opt) { + min_byte = offset; + max_byte = offset + nbytes; + + if (lock_file_region(file, fd, F_WRLCK, + min_byte, (nbytes + 1)) < 0) { + doio_fprintf(stderr, "file lock failed:\n"); + doio_fprintf(stderr, + " buffer(req, %d, 0, 0x%x, 0x%x)\n", + offset, min_byte, max_byte); + alloc_mem(-1); + exit(E_INTERNAL); + } + + got_lock = 1; + } + + switch (req->r_type) { + case RESVSP: + op = F_RESVSP; + msg = "f_resvsp"; + break; + case UNRESVSP: + op = F_UNRESVSP; + msg = "f_unresvsp"; + break; +#ifdef F_FSYNC + case DFFSYNC: + op = F_FSYNC; + msg = "f_fsync"; + break; +#endif + } + + rval = fcntl(fd, op, &flk); + + if (rval == -1) { + doio_fprintf(stderr, + "fcntl %s request failed: %s (%d)\n\tfcntl(%d, %s %d, {%d %lld ==> %lld}\n", + msg, SYSERR, errno, + fd, msg, op, flk.l_whence, + (long long)flk.l_start, (long long)flk.l_len); + + doio_upanic(U_RVAL); + rval = -1; + } + + /* + * Unlock file region if necessary + */ + + if (got_lock) { + if (lock_file_region(file, fd, F_UNLCK, + min_byte, (max_byte - min_byte + 1)) < 0) { + alloc_mem(-1); + exit(E_INTERNAL); + } + } + + return (rval == -1) ? -1 : 0; +} +#endif /* sgi */ + +/* + * fsync(2) and fdatasync(2) + */ +#ifndef CRAY +int do_sync(struct io_req *req) +{ + int fd, oflags; + int rval; + char *file; + + /* + * Initialize common fields - assumes r_oflags, r_file, r_offset, and + * r_nbytes are at the same offset in the read_req and reada_req + * structures. + */ + file = req->r_data.io.r_file; + oflags = req->r_data.io.r_oflags; + + /* + * Get an open file descriptor + */ + + if ((fd = alloc_fd(file, oflags)) == -1) + return -1; + + rval = 0; + switch (req->r_type) { + case FSYNC2: + rval = fsync(fd); + break; + case FDATASYNC: + rval = fdatasync(fd); + break; + default: + rval = -1; + } + return (rval == -1) ? -1 : 0; +} +#endif /* !CRAY */ + +int +doio_pat_fill(char *addr, int mem_needed, char *Pattern, int Pattern_Length, + int shift) +{ + return pattern_fill(addr, mem_needed, Pattern, Pattern_Length, 0); +} + +char *doio_pat_check(char *buf, int offset, int length, char *pattern, + int pattern_length, int patshift) +{ + static char errbuf[4096]; + int nb, i, pattern_index; + char *cp, *bufend, *ep; + char actual[33], expected[33]; + + if (pattern_check(buf, length, pattern, pattern_length, patshift) != 0) { + ep = errbuf; + ep += + sprintf(ep, + "Corrupt regions follow - unprintable chars are represented as '.'\n"); + ep += + sprintf(ep, + "-----------------------------------------------------------------\n"); + + pattern_index = patshift % pattern_length;; + cp = buf; + bufend = buf + length; + + while (cp < bufend) { + if (*cp != pattern[pattern_index]) { + nb = bufend - cp; + if ((unsigned int)nb > sizeof(expected) - 1) { + nb = sizeof(expected) - 1; + } + + ep += + sprintf(ep, + "corrupt bytes starting at file offset %d\n", + offset + (int)(cp - buf)); + + /* + * Fill in the expected and actual patterns + */ + memset(expected, 0x00, sizeof(expected)); + memset(actual, 0x00, sizeof(actual)); + + for (i = 0; i < nb; i++) { + expected[i] = + pattern[(pattern_index + + i) % pattern_length]; + if (!isprint(expected[i])) { + expected[i] = '.'; + } + + actual[i] = cp[i]; + if (!isprint(actual[i])) { + actual[i] = '.'; + } + } + + ep += + sprintf(ep, + " 1st %2d expected bytes: %s\n", + nb, expected); + ep += + sprintf(ep, + " 1st %2d actual bytes: %s\n", + nb, actual); + fflush(stderr); + return errbuf; + } else { + cp++; + pattern_index++; + + if (pattern_index == pattern_length) { + pattern_index = 0; + } + } + } + return errbuf; + } + + return NULL; +} + +/* + * Check the contents of a file beginning at offset, for length bytes. It + * is assumed that there is a string of pattern bytes in this area of the + * file. Use normal buffered reads to do the verification. + * + * If there is a data mismatch, write a detailed message into a static buffer + * suitable for the caller to print. Otherwise print NULL. + * + * The fsa flag is set to non-zero if the buffer should be read back through + * the FSA (unicos/mk). This implies the file will be opened + * O_PARALLEL|O_RAW|O_WELLFORMED to do the validation. We must do this because + * FSA will not allow the file to be opened for buffered io if it was + * previously opened for O_PARALLEL io. + */ + +char *check_file(char *file, int offset, int length, char *pattern, + int pattern_length, int patshift, int fsa) +{ + static char errbuf[4096]; + int fd, nb, flags; + char *buf, *em, *ep; +#ifdef sgi + struct fd_cache *fdc; +#endif + + buf = Memptr; + + if (V_opt) { + flags = Validation_Flags | O_RDONLY; + } else { + flags = O_RDONLY; + if (fsa) { +#ifdef CRAY + flags |= O_PARALLEL | O_RAW | O_WELLFORMED; +#endif + } + } + + if ((fd = alloc_fd(file, flags)) == -1) { + sprintf(errbuf, + "Could not open file %s with flags %#o (%s) for data comparison: %s (%d)\n", + file, flags, format_oflags(flags), SYSERR, errno); + return errbuf; + } + + if (lseek(fd, offset, SEEK_SET) == -1) { + sprintf(errbuf, + "Could not lseek to offset %d in %s for verification: %s (%d)\n", + offset, file, SYSERR, errno); + return errbuf; + } +#ifdef sgi + /* Irix: Guarantee a properly aligned address on Direct I/O */ + fdc = alloc_fdcache(file, flags); + if ((flags & O_DIRECT) && ((long)buf % fdc->c_memalign != 0)) { + buf += fdc->c_memalign - ((long)buf % fdc->c_memalign); + } +#endif + + if ((nb = read(fd, buf, length)) == -1) { +#ifdef sgi + sprintf(errbuf, + "Could not read %d bytes from %s for verification: %s (%d)\n\tread(%d, 0x%lx, %d)\n\tbuf %% alignment(%d) = %ld\n", + length, file, SYSERR, errno, + fd, buf, length, + fdc->c_memalign, (long)buf % fdc->c_memalign); +#else + sprintf(errbuf, + "Could not read %d bytes from %s for verification: %s (%d)\n", + length, file, SYSERR, errno); + +#endif + return errbuf; + } + + if (nb != length) { + sprintf(errbuf, + "Read wrong # bytes from %s. Expected %d, got %d\n", + file, length, nb); + return errbuf; + } + + if ((em = + (*Data_Check) (buf, offset, length, pattern, pattern_length, + patshift)) != NULL) { + ep = errbuf; + ep += sprintf(ep, "*** DATA COMPARISON ERROR ***\n"); + ep += + sprintf(ep, "check_file(%s, %d, %d, %s, %d, %d) failed\n\n", + file, offset, length, pattern, pattern_length, + patshift); + ep += + sprintf(ep, "Comparison fd is %d, with open flags %#o\n", + fd, flags); + strcpy(ep, em); + return (errbuf); + } + return NULL; +} + +/* + * Function to single-thread stdio output. + */ + +int doio_fprintf(FILE * stream, char *format, ...) +{ + static int pid = -1; + char *date; + int rval; + struct flock flk; + va_list arglist; + struct timeval ts; + gettimeofday(&ts, NULL); + date = hms(ts.tv_sec); + + if (pid == -1) { + pid = getpid(); + } + + flk.l_whence = flk.l_start = flk.l_len = 0; + flk.l_type = F_WRLCK; + fcntl(fileno(stream), F_SETLKW, &flk); + + va_start(arglist, format); + rval = fprintf(stream, "\n%s%s (%5d) %s\n", Prog, TagName, pid, date); + rval += fprintf(stream, "---------------------\n"); + vfprintf(stream, format, arglist); + va_end(arglist); + + fflush(stream); + + flk.l_type = F_UNLCK; + fcntl(fileno(stream), F_SETLKW, &flk); + + return rval; +} + +/* + * Simple function for allocating core memory. Uses Memsize and Memptr to + * keep track of the current amount allocated. + */ +#ifndef CRAY +int alloc_mem(int nbytes) +{ + char *cp; + void *addr; + int me = 0, flags, key, shmid; + static int mturn = 0; /* which memory type to use */ + struct memalloc *M; + char filename[255]; +#ifdef __linux__ + struct shmid_ds shm_ds; +#endif + +#ifdef __linux__ + memset(&shm_ds, 0x00, sizeof(struct shmid_ds)); +#endif + + /* nbytes = -1 means "free all allocated memory" */ + if (nbytes == -1) { + + for (me = 0; me < Nmemalloc; me++) { + if (Memalloc[me].space == NULL) + continue; + + switch (Memalloc[me].memtype) { + case MEM_DATA: +#ifdef sgi + if (Memalloc[me].flags & MEMF_MPIN) + munpin(Memalloc[me].space, + Memalloc[me].size); +#endif + free(Memalloc[me].space); + Memalloc[me].space = NULL; + Memptr = NULL; + Memsize = 0; + break; + case MEM_SHMEM: +#ifdef sgi + if (Memalloc[me].flags & MEMF_MPIN) + munpin(Memalloc[me].space, + Memalloc[me].size); +#endif + shmdt(Memalloc[me].space); + Memalloc[me].space = NULL; +#ifdef sgi + shmctl(Memalloc[me].fd, IPC_RMID); +#else + shmctl(Memalloc[me].fd, IPC_RMID, &shm_ds); +#endif + break; + case MEM_MMAP: +#ifdef sgi + if (Memalloc[me].flags & MEMF_MPIN) + munpin(Memalloc[me].space, + Memalloc[me].size); +#endif + munmap(Memalloc[me].space, Memalloc[me].size); + close(Memalloc[me].fd); + if (Memalloc[me].flags & MEMF_FILE) { + unlink(Memalloc[me].name); + } + Memalloc[me].space = NULL; + break; + default: + doio_fprintf(stderr, + "alloc_mem: HELP! Unknown memory space type %d index %d\n", + Memalloc[me].memtype, me); + break; + } + } + return 0; + } + + /* + * Select a memory area (currently round-robbin) + */ + + if (mturn >= Nmemalloc) + mturn = 0; + + M = &Memalloc[mturn]; + + switch (M->memtype) { + case MEM_DATA: + if (nbytes > M->size) { + if (M->space != NULL) { +#ifdef sgi + if (M->flags & MEMF_MPIN) + munpin(M->space, M->size); +#endif + free(M->space); + } + M->space = NULL; + M->size = 0; + } + + if (M->space == NULL) { + if ((cp = malloc(nbytes)) == NULL) { + doio_fprintf(stderr, + "malloc(%d) failed: %s (%d)\n", + nbytes, SYSERR, errno); + return -1; + } +#ifdef sgi + if (M->flags & MEMF_MPIN) { + if (mpin(cp, nbytes) == -1) { + doio_fprintf(stderr, + "mpin(0x%lx, %d) failed: %s (%d)\n", + cp, nbytes, SYSERR, errno); + } + } +#endif + M->space = (void *)cp; + M->size = nbytes; + } + break; + + case MEM_MMAP: + if (nbytes > M->size) { + if (M->space != NULL) { +#ifdef sgi + if (M->flags & MEMF_MPIN) + munpin(M->space, M->size); +#endif + munmap(M->space, M->size); + close(M->fd); + if (M->flags & MEMF_FILE) + unlink(M->name); + } + M->space = NULL; + M->size = 0; + } + + if (M->space == NULL) { + if (strchr(M->name, '%')) { + sprintf(filename, M->name, getpid()); + M->name = strdup(filename); + } + + if ((M->fd = + open(M->name, O_CREAT | O_RDWR, 0666)) == -1) { + doio_fprintf(stderr, + "alloc_mmap: error %d (%s) opening '%s'\n", + errno, SYSERR, M->name); + return (-1); + } + + addr = NULL; + flags = 0; + M->size = nbytes * 4; + + /* bias addr if MEMF_ADDR | MEMF_FIXADDR */ + /* >>> how to pick a memory address? */ + + /* bias flags on MEMF_PRIVATE etc */ + if (M->flags & MEMF_PRIVATE) + flags |= MAP_PRIVATE; +#ifdef sgi + if (M->flags & MEMF_LOCAL) + flags |= MAP_LOCAL; + if (M->flags & MEMF_AUTORESRV) + flags |= MAP_AUTORESRV; + if (M->flags & MEMF_AUTOGROW) + flags |= MAP_AUTOGROW; +#endif + if (M->flags & MEMF_SHARED) + flags |= MAP_SHARED; + +/*printf("alloc_mem, about to mmap, fd=%d, name=(%s)\n", M->fd, M->name);*/ + if ((M->space = mmap(addr, M->size, + PROT_READ | PROT_WRITE, + flags, M->fd, 0)) + == MAP_FAILED) { + doio_fprintf(stderr, + "alloc_mem: mmap error. errno %d (%s)\n\tmmap(addr 0x%x, size %d, read|write 0x%x, mmap flags 0x%x [%#o], fd %d, 0)\n\tfile %s\n", + errno, SYSERR, addr, M->size, + PROT_READ | PROT_WRITE, flags, + M->flags, M->fd, M->name); + doio_fprintf(stderr, "\t%s%s%s%s%s", + (flags & MAP_PRIVATE) ? "private " + : "", +#ifdef sgi + (flags & MAP_LOCAL) ? "local " : + "", + (flags & MAP_AUTORESRV) ? + "autoresrv " : "", + (flags & MAP_AUTOGROW) ? + "autogrow " : "", +#endif + (flags & MAP_SHARED) ? "shared" : + ""); + return (-1); + } + } + break; + + case MEM_SHMEM: + if (nbytes > M->size) { + if (M->space != NULL) { +#ifdef sgi + if (M->flags & MEMF_MPIN) + munpin(M->space, M->size); +#endif + shmdt(M->space); +#ifdef sgi + shmctl(M->fd, IPC_RMID); +#else + shmctl(M->fd, IPC_RMID, &shm_ds); +#endif + } + M->space = NULL; + M->size = 0; + } + + if (M->space == NULL) { + if (!strcmp(M->name, "private")) { + key = IPC_PRIVATE; + } else { + sscanf(M->name, "%i", &key); + } + + M->size = M->nblks ? M->nblks * 512 : nbytes; + + if (nbytes > M->size) { +#ifdef DEBUG + doio_fprintf(stderr, + "MEM_SHMEM: nblks(%d) too small: nbytes=%d Msize=%d, skipping this req.\n", + M->nblks, nbytes, M->size); +#endif + return SKIP_REQ; + } + + shmid = shmget(key, M->size, IPC_CREAT | 0666); + if (shmid == -1) { + doio_fprintf(stderr, + "shmget(0x%x, %d, CREAT) failed: %s (%d)\n", + key, M->size, SYSERR, errno); + return (-1); + } + M->fd = shmid; + M->space = shmat(shmid, NULL, SHM_RND); + if (M->space == (void *)-1) { + doio_fprintf(stderr, + "shmat(0x%x, NULL, SHM_RND) failed: %s (%d)\n", + shmid, SYSERR, errno); + return (-1); + } +#ifdef sgi + if (M->flags & MEMF_MPIN) { + if (mpin(M->space, M->size) == -1) { + doio_fprintf(stderr, + "mpin(0x%lx, %d) failed: %s (%d)\n", + M->space, M->size, SYSERR, + errno); + } + } +#endif + } + break; + + default: + doio_fprintf(stderr, + "alloc_mem: HELP! Unknown memory space type %d index %d\n", + Memalloc[me].memtype, mturn); + break; + } + + Memptr = M->space; + Memsize = M->size; + + mturn++; + return 0; +} +#else /* CRAY */ +int alloc_mem(int nbytes) +{ + char *cp; + int ip; + static char *malloc_space; + + /* + * The "unicos" version of this did some stuff with sbrk; + * this caused problems with async I/O on irix, and now appears + * to be causing problems with FSA I/O on unicos/mk. + */ +#ifdef NOTDEF + if (nbytes > Memsize) { + if ((cp = (char *)sbrk(nbytes - Memsize)) == (char *)-1) { + doio_fprintf(stderr, "sbrk(%d) failed: %s (%d)\n", + nbytes - Memsize, SYSERR, errno); + return -1; + } + + if (Memsize == 0) + Memptr = cp; + Memsize += nbytes - Memsize; + } +#else + + /* nbytes = -1 means "free all allocated memory" */ + if (nbytes == -1) { + free(malloc_space); + Memptr = NULL; + Memsize = 0; + return 0; + } + + if (nbytes > Memsize) { + if (Memsize != 0) + free(malloc_space); + + if ((cp = malloc_space = malloc(nbytes)) == NULL) { + doio_fprintf(stderr, "malloc(%d) failed: %s (%d)\n", + nbytes, SYSERR, errno); + return -1; + } +#ifdef _CRAYT3E + /* T3E requires memory to be aligned on 0x40 word boundaries */ + ip = (int)cp; + if ((ip & 0x3F) != 0) { + doio_fprintf(stderr, + "malloc(%d) = 0x%x(0x%x) not aligned by 0x%x\n", + nbytes, cp, ip, ip & 0x3f); + + free(cp); + if ((cp = malloc_space = malloc(nbytes + 0x40)) == NULL) { + doio_fprintf(stderr, + "malloc(%d) failed: %s (%d)\n", + nbytes, SYSERR, errno); + return -1; + } + ip = (int)cp; + cp += (0x40 - (ip & 0x3F)); + } +#endif /* _CRAYT3E */ + Memptr = cp; + Memsize = nbytes; + } +#endif /* NOTDEF */ + return 0; +} +#endif /* CRAY */ + +/* + * Simple function for allocating sds space. Uses Sdssize and Sdsptr to + * keep track of location and size of currently allocated chunk. + */ + +#ifdef _CRAY1 + +int alloc_sds(int nbytes) +{ + int nblks; + + if (nbytes > Sdssize) { + if ((nblks = ssbreak(btoc(nbytes - Sdssize))) == -1) { + doio_fprintf(stderr, "ssbreak(%d) failed: %s (%d)\n", + btoc(nbytes - Sdssize), SYSERR, errno); + return -1; + } + + Sdssize = ctob(nblks); + Sdsptr = 0; + } + + return 0; +} + +#else + +#ifdef CRAY + +int alloc_sds(int nbytes) +{ + doio_fprintf(stderr, + "Internal Error - alloc_sds() called on a CRAY2 system\n"); + alloc_mem(-1); + exit(E_INTERNAL); +} + +#endif + +#endif /* _CRAY1 */ + +/* + * Function to maintain a file descriptor cache, so that doio does not have + * to do so many open() and close() calls. Descriptors are stored in the + * cache by file name, and open flags. Each entry also has a _rtc value + * associated with it which is used in aging. If doio cannot open a file + * because it already has too many open (ie. system limit hit) it will close + * the one in the cache that has the oldest _rtc value. + * + * If alloc_fd() is called with a file of NULL, it will close all descriptors + * in the cache, and free the memory in the cache. + */ + +int alloc_fd(char *file, int oflags) +{ + struct fd_cache *fdc; + struct fd_cache *alloc_fdcache(char *file, int oflags); + + fdc = alloc_fdcache(file, oflags); + if (fdc != NULL) + return (fdc->c_fd); + else + return (-1); +} + +struct fd_cache *alloc_fdcache(char *file, int oflags) +{ + int fd; + struct fd_cache *free_slot, *oldest_slot, *cp; + static int cache_size = 0; + static struct fd_cache *cache = NULL; +#ifdef sgi + struct dioattr finfo; +#endif + + /* + * If file is NULL, it means to free up the fd cache. + */ + + if (file == NULL && cache != NULL) { + for (cp = cache; cp < &cache[cache_size]; cp++) { + if (cp->c_fd != -1) { + close(cp->c_fd); + } +#ifndef CRAY + if (cp->c_memaddr != NULL) { + munmap(cp->c_memaddr, cp->c_memlen); + } +#endif + } + + free(cache); + cache = NULL; + cache_size = 0; + return 0; + } + + free_slot = NULL; + oldest_slot = NULL; + + /* + * Look for a fd in the cache. If one is found, return it directly. + * Otherwise, when this loop exits, oldest_slot will point to the + * oldest fd slot in the cache, and free_slot will point to an + * unoccupied slot if there are any. + */ + + for (cp = cache; cp != NULL && cp < &cache[cache_size]; cp++) { + if (cp->c_fd != -1 && + cp->c_oflags == oflags && strcmp(cp->c_file, file) == 0) { +#ifdef CRAY + cp->c_rtc = _rtc(); +#else + cp->c_rtc = Reqno; +#endif + return cp; + } + + if (cp->c_fd == -1) { + if (free_slot == NULL) { + free_slot = cp; + } + } else { + if (oldest_slot == NULL || + cp->c_rtc < oldest_slot->c_rtc) { + oldest_slot = cp; + } + } + } + + /* + * No matching file/oflags pair was found in the cache. Attempt to + * open a new fd. + */ + + if ((fd = open(file, oflags, 0666)) < 0) { + if (errno != EMFILE) { + doio_fprintf(stderr, + "Could not open file %s with flags %#o (%s): %s (%d)\n", + file, oflags, format_oflags(oflags), + SYSERR, errno); + alloc_mem(-1); + exit(E_SETUP); + } + + /* + * If we get here, we have as many open fd's as we can have. + * Close the oldest one in the cache (pointed to by + * oldest_slot), and attempt to re-open. + */ + + close(oldest_slot->c_fd); + oldest_slot->c_fd = -1; + free_slot = oldest_slot; + + if ((fd = open(file, oflags, 0666)) < 0) { + doio_fprintf(stderr, + "Could not open file %s with flags %#o (%s): %s (%d)\n", + file, oflags, format_oflags(oflags), + SYSERR, errno); + alloc_mem(-1); + exit(E_SETUP); + } + } + +/*printf("alloc_fd: new file %s flags %#o fd %d\n", file, oflags, fd);*/ + + /* + * If we get here, fd is our open descriptor. If free_slot is NULL, + * we need to grow the cache, otherwise free_slot is the slot that + * should hold the fd info. + */ + + if (free_slot == NULL) { + cache = + (struct fd_cache *)realloc(cache, + sizeof(struct fd_cache) * + (FD_ALLOC_INCR + cache_size)); + if (cache == NULL) { + doio_fprintf(stderr, + "Could not malloc() space for fd chace"); + alloc_mem(-1); + exit(E_SETUP); + } + + cache_size += FD_ALLOC_INCR; + + for (cp = &cache[cache_size - FD_ALLOC_INCR]; + cp < &cache[cache_size]; cp++) { + cp->c_fd = -1; + } + + free_slot = &cache[cache_size - FD_ALLOC_INCR]; + } + + /* + * finally, fill in the cache slot info + */ + + free_slot->c_fd = fd; + free_slot->c_oflags = oflags; + strcpy(free_slot->c_file, file); +#ifdef CRAY + free_slot->c_rtc = _rtc(); +#else + free_slot->c_rtc = Reqno; +#endif + +#ifdef sgi + if (oflags & O_DIRECT) { + if (fcntl(fd, F_DIOINFO, &finfo) == -1) { + finfo.d_mem = 1; + finfo.d_miniosz = 1; + finfo.d_maxiosz = 1; + } + } else { + finfo.d_mem = 1; + finfo.d_miniosz = 1; + finfo.d_maxiosz = 1; + } + + free_slot->c_memalign = finfo.d_mem; + free_slot->c_miniosz = finfo.d_miniosz; + free_slot->c_maxiosz = finfo.d_maxiosz; +#endif /* sgi */ +#ifndef CRAY + free_slot->c_memaddr = NULL; + free_slot->c_memlen = 0; +#endif + + return free_slot; +} + +/* + * + * Signal Handling Section + * + * + */ + +#ifdef sgi +/* + * "caller-id" for signals + */ +void signal_info(int sig, siginfo_t * info, void *v) +{ + int haveit = 0; + + if (info != NULL) { + switch (info->si_code) { + case SI_USER: + doio_fprintf(stderr, + "signal_info: si_signo %d si_errno %d si_code SI_USER pid %d uid %d\n", + info->si_signo, info->si_errno, + info->si_pid, info->si_uid); + haveit = 1; + break; + + case SI_QUEUE: + doio_fprintf(stderr, + "signal_info si_signo %d si_code = SI_QUEUE\n", + info->si_signo); + haveit = 1; + break; + } + + if (!haveit) { + if ((info->si_signo == SIGSEGV) || + (info->si_signo == SIGBUS)) { + doio_fprintf(stderr, + "signal_info si_signo %d si_errno %d si_code = %d si_addr=%p active_mmap_rw=%d havesigint=%d\n", + info->si_signo, info->si_errno, + info->si_code, info->si_addr, + active_mmap_rw, havesigint); + haveit = 1; + } + } + + if (!haveit) { + doio_fprintf(stderr, + "signal_info: si_signo %d si_errno %d unknown code %d\n", + info->si_signo, info->si_errno, + info->si_code); + } + } else { + doio_fprintf(stderr, "signal_info: sig %d\n", sig); + } +} + +void cleanup_handler(int sig, siginfo_t * info, void *v) +{ + havesigint = 1; /* in case there's a followup signal */ + /*signal_info(sig, info, v); *//* be quiet on "normal" kill */ + alloc_mem(-1); + exit(0); +} + +void die_handler(int sig, siginfo_t * info, void *v) +{ + doio_fprintf(stderr, "terminating on signal %d\n", sig); + signal_info(sig, info, v); + alloc_mem(-1); + exit(1); +} + +void sigbus_handler(int sig, siginfo_t * info, void *v) +{ + /* While we are doing a memcpy to/from an mmapped region we can + get a SIGBUS for a variety of reasons--and not all of them + should be considered failures. + + Under normal conditions if we get a SIGINT it means we've been + told to shutdown. However, if we're currently doing the above- + mentioned memcopy then the kernel will follow that SIGINT with + a SIGBUS. We can guess that we're in this situation by seeing + that the si_errno field in the siginfo structure has EINTR as + an errno. (We might make the guess stronger by looking at the + si_addr field to see that it's not faulting off the end of the + mmapped region, but it seems that in such a case havesigint + would not have been set so maybe that doesn't make the guess + stronger.) + */ + + if (active_mmap_rw && havesigint && (info->si_errno == EINTR)) { + cleanup_handler(sig, info, v); + } else { + die_handler(sig, info, v); + } +} +#else + +void cleanup_handler(int sig) +{ + havesigint = 1; /* in case there's a followup signal */ + alloc_mem(-1); + exit(0); +} + +void die_handler(int sig) +{ + doio_fprintf(stderr, "terminating on signal %d\n", sig); + alloc_mem(-1); + exit(1); +} + +#ifndef CRAY +void sigbus_handler(int sig) +{ + /* See sigbus_handler() in the 'ifdef sgi' case for details. Here, + we don't have the siginfo stuff so the guess is weaker but we'll + do it anyway. + */ + + if (active_mmap_rw && havesigint) + cleanup_handler(sig); + else + die_handler(sig); +} +#endif /* !CRAY */ +#endif /* sgi */ + +void noop_handler(int sig) +{ + return; +} + +/* + * SIGINT handler for the parent (original doio) process. It simply sends + * a SIGINT to all of the doio children. Since they're all in the same + * pgrp, this can be done with a single kill(). + */ + +void sigint_handler(int sig) +{ + int i; + + for (i = 0; i < Nchildren; i++) { + if (Children[i] != -1) { + kill(Children[i], SIGINT); + } + } +} + +/* + * Signal handler used to inform a process when async io completes. Referenced + * in do_read() and do_write(). Note that the signal handler is not + * re-registered. + */ + +void aio_handler(int sig) +{ + unsigned int i; + struct aio_info *aiop; + + for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) { + aiop = &Aio_Info[i]; + + if (aiop->strategy == A_SIGNAL && aiop->sig == sig) { + aiop->signalled++; + + if (aio_done(aiop)) { + aiop->done++; + } + } + } +} + +/* + * dump info on all open aio slots + */ +void dump_aio(void) +{ + unsigned int i, count; + + count = 0; + for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) { + if (Aio_Info[i].busy) { + count++; + fprintf(stderr, + "Aio_Info[%03d] id=%d fd=%d signal=%d signaled=%d\n", + i, Aio_Info[i].id, + Aio_Info[i].fd, + Aio_Info[i].sig, Aio_Info[i].signalled); + fprintf(stderr, "\tstrategy=%s\n", + format_strat(Aio_Info[i].strategy)); + } + } + fprintf(stderr, "%d active async i/os\n", count); +} + +#ifdef sgi +/* + * Signal handler called as a callback, not as a signal. + * 'val' is the value from sigev_value and is assumed to be the + * Aio_Info[] index. + */ +void cb_handler(sigval_t val) +{ + struct aio_info *aiop; + +/*printf("cb_handler requesting slot %d\n", val.sival_int);*/ + aiop = aio_slot(val.sival_int); +/*printf("cb_handler, aiop=%p\n", aiop);*/ + +/*printf("%d in cb_handler\n", getpid() );*/ + if (aiop->strategy == A_CALLBACK) { + aiop->signalled++; + + if (aio_done(aiop)) { + aiop->done++; + } + } +} +#endif + +struct aio_info *aio_slot(int aio_id) +{ + unsigned int i; + static int id = 1; + struct aio_info *aiop; + + aiop = NULL; + + for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) { + if (aio_id == -1) { + if (!Aio_Info[i].busy) { + aiop = &Aio_Info[i]; + aiop->busy = 1; + aiop->id = id++; + break; + } + } else { + if (Aio_Info[i].busy && Aio_Info[i].id == aio_id) { + aiop = &Aio_Info[i]; + break; + } + } + } + + if (aiop == NULL) { + doio_fprintf(stderr, "aio_slot(%d) not found. Request %d\n", + aio_id, Reqno); + dump_aio(); + alloc_mem(-1); + exit(E_INTERNAL); + } + + return aiop; +} + +int aio_register(int fd, int strategy, int sig) +{ + struct aio_info *aiop; + struct sigaction sa; + + aiop = aio_slot(-1); + + aiop->fd = fd; + aiop->strategy = strategy; + aiop->done = 0; +#ifdef CRAY + memset((char *)&aiop->iosw, 0x00, sizeof(aiop->iosw)); +#endif + + if (strategy == A_SIGNAL) { + aiop->sig = sig; + aiop->signalled = 0; + + sa.sa_handler = aio_handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + + sigaction(sig, &sa, &aiop->osa); + } else { + aiop->sig = -1; + aiop->signalled = 0; + } + + return aiop->id; +} + +int aio_unregister(int aio_id) +{ + struct aio_info *aiop; + + aiop = aio_slot(aio_id); + + if (aiop->strategy == A_SIGNAL) { + sigaction(aiop->sig, &aiop->osa, NULL); + } + + aiop->busy = 0; + return 0; +} + +#ifndef __linux__ +int aio_wait(int aio_id) +{ +#ifdef RECALL_SIZEOF + long mask[RECALL_SIZEOF]; +#endif + sigset_t signalset; + struct aio_info *aiop; +#ifdef CRAY + struct iosw *ioswlist[1]; +#endif +#ifdef sgi + const aiocb_t *aioary[1]; +#endif + int r, cnt; + + aiop = aio_slot(aio_id); +/*printf("%d aiop B =%p\n", getpid(), aiop);*/ + + switch (aiop->strategy) { + case A_POLL: + while (!aio_done(aiop)) ; + break; + + case A_SIGNAL: + sigemptyset(&signalset); + sighold(aiop->sig); + + while (!aiop->signalled || !aiop->done) { + sigsuspend(&signalset); + sighold(aiop->sig); + } + break; + +#ifdef CRAY + case A_RECALL: + ioswlist[0] = &aiop->iosw; + if (recall(aiop->fd, 1, ioswlist) < 0) { + doio_fprintf(stderr, "recall() failed: %s (%d)\n", + SYSERR, errno); + exit(E_SETUP); + } + break; + +#ifdef RECALL_SIZEOF + + case A_RECALLA: + RECALL_INIT(mask); + RECALL_SET(mask, aiop->fd); + if (recalla(mask) < 0) { + doio_fprintf(stderr, "recalla() failed: %s (%d)\n", + SYSERR, errno); + exit(E_SETUP); + } + + RECALL_CLR(mask, aiop->fd); + break; +#endif + + case A_RECALLS: + ioswlist[0] = &aiop->iosw; + if (recalls(1, ioswlist) < 0) { + doio_fprintf(stderr, "recalls failed: %s (%d)\n", + SYSERR, errno); + exit(E_SETUP); + } + break; +#endif /* CRAY */ + +#ifdef sgi + case A_CALLBACK: + aioary[0] = &aiop->aiocb; + cnt = 0; + do { + r = aio_suspend(aioary, 1, NULL); + if (r == -1) { + doio_fprintf(stderr, + "aio_suspend failed: %s (%d)\n", + SYSERR, errno); + exit(E_SETUP); + } + cnt++; + } while (aiop->done == 0); + +#if 0 + /* + * after having this set for a while, I've decided that + * it's too noisy + */ + if (cnt > 1) + doio_fprintf(stderr, + "aio_wait: callback wait took %d tries\n", + cnt); +#endif + + /* + * Note: cb_handler already calls aio_done + */ + break; + + case A_SUSPEND: + aioary[0] = &aiop->aiocb; + r = aio_suspend(aioary, 1, NULL); + if (r == -1) { + doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n", + SYSERR, errno); + exit(E_SETUP); + } + + aio_done(aiop); + break; +#endif + } + +/*printf("aio_wait: errno %d return %d\n", aiop->aio_errno, aiop->aio_ret);*/ + + return 0; +} +#endif /* !linux */ + +/* + * Format specified time into HH:MM:SS format. t is the time to format + * in seconds (as returned from time(2)). + */ + +char *hms(time_t t) +{ + static char ascii_time[9]; + struct tm *ltime; + + ltime = localtime(&t); + strftime(ascii_time, sizeof(ascii_time), "%H:%M:%S", ltime); + + return ascii_time; +} + +/* + * Simple routine to check if an async io request has completed. + */ + +int aio_done(struct aio_info *ainfo) +{ +#ifdef CRAY + return ainfo->iosw.sw_flag; +#endif + +#ifdef sgi + if ((ainfo->aio_errno = aio_error(&ainfo->aiocb)) == -1) { + doio_fprintf(stderr, "aio_done: aio_error failed: %s (%d)\n", + SYSERR, errno); + exit(E_SETUP); + } + /*printf("%d aio_done aio_errno=%d\n", getpid(), ainfo->aio_errno); */ + if (ainfo->aio_errno != EINPROGRESS) { + if ((ainfo->aio_ret = aio_return(&ainfo->aiocb)) == -1) { + doio_fprintf(stderr, + "aio_done: aio_return failed: %s (%d)\n", + SYSERR, errno); + exit(E_SETUP); + } + } + + return (ainfo->aio_errno != EINPROGRESS); +#else + return -1; /* invalid */ +#endif +} + +/* + * Routine to handle upanic() - it first attempts to set the panic flag. If + * the flag cannot be set, an error message is issued. A call to upanic + * with PA_PANIC is then done unconditionally, in case the panic flag was set + * from outside the program (as with the panic(8) program). + * + * Note - we only execute the upanic code if -U was used, and the passed in + * mask is set in the Upanic_Conditions bitmask. + */ + +void doio_upanic(int mask) +{ + if (U_opt == 0 || (mask & Upanic_Conditions) == 0) { + return; + } +#ifdef CRAY + if (upanic(PA_SET) < 0) { + doio_fprintf(stderr, + "WARNING - Could not set the panic flag - upanic(PA_SET) failed: %s (%d)\n", + SYSERR, errno); + } + + upanic(PA_PANIC); +#endif +#ifdef sgi + syssgi(1005); /* syssgi test panic - DEBUG kernels only */ +#endif + doio_fprintf(stderr, "WARNING - upanic() failed\n"); +} + +/* + * Parse cmdline options/arguments and set appropriate global variables. + * If the cmdline is valid, return 0 to caller. Otherwise exit with a status + * of 1. + */ + +int parse_cmdline(int argc, char **argv, char *opts) +{ + int c; + char cc, *cp = NULL, *tok = NULL; + extern int opterr; + extern int optind; + extern char *optarg; + struct smap *s; + char *memargs[NMEMALLOC]; + int nmemargs, ma; + + if (*argv[0] == '-') { + argv[0]++; + Execd = 1; + } + + if ((Prog = strrchr(argv[0], '/')) == NULL) { + Prog = argv[0]; + } else { + Prog++; + } + + opterr = 0; + while ((c = getopt(argc, argv, opts)) != EOF) { + switch ((char)c) { + case 'a': + a_opt++; + break; + + case 'C': + C_opt++; + for (s = checkmap; s->string != NULL; s++) + if (!strcmp(s->string, optarg)) + break; + if (s->string == NULL && tok != NULL) { + fprintf(stderr, + "%s%s: Illegal -C arg (%s). Must be one of: ", + Prog, TagName, tok); + + for (s = checkmap; s->string != NULL; s++) + fprintf(stderr, "%s ", s->string); + fprintf(stderr, "\n"); + exit(1); + } + + switch (s->value) { + case C_DEFAULT: + Data_Fill = doio_pat_fill; + Data_Check = doio_pat_check; + break; + default: + fprintf(stderr, + "%s%s: Unrecognised -C arg '%s' %d", + Prog, TagName, s->string, s->value); + exit(1); + } + break; + + case 'd': /* delay between i/o ops */ + parse_delay(optarg); + break; + + case 'e': + if (Npes > 1 && Nprocs > 1) { + fprintf(stderr, + "%s%s: Warning - Program is a multi-pe application - exec option is ignored.\n", + Prog, TagName); + } + e_opt++; + break; + + case 'h': + help(stdout); + exit(0); + break; + + case 'k': + k_opt++; + break; + + case 'm': + Message_Interval = strtol(optarg, &cp, 10); + if (*cp != '\0' || Message_Interval < 0) { + fprintf(stderr, + "%s%s: Illegal -m arg (%s): Must be an integer >= 0\n", + Prog, TagName, optarg); + exit(1); + } + m_opt++; + break; + + case 'M': /* memory allocation types */ +#ifndef CRAY + nmemargs = string_to_tokens(optarg, memargs, 32, ","); + for (ma = 0; ma < nmemargs; ma++) { + parse_memalloc(memargs[ma]); + } + /*dump_memalloc(); */ +#else + fprintf(stderr, + "%s%s: Error: -M isn't supported on this platform\n", + Prog, TagName); + exit(1); +#endif + M_opt++; + break; + + case 'N': + sprintf(TagName, "(%.39s)", optarg); + break; + + case 'n': + Nprocs = strtol(optarg, &cp, 10); + if (*cp != '\0' || Nprocs < 1) { + fprintf(stderr, + "%s%s: Illegal -n arg (%s): Must be integer > 0\n", + Prog, TagName, optarg); + exit(E_USAGE); + } + + if (Npes > 1 && Nprocs > 1) { + fprintf(stderr, + "%s%s: Program has been built as a multi-pe app. -n1 is the only nprocs value allowed\n", + Prog, TagName); + exit(E_SETUP); + } + n_opt++; + break; + + case 'r': + Release_Interval = strtol(optarg, &cp, 10); + if (*cp != '\0' || Release_Interval < 0) { + fprintf(stderr, + "%s%s: Illegal -r arg (%s): Must be integer >= 0\n", + Prog, TagName, optarg); + exit(E_USAGE); + } + + r_opt++; + break; + + case 'w': + Write_Log = optarg; + w_opt++; + break; + + case 'v': + v_opt++; + break; + + case 'V': + if (strcasecmp(optarg, "sync") == 0) { + Validation_Flags = O_SYNC; + } else if (strcasecmp(optarg, "buffered") == 0) { + Validation_Flags = 0; +#ifdef CRAY + } else if (strcasecmp(optarg, "parallel") == 0) { + Validation_Flags = O_PARALLEL; + } else if (strcasecmp(optarg, "ldraw") == 0) { + Validation_Flags = O_LDRAW; + } else if (strcasecmp(optarg, "raw") == 0) { + Validation_Flags = O_RAW; +#endif +#ifdef sgi + } else if (strcasecmp(optarg, "direct") == 0) { + Validation_Flags = O_DIRECT; +#endif + } else { + if (sscanf + (optarg, "%i%c", &Validation_Flags, + &cc) != 1) { + fprintf(stderr, + "%s: Invalid -V argument (%s) - must be a decimal, hex, or octal\n", + Prog, optarg); + fprintf(stderr, + " number, or one of the following strings: 'sync',\n"); + fprintf(stderr, + " 'buffered', 'parallel', 'ldraw', or 'raw'\n"); + exit(E_USAGE); + } + } + V_opt++; + break; + case 'U': + tok = strtok(optarg, ","); + while (tok != NULL) { + for (s = Upanic_Args; s->string != NULL; s++) + if (strcmp(s->string, tok) == 0) + break; + + if (s->string == NULL) { + fprintf(stderr, + "%s%s: Illegal -U arg (%s). Must be one of: ", + Prog, TagName, tok); + + for (s = Upanic_Args; s->string != NULL; + s++) + fprintf(stderr, "%s ", + s->string); + + fprintf(stderr, "\n"); + + exit(1); + } + + Upanic_Conditions |= s->value; + tok = strtok(NULL, ","); + } + + U_opt++; + break; + + case '?': + usage(stderr); + exit(E_USAGE); + break; + } + } + + /* + * Supply defaults + */ + + if (!C_opt) { + Data_Fill = doio_pat_fill; + Data_Check = doio_pat_check; + } + + if (!U_opt) + Upanic_Conditions = 0; + + if (!n_opt) + Nprocs = 1; + + if (!r_opt) + Release_Interval = DEF_RELEASE_INTERVAL; + + if (!M_opt) { + Memalloc[Nmemalloc].memtype = MEM_DATA; + Memalloc[Nmemalloc].flags = 0; + Memalloc[Nmemalloc].name = NULL; + Memalloc[Nmemalloc].space = NULL; + Nmemalloc++; + } + + /* + * Initialize input stream + */ + + if (argc == optind) { + Infile = NULL; + } else { + Infile = argv[optind++]; + } + + if (argc != optind) { + usage(stderr); + exit(E_USAGE); + } + + return 0; +} + +/* + * Parse memory allocation types + * + * Types are: + * Data + * T3E-shmem:blksize[:nblks] + * SysV-shmem:shmid:blksize:nblks + * if shmid is "private", use IPC_PRIVATE + * and nblks is not required + * + * mmap:flags:filename:blksize[:nblks] + * flags are one of: + * p - private (MAP_PRIVATE) + * a - private, MAP_AUTORESRV + * l - local (MAP_LOCAL) + * s - shared (nblks required) + * + * plus any of: + * f - fixed address (MAP_FIXED) + * A - use an address without MAP_FIXED + * a - autogrow (map once at startup) + * + * mmap:flags:devzero + * mmap /dev/zero (shared not allowd) + * maps the first 4096 bytes of /dev/zero + * + * - put a directory at the beginning of the shared + * regions saying what pid has what region. + * DIRMAGIC + * BLKSIZE + * NBLKS + * nblks worth of directories - 1 int pids + */ +#ifndef CRAY +void parse_memalloc(char *arg) +{ + char *allocargs[NMEMALLOC]; + int nalloc; + struct memalloc *M; + + if (Nmemalloc >= NMEMALLOC) { + doio_fprintf(stderr, "Error - too many memory types (%d).\n", + Nmemalloc); + return; + } + + M = &Memalloc[Nmemalloc]; + + nalloc = string_to_tokens(arg, allocargs, 32, ":"); + if (!strcmp(allocargs[0], "data")) { + M->memtype = MEM_DATA; + M->flags = 0; + M->name = NULL; + M->space = NULL; + Nmemalloc++; + if (nalloc >= 2) { + if (strchr(allocargs[1], 'p')) + M->flags |= MEMF_MPIN; + } + } else if (!strcmp(allocargs[0], "mmap")) { + /* mmap:flags:filename[:size] */ + M->memtype = MEM_MMAP; + M->flags = 0; + M->space = NULL; + if (nalloc >= 1) { + if (strchr(allocargs[1], 'p')) + M->flags |= MEMF_PRIVATE; + if (strchr(allocargs[1], 'a')) + M->flags |= MEMF_AUTORESRV; + if (strchr(allocargs[1], 'l')) + M->flags |= MEMF_LOCAL; + if (strchr(allocargs[1], 's')) + M->flags |= MEMF_SHARED; + + if (strchr(allocargs[1], 'f')) + M->flags |= MEMF_FIXADDR; + if (strchr(allocargs[1], 'A')) + M->flags |= MEMF_ADDR; + if (strchr(allocargs[1], 'G')) + M->flags |= MEMF_AUTOGROW; + + if (strchr(allocargs[1], 'U')) + M->flags |= MEMF_FILE; + } else { + M->flags |= MEMF_PRIVATE; + } + + if (nalloc > 2) { + if (!strcmp(allocargs[2], "devzero")) { + M->name = "/dev/zero"; + if (M->flags & + ((MEMF_PRIVATE | MEMF_LOCAL) == 0)) + M->flags |= MEMF_PRIVATE; + } else { + M->name = allocargs[2]; + } + } else { + M->name = "/dev/zero"; + if (M->flags & ((MEMF_PRIVATE | MEMF_LOCAL) == 0)) + M->flags |= MEMF_PRIVATE; + } + Nmemalloc++; + + } else if (!strcmp(allocargs[0], "shmem")) { + /* shmem:shmid:size */ + M->memtype = MEM_SHMEM; + M->flags = 0; + M->space = NULL; + if (nalloc >= 2) { + M->name = allocargs[1]; + } else { + M->name = NULL; + } + if (nalloc >= 3) { + sscanf(allocargs[2], "%i", &M->nblks); + } else { + M->nblks = 0; + } + if (nalloc >= 4) { + if (strchr(allocargs[3], 'p')) + M->flags |= MEMF_MPIN; + } + + Nmemalloc++; + } else { + doio_fprintf(stderr, "Error - unknown memory type '%s'.\n", + allocargs[0]); + exit(1); + } +} + +void dump_memalloc(void) +{ + int ma; + char *mt; + + if (Nmemalloc == 0) { + printf("No memory allocation strategies devined\n"); + return; + } + + for (ma = 0; ma < Nmemalloc; ma++) { + switch (Memalloc[ma].memtype) { + case MEM_DATA: + mt = "data"; + break; + case MEM_SHMEM: + mt = "shmem"; + break; + case MEM_MMAP: + mt = "mmap"; + break; + default: + mt = "unknown"; + break; + } + printf("mstrat[%d] = %d %s\n", ma, Memalloc[ma].memtype, mt); + printf("\tflags=%#o name='%s' nblks=%d\n", + Memalloc[ma].flags, + Memalloc[ma].name, Memalloc[ma].nblks); + } +} + +#endif /* !CRAY */ + +/* + * -d :

+What is this? | +How to build? | +How to run? | +V4L2 | +Code Coverage | +Status | +Results | +Similar projects | +Feedback
+