Skip to content

Commit

Permalink
Workaround musl bug when mountdir has whitespace
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiasgoergens committed Apr 2, 2023
1 parent 2113871 commit ab638c6
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 5 deletions.
32 changes: 32 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
63 changes: 58 additions & 5 deletions util/fusermount.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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 ||
Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand Down Expand Up @@ -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 ++;
Expand Down

0 comments on commit ab638c6

Please sign in to comment.