vasi/squashfuse

Support libfuse2 and libfuse3 at the same time with dlopen?

haampie opened this issue ยท 12 comments

Now that squashfuse_ll.a is a library on its own, it can be used to create self-mounting squashfs executables (e.g. appimage / xar). When distributing those, the problem is we don't know whether the target machine has libfuse2 or 3, and right now that is fixed at compile-time.

Can we use dlopen to figure this out at runtime instead?

Now that squashfuse_ll.a is a library on its own, it can be used to create self-mounting squashfs executables (e.g. appimage / xar).

Is there an example somewhere for how to do that?

I haven't done that yet, you can use the squashfuse_ll.pc package config file to get the ll.h header & libsquashfuse_ll.{a,so} lib, and then copy the bits you need from ll_main.c to your own project.

I would suggest finding some other FUSE filesystem that does fuse2/fuse3 at runtime. It seems like it would probably be an invasive (perhaps impossible, given data structure changes). But maybe it's possible and someone has done it. But I don't want to be first :)

Ok, that's understandable. I think I'll just happily link against a particular version of libfuse instead of dlopening anyways.

vasi commented

Yeah, it's probably just easier to build a static binary. Is there a reason you can't do that in your use case?

The issue is licensing; libfuse is LGPL which means

If you statically link against an LGPLed library, you must also provide your application in an object (not necessarily source) format, so that a user has the opportunity to modify the library and relink the application.

This can be problematic for users.

Edit: potentially though I could see how you could be compliant to the LGPL license without have to license your own squashfs sources in these self-mounting binaries LGPL... but IANAL.

vasi commented

Mmm, that makes sense. The good news is that use of fuse functions/constants is pretty isolated in squashfuse. So you could imagine just compiling ll.c twice with different headers and function-prefixes, and then your wrapper would just have to dlopen libfuse and call the right entrypoint.

I guess you'd also want to move a bunch of ll_main.c into ll.c, but honestly that seems like the right decision anyhow? @haampie does your code that uses libsquashfuse_ll end up duplicating most of ll_main.c?

That sounds like an idea indeed :)

And yes, moving things from ll_main to ll would make sense. If ll_main could just do argument parsing that'd be nice.

I've made a minimal working example here: https://github.com/haampie/appimage_runtime/ hacked together from AppImageKit's runtime.c and ll_main.c. Note that the spack commands don't work yet because PRs are pending, but installation should be reasonably easy from start to finish soon (tm).

Hm, statically linking libfuse is not a good idea because the path to the setuid binary fusermount (FUSERMOUNT_DIR) is set compile-time, so it wouldn't be portable. Shared linking is more portable.

I am concerned all of these options add a bit of complexity for fairly niche use case. What systems only have libfuse2? libfuse3 is four years old and the last release of libfuse2 was Jan 2019.

Probably @probonopd can correct me, but appimagekit is rather conservative with dependencies (compiling against old libc etc) so that they can distribute one binary that works everywhere assuming abi compatibility. To support old systems they dlopen libfuse2, but now there are new distro's that might not have libfuse2 installed anymore, so they might need to add a hack to support both. I guess libfuse is their only dep that is breaking abi

vasi commented

How bad would it be to just build separate binaries, and have a small wrapper choose between them at runtime? Most Linux games do something like that.