aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernd Schubert <bernd.schubert@fastmail.fm>2024-03-20 13:30:12 +0100
committerGitHub <noreply@github.com>2024-03-20 13:30:12 +0100
commit694f3d5231e0ec4b25416db97ac113b4f89630d6 (patch)
tree860e0d6c96cd91858c2361a935b8fdd14532b68e
parenta6a219f5344a5c09cec34416818342ac220a0df2 (diff)
parent425f52a1f515cd0e2148a427330bb82c96b18856 (diff)
downloadlibfuse-694f3d5231e0ec4b25416db97ac113b4f89630d6.tar.gz
Merge pull request #904 from bsbernd/s-bit-fusermount
Add back s-bit for compiled fusermount
-rw-r--r--README.md5
-rw-r--r--example/poll.c22
-rw-r--r--lib/fuse_signals.c15
-rw-r--r--meson.build2
-rwxr-xr-xtest/ci-build.sh107
-rw-r--r--test/pytest.ini2
-rw-r--r--test/test_ctests.py9
-rw-r--r--test/util.py6
8 files changed, 119 insertions, 49 deletions
diff --git a/README.md b/README.md
index 6855cef..eaf1308 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,10 @@ nevertheless want to adjust them, you can do so with the
*meson configure* command:
$ meson configure # list options
- $ meson configure -D disable-mtab=true # set an option
+ $ meson configure -D disable-mtab=true # set an optionq
+
+ $ # ensure all meson options are applied to the final build system
+ $ meson setup --reconfigure ../
To build, test, and install libfuse, you then use Ninja:
diff --git a/example/poll.c b/example/poll.c
index f9430a9..fd53ec0 100644
--- a/example/poll.c
+++ b/example/poll.c
@@ -33,6 +33,7 @@
#include <time.h>
#include <pthread.h>
#include <poll.h>
+#include <stdbool.h>
/*
* fsel_open_mask is used to limit the number of opens to 1 per file.
@@ -51,6 +52,9 @@ static pthread_mutex_t fsel_mutex; /* protects notify_mask and cnt array */
static unsigned fsel_poll_notify_mask; /* poll notification scheduled? */
static struct fuse_pollhandle *fsel_poll_handle[FSEL_FILES]; /* poll notify handles */
static unsigned fsel_cnt[FSEL_FILES]; /* nbytes stored in each file */
+static _Atomic bool fsel_stop = false;
+static pthread_t fsel_producer_thread;
+
static int fsel_path_index(const char *path)
{
@@ -61,6 +65,15 @@ static int fsel_path_index(const char *path)
return ch <= '9' ? ch - '0' : ch - 'A' + 10;
}
+static void fsel_destroy(void *private_data)
+{
+ (void)private_data;
+
+ fsel_stop = true;
+
+ pthread_join(fsel_producer_thread, NULL);
+}
+
static int fsel_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
@@ -205,6 +218,7 @@ static int fsel_poll(const char *path, struct fuse_file_info *fi,
}
static const struct fuse_operations fsel_oper = {
+ .destroy = fsel_destroy,
.getattr = fsel_getattr,
.readdir = fsel_readdir,
.open = fsel_open,
@@ -220,7 +234,7 @@ static void *fsel_producer(void *data)
(void) data;
- while (1) {
+ while (!fsel_stop) {
int i, t;
pthread_mutex_lock(&fsel_mutex);
@@ -263,7 +277,6 @@ static void *fsel_producer(void *data)
int main(int argc, char *argv[])
{
- pthread_t producer;
pthread_attr_t attr;
int ret;
@@ -279,7 +292,7 @@ int main(int argc, char *argv[])
return 1;
}
- errno = pthread_create(&producer, &attr, fsel_producer, NULL);
+ errno = pthread_create(&fsel_producer_thread, &attr, fsel_producer, NULL);
if (errno) {
perror("pthread_create");
return 1;
@@ -287,8 +300,5 @@ int main(int argc, char *argv[])
ret = fuse_main(argc, argv, &fsel_oper, NULL);
- pthread_cancel(producer);
- pthread_join(producer, NULL);
-
return ret;
}
diff --git a/lib/fuse_signals.c b/lib/fuse_signals.c
index 048d047..4c1d172 100644
--- a/lib/fuse_signals.c
+++ b/lib/fuse_signals.c
@@ -16,15 +16,30 @@
#include <string.h>
#include <signal.h>
#include <stdlib.h>
+#include <execinfo.h>
static struct fuse_session *fuse_instance;
+static void dump_stack(void)
+{
+#ifdef HAVE_BACKTRACE
+ const size_t backtrace_sz = 1024 * 1024;
+ void* backtrace_buffer[backtrace_sz];
+
+ int err_fd = fileno(stderr);
+
+ int trace_len = backtrace(backtrace_buffer, backtrace_sz);
+ backtrace_symbols_fd(backtrace_buffer, trace_len, err_fd);
+#endif
+}
+
static void exit_handler(int sig)
{
if (fuse_instance) {
fuse_session_exit(fuse_instance);
if(sig <= 0) {
fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n");
+ dump_stack();
abort();
}
fuse_instance->error = sig;
diff --git a/meson.build b/meson.build
index 7d62dcf..7d8db7f 100644
--- a/meson.build
+++ b/meson.build
@@ -61,6 +61,8 @@ private_cfg.set('HAVE_SETXATTR',
cc.has_function('setxattr', prefix: '#include <sys/xattr.h>'))
private_cfg.set('HAVE_ICONV',
cc.has_function('iconv', prefix: '#include <iconv.h>'))
+private_cfg.set('HAVE_BACKTRACE',
+ cc.has_function('backtrace', prefix: '#include <execinfo.h>'))
# Test if structs have specific member
private_cfg.set('HAVE_STRUCT_STAT_ST_ATIM',
diff --git a/test/ci-build.sh b/test/ci-build.sh
index a023c15..0307865 100755
--- a/test/ci-build.sh
+++ b/test/ci-build.sh
@@ -1,8 +1,8 @@
-#!/bin/bash
+#!/bin/bash -x
set -e
-TEST_CMD="python3 -m pytest --maxfail=99 test/"
+TEST_CMD="pytest -v --maxfail=1 --log-level=DEBUG --log-cli-level=DEBUG test/"
SAN="-Db_sanitize=address,undefined"
# not default
@@ -30,38 +30,48 @@ export LSAN_OPTIONS="suppressions=$(pwd)/lsan_suppress.txt"
export ASAN_OPTIONS="detect_leaks=1"
export CC
-# Standard build
-for CC in gcc gcc-9 gcc-10 clang; do
- echo "=== Building with ${CC} ==="
- mkdir build-${CC}; pushd build-${CC}
- if [ "${CC}" == "clang" ]; then
- export CXX="clang++"
- export TEST_WITH_VALGRIND=false
- else
- export TEST_WITH_VALGRIND=true
- fi
- if [ ${CC} == 'gcc-7' ]; then
- build_opts='-D b_lundef=false'
- else
- build_opts=''
- fi
- if [ ${CC} == 'gcc-10' ]; then
- build_opts='-Dc_args=-flto=auto'
- else
- build_opts=''
- fi
- meson setup -Dprefix=${PREFIX_DIR} -D werror=true ${build_opts} "${SOURCE_DIR}" || (cat meson-logs/meson-log.txt; false)
- ninja
- sudo ninja install
-
- # libfuse will first try the install path and then system defaults
- sudo chmod 4755 ${PREFIX_DIR}/bin/fusermount3
-
- ${TEST_CMD}
- popd
- rm -fr build-${CC}
- sudo rm -fr ${PREFIX_DIR}
-done
+non_sanitized_build()
+(
+ echo "Standard build (without sanitizers)"
+ for CC in gcc gcc-9 gcc-10 clang; do
+ echo "=== Building with ${CC} ==="
+ mkdir build-${CC}; pushd build-${CC}
+ if [ "${CC}" == "clang" ]; then
+ export CXX="clang++"
+ export TEST_WITH_VALGRIND=false
+ else
+ unset CXX
+ export TEST_WITH_VALGRIND=true
+ fi
+ if [ ${CC} == 'gcc-7' ]; then
+ build_opts='-D b_lundef=false'
+ else
+ build_opts=''
+ fi
+ if [ ${CC} == 'gcc-10' ]; then
+ build_opts='-Dc_args=-flto=auto'
+ else
+ build_opts=''
+ fi
+
+ meson setup -Dprefix=${PREFIX_DIR} -D werror=true ${build_opts} "${SOURCE_DIR}" || (cat meson-logs/meson-log.txt; false)
+ ninja
+ sudo ninja install
+
+ # libfuse will first try the install path and then system defaults
+ sudo chmod 4755 ${PREFIX_DIR}/bin/fusermount3
+
+ # also needed for some of the tests
+ sudo chown root:root util/fusermount3
+ sudo chmod 4755 util/fusermount3
+
+ ${TEST_CMD}
+ popd
+ rm -fr build-${CC}
+ sudo rm -fr ${PREFIX_DIR}
+
+ done
+)
sanitized_build()
(
@@ -78,11 +88,24 @@ sanitized_build()
# bug, cf. https://groups.google.com/forum/#!topic/mesonbuild/tgEdAXIIdC4
meson configure -D b_lundef=false
- meson configure
+ # additional options
+ if [ -n "$@" ]; then
+ meson configure "$@"
+ fi
+
+ # print all options
+ meson configure --no-pager
+
+ # reconfigure to ensure it uses all additional options
+ meson setup --reconfigure "${SOURCE_DIR}"
ninja
sudo ninja install
sudo chmod 4755 ${PREFIX_DIR}/bin/fusermount3
+ # also needed for some of the tests
+ sudo chown root:root util/fusermount3
+ sudo chmod 4755 util/fusermount3
+
# Test as root and regular user
sudo ${TEST_CMD}
# Cleanup temporary files (since they are now owned by root)
@@ -96,15 +119,17 @@ sanitized_build()
)
# Sanitized build
-CC=clang
-CXX=clang++
+export CC=clang
+export CXX=clang++
TEST_WITH_VALGRIND=false
-sanitized_build $SAN
+sanitized_build
# Sanitized build without libc versioned symbols
-CC=clang
-CXX=clang++
-sanitized_build
+export CC=clang
+export CXX=clang++
+sanitized_build "-Ddisable-libc-symbol-version=true"
+
+non_sanitized_build
# Documentation.
(cd "${SOURCE_DIR}"; doxygen doc/Doxyfile)
diff --git a/test/pytest.ini b/test/pytest.ini
index 036a9f4..bbc8de8 100644
--- a/test/pytest.ini
+++ b/test/pytest.ini
@@ -2,3 +2,5 @@
addopts = --verbose --assert=rewrite --tb=native -x -r a
markers =
uses_fuse: Indicates that FUSE is supported.
+log_cli=true
+faulthandler_timeout=60
diff --git a/test/test_ctests.py b/test/test_ctests.py
index 951a34b..55db156 100644
--- a/test/test_ctests.py
+++ b/test/test_ctests.py
@@ -9,10 +9,11 @@ import subprocess
import pytest
import platform
import sys
+import os
from looseversion import LooseVersion
from util import (wait_for_mount, umount, cleanup, base_cmdline,
safe_sleep, basename, fuse_test_marker, fuse_caps,
- fuse_proto)
+ fuse_proto, create_tmpdir)
from os.path import join as pjoin
import os.path
@@ -29,6 +30,9 @@ def test_write_cache(tmpdir, writeback, output_checker):
# deadlock in valgrind, it probably assumes that until close() returns,
# control does not come to the program.
mnt_dir = str(tmpdir)
+ print("mnt_dir: '" + mnt_dir + "'")
+ create_tmpdir(mnt_dir)
+
cmdline = [ pjoin(basename, 'test', 'test_write_cache'),
mnt_dir ]
if writeback:
@@ -50,6 +54,7 @@ if fuse_proto >= (7,15):
@pytest.mark.parametrize("notify", (True, False))
def test_notify1(tmpdir, name, notify, output_checker):
mnt_dir = str(tmpdir)
+ create_tmpdir(mnt_dir)
cmdline = base_cmdline + \
[ pjoin(basename, 'example', name),
'-f', '--update-interval=1', mnt_dir ]
@@ -70,6 +75,7 @@ def test_notify1(tmpdir, name, notify, output_checker):
else:
assert read1 == read2
except:
+ print("Failure in notify test: '" + str(cmdline) + "'")
cleanup(mount_process, mnt_dir)
raise
else:
@@ -80,6 +86,7 @@ def test_notify1(tmpdir, name, notify, output_checker):
@pytest.mark.parametrize("notify", (True, False))
def test_notify_file_size(tmpdir, notify, output_checker):
mnt_dir = str(tmpdir)
+ create_tmpdir(mnt_dir)
cmdline = base_cmdline + \
[ pjoin(basename, 'example', 'invalidate_path'),
'-f', '--update-interval=1', mnt_dir ]
diff --git a/test/util.py b/test/util.py
index 0a1fa93..623b031 100644
--- a/test/util.py
+++ b/test/util.py
@@ -151,6 +151,12 @@ def powerset(iterable):
return itertools.chain.from_iterable(
itertools.combinations(s, r) for r in range(len(s)+1))
+def create_tmpdir(mnt_dir):
+ if not os.path.exists(mnt_dir):
+ print("makedirs: '" + mnt_dir + "'")
+ os.makedirs(mnt_dir)
+ else:
+ print("mnt_dir exists: '" + mnt_dir + "'")
# Use valgrind if requested
if os.environ.get('TEST_WITH_VALGRIND', 'no').lower().strip() \