summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Görgens <matthias.goergens@gmail.com>2023-04-02 17:45:27 +0800
committerGitHub <noreply@github.com>2023-04-02 10:45:27 +0100
commit7be56c57f93e3436b1fbd9ecc320de5c03a3e4b8 (patch)
tree91ba1e928cca176f23776715dc076a99ea36bd82
parent2113871279d3c270c01c54c81782e982ec6e8246 (diff)
downloadfuse-7be56c57f93e3436b1fbd9ecc320de5c03a3e4b8.tar.gz
Workaround musl bug when mountdir has whitespace (#761)
Fixes https://github.com/libfuse/libfuse/issues/634 and https://github.com/mpartel/bindfs/issues/106
-rw-r--r--meson.build32
-rw-r--r--util/fusermount.c63
2 files changed, 90 insertions, 5 deletions
diff --git a/meson.build b/meson.build
index 0b3bd68..6aa23c1 100644
--- a/meson.build
+++ b/meson.build
@@ -151,6 +151,38 @@ else
message('Disabling versioned libc symbols')
endif
+# Older versions of musl libc don't unescape entries in /etc/mtab
+# Try to detect this behaviour, and work around, if necessary.
+detect_getmntent_needs_unescape = '''
+#define _GNU_SOURCE
+#include <mntent.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define dir_space_tab "dir\\040space\\011tab"
+
+int main()
+{
+ const char *fake_mtab = "name " dir_space_tab " type opts 0 0\n";
+ FILE *f = fmemopen((void *)fake_mtab, strlen(fake_mtab) + 1, "r");
+ struct mntent *entp = getmntent(f);
+ fclose(f);
+ if(NULL == entp)
+ exit(EXIT_FAILURE);
+ if (0 == strcmp(entp->mnt_dir, dir_space_tab))
+ printf("needs escaping\n");
+ else
+ printf("no need to escape\n");
+}
+'''
+
+result = cc.run(detect_getmntent_needs_unescape)
+if result.compiled() and result.returncode() == 0 and result.stdout().strip() == 'needs escaping'
+ message('getmntent does not unescape')
+ add_project_arguments('-DGETMNTENT_NEEDS_UNESCAPING', language: 'c')
+endif
+
# Write private test results into fuse_config.h (stored in build directory)
configure_file(output: 'fuse_config.h', configuration : private_cfg)
diff --git a/util/fusermount.c b/util/fusermount.c
index f8124cb..7a6bc24 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -7,7 +7,7 @@
*/
/* This program does the mounting and unmounting of FUSE filesystems */
-#define _GNU_SOURCE /* for clone */
+#define _GNU_SOURCE /* for clone and strchrnul */
#include "fuse_config.h"
#include "mount_util.h"
@@ -63,6 +63,59 @@ static int mount_max = 1000;
static int auto_unmount = 0;
+#ifdef GETMNTENT_NEEDS_UNESCAPING
+// Older versions of musl libc don't unescape entries in /etc/mtab
+
+// unescapes octal sequences like \040 in-place
+// That's ok, because unescaping can not extend the length of the string.
+static void unescape(char *buf) {
+ char *src = buf;
+ char *dest = buf;
+ while (1) {
+ char *next_src = strchrnul(src, '\\');
+ int offset = next_src - src;
+ memmove(dest, src, offset);
+ src = next_src;
+ dest += offset;
+
+ if(*src == '\0') {
+ *dest = *src;
+ return;
+ }
+ src++;
+
+ if('0' <= src[0] && src[0] < '2' &&
+ '0' <= src[1] && src[1] < '8' &&
+ '0' <= src[2] && src[2] < '8') {
+ *dest++ = (src[0] - '0') << 6
+ | (src[1] - '0') << 3
+ | (src[2] - '0') << 0;
+ src += 3;
+ } else if (src[0] == '\\') {
+ *dest++ = '\\';
+ src += 1;
+ } else {
+ *dest++ = '\\';
+ }
+ }
+}
+
+static struct mntent *GETMNTENT(FILE *stream)
+{
+ struct mntent *entp = getmntent(stream);
+ if(entp != NULL) {
+ unescape(entp->mnt_fsname);
+ unescape(entp->mnt_dir);
+ unescape(entp->mnt_type);
+ unescape(entp->mnt_opts);
+ }
+ return entp;
+}
+#else
+#define GETMNTENT getmntent
+#endif // GETMNTENT_NEEDS_UNESCAPING
+
+
static const char *get_user_name(void)
{
struct passwd *pw = getpwuid(getuid());
@@ -169,7 +222,7 @@ static int may_unmount(const char *mnt, int quiet)
uidlen = sprintf(uidstr, "%u", getuid());
found = 0;
- while ((entp = getmntent(fp)) != NULL) {
+ while ((entp = GETMNTENT(fp)) != NULL) {
if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
(strcmp(entp->mnt_type, "fuse") == 0 ||
strcmp(entp->mnt_type, "fuseblk") == 0 ||
@@ -261,7 +314,7 @@ static int check_is_mount_child(void *p)
}
count = 0;
- while (getmntent(fp) != NULL)
+ while (GETMNTENT(fp) != NULL)
count++;
endmntent(fp);
@@ -280,7 +333,7 @@ static int check_is_mount_child(void *p)
}
found = 0;
- while ((entp = getmntent(fp)) != NULL) {
+ while ((entp = GETMNTENT(fp)) != NULL) {
if (count > 0) {
count--;
continue;
@@ -464,7 +517,7 @@ static int count_fuse_fs(void)
strerror(errno));
return -1;
}
- while ((entp = getmntent(fp)) != NULL) {
+ while ((entp = GETMNTENT(fp)) != NULL) {
if (strcmp(entp->mnt_type, "fuse") == 0 ||
strncmp(entp->mnt_type, "fuse.", 5) == 0)
count ++;