commit: 722a1008ed5cf8ecb3396d59e57e3c437e4f6a77
parent 229f34110452281f787f1d3ca31c90247bcea57c
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Fri, 1 Mar 2024 06:32:33 +0100
cmd/df: escape getmntent output, note on musl prior to 1.2.5
Diffstat:
M | cmd/df.c | 61 | +++++++++++++++++++++---------------------------------------- |
1 file changed, 21 insertions(+), 40 deletions(-)
diff --git a/cmd/df.c b/cmd/df.c
@@ -7,6 +7,7 @@
#include "../lib/humanize.h"
+#include <ctype.h> // iscntrl, isspace
#include <errno.h> // errno
#include <mntent.h>
#include <stdbool.h>
@@ -18,28 +19,12 @@
size_t forced_bsize = 0;
+// Replaces control characters and whitespaces with '?' in-place (no allocation)
static void
-unescape_path(char *path)
+static_escape(char *str)
{
- char *needle = "\\040";
- size_t esc_len = 3; // 4 chars but leading-slash is kept for space
-
- char *str = strstr(path, needle);
-
- if(str != NULL)
- {
- size_t pos = 0;
-
- str[pos++] = ' ';
-
- while(str[pos] != '\0')
- {
- str[pos] = str[pos + esc_len];
- pos++;
- }
-
- unescape_path(str + pos);
- }
+ for(int i = 0; i < strlen(str); i++)
+ if(iscntrl(str[i]) || isspace(str[i])) str[i] = '?';
}
int
@@ -84,8 +69,8 @@ main(int argc, char *argv[])
printf("Filesystem Total Used Available Use%% Mountpoint\n");
}
- FILE *mnt = setmntent(MOUNTED, "r");
- if(mnt == NULL)
+ FILE *mounted = setmntent(MOUNTED, "r");
+ if(mounted == NULL)
{
fprintf(stderr, "df: Error opening setmntent(\"" MOUNTED "\", \"r\"): %s", strerror(errno));
return 1;
@@ -93,31 +78,27 @@ main(int argc, char *argv[])
while(1)
{
- struct mntent *mntent = getmntent(mnt);
+ struct mntent *mntent = getmntent(mounted);
if(mntent == NULL) break;
- // Linux escapes spaces in filesystems and mountpoints with \040
- // which statvfs(3) doesn't interprets
- // Also shouldn't be printed out to not break parsing of df(1) output
- char *mountpoint = strdup(mntent->mnt_dir);
- if(mountpoint == NULL)
- {
- fprintf(stderr, "df: Failed duplicating mnt_dir string: %s\n", strerror(errno));
- return 1;
- exit(1);
- }
- unescape_path(mountpoint);
-
+ // Note: musl prior to 1.2.5 has broken getmntent when octal sequences and carriage return is used
+ // https://git.musl-libc.org/cgit/musl/commit/src/misc/mntent.c?id=f314e133929b6379eccc632bef32eaebb66a7335
+ // https://git.musl-libc.org/cgit/musl/commit/src/misc/mntent.c?id=ee1d39bc1573c1ae49ee6b658938b56bbef95a6c
struct statvfs stats;
- if(statvfs(mountpoint, &stats) != 0)
+ if(statvfs(mntent->mnt_dir, &stats) != 0)
{
- fprintf(stderr, "df: Error statvfs(\"%s\", _): %s\n", mountpoint, strerror(errno));
+ fprintf(stderr, "df: Error statvfs(\"%s\", _): %s\n", mntent->mnt_dir, strerror(errno));
+
+ static_escape(mntent->mnt_fsname);
+ static_escape(mntent->mnt_dir);
printf("%s - - - - %s\n", mntent->mnt_fsname, mntent->mnt_dir);
- free(mountpoint);
continue;
}
- free(mountpoint);
+
+ // Needs to be done after calling statvfs(3)
+ static_escape(mntent->mnt_fsname);
+ static_escape(mntent->mnt_dir);
size_t percent = 0;
size_t total = stats.f_frsize * stats.f_blocks;
@@ -166,7 +147,7 @@ main(int argc, char *argv[])
}
}
- endmntent(mnt);
+ endmntent(mounted);
return 0;
}