[PATCH 2/4] libfuse: integrate fuse services into mount.fuse3

Darrick J. Wong
2025-09-16T00:49:05Z

Teach mount.fuse3 how to start fuse via service, if present.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
util/mount_service.h | 9 ++++++++
doc/fuservicemount3.8 | 10 ++++++++
util/fuservicemount.c | 48 +++++++++++++++++++++++++++++++++++++++++
util/meson.build | 4 +++
util/mount.fuse.c | 58 +++++++++++++++++++++++++++++++------------------
util/mount_service.c | 18 +++++++++++++++
6 files changed, 124 insertions(+), 23 deletions(-)

diff --git a/util/mount_service.h b/util/mount_service.h
index 986a785bed3e74..b3e449ef005231 100644
--- a/util/mount_service.h
+++ b/util/mount_service.h
@@ -29,4 +29,13 @@ int mount_service_main(int argc, char *argv[]);
*/
const char *mount_service_subtype(const char *fstype);

+/**
+ * Discover if there is a fuse service socket for the given fuse subtype.
+ *
+ * @param subtype subtype of a fuse filesystem type (e.g. Y from
+ * mount_service_subtype)
+ * @return true if available, false if not
+ */
+bool mount_service_present(const char *subtype);
+
#endif /* MOUNT_SERVICE_H_ */
diff --git a/doc/fuservicemount3.8 b/doc/fuservicemount3.8
index e45d6a89c8b81a..aa2167cb4872c6 100644
--- a/doc/fuservicemount3.8
+++ b/doc/fuservicemount3.8
@@ -7,12 +7,20 @@ .SH SYNOPSIS
.B mountpoint
.BI -t " fstype"
[
-.I options
+.BI -o " options"
]
+
+.B fuservicemount3
+.BI -t " fstype"
+.B --check
+
.SH DESCRIPTION
Mount a filesystem using a FUSE server that runs as a socket service.
These servers can be contained using the platform's service management
framework.
+
+The second form checks if there is a FUSE service available for the given
+filesystem type.
.SH "AUTHORS"
.LP
The author of the fuse socket service code is Darrick J. Wong <djwong@kernel.org>.
diff --git a/util/fuservicemount.c b/util/fuservicemount.c
index c54d5b0767f760..edff2ed08ac23b 100644
--- a/util/fuservicemount.c
+++ b/util/fuservicemount.c
@@ -9,10 +9,58 @@
/* This program does the mounting of FUSE filesystems that run in systemd */

#define _GNU_SOURCE
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
#include "fuse_config.h"
#include "mount_service.h"

+static int check_service(const char *fstype)
+{
+ const char *subtype;
+
+ if (!fstype) {
+ fprintf(stderr,
+ "fuservicemount: expected fs type for --check\n");
+ return EXIT_FAILURE;
+ }
+
+ subtype = mount_service_subtype(fstype);
+ return mount_service_present(subtype) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
int main(int argc, char *argv[])
{
+ char *fstype = NULL;
+ bool check = false;
+ int i;
+
+ /*
+ * If the user passes us exactly the args -t FSTYPE --check then
+ * we'll just check if there's a service for the FSTYPE fuse server.
+ */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "--check")) {
+ if (check) {
+ check = false;
+ break;
+ }
+ check = true;
+ } else if (!strcmp(argv[i], "-t") && i + 1 < argc) {
+ if (fstype) {
+ check = false;
+ break;
+ }
+ fstype = argv[i + 1];
+ i++;
+ } else {
+ check = false;
+ break;
+ }
+ }
+ if (check)
+ return check_service(fstype);
+
return mount_service_main(argc, argv);
}
diff --git a/util/meson.build b/util/meson.build
index 68d8bb11f92955..3adf395bfb6386 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -6,7 +6,9 @@ executable('fusermount3', ['fusermount.c', '../lib/mount_util.c', '../lib/util.c
install_dir: get_option('bindir'),
c_args: '-DFUSE_CONF="@0@"'.format(fuseconf_path))

+mount_fuse3_sources = ['mount.fuse.c']
if private_cfg.get('HAVE_SERVICEMOUNT', false)
+ mount_fuse3_sources += ['mount_service.c']
executable('fuservicemount3', ['mount_service.c', 'fuservicemount.c'],
include_directories: include_dirs,
link_with: [ libfuse ],
@@ -15,7 +17,7 @@ if private_cfg.get('HAVE_SERVICEMOUNT', false)
c_args: '-DFUSE_USE_VERSION=317')
endif

-executable('mount.fuse3', ['mount.fuse.c'],
+executable('mount.fuse3', mount_fuse3_sources,
include_directories: include_dirs,
link_with: [ libfuse ],
install: true,
diff --git a/util/mount.fuse.c b/util/mount.fuse.c
index f1a90fe8abae7c..b6a55eebb7f88b 100644
--- a/util/mount.fuse.c
+++ b/util/mount.fuse.c
@@ -49,6 +49,9 @@
#endif

#include "fuse.h"
+#ifdef HAVE_SERVICEMOUNT
+# include "mount_service.h"
+#endif

static char *progname;

@@ -280,9 +283,7 @@ int main(int argc, char *argv[])
mountpoint = argv[2];

for (i = 3; i < argc; i++) {
- if (strcmp(argv[i], "-v") == 0) {
- continue;
- } else if (strcmp(argv[i], "-t") == 0) {
+ if (strcmp(argv[i], "-t") == 0) {
i++;

if (i == argc) {
@@ -303,6 +304,39 @@ int main(int argc, char *argv[])
progname);
exit(1);
}
+ }
+ }
+
+ if (!type) {
+ if (source) {
+ dup_source = xstrdup(source);
+ type = dup_source;
+ source = strchr(type, '#');
+ if (source)
+ *source++ = '\0';
+ if (!type[0]) {
+ fprintf(stderr, "%s: empty filesystem type\n",
+ progname);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "%s: empty source\n", progname);
+ exit(1);
+ }
+ }
+
+#ifdef HAVE_SERVICEMOUNT
+ /*
+ * Now that we know the desired filesystem type, see if we can find
+ * a socket service implementing that.
+ */
+ if (mount_service_present(type))
+ return mount_service_main(argc, argv);
+#endif
+
+ for (i = 3; i < argc; i++) {
+ if (strcmp(argv[i], "-v") == 0) {
+ continue;
} else if (strcmp(argv[i], "-o") == 0) {
char *opts;
char *opt;
@@ -366,24 +400,6 @@ int main(int argc, char *argv[])
if (suid)
options = add_option("suid", options);

- if (!type) {
- if (source) {
- dup_source = xstrdup(source);
- type = dup_source;
- source = strchr(type, '#');
- if (source)
- *source++ = '\0';
- if (!type[0]) {
- fprintf(stderr, "%s: empty filesystem type\n",
- progname);
- exit(1);
- }
- } else {
- fprintf(stderr, "%s: empty source\n", progname);
- exit(1);
- }
- }
-
if (setuid_name && setuid_name[0]) {
#ifdef linux
if (drop_privileges) {
diff --git a/util/mount_service.c b/util/mount_service.c
index 46d368d0cba922..612fec327cedde 100644
--- a/util/mount_service.c
+++ b/util/mount_service.c
@@ -960,3 +960,21 @@ int mount_service_main(int argc, char *argv[])
mount_service_destroy(&mo);
return ret;
}
+
+bool mount_service_present(const char *fstype)
+{
+ struct stat stbuf;
+ char path[PATH_MAX];
+ int ret;
+
+ snprintf(path, sizeof(path), FUSE_SERVICE_SOCKET_DIR "/%s", fstype);
+ ret = stat(path, &stbuf);
+ if (ret)
+ return false;
+
+ if (!S_ISSOCK(stbuf.st_mode))
+ return false;
+
+ ret = access(path, R_OK | W_OK);
+ return ret == 0;
+}