diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 15d3289..972e898 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,9 +25,12 @@ jobs: - name: Build project run: scripts/linux/build.sh - - name: Run example + - name: Test project run: scripts/linux/test.sh + - name: Run example + run: scripts/linux/example.sh + qemu-linux-x86_64: runs-on: ubuntu-latest strategy: @@ -59,7 +62,7 @@ jobs: run: scripts/qemu/build.sh ${{ matrix.kernel }} - name: Run example - run: scripts/qemu/test.sh + run: scripts/qemu/example.sh release: needs: [linux-x86_64, qemu-linux-x86_64] diff --git a/.gitignore b/.gitignore index 2afb629..5050f07 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,4 @@ m4/* !m4/ac_sphinx.m4 !m4/ac_docs_enable.m4 !m4/ax_pthread.m4 +!m4/ax_check_link_flag.m4 diff --git a/Makefile.am b/Makefile.am index fc9b25c..81bf7a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,15 +1,15 @@ ACLOCAL_AMFLAGS = -I m4 if BUILD_EXAMPLES - MAYBE_EXAMPLES = examples +MAYBE_EXAMPLES = examples endif if BUILD_BENCHMARK - MAYBE_BENCHMARK = benchmark +MAYBE_BENCHMARK = benchmark endif if BUILD_DOCS - MAYBE_DOCS = doc +MAYBE_DOCS = doc endif SUBDIRS = src/module src/lib src/util $(MAYBE_EXAMPLES) $(MAYBE_BENCHMARK) $(MAYBE_DOCS) diff --git a/README.md b/README.md index 02b884b..50e89c9 100644 --- a/README.md +++ b/README.md @@ -36,15 +36,18 @@ A PDF version of the documentation is also available [here](https://github.com/M - libtool - pkg-config - linux-headers -- sphinx [1](#f1) -- doxygen [1](#f1) -- breathe [1](#f1) -- sphinx_rtd_theme [1](#f1) -- latex [2](#f2) +- check [1](#f1) +- sphinx [2](#f2) +- doxygen [2](#f2) +- breathe [2](#f2) +- sphinx_rtd_theme [2](#f2) +- latex [3](#f3) -1 Optional: needed only to build the documentation +1 Optional: needed only for userspace library tests -2 Optional: needed only to build the pdf documentation +2 Optional: needed only to build the documentation + +3 Optional: needed only to build the pdf documentation ### Minimal Build @@ -52,7 +55,8 @@ Build the userspace library and the LKM and install them into the system with: ``` $ ./configure $ make -$ make install +$ make check +$ sudo make install $ sudo ldconfig $ sudo modprobe ums ``` @@ -65,9 +69,9 @@ The following dependencies are needed in case of development build: - autoconf - automake - git -- cppcheck [3](#f2) +- cppcheck [4](#f4) -3 Optional: needed only for userspace library static code analysis +4 Optional: needed only for userspace library static code analysis ### Development Build diff --git a/benchmark/configure.ac b/benchmark/configure.ac index 60995c7..4934ef8 100644 --- a/benchmark/configure.ac +++ b/benchmark/configure.ac @@ -19,6 +19,11 @@ AC_PROG_CC LT_PREREQ([2.4]) LT_INIT +AC_PATH_PROG([CPPCHECK], [cppcheck], [true]) +AS_IF([test "x$CPPCHECK" = xtrue], [ + AC_MSG_WARN(['cppcheck' is recommended for developing this package.]) +]) + # Use the C language and compiler for the following checks AC_LANG([C]) diff --git a/doc/install.rst b/doc/install.rst index 8042181..1a93518 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -11,14 +11,16 @@ Minimal Requirements - libtool - pkg-config - linux-headers -- sphinx\ [#f1]_ -- doxygen\ [#f1]_ -- breathe\ [#f1]_ -- sphinx_rtd_theme\ [#f1]_ -- latex\ [#f2]_ +- check\ [#f1]_ +- sphinx\ [#f2]_ +- doxygen\ [#f2]_ +- breathe\ [#f2]_ +- sphinx_rtd_theme\ [#f2]_ +- latex\ [#f3]_ -.. [#f1] Optional: needed only to build the documentation -.. [#f2] Optional: needed only to build the pdf documentation +.. [#f1] Optional: needed only for userspace library tests +.. [#f2] Optional: needed only to build the documentation +.. [#f3] Optional: needed only to build the pdf documentation Development Requirements ======================== @@ -29,9 +31,9 @@ The following dependencies are needed in case of development build: - autoconf - automake - git -- cppcheck\ [#f3]_ +- cppcheck\ [#f4]_ -.. [#f3] Optional: needed only for userspace library static code analysis +.. [#f4] Optional: needed only for userspace library static code analysis Build ===== @@ -103,6 +105,7 @@ Targets ``html`` Build the html documentation ``pdf`` Build the pdf documentation ``install`` Install into the system +``installcheck`` Install tests into the system ``uninstall`` Uninstall from the system ``clean`` Delete all files in the current directory that are normally created by building the program @@ -110,11 +113,14 @@ Targets created by configuring or building the program ========================== ==================================================== -Install -======= +Minimal installation steps +========================== .. code:: - $ make install + $ ./configure + $ make + $ make check + $ sudo make install $ sudo ldconfig $ sudo modprobe ums diff --git a/doc/userspace/internals/library_lifecycle.rst b/doc/userspace/internals/library_lifecycle.rst index b88d0ba..d6df975 100644 --- a/doc/userspace/internals/library_lifecycle.rst +++ b/doc/userspace/internals/library_lifecycle.rst @@ -23,7 +23,7 @@ In particular the :c:var:`UMS_FILENO` is declared as .. literalinclude:: /../src/lib/src/private.h :language: c - :lines: 18 + :lines: 20 :lineno-match: :dedent: :caption: src/lib/src/private.h diff --git a/doc/userspace/internals/scheduler.rst b/doc/userspace/internals/scheduler.rst index d8bac39..b764283 100644 --- a/doc/userspace/internals/scheduler.rst +++ b/doc/userspace/internals/scheduler.rst @@ -15,7 +15,7 @@ in particular the :c:func:`enter_ums_scheduling_mode()` begins with: .. literalinclude:: /../src/lib/src/scheduler.c :language: c - :lines: 13-21 + :lines: 13-27 :lineno-match: :dedent: :caption: src/lib/src/scheduler.c @@ -24,7 +24,7 @@ where the ``enter_ums_mode`` is defined at .. literalinclude:: /../src/lib/src/private.h :language: c - :lines: 20-23 + :lines: 22-25 :lineno-match: :dedent: :caption: src/lib/src/private.h @@ -36,7 +36,7 @@ UMS :c:type:`ums_scheduler_entry_point_t`. .. literalinclude:: /../src/lib/src/scheduler.c :language: c - :lines: 23-61 + :lines: 29-67 :lineno-match: :dedent: :caption: src/lib/src/scheduler.c @@ -48,7 +48,7 @@ The execution of a worker thread context is implemented as follows: .. literalinclude:: /../src/lib/src/scheduler.c :language: c - :lines: 66-69 + :lines: 72-75 :lineno-match: :dedent: :caption: src/lib/src/scheduler.c diff --git a/doc/userspace/internals/worker.rst b/doc/userspace/internals/worker.rst index aaffb3e..69da521 100644 --- a/doc/userspace/internals/worker.rst +++ b/doc/userspace/internals/worker.rst @@ -16,7 +16,7 @@ The function is implemented as follows: .. literalinclude:: /../src/lib/src/worker.c :language: c - :lines: 53-70 + :lines: 53-75 :lineno-match: :dedent: :caption: src/lib/src/worker.c @@ -56,7 +56,7 @@ The yielding of a UMS worker thread is implemented as follows: .. literalinclude:: /../src/lib/src/worker.c :language: c - :lines: 72-75 + :lines: 77-80 :lineno-match: :dedent: :caption: src/lib/src/worker.c diff --git a/m4/ax_check_link_flag.m4 b/m4/ax_check_link_flag.m4 new file mode 100644 index 0000000..03a30ce --- /dev/null +++ b/m4/ax_check_link_flag.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker 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 linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_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_LINK_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS diff --git a/qemu/configs/qemu_x86_64_defconfig b/qemu/configs/qemu_x86_64_defconfig index 84d33b0..77d176d 100755 --- a/qemu/configs/qemu_x86_64_defconfig +++ b/qemu/configs/qemu_x86_64_defconfig @@ -36,6 +36,12 @@ BR2_ROOTFS_OVERLAY="../rootfs_overlay" # OpenSSH BR2_PACKAGE_OPENSSH=y +# check +BR2_PACKAGE_CHECK=y + +# pkg-config +BR2_PACKAGE_PKGCONF=y + BR2_PACKAGE_HOST_ENVIRONMENT_SETUP=y EOF diff --git a/scripts/build/build-sdk.sh b/scripts/build/build-sdk.sh index b7ba6b7..6ed6d44 100755 --- a/scripts/build/build-sdk.sh +++ b/scripts/build/build-sdk.sh @@ -91,6 +91,7 @@ rm $SDK_NAME.tar.gz sed -i "/alias configure=/d" $SDK_NAME/environment-setup sed -i "/export \"KERNELDIR=/c\export \"KERNELDIR=\$(dirname \$(dirname \$SDK_PATH))/linux-$KERNEL_VERSION\"" \ $SDK_NAME/environment-setup +echo "export \"PKG_CONFIG_SYSROOT_DIR=\$SDK_NAME\"" >> $SDK_NAME/environment-setup rm start-qemu.sh cd $WORKDIR && mkdir -p $OUTPUT_DIR diff --git a/scripts/linux/build.sh b/scripts/linux/build.sh index 190c1bb..2213df0 100755 --- a/scripts/linux/build.sh +++ b/scripts/linux/build.sh @@ -49,4 +49,3 @@ cd $BUILDDIR $BASEDIR/configure CFLAGS="-ggdb3" --enable-examples make -j $(nproc) V=1 -make -j $(nproc) V=1 check diff --git a/scripts/linux/example.sh b/scripts/linux/example.sh new file mode 100755 index 0000000..4362188 --- /dev/null +++ b/scripts/linux/example.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash + +set -eo pipefail +if [ ! -z "${CI+x}" ] || [ "$CI" = "true" ]; then + set -x +fi + +BASEDIR=$(dirname $(dirname $(dirname $(realpath "$0")))) +ME=$(basename "$0") + +usage() { + cat <&2 + usage >&2 + exit 1 + ;; + :) + echo "missing value for option [-$OPTARG]" >&2 + usage >&2 + exit 1 + ;; + esac +done +shift $(($OPTIND - 1)) + +$BASEDIR/scripts/linux/install.sh -i $BUILDDIR + +mkdir -p $LOGDIR + +readarray -d '' examples < <(find $EXAMPLESDIR/*/.libs -type f -print0) + +for e in "${examples[@]}"; do + EXAMPLE_NAME=$(basename $e) + EXAMPLE_TIMESTAMP=$(date +%s) + LOGPREFIX=$LOGDIR/$EXAMPLE_NAME-$EXAMPLE_TIMESTAMP + GDB_LOGFILE=$LOGPREFIX.gdb.log + TEST_LOGFILE=$LOGPREFIX.out.log + set +e + printf "\033[1;32m[TEST] %s\033[0m\n" $EXAMPLE_NAME + + timeout -s SIGINT $TEST_TIMEOUT gdb -batch -q -n \ + -ex "set pagination off" \ + -ex "set logging file $GDB_LOGFILE" \ + -ex "set logging on" \ + -ex "file $e" \ + -ex "run > $TEST_LOGFILE" \ + -ex "call setvbuf(stdout, 0, 2, 0)" \ + -ex "thread apply all bt full" &> /dev/null + EXIT_STATUS=$? + set -e; set +x + + printf "\033[1;32mOUTPUT:\033[0m\n" + cat $TEST_LOGFILE + + if [ $EXIT_STATUS != 0 ]; then + printf "\n\033[1;32mGDB:\033[0m\n" + cat $GDB_LOGFILE + + printf "\n\033[1;32mDMESG:\033[0m\n" + dmesg | grep ums + + exit $EXIT_STATUS + fi + + if [ ! -z "${CI+x}" ] || [ "$CI" = "true" ]; then + set -x + fi +done diff --git a/scripts/linux/install_deps.sh b/scripts/linux/install_deps.sh index 6588fa5..86fe482 100755 --- a/scripts/linux/install_deps.sh +++ b/scripts/linux/install_deps.sh @@ -14,4 +14,5 @@ sudo apt-get install -y \ libtool \ pkg-config \ gdb \ + check \ cppcheck diff --git a/scripts/linux/test.sh b/scripts/linux/test.sh index baafbac..a85b0f1 100755 --- a/scripts/linux/test.sh +++ b/scripts/linux/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -eo pipefail +set -e if [ ! -z "${CI+x}" ] || [ "$CI" = "true" ]; then set -x fi @@ -10,30 +10,23 @@ ME=$(basename "$0") usage() { cat <&2 usage >&2 @@ -48,46 +41,5 @@ while getopts ":hb:l:t:" opt; do done shift $(($OPTIND - 1)) -$BASEDIR/scripts/linux/install.sh -i $BUILDDIR - -mkdir -p $LOGDIR - -readarray -d '' tests < <(find $TESTDIR/*/.libs -type f -print0) - -for t in "${tests[@]}"; do - TEST_NAME=$(basename $t) - TEST_TIMESTAMP=$(date +%s) - LOGPREFIX=$LOGDIR/$TEST_NAME-$TEST_TIMESTAMP - GDB_LOGFILE=$LOGPREFIX.gdb.log - TEST_LOGFILE=$LOGPREFIX.out.log - set +e - printf "\033[1;32m[TEST] %s\033[0m\n" $TEST_NAME - - timeout -s SIGINT $TEST_TIMEOUT gdb -batch -q -n \ - -ex "set pagination off" \ - -ex "set logging file $GDB_LOGFILE" \ - -ex "set logging on" \ - -ex "file $t" \ - -ex "run > $TEST_LOGFILE" \ - -ex "call setvbuf(stdout, 0, 2, 0)" \ - -ex "thread apply all bt full" &> /dev/null - EXIT_STATUS=$? - set -e; set +x - - printf "\033[1;32mOUTPUT:\033[0m\n" - cat $TEST_LOGFILE - - if [ $EXIT_STATUS != 0 ]; then - printf "\n\033[1;32mGDB:\033[0m\n" - cat $GDB_LOGFILE - - printf "\n\033[1;32mDMESG:\033[0m\n" - dmesg | grep ums - - exit $EXIT_STATUS - fi - - if [ ! -z "${CI+x}" ] || [ "$CI" = "true" ]; then - set -x - fi -done +cd $BUILDDIR +make -j $(nproc) V=1 check diff --git a/scripts/qemu/build.sh b/scripts/qemu/build.sh index 3fff96d..dacc79c 100755 --- a/scripts/qemu/build.sh +++ b/scripts/qemu/build.sh @@ -28,7 +28,7 @@ EOF BUILDDIR=$BASEDIR/build -while getopts ":ho:" opt; do +while getopts ":ho:i:" opt; do case "$opt" in h) usage @@ -72,3 +72,4 @@ cd $BUILDDIR $BASEDIR/configure $CONFIGURE_FLAGS --enable-examples make -j $(nproc) V=1 +make -j $(nproc) V=1 TESTS= check diff --git a/scripts/qemu/test.sh b/scripts/qemu/example.sh similarity index 75% rename from scripts/qemu/test.sh rename to scripts/qemu/example.sh index e8652f1..6dd5755 100755 --- a/scripts/qemu/test.sh +++ b/scripts/qemu/example.sh @@ -13,7 +13,7 @@ usage() { Usage: $ME [OPTIONS]... Options: - -b BUILD-DIR source build directory + -b BUILD-DIR use BUILD-DIR as input build directory -l LOG-DIR output directory to place logfile -t TIMEOUT test timeout in seconds -h show this help and exit @@ -46,13 +46,12 @@ while getopts ":hb:l:t:" opt; do done shift $(($OPTIND - 1)) -TESTDIR=$BUILDDIR/examples -LOGDIR=$BUILDDIR/test +INSTALLDIR=$BUILDDIR/install +EXAMPLESDIR=$BUILDDIR/examples +LOGDIR=${LOGDIR:-"$BUILDDIR/test"} SDK_NAME=x86_64-buildroot-linux-gnu SDK_PATH="$BUILDDIR/images/${SDK_NAME}_sdk-buildroot" SYSROOT="$SDK_PATH/$SDK_NAME/sysroot" -TARGET_LIBDIR="/lib64" -TARGET_TESTDIR="/root" export PATH="$SDK_PATH/bin:$SDK_PATH/sbin:$BASEDIR/scripts/qemu:$PATH" @@ -62,31 +61,29 @@ trap "qemu-bridge.sh kill" EXIT qemu-bridge.sh shell "uname -a" -install.sh -i $BUILDDIR +install.sh -b $BUILDDIR -i $INSTALLDIR mkdir -p $LOGDIR -readarray -d '' tests < <(find $TESTDIR/*/.libs -type f -print0) +readarray -d '' examples < <(find $EXAMPLESDIR/*/.libs -type f -print0) -for t in "${tests[@]}"; do - TEST_NAME=$(basename $t) - TEST_TIMESTAMP=$(date +%s) - LOGPREFIX=$LOGDIR/$TEST_NAME-$TEST_TIMESTAMP +for e in "${examples[@]}"; do + EXAMPLE_NAME=$(basename $e) + EXAMPLE_TIMESTAMP=$(date +%s) + LOGPREFIX=$LOGDIR/$EXAMPLE_NAME-$EXAMPLE_TIMESTAMP GDB_LOGFILE=$LOGPREFIX.gdb.log - qemu-bridge.sh push $t $TARGET_TESTDIR 1>/dev/null - set +e - printf "\033[1;32m[TEST] %s\033[0m\n" $TEST_NAME + printf "\033[1;32m[TEST] %s\033[0m\n" $EXAMPLE_NAME timeout -s SIGINT $TEST_TIMEOUT x86_64-buildroot-linux-gnu-gdb -batch -q -n \ - -ex "target remote | qemu-bridge.sh shell 'gdbserver - $TARGET_TESTDIR/$TEST_NAME'" \ + -ex "target remote | qemu-bridge.sh shell 'gdbserver - $EXAMPLE_NAME'" \ -ex "set pagination off" \ -ex "set logging file $GDB_LOGFILE" \ -ex "set logging on" \ -ex "tb main" \ -ex "c" \ - -ex "set solib-search-path $BUILDDIR/src/lib/.libs" \ + -ex "set solib-search-path $INSTALLDIR/usr/lib" \ -ex "set sysroot $SYSROOT" \ -ex "info sharedlibrary" \ -ex "show solib-search-path" \ diff --git a/scripts/qemu/install.sh b/scripts/qemu/install.sh index 1bc9b40..3947e40 100755 --- a/scripts/qemu/install.sh +++ b/scripts/qemu/install.sh @@ -13,20 +13,22 @@ usage() { Usage: $ME [OPTIONS] Options: - -i BUILD-DIR use BUILD-DIR as input build directory + -b BUILD-DIR build directory + -i INSTALL-DIR temporary installation directory -h show this help and exit EOF } BUILDDIR=$BASEDIR/build -while getopts ":hi:" opt; do +while getopts ":hb:i:" opt; do case "$opt" in h) usage exit 0 ;; - i) BUILDDIR=$OPTARG ;; + b) BUILDDIR=$OPTARG ;; + i) INSTALLDIR=$OPTARG ;; \?) echo "unknown option $OPTARG!" >&2 usage >&2 @@ -41,18 +43,18 @@ while getopts ":hi:" opt; do done shift $(($OPTIND - 1)) -SDK_NAME=x86_64-buildroot-linux-gnu -SDK_PATH="$BUILDDIR/images/${SDK_NAME}_sdk-buildroot" -SYSROOT="$SDK_PATH/$SDK_NAME/sysroot" -TARGET_LIBDIR="/lib64" -TARGET_TESTDIR="/root" +INSTALLDIR=${INSTALLDIR:-"$BUILDDIR/install"} +TARGET_TESTDIR="/" -export PATH=$PATH:$BASEDIR/scripts/qemu +cd $BUILDDIR +make -j $(nproc) V=1 DESTDIR=$INSTALLDIR install +make -j $(nproc) V=1 DESTDIR=$INSTALLDIR/tests installcheck -# extract library SONAME from the symlink -LIBUMS_SYMLINK=$(readlink $BUILDDIR/src/lib/.libs/libums.so) -LIBUMS=$(readelf -d $BUILDDIR/src/lib/.libs/$LIBUMS_SYMLINK | grep -oP 'SONAME.*\K(?<=\[).*(?=\])') +$BASEDIR/scripts/qemu/qemu-bridge.sh push $INSTALLDIR/usr $TARGET_TESTDIR 1>/dev/null -qemu-bridge.sh push $BUILDDIR/src/lib/.libs/$LIBUMS $TARGET_LIBDIR 1>/dev/null -qemu-bridge.sh push $BUILDDIR/src/module/src/ums.ko $TARGET_TESTDIR 1>/dev/null -qemu-bridge.sh shell "insmod $TARGET_TESTDIR/ums.ko" +if [ -d $INSTALLDIR/tests ]; then + $BASEDIR/scripts/qemu/qemu-bridge.sh push $INSTALLDIR/tests/usr $TARGET_TESTDIR 1>/dev/null +fi + +$BASEDIR/scripts/qemu/qemu-bridge.sh push $INSTALLDIR/ums.ko $TARGET_TESTDIRums.ko 1>/dev/null +$BASEDIR/scripts/qemu/qemu-bridge.sh shell "insmod $TARGET_TESTDIRums.ko" diff --git a/scripts/qemu/qemu-bridge.sh b/scripts/qemu/qemu-bridge.sh index b28adf8..f1af343 100755 --- a/scripts/qemu/qemu-bridge.sh +++ b/scripts/qemu/qemu-bridge.sh @@ -85,9 +85,15 @@ EOF } push() { - SRCFILE=$1 + SRC=$1 DESTDIR=$2 - scp -P $SSH_PORT $SSH_OPTS $SRCFILE $SSH_USER@$SSH_IP:$DESTDIR + SCP_OPTS= + + if [ -d "$SRC" ]; then + SCP_OPTS="$SCP_OPTS -r" + fi + + scp -P $SSH_PORT $SSH_OPTS $SCP_OPTS $SRC $SSH_USER@$SSH_IP:$DESTDIR } shell() { diff --git a/src/lib/Doxyfile.in b/src/lib/Doxyfile.in index d0c6b47..0c8a3b4 100644 --- a/src/lib/Doxyfile.in +++ b/src/lib/Doxyfile.in @@ -10,7 +10,7 @@ EXTRACT_STATIC = YES ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES -PREDEFINED = __attribute__(x)= __BEGIN_DECLS= __THROW= __nonnull(x)= __END_DECLS= +PREDEFINED = __attribute__(x)= __BEGIN_DECLS= __THROW= __END_DECLS= GENERATE_XML = YES GENERATE_HTML = NO diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 1a012b9..8e0066a 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -14,7 +14,6 @@ EXTRA_DIST = \ src/private.h libums_la_CFLAGS = -I$(srcdir)/include -I$(srcdir)/../module/src/uapi - libums_la_LDFLAGS = -version-info 0:0:0 libums_la_LIBADD = @PTHREAD_LIBS@ @@ -22,6 +21,57 @@ SUBDIRS = include pkgconfig_DATA = libums.pc +if BUILD_TESTS + +if HAVE_LD_WRAP +lib_LTLIBRARIES += libums_mock.la +libums_mock_la_SOURCES = $(libums_la_SOURCES) tests/mock_ums_syscalls.c +libums_mock_la_CFLAGS = $(libums_la_CFLAGS) +libums_mock_la_LIBADD = $(libums_la_LIBADD) +libums_mock_la_LDFLAGS = $(libums_la_LDFLAGS) -Wl,-wrap,open -Wl,-wrap,close -Wl,-wrap,ioctl + +TESTS = \ + check_ums_completion_list \ + check_ums_worker \ + check_ums_scheduler + +check_PROGRAMS = \ + check_ums_completion_list \ + check_ums_worker \ + check_ums_scheduler + +check_ums_completion_list_SOURCES = \ + tests/check_ums.h \ + tests/check_ums_completion_list.c +check_ums_completion_list_CFLAGS = -I$(srcdir)/include @CHECK_CFLAGS@ +check_ums_completion_list_LDADD = libums_mock.la @CHECK_LIBS@ + +check_ums_worker_SOURCES = \ + tests/check_ums.h \ + tests/check_ums_worker.c +check_ums_worker_CFLAGS = -I$(srcdir)/include @CHECK_CFLAGS@ +check_ums_worker_LDADD = libums_mock.la @CHECK_LIBS@ + +check_ums_scheduler_SOURCES = \ + tests/check_ums.h \ + tests/check_ums_scheduler.c +check_ums_scheduler_CFLAGS = -I$(srcdir)/include @CHECK_CFLAGS@ +check_ums_scheduler_LDADD = libums_mock.la @CHECK_LIBS@ + +installcheck-local: $(check_PROGRAMS) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(check_PROGRAMS)'; d=".libs/"; for p in $$list; do \ + $(INSTALL_DATA) $$d$$p $(DESTDIR)$(bindir)/$$p; \ + chmod +x $(DESTDIR)$(bindir)/$$p; \ + done +uninstall-hook: + @list='$(check_PROGRAMS)'; d=".libs/"; for p in $$list; do \ + rm -rf $(DESTDIR)$(bindir)/$$p; \ + done +endif + +endif + # add static C code analysis static-check: -@$(CPPCHECK) -I $(srcdir)/include -I $(srcdir)/../module/src/uapi $(srcdir) diff --git a/src/lib/configure.ac b/src/lib/configure.ac index e14fe59..aa3a845 100644 --- a/src/lib/configure.ac +++ b/src/lib/configure.ac @@ -20,6 +20,9 @@ LT_PREREQ([2.4]) LT_INIT PKG_INSTALLDIR +PKG_CHECK_MODULES([CHECK], [check >= 0.9.6], [], [have_check=no]) +AM_CONDITIONAL([BUILD_TESTS], [test x$have_check != xno]) + AC_PATH_PROG([CPPCHECK], [cppcheck], [true]) AS_IF([test "x$CPPCHECK" = xtrue], [ AC_MSG_WARN(['cppcheck' is recommended for developing this package.]) @@ -42,6 +45,10 @@ AC_CHECK_HEADERS_ONCE([ features.h # Checks for pthread implementation. AX_PTHREAD +# Check if linker supports -wrap +AX_CHECK_LINK_FLAG([-Wl,-wrap,open], [], [have_ld_wrap=no]) +AM_CONDITIONAL([HAVE_LD_WRAP], [test x$have_ld_wrap != xno]) + AC_CONFIG_FILES([libums.pc Makefile include/Makefile]) diff --git a/src/lib/include/ums.h b/src/lib/include/ums.h index 64b3c7b..7ffb614 100644 --- a/src/lib/include/ums.h +++ b/src/lib/include/ums.h @@ -35,7 +35,7 @@ __BEGIN_DECLS * accordingly). */ extern int create_ums_completion_list(ums_completion_list_t *completion_list) - __THROW __nonnull ((1)); + __THROW; /** * @brief Create UMS worker thread. @@ -87,8 +87,7 @@ extern int ums_pthread_create(pthread_t *thread, ums_attr_t *ums_attr, * accordingly). */ extern int enter_ums_scheduling_mode( - ums_scheduler_startup_info_t *scheduler_startup_info) - __THROW __nonnull ((1)); + ums_scheduler_startup_info_t *scheduler_startup_info) __THROW; /** * @brief Retrieves user-mode scheduling (UMS) worker threads from the @@ -126,7 +125,7 @@ extern int enter_ums_scheduling_mode( */ extern int dequeue_ums_completion_list_items( ums_completion_list_t completion_list, ums_context_t *ums_thread_list) - __THROW __nonnull ((2)); + __THROW; /** * @brief Returns the next user-mode scheduling (UMS) thread context in a list @@ -198,7 +197,7 @@ extern int ums_thread_yield(void *scheduler_param) __THROW; * accordingly). */ extern int delete_ums_completion_list(ums_completion_list_t *completion_list) - __THROW __nonnull ((1)); + __THROW; __END_DECLS diff --git a/src/lib/src/complist.c b/src/lib/src/complist.c index 28d7bb8..c48c83f 100644 --- a/src/lib/src/complist.c +++ b/src/lib/src/complist.c @@ -4,14 +4,12 @@ int create_ums_completion_list(ums_completion_list_t *completion_list) { - ums_comp_list_id_t complist; - int retval; - - retval = ioctl(UMS_FILENO, IOCTL_CREATE_UMS_CLIST, &complist); - if (!retval) - *completion_list = complist; + if (!completion_list) { + errno = EFAULT; + return -1; + } - return retval; + return ioctl(UMS_FILENO, IOCTL_CREATE_UMS_CLIST, completion_list); } int dequeue_ums_completion_list_items(ums_completion_list_t completion_list, @@ -22,6 +20,11 @@ int dequeue_ums_completion_list_items(ums_completion_list_t completion_list, }; int retval; + if (!ums_thread_list) { + errno = EFAULT; + return -1; + } + retval = ioctl(UMS_FILENO, IOCTL_DEQUEUE_UMS_CLIST, &dequeue_args); if (!retval) *ums_thread_list = dequeue_args.ums_context; @@ -50,6 +53,11 @@ int delete_ums_completion_list(ums_completion_list_t *completion_list) { int retval; + if (!completion_list) { + errno = EFAULT; + return -1; + } + retval = ioctl(UMS_FILENO, IOCTL_DELETE_UMS_CLIST, *completion_list); diff --git a/src/lib/src/private.h b/src/lib/src/private.h index b1b1d0f..1e77d82 100644 --- a/src/lib/src/private.h +++ b/src/lib/src/private.h @@ -3,6 +3,8 @@ #ifndef UMS_PRIVATE_H #define UMS_PRIVATE_H +#include + #include "../include/ums.h" #include "ums/ums_ioctl.h" diff --git a/src/lib/src/scheduler.c b/src/lib/src/scheduler.c index 7520b8a..762ffcd 100644 --- a/src/lib/src/scheduler.c +++ b/src/lib/src/scheduler.c @@ -11,12 +11,18 @@ int enter_ums_scheduling_mode( ums_scheduler_startup_info_t *scheduler_startup_info) { struct enter_ums_mode_args enter_args = { - .flags = ENTER_UMS_SCHED, - .ums_complist = scheduler_startup_info->completion_list + .flags = ENTER_UMS_SCHED }; struct ums_sched_event event; ums_activation_t scheduler_activation; + if (!scheduler_startup_info) { + errno = EFAULT; + return -1; + } + + enter_args.ums_complist = scheduler_startup_info->completion_list; + if (enter_ums_mode(&enter_args)) return -1; diff --git a/src/lib/src/worker.c b/src/lib/src/worker.c index 42bea6a..e9a89ef 100644 --- a/src/lib/src/worker.c +++ b/src/lib/src/worker.c @@ -55,6 +55,11 @@ int ums_pthread_create(pthread_t *thread, ums_attr_t *ums_attr, { worker_proc_args_t *ums_args; + if (!ums_attr || !func) { + errno = EFAULT; + return -1; + } + ums_args = malloc(sizeof(*ums_args)); if (!ums_args) return -1; diff --git a/src/lib/tests/check_ums.h b/src/lib/tests/check_ums.h new file mode 100644 index 0000000..a370a52 --- /dev/null +++ b/src/lib/tests/check_ums.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: AGPL-3.0-only */ + +#ifndef UMS_TESTS_H +#define UMS_TESTS_H + +#include + +#include +#include + +Suite *create_ums_completion_list_suite(void); +Suite *create_ums_scheduler_suite(void); +Suite *create_ums_worker_suite(void); + +#endif /* UMS_TESTS_H */ diff --git a/src/lib/tests/check_ums_completion_list.c b/src/lib/tests/check_ums_completion_list.c new file mode 100644 index 0000000..dbe58af --- /dev/null +++ b/src/lib/tests/check_ums_completion_list.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +#include + +#include +#include + +START_TEST(test_ums_completion_list_create) +{ + ums_completion_list_t comp_list; + + ck_assert_int_eq(create_ums_completion_list(&comp_list), 0); + ck_assert_int_eq(delete_ums_completion_list(&comp_list), 0); + ck_assert_int_eq(delete_ums_completion_list(&comp_list), -1); +} +END_TEST + +START_TEST(test_ums_completion_list_create_bad) +{ + ck_assert_int_eq(create_ums_completion_list(NULL), -1); +} +END_TEST + +START_TEST(test_ums_completion_list_delete_bad) +{ + ums_completion_list_t comp_list = -1; + + ck_assert_int_eq(delete_ums_completion_list(NULL), -1); + ck_assert_int_eq(delete_ums_completion_list(&comp_list), -1); +} +END_TEST + +Suite *create_ums_completion_list_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("UMS Completion List Suite"); + + tc_core = tcase_create("UMS Completion List"); + + tcase_add_test(tc_core, test_ums_completion_list_create); + tcase_add_test(tc_core, test_ums_completion_list_create_bad); + tcase_add_test(tc_core, test_ums_completion_list_delete_bad); + + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = create_ums_completion_list_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/lib/tests/check_ums_scheduler.c b/src/lib/tests/check_ums_scheduler.c new file mode 100644 index 0000000..752ec76 --- /dev/null +++ b/src/lib/tests/check_ums_scheduler.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +#include + +#include +#include + +typedef struct ums_scheduler_startup_info_tcase_t { + ums_scheduler_startup_info_t *sched_info; + int expected_retval; +} ums_scheduler_startup_info_tcase_t; + +ums_completion_list_t comp_list; +ums_scheduler_startup_info_t sched_info; +ums_scheduler_startup_info_tcase_t sched_info_tcase = { + .sched_info = &sched_info +}; +pthread_t scheduler; + +ums_attr_t ums_attr = { 0 }; + +void setup(void) +{ + create_ums_completion_list(&comp_list); + sched_info.completion_list = comp_list; + ums_attr.completion_list = comp_list; +} + +void teardown(void) +{ + delete_ums_completion_list(&comp_list); +} + +static void *sched_pthread_proc(void *arg) +{ + ums_scheduler_startup_info_tcase_t *sched_info = arg; + + ck_assert_int_eq(enter_ums_scheduling_mode(sched_info->sched_info), + sched_info->expected_retval); + + return NULL; +} + +static void startup_sched_entry_proc(ums_reason_t reason, + ums_activation_t *activation, + void *args) +{ + pthread_exit(NULL); +} + +static void dequeue_comp_list_sched_entry_proc(ums_reason_t reason, + ums_activation_t *activation, + void *args) +{ + ums_context_t context; + + ck_assert_int_eq( + dequeue_ums_completion_list_items(comp_list, &context), + 0 + ); + pthread_exit(NULL); +} + +static void dequeue_comp_list_sched_entry_proc_bad(ums_reason_t reason, + ums_activation_t *activation, + void *args) +{ + ck_assert_int_eq( + dequeue_ums_completion_list_items(comp_list, NULL), + -1 + ); + pthread_exit(NULL); +} + +static void next_comp_list_sched_entry_proc(ums_reason_t reason, + ums_activation_t *activation, + void *args) +{ + ums_context_t context_list; + + ck_assert_int_eq( + dequeue_ums_completion_list_items(comp_list, &context_list), + 0 + ); + ck_assert_int_gt( + get_next_ums_list_item(context_list), + 0 + ); + pthread_exit(NULL); +} + +static void *work_pthread_proc(void *arg) +{ + return NULL; +} + +START_TEST(test_enter_ums_scheduling_mode) +{ + sched_info.ums_scheduler_entry_point = startup_sched_entry_proc; + sched_info_tcase.expected_retval = 0; + + pthread_create(&scheduler, NULL, sched_pthread_proc, + &sched_info_tcase); + + pthread_join(scheduler, NULL); +} +END_TEST + +START_TEST(test_enter_ums_scheduling_mode_bad) +{ + ums_scheduler_startup_info_t *old = sched_info_tcase.sched_info; + sched_info_tcase.sched_info = NULL; + sched_info_tcase.expected_retval = -1; + + pthread_create(&scheduler, NULL, sched_pthread_proc, + &sched_info_tcase); + + pthread_join(scheduler, NULL); + + sched_info_tcase.sched_info = old; +} +END_TEST + +START_TEST(test_ums_scheduler_dequeue_comp_list) +{ + pthread_t worker; + + sched_info.ums_scheduler_entry_point = + dequeue_comp_list_sched_entry_proc; + sched_info_tcase.expected_retval = 0; + + ck_assert_int_eq( + ums_pthread_create(&worker, &ums_attr, work_pthread_proc, NULL), + 0 + ); + + pthread_create(&scheduler, NULL, sched_pthread_proc, + &sched_info_tcase); + + pthread_join(worker, NULL); + pthread_join(scheduler, NULL); +} +END_TEST + +START_TEST(test_ums_scheduler_dequeue_comp_list_bad) +{ + sched_info.ums_scheduler_entry_point = + dequeue_comp_list_sched_entry_proc_bad; + sched_info_tcase.expected_retval = 0; + + pthread_create(&scheduler, NULL, sched_pthread_proc, + &sched_info_tcase); + + pthread_join(scheduler, NULL); +} +END_TEST + +START_TEST(test_ums_scheduler_next_comp_list) +{ + pthread_t worker1, worker2; + + sched_info.ums_scheduler_entry_point = + next_comp_list_sched_entry_proc; + sched_info_tcase.expected_retval = 0; + + ck_assert_int_eq( + ums_pthread_create(&worker1, &ums_attr, + work_pthread_proc, NULL), + 0 + ); + ck_assert_int_eq( + ums_pthread_create(&worker2, &ums_attr, + work_pthread_proc, NULL), + 0 + ); + + pthread_create(&scheduler, NULL, sched_pthread_proc, + &sched_info_tcase); + + pthread_join(worker1, NULL); + pthread_join(worker2, NULL); + pthread_join(scheduler, NULL); +} +END_TEST + +Suite *create_ums_scheduler_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("UMS Scheduler Suite"); + + tc_core = tcase_create("UMS Scheduler"); + + tcase_add_checked_fixture(tc_core, setup, teardown); + tcase_add_test(tc_core, test_enter_ums_scheduling_mode); + tcase_add_test(tc_core, test_enter_ums_scheduling_mode_bad); + tcase_add_test(tc_core, test_ums_scheduler_dequeue_comp_list); + tcase_add_test(tc_core, test_ums_scheduler_dequeue_comp_list_bad); + tcase_add_test(tc_core, test_ums_scheduler_next_comp_list); + + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = create_ums_scheduler_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/lib/tests/check_ums_worker.c b/src/lib/tests/check_ums_worker.c new file mode 100644 index 0000000..44e4572 --- /dev/null +++ b/src/lib/tests/check_ums_worker.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +#include + +#include +#include + +ums_completion_list_t comp_list; +pthread_t worker; + +void setup(void) +{ + create_ums_completion_list(&comp_list); +} + +void teardown(void) +{ + delete_ums_completion_list(&comp_list); +} + +static void *work_pthread_proc(void *arg) +{ + return NULL; +} + +static void *work_pthread_yield_proc(void *arg) +{ + ck_assert_int_eq(ums_thread_yield(NULL), 0); +} + +START_TEST(test_enter_ums_worker_mode) +{ + ums_attr_t ums_attr = { 0 }; + + ums_attr.completion_list = comp_list; + + ck_assert_int_eq( + ums_pthread_create(&worker, &ums_attr, work_pthread_proc, NULL), + 0 + ); + + pthread_join(worker, NULL); +} +END_TEST + +START_TEST(test_enter_ums_worker_mode_bad) +{ + ums_attr_t ums_attr = { 0 }; + + ums_attr.completion_list = comp_list; + + ck_assert_int_eq( + ums_pthread_create(&worker, NULL, work_pthread_proc, NULL), + -1 + ); + ck_assert_int_eq( + ums_pthread_create(&worker, &ums_attr, NULL, NULL), + -1 + ); +} +END_TEST + +START_TEST(test_ums_worker_yield) +{ + ums_attr_t ums_attr = { 0 }; + + ums_attr.completion_list = comp_list; + + ck_assert_int_eq( + ums_pthread_create(&worker, + &ums_attr, + work_pthread_yield_proc, + NULL), + 0 + ); + + pthread_join(worker, NULL); +} +END_TEST + +Suite *create_ums_worker_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("UMS Worker Suite"); + + tc_core = tcase_create("UMS Worker"); + + tcase_add_checked_fixture(tc_core, setup, teardown); + tcase_add_test(tc_core, test_enter_ums_worker_mode); + tcase_add_test(tc_core, test_enter_ums_worker_mode_bad); + tcase_add_test(tc_core, test_ums_worker_yield); + + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = create_ums_worker_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/lib/tests/mock_ums_syscalls.c b/src/lib/tests/mock_ums_syscalls.c new file mode 100644 index 0000000..af19e6a --- /dev/null +++ b/src/lib/tests/mock_ums_syscalls.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +#include +#include +#include +#include +#include +#include +#include + +#include "ums/ums_ioctl.h" + +// TODO: implement better test fixtures +static int UMS_FILENO = (INT_MAX >> 2); +static ums_comp_list_id_t ums_complist_id = 1; +static pid_t ums_context = 1; +static pid_t next_ums_context = 1; + +int __real_open(const char *pathname, int flags, ...); +int __real_close(int fd); +int __real_ioctl(int fd, unsigned long request, ...); + +int __wrap_open(const char *pathname, int flags, ...) +{ + va_list args; + int retval; + + if (!strncmp(pathname, "/dev/ums", 8)) + return UMS_FILENO; + + va_start(args, flags); + retval = __real_open(pathname, flags, args); + va_end(args); + + return retval; +} + +int __wrap_close(int fd) +{ + if (fd == UMS_FILENO) + return 0; + + return __real_close(fd); +} + +static int ums_ioctl(int fd, unsigned long request, unsigned long arg) +{ + ums_comp_list_id_t comp_list; + ums_comp_list_id_t *comp_listp; + struct enter_ums_mode_args *enter_ums_args; + struct ums_sched_event *sched_event_args; + struct dequeue_ums_complist_args *dequeue_args; + struct ums_next_context_list_args *next_context_args; + + switch (request) { + case IOCTL_CREATE_UMS_CLIST: + comp_listp = (ums_comp_list_id_t *) arg; + *comp_listp = ums_complist_id; + return 0; + case IOCTL_DELETE_UMS_CLIST: + comp_list = (ums_comp_list_id_t) arg; + /* completion list not found */ + if (comp_list != ums_complist_id) { + errno = EINVAL; + return -1; + } + return 0; + case IOCTL_ENTER_UMS: + enter_ums_args = (struct enter_ums_mode_args *) arg; + if (enter_ums_args->flags == ENTER_UMS_SCHED) + return 0; + else if (enter_ums_args->flags == ENTER_UMS_WORK) + return 0; + break; + case IOCTL_UMS_SCHED_DQEVENT: + return 0; + case IOCTL_DEQUEUE_UMS_CLIST: + dequeue_args = (struct dequeue_ums_complist_args *) arg; + /* completion list not found */ + if (dequeue_args->ums_complist != ums_complist_id) { + errno = EINVAL; + return -1; + } + dequeue_args->ums_context = ums_context; + return 0; + case IOCTL_NEXT_UMS_CTX_LIST: + next_context_args = (struct ums_next_context_list_args *) arg; + + if (next_context_args->ums_context != ums_context) + next_context_args->ums_next_context = -1; + + next_context_args->ums_next_context = next_ums_context; + + return 0; + case IOCTL_UMS_YIELD: + return 0; + default: + errno = ENOTSUP; + return -1; + } + + return -1; +} + +int __wrap_ioctl(int fd, unsigned long request, ...) +{ + va_list args; + int retval; + + va_start(args, request); + + if (fd == UMS_FILENO) + retval = ums_ioctl(fd, request, va_arg(args, unsigned long)); + else + retval = __real_ioctl(fd, request, args); + + va_end(args); + + return retval; +} diff --git a/src/module/Makefile.am b/src/module/Makefile.am index f229f11..d7d1c42 100644 --- a/src/module/Makefile.am +++ b/src/module/Makefile.am @@ -64,15 +64,17 @@ $(module_DATA): $(automake_dummy_SOURCES) FORCE $(MAKE) -C $(KERNELDIR) M=$(abs_builddir)/src modules install-moduleDATA: $(module_DATA) - @test -z $(DESTDIR)$(moduledir) || \ - $(MKDIR_P) $(DESTDIR)$(moduledir) + $(mkinstalldirs) $(DESTDIR)$(moduledir) $(INSTALL_DATA) $(abs_builddir)/src/ums.ko $(DESTDIR)$(moduledir)/ums.ko uninstall-moduleDATA: $(RM) $(DESTDIR)$(moduledir)/ums.ko +if SANDBOXED +else install-data-local: install-moduleDATA $(DEPMOD) -a +endif uninstall-local: uninstall-moduleDATA diff --git a/src/module/configure.ac b/src/module/configure.ac index 1a504b8..6fa4783 100644 --- a/src/module/configure.ac +++ b/src/module/configure.ac @@ -16,6 +16,7 @@ AC_SUBST([with_kernel], [`uname -r`]) AC_ARG_VAR([KERNELDIR], ["linux kernel dir"]) +AM_CONDITIONAL([SANDBOXED], [test x$KERNELDIR != x]) AS_IF([test "x$KERNELDIR" = x], [ [KERNELDIR=/lib/modules/$with_kernel/build] [moduledir=/lib/modules/$with_kernel/extra]