From 78551049d53eed990f0d823ebf3da132b166e3b1 Mon Sep 17 00:00:00 2001 From: trapexit Date: Thu, 6 Nov 2025 11:05:19 -0600 Subject: [PATCH] Add ability to passthrough 'nofail' mount option (#1567) --- libfuse/util/mount.mergerfs.c | 397 +++++++++++++++++----------------- 1 file changed, 201 insertions(+), 196 deletions(-) diff --git a/libfuse/util/mount.mergerfs.c b/libfuse/util/mount.mergerfs.c index cf447a96..854bbdb6 100644 --- a/libfuse/util/mount.mergerfs.c +++ b/libfuse/util/mount.mergerfs.c @@ -16,216 +16,221 @@ static char *progname; static char *xstrdup(const char *s) { - char *t = strdup(s); - if (!t) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - exit(1); - } - return t; + char *t = strdup(s); + if (!t) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + exit(1); + } + return t; } static void *xrealloc(void *oldptr, size_t size) { - void *ptr = realloc(oldptr, size); - if (!ptr) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - exit(1); - } - return ptr; + void *ptr = realloc(oldptr, size); + if (!ptr) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + exit(1); + } + return ptr; } static void add_arg(char **cmdp, const char *opt) { - size_t optlen = strlen(opt); - size_t cmdlen = *cmdp ? strlen(*cmdp) : 0; - char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4); - char *s; - s = cmd + cmdlen; - if (*cmdp) - *s++ = ' '; - - *s++ = '\''; - for (; *opt; opt++) { - if (*opt == '\'') { - *s++ = '\''; - *s++ = '\\'; - *s++ = '\''; - *s++ = '\''; - } else - *s++ = *opt; - } - *s++ = '\''; - *s = '\0'; - *cmdp = cmd; + size_t optlen = strlen(opt); + size_t cmdlen = *cmdp ? strlen(*cmdp) : 0; + char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4); + char *s; + s = cmd + cmdlen; + if (*cmdp) + *s++ = ' '; + + *s++ = '\''; + for (; *opt; opt++) { + if (*opt == '\'') { + *s++ = '\''; + *s++ = '\\'; + *s++ = '\''; + *s++ = '\''; + } else + *s++ = *opt; + } + *s++ = '\''; + *s = '\0'; + *cmdp = cmd; } static char *add_option(const char *opt, char *options) { - int oldlen = options ? strlen(options) : 0; - - options = xrealloc(options, oldlen + 1 + strlen(opt) + 1); - if (!oldlen) - strcpy(options, opt); - else { - strcat(options, ","); - strcat(options, opt); - } - return options; + int oldlen = options ? strlen(options) : 0; + + options = xrealloc(options, oldlen + 1 + strlen(opt) + 1); + if (!oldlen) + strcpy(options, opt); + else { + strcat(options, ","); + strcat(options, opt); + } + return options; } int main(int argc, char *argv[]) { - char *type = NULL; - char *source; - const char *mountpoint; - char *basename; - char *options = NULL; - char *command = NULL; - char *setuid = NULL; - int i; - int dev = 1; - int suid = 1; - - progname = argv[0]; - basename = strrchr(argv[0], '/'); - if (basename) - basename++; - else - basename = argv[0]; - - type = "mergerfs"; - if (strncmp(basename, "mount.fuse.", 11) == 0) - type = basename + 11; - if (strncmp(basename, "mount.fuseblk.", 14) == 0) - type = basename + 14; - - if (type && !type[0]) - type = NULL; - - if (argc < 3) { - fprintf(stderr, - "usage: %s %s destination [-t type] [-o opt[,opts...]]\n", - progname, type ? "source" : "type#[source]"); - exit(1); - } - - source = argv[1]; - if (!source[0]) - source = NULL; - - mountpoint = argv[2]; - - for (i = 3; i < argc; i++) { - if (strcmp(argv[i], "-v") == 0) { - continue; - } else if (strcmp(argv[i], "-t") == 0) { - i++; - - if (i == argc) { - fprintf(stderr, - "%s: missing argument to option '-t'\n", - progname); - exit(1); - } - type = argv[i]; - if (strncmp(type, "fuse.", 5) == 0) - type += 5; - else if (strncmp(type, "fuseblk.", 8) == 0) - type += 8; - - if (!type[0]) { - fprintf(stderr, - "%s: empty type given as argument to option '-t'\n", - progname); - exit(1); - } - } else if (strcmp(argv[i], "-o") == 0) { - char *opts; - char *opt; - i++; - if (i == argc) - break; - - opts = xstrdup(argv[i]); - opt = strtok(opts, ","); - while (opt) { - int j; - int ignore = 0; - const char *ignore_opts[] = { "", - "user", - "nouser", - "users", - "auto", - "noauto", - "_netdev", - NULL}; - if (strncmp(opt, "setuid=", 7) == 0) { - setuid = xstrdup(opt + 7); - ignore = 1; - } - for (j = 0; ignore_opts[j]; j++) - if (strcmp(opt, ignore_opts[j]) == 0) - ignore = 1; - - if (!ignore) { - if (strcmp(opt, "nodev") == 0) - dev = 0; - else if (strcmp(opt, "nosuid") == 0) - suid = 0; - - options = add_option(opt, options); - } - opt = strtok(NULL, ","); - } - } - } - - if (dev) - options = add_option("dev", options); - if (suid) - options = add_option("suid", options); - - if (!type) { - if (source) { - type = xstrdup(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); - } - } - - add_arg(&command, type); - if (source) - add_arg(&command, source); - add_arg(&command, mountpoint); - if (options) { - add_arg(&command, "-o"); - add_arg(&command, options); - } - - if (setuid && setuid[0]) { - char *sucommand = command; - command = NULL; - add_arg(&command, "su"); - add_arg(&command, "-"); - add_arg(&command, setuid); - add_arg(&command, "-c"); - add_arg(&command, sucommand); - } else if (!getenv("HOME")) { - /* Hack to make filesystems work in the boot environment */ - setenv("HOME", "/root", 0); - } - - execl("/bin/sh", "/bin/sh", "-c", command, NULL); - fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, - strerror(errno)); - return 1; + char *type = NULL; + char *source; + const char *mountpoint; + char *basename; + char *options = NULL; + char *command = NULL; + char *setuid = NULL; + int i; + int dev = 1; + int suid = 1; + + progname = argv[0]; + basename = strrchr(argv[0], '/'); + if (basename) + basename++; + else + basename = argv[0]; + + type = "mergerfs"; + if (strncmp(basename, "mount.fuse.", 11) == 0) + type = basename + 11; + if (strncmp(basename, "mount.fuseblk.", 14) == 0) + type = basename + 14; + + if (type && !type[0]) + type = NULL; + + if (argc < 3) { + fprintf(stderr, + "usage: %s %s destination [-t type] [-o opt[,opts...]]\n", + progname, type ? "source" : "type#[source]"); + exit(1); + } + + source = argv[1]; + if (!source[0]) + source = NULL; + + mountpoint = argv[2]; + + for (i = 3; i < argc; i++) { + if (strcmp(argv[i], "-v") == 0) { + continue; + } else if (strcmp(argv[i], "-t") == 0) { + i++; + + if (i == argc) { + fprintf(stderr, + "%s: missing argument to option '-t'\n", + progname); + exit(1); + } + type = argv[i]; + if (strncmp(type, "fuse.", 5) == 0) + type += 5; + else if (strncmp(type, "fuseblk.", 8) == 0) + type += 8; + + if (!type[0]) { + fprintf(stderr, + "%s: empty type given as argument to option '-t'\n", + progname); + exit(1); + } + } else if (strcmp(argv[i], "-o") == 0) { + char *opts; + char *opt; + i++; + if (i == argc) + break; + + opts = xstrdup(argv[i]); + opt = strtok(opts, ","); + while (opt) + { + int j; + int ignore = 0; + const char *ignore_opts[] = + { + "", + "nofail", + "user", + "nouser", + "users", + "auto", + "noauto", + "_netdev", + NULL + }; + if (strncmp(opt, "setuid=", 7) == 0) { + setuid = xstrdup(opt + 7); + ignore = 1; + } + for (j = 0; ignore_opts[j]; j++) + if (strcmp(opt, ignore_opts[j]) == 0) + ignore = 1; + + if (!ignore) { + if (strcmp(opt, "nodev") == 0) + dev = 0; + else if (strcmp(opt, "nosuid") == 0) + suid = 0; + + options = add_option(opt, options); + } + opt = strtok(NULL, ","); + } + } + } + + if (dev) + options = add_option("dev", options); + if (suid) + options = add_option("suid", options); + + if (!type) { + if (source) { + type = xstrdup(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); + } + } + + add_arg(&command, type); + if (source) + add_arg(&command, source); + add_arg(&command, mountpoint); + if (options) { + add_arg(&command, "-o"); + add_arg(&command, options); + } + + if (setuid && setuid[0]) { + char *sucommand = command; + command = NULL; + add_arg(&command, "su"); + add_arg(&command, "-"); + add_arg(&command, setuid); + add_arg(&command, "-c"); + add_arg(&command, sucommand); + } else if (!getenv("HOME")) { + /* Hack to make filesystems work in the boot environment */ + setenv("HOME", "/root", 0); + } + + execl("/bin/sh", "/bin/sh", "-c", command, NULL); + fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, + strerror(errno)); + return 1; }