--- /dev/null
+#!/bin/bash
+
+HERE="$(dirname "$(readlink -f "${0}")")"
+echo $HERE
+
+# Tails 5.8 sets QT_QPA_PLATFORM to wayland which breaks our app
+export QT_QPA_PLATFORM=xcb
+${APPDIR}/usr/bin/feather $*
--- /dev/null
+#!/bin/bash
+
+set -e
+unset SOURCE_DATE_EPOCH
+
+# Manually create the AppImage (reproducibly) since linuxdeployqt is not able to create cross-compiled AppImages
+
+APPDIR="$PWD/feather.AppDir"
+
+mkdir -p "$APPDIR"
+mkdir -p "$APPDIR/usr/share/applications/"
+mkdir -p "$APPDIR/usr/bin"
+
+cp "src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop"
+cp "src/assets/feather.desktop" "$APPDIR/feather.desktop"
+cp "src/assets/images/appicons/64x64.png" "$APPDIR/feather.png"
+cp "build/bin/feather" "$APPDIR/usr/bin/feather"
+chmod +x "$APPDIR/usr/bin/feather"
+
+cp "contrib/AppImage/AppRun" "$APPDIR/"
+chmod +x "$APPDIR/AppRun"
+
+find feather.AppDir/ -exec touch -h -a -m -t 202101010100.00 {} \;
+
+mksquashfs feather.AppDir feather.squashfs -comp zstd -info -root-owned -no-xattrs -noappend -fstime 0
+# mksquashfs writes a timestamp to the header
+printf '\x00\x00\x00\x00' | dd conv=notrunc of=feather.squashfs bs=1 seek=$((0x8))
+
+rm -f feather.AppImage
+
+cat /feather/contrib/depends/${HOST}/runtime >> feather.AppImage
+cat feather.squashfs >> feather.AppImage
+chmod a+x feather.AppImage
--- /dev/null
+package=appimage_runtime
+$(package)_version=c9553b05938b22849ac3255ac923bf8e775ce539
+$(package)_download_path=https://github.com/AppImage/type2-runtime/archive/
+$(package)_file_name=$($(package)_version).tar.gz
+$(package)_sha256_hash=4a27451013b571cf9f5a13660719d091cc79f2344aafa2e48578ddc0e4618af1
+$(package)_dependencies=libsquashfuse zstd
+$(package)_patches=depends-fix.patch
+
+define $(package)_preprocess_cmds
+ patch -p1 < $($(package)_patch_dir)/depends-fix.patch
+endef
+
+define $(package)_build_cmds
+ cd src/runtime && \
+ export host_prefix="$(host_prefix)" && \
+ $(MAKE) runtime-fuse3 -e CC=$($(package)_cc) LDLAGS="$($(package)_ldflags)" && \
+ "${HOST}-strip" runtime-fuse3
+endef
+
+define $(package)_stage_cmds
+ cd src/runtime && \
+ cp -a runtime-fuse3 $($(package)_staging_prefix_dir)/runtime
+endef
\ No newline at end of file
--- /dev/null
+package=libfuse
+$(package)_version=3.16.2
+$(package)_download_path=https://github.com/libfuse/libfuse/releases/download/fuse-$($(package)_version)
+$(package)_file_name=fuse-$($(package)_version).tar.gz
+$(package)_sha256_hash=f797055d9296b275e981f5f62d4e32e089614fc253d1ef2985851025b8a0ce87
+$(package)_patches=toolchain.txt mount.c.diff no-dlopen.patch set_fusermount_path.patch
+
+define $(package)_preprocess_cmds
+ patch -p1 < $($(package)_patch_dir)/set_fusermount_path.patch && \
+ patch -p1 < $($(package)_patch_dir)/no-dlopen.patch && \
+ patch -p1 < $($(package)_patch_dir)/mount.c.diff && \
+ cp $($(package)_patch_dir)/toolchain.txt toolchain.txt && \
+ sed -i -e 's|@host_prefix@|$(host_prefix)|' \
+ -e 's|@cc@|$($(package)_cc)|' \
+ -e 's|@cxx@|$($(package)_cxx)|' \
+ -e 's|@ar@|$($(package)_ar)|' \
+ -e 's|@strip@|$(host_STRIP)|' \
+ -e 's|@arch@|$(host_arch)|' \
+ toolchain.txt
+endef
+
+define $(package)_config_cmds
+ meson setup --cross-file toolchain.txt build
+endef
+
+define $(package)_build_cmds
+ ninja -C build
+endef
+
+define $(package)_stage_cmds
+ DESTDIR=$($(package)_staging_dir) ninja -C build install
+endef
--- /dev/null
+package=libsquashfuse
+$(package)_version=e51978cd6bb5c4d16fae9eee43d0b258f570bb0f
+$(package)_download_path=https://github.com/vasi/squashfuse/archive/
+$(package)_file_name=$($(package)_version).tar.gz
+$(package)_sha256_hash=f544029ad30d8fbde4e4540c574b8cdc6d38b94df025a98d8551a9441f07d341
+$(package)_dependencies=libfuse zstd
+
+define $(package)_preprocess_cmds
+ ./autogen.sh
+endef
+
+define $(package)_config_cmds
+ $($(package)_autoconf) --with-zstd=$(host_prefix) --without-zlib CFLAGS=-no-pie LDFLAGS=-static
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install && \
+ mkdir -p $($(package)_staging_prefix_dir)/lib && \
+ mkdir -p $($(package)_staging_prefix_dir)/include/squashfuse && \
+ cp .libs/libfuseprivate.a $($(package)_staging_prefix_dir)/lib/ && \
+ cp .libs/libsquashfuse.a $($(package)_staging_prefix_dir)/lib/ && \
+ cp .libs/libsquashfuse_ll.a $($(package)_staging_prefix_dir)/lib/ && \
+ find . -name "*.h" -exec cp --parents '{}' $($(package)_staging_prefix_dir)/include/squashfuse \;
+endef
packages := boost openssl unbound qrencode libsodium polyseed hidapi abseil protobuf libusb zlib libgpg-error libgcrypt expat libzip zxing-cpp
native_packages := native_qt native_abseil native_protobuf
-linux_packages := eudev
+linux_packages := eudev libfuse libsquashfuse zstd appimage_runtime
linux_native_packages =
x86_64_linux_packages := flatstart
--- /dev/null
+package=zstd
+$(package)_version=1.5.6
+$(package)_download_path=https://github.com/facebook/zstd/releases/download/v$($(package)_version)
+$(package)_file_name=zstd-$($(package)_version).tar.gz
+$(package)_sha256_hash=8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1
+
+define $(package)_build_cmds
+ $($(package)_cmake) -DCMAKE_INSTALL_PREFIX=$(host_prefix) -DHOST=$(host) -DZSTD_LEGACY_SUPPORT=OFF -B build-cmake-debug -S build/cmake && \
+ cd build-cmake-debug && \
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ cd build-cmake-debug && \
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
--- /dev/null
+diff --git a/src/runtime/Makefile b/src/runtime/Makefile
+index d0cbf1f..905b130 100644
+--- a/src/runtime/Makefile
++++ b/src/runtime/Makefile
+@@ -1,21 +1,21 @@
+ CC = gcc
+ CFLAGS = -std=gnu99 -s -Os -D_FILE_OFFSET_BITS=64 -DGIT_COMMIT=\"${GIT_COMMIT}\" -T data_sections.ld -ffunction-sections -fdata-sections -Wl,--gc-sections -static
+-LIBS = -lsquashfuse -lsquashfuse_ll -lzstd -lz
++LIBS = -lsquashfuse -lsquashfuse_ll -lzstd -lpthread
+
+ all: runtime-fuse3 runtime-fuse3
+
+ # Compile runtime
+ runtime-fuse3.o: runtime.c
+- $(CC) -I/usr/local/include/squashfuse -I/usr/include/fuse -o runtime-fuse3.o -c $(CFLAGS) $^
++ $(CC) -I${host_prefix}/include -I${host_prefix}/include/squashfuse -I${host_prefix}/include/fuse -o runtime-fuse3.o -c $(CFLAGS) $^
+
+ runtime-fuse3: runtime-fuse3.o
+ $(CC) $(CFLAGS) $^ $(LIBS) -lfuse -o runtime-fuse3
+
+ runtime-fuse3.o: runtime.c
+- $(CC) -I/usr/local/include/squashfuse -I/usr/include/fuse3 -o runtime-fuse3.o -c $(CFLAGS) $^
++ $(CC) -I${host_prefix}/include -I${host_prefix}/include/squashfuse -I${host_prefix}/include/fuse3 -o runtime-fuse3.o -c $(CFLAGS) $^
+
+ runtime-fuse3: runtime-fuse3.o
+- $(CC) $(CFLAGS) $^ $(LIBS) -lfuse3 -o runtime-fuse3
++ $(CC) $(CFLAGS) $^ -L${host_prefix}/lib $(LIBS) -lfuse3 -lpthread -o runtime-fuse3
+
+ clean:
+ rm -f *.o runtime-fuse3 runtime-fuse3
--- /dev/null
+diff --git a/lib/mount.c b/lib/mount.c
+index d71e6fc..e9c2ff0 100644
+--- a/lib/mount.c
++++ b/lib/mount.c
+@@ -41,7 +41,6 @@
+ #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
+ #endif
+
+-#define FUSERMOUNT_PROG "fusermount3"
+ #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
+
+ #ifndef HAVE_FORK
+@@ -117,17 +116,87 @@ static const struct fuse_opt fuse_mount_opts[] = {
+ FUSE_OPT_END
+ };
+
++int fileExists(const char* path);
++char* findBinaryInFusermountDir(const char* binaryName);
++
++int fileExists(const char* path) {
++ FILE* file = fopen(path, "r");
++ if (file) {
++ fclose(file);
++ return 1;
++ }
++ return 0;
++}
++
++char* findBinaryInFusermountDir(const char* binaryName) {
++ // For security reasons, we do not search the binary on the $PATH;
++ // instead, we check if the binary exists in FUSERMOUNT_DIR
++ // as defined in meson.build
++ char* binaryPath = malloc(strlen(FUSERMOUNT_DIR) + strlen(binaryName) + 2);
++ strcpy(binaryPath, FUSERMOUNT_DIR);
++ strcat(binaryPath, "/");
++ strcat(binaryPath, binaryName);
++ if (fileExists(binaryPath)) {
++ return binaryPath;
++ }
++
++ // Debian, Ubuntu
++ char* binaryPath2 = malloc(strlen(binaryName) + 6);
++ strcat(binaryPath2, "/bin/");
++ strcat(binaryPath2, binaryName);
++ if (fileExists(binaryPath2)) {
++ return binaryPath2;
++ }
++
++ // If the binary does not exist in FUSERMOUNT_DIR, return NULL
++ return NULL;
++}
++
++static const char *fuse_mount_prog(void)
++{
++ // Check if the FUSERMOUNT_PROG environment variable is set and if so, use it
++ const char *prog = getenv("FUSERMOUNT_PROG");
++ if (prog) {
++ if (access(prog, X_OK) == 0)
++ return prog;
++ }
++
++ // Check if there is a binary "fusermount3"
++ prog = findBinaryInFusermountDir("fusermount3");
++ if (access(prog, X_OK) == 0)
++ return prog;
++
++ // Check if there is a binary called "fusermount"
++ // This is known to work for our purposes
++ prog = findBinaryInFusermountDir("fusermount");
++ if (access(prog, X_OK) == 0)
++ return prog;
++
++ // For i = 4...99, check if there is a binary called "fusermount" + i
++ // It is not yet known whether this will work for our purposes, but it is better than not even attempting
++ for (int i = 4; i < 100; i++) {
++ prog = findBinaryInFusermountDir("fusermount" + i);
++ if (access(prog, X_OK) == 0)
++ return prog;
++ }
++
++ // If all else fails, return NULL
++ return NULL;
++}
++
+ static void exec_fusermount(const char *argv[])
+ {
+- execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
+- execvp(FUSERMOUNT_PROG, (char **) argv);
++ const char *fusermount_prog = fuse_mount_prog();
++ if (fusermount_prog) {
++ execv(fusermount_prog, (char **) argv);
++ }
+ }
+
+ void fuse_mount_version(void)
+ {
+ int pid = fork();
+ if (!pid) {
+- const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
++ const char *argv[] = { fuse_mount_prog(), "--version", NULL };
+ exec_fusermount(argv);
+ _exit(1);
+ } else if (pid != -1)
+@@ -300,7 +369,7 @@ void fuse_kern_unmount(const char *mountpoint, int fd)
+ return;
+
+ if(pid == 0) {
+- const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
++ const char *argv[] = { fuse_mount_prog(), "-u", "-q", "-z",
+ "--", mountpoint, NULL };
+
+ exec_fusermount(argv);
+@@ -346,7 +415,7 @@ static int setup_auto_unmount(const char *mountpoint, int quiet)
+ }
+ }
+
+- argv[a++] = FUSERMOUNT_PROG;
++ argv[a++] = fuse_mount_prog();
+ argv[a++] = "--auto-unmount";
+ argv[a++] = "--";
+ argv[a++] = mountpoint;
+@@ -407,7 +476,7 @@ static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
+ }
+ }
+
+- argv[a++] = FUSERMOUNT_PROG;
++ argv[a++] = fuse_mount_prog();
+ if (opts) {
+ argv[a++] = "-o";
+ argv[a++] = opts;
+@@ -421,7 +490,7 @@ static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
+ snprintf(env, sizeof(env), "%i", fds[0]);
+ setenv(FUSE_COMMFD_ENV, env, 1);
+ exec_fusermount(argv);
+- perror("fuse: failed to exec fusermount3");
++ perror("fuse: failed to exec fusermount");
+ _exit(1);
+ }
+
--- /dev/null
+diff --git a/lib/fuse.c b/lib/fuse.c
+index 2a88918..34a46c3 100644
+--- a/lib/fuse.c
++++ b/lib/fuse.c
+@@ -242,50 +242,7 @@ static void fuse_unregister_module(struct fuse_module *m)
+
+ static int fuse_load_so_module(const char *module)
+ {
+- int ret = -1;
+- char *tmp;
+- struct fusemod_so *so;
+- fuse_module_factory_t *factory;
+-
+- tmp = malloc(strlen(module) + 64);
+- if (!tmp) {
+- fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
+- return -1;
+- }
+- sprintf(tmp, "libfusemod_%s.so", module);
+- so = calloc(1, sizeof(struct fusemod_so));
+- if (!so) {
+- fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module so\n");
+- goto out;
+- }
+-
+- so->handle = dlopen(tmp, RTLD_NOW);
+- if (so->handle == NULL) {
+- fuse_log(FUSE_LOG_ERR, "fuse: dlopen(%s) failed: %s\n",
+- tmp, dlerror());
+- goto out_free_so;
+- }
+-
+- sprintf(tmp, "fuse_module_%s_factory", module);
+- factory = (fuse_module_factory_t*)dlsym(so->handle, tmp);
+- if (factory == NULL) {
+- fuse_log(FUSE_LOG_ERR, "fuse: symbol <%s> not found in module: %s\n",
+- tmp, dlerror());
+- goto out_dlclose;
+- }
+- ret = fuse_register_module(module, *factory, so);
+- if (ret)
+- goto out_dlclose;
+-
+-out:
+- free(tmp);
+- return ret;
+-
+-out_dlclose:
+- dlclose(so->handle);
+-out_free_so:
+- free(so);
+- goto out;
++ return -1;
+ }
+
+ static struct fuse_module *fuse_find_module(const char *module)
+@@ -335,7 +292,6 @@ static void fuse_put_module(struct fuse_module *m)
+ else
+ mp = &(*mp)->next;
+ }
+- dlclose(so->handle);
+ free(so);
+ }
+ } else if (!m->ctr) {
--- /dev/null
+diff --git a/lib/meson.build b/lib/meson.build
+index 9044630..ea09d45 100644
+--- a/lib/meson.build
++++ b/lib/meson.build
+@@ -32,7 +32,7 @@ else
+ deps += cc.find_library('rt')
+ endif
+
+-fusermount_path = join_paths(get_option('prefix'), get_option('bindir'))
++fusermount_path = '/usr/bin'
+ libfuse = library('fuse3', libfuse_sources, version: meson.project_version(),
+ soversion: '3', include_directories: include_dirs,
+ dependencies: deps, install: true,
--- /dev/null
+[binaries]
+c = '@cc@'
+cpp = '@cxx@'
+ar = '@ar@'
+strip = '@strip@'
+pkgconfig = '/home/user/.guix-profile/bin/pkg-config'
+
+[host_machine]
+system = 'linux'
+cpu_family = '@arch@'
+cpu = '@arch@'
+endian = 'little'
+
+[project options]
+utils = false
+examples = false
+
+[built-in options]
+default_library = 'static'
+prefix = '@host_prefix@'
\ No newline at end of file
;;
esac
- # We no longer ship 'real' AppImages
- # The .AppImage extension is just there to trick file managers into allowing right click -> open.
case "$HOST" in
- riscv64-linux*)
- ;;
*linux*)
- upx build/bin/feather -o build/bin/feather.upx
if [ "$OPTIONS" != "pack" ]; then
+ bash contrib/AppImage/build-appimage.sh
APPIMAGENAME=${DISTNAME}${ANONDIST}${LINUX_ARCH}.AppImage
- cp build/bin/feather.upx "${APPIMAGENAME}"
+ mv feather.AppImage "${APPIMAGENAME}"
cp "${APPIMAGENAME}" "${INSTALLPATH}/"
cp "${APPIMAGENAME}" "${OUTDIR}/"
fi
|| ( rm -f "${OUTDIR}/${DISTNAME}-linux${LINUX_ARCH}${ANONDIST}.zip" && exit 1 )
;;
esac
- case "$HOST" in
- riscv64-*)
- ;;
- *)
- find . -name "*.AppImage" -print0 \
- | xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
- find . -name "*.AppImage" \
- | sort \
- | zip -X@ "${OUTDIR}/${DISTNAME}-linux${LINUX_ARCH}-appimage${ANONDIST}.zip" \
- || ( rm -f "${OUTDIR}/${DISTNAME}-linux${LINUX_ARCH}-appimage${ANONDIST}.zip" && exit 1 )
- ;;
- esac
+ find . -name "*.AppImage" -print0 \
+ | xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
+ find . -name "*.AppImage" \
+ | sort \
+ | zip -X@ "${OUTDIR}/${DISTNAME}-linux${LINUX_ARCH}-appimage${ANONDIST}.zip" \
+ || ( rm -f "${OUTDIR}/${DISTNAME}-linux${LINUX_ARCH}-appimage${ANONDIST}.zip" && exit 1 )
else
find . -print0 \
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
p7zip
zip
unzip
- upx
;; Build tools
gnu-make
libtool
bison
gperf
gettext-minimal
+ squashfs-tools
cmake-minimal
meson
ninja