From c9b400aa41fb26f9c9d33f9917e027359ab9ef57 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 3 Apr 2024 02:54:35 +0900 Subject: [PATCH] libnilfs: fix nilfs_open failure for mount points with escaped characters nilfs_find_fs(), called from nilfs_open(), parses "/proc/mounts" using its own routines, but these parsing routines have a problem in that they cannot handle escaped path strings. For example, if the mount point path name contains spaces, the search will fail. This is causing errors when running lscp, lssu, and other nilfs tools. Fix this issue by avoiding custom parsing and using standard mount table access routines such as setmntent(), getmntent_r(), endmntent(), and hasmntopt(). Closes: https://github.com/nilfs-dev/nilfs-utils/issues/22 Signed-off-by: Ryusuke Konishi --- lib/nilfs.c | 86 +++++++++-------------------------------------------- 1 file changed, 14 insertions(+), 72 deletions(-) diff --git a/lib/nilfs.c b/lib/nilfs.c index ed8d42b..c79e54b 100644 --- a/lib/nilfs.c +++ b/lib/nilfs.c @@ -73,6 +73,7 @@ #include #include #include +#include /* setmntent, getmntent_r, endmntent, etc */ #include "nilfs.h" #include "compat.h" /* PATH_MAX, etc */ #include "util.h" @@ -110,65 +111,8 @@ enum { }; -static inline int iseol(int c) -{ - return c == '\n' || c == '\0'; -} - -static size_t tokenize(char *line, char **tokens, size_t ntoks) -{ - char *p; - size_t n; - - p = line; - for (n = 0; n < ntoks; n++) { - while (isspace(*p)) - p++; - if (iseol(*p)) - break; - tokens[n] = p++; - while (!isspace(*p) && !iseol(*p)) - p++; - if (isspace(*p)) - *p++ = '\0'; - else - *p = '\0'; - } - return n; -} - -#define NMNTFLDS 6 -#define MNTFLD_FS 0 -#define MNTFLD_DIR 1 -#define MNTFLD_TYPE 2 -#define MNTFLD_OPTS 3 -#define MNTFLD_FREQ 4 -#define MNTFLD_PASSNO 5 #define MNTOPT_RW "rw" #define MNTOPT_RO "ro" -#define MNTOPT_SEP ',' - -static int has_mntopt(const char *opts, const char *opt) -{ - const char *p, *q; - size_t len, n; - - p = opts; - len = strlen(opt); - while (p != NULL) { - q = strchr(p, MNTOPT_SEP); - if (q) { - n = max_t(size_t, q - p, len); - q++; - } else { - n = max_t(size_t, strlen(p), len); - } - if (strncmp(p, opt, n) == 0) - return 1; - p = q; - } - return 0; -} #ifndef LINE_MAX #define LINE_MAX 2048 @@ -177,12 +121,13 @@ static int has_mntopt(const char *opts, const char *opt) static int nilfs_find_fs(struct nilfs *nilfs, const char *dev, const char *dir, const char *opt) { - FILE *fp; - char line[LINE_MAX], *mntent[NMNTFLDS]; - int ret, n; + struct mntent *mntent, mntbuf; + char buf[LINE_MAX]; char canonical[PATH_MAX + 2]; char *cdev = NULL, *cdir = NULL; char *mdev, *mdir; + FILE *fp; + int ret; ret = -1; if (dev && myrealpath(dev, canonical, sizeof(canonical))) { @@ -199,19 +144,16 @@ static int nilfs_find_fs(struct nilfs *nilfs, const char *dev, const char *dir, dir = cdir; } - fp = fopen(_PATH_PROC_MOUNTS, "r"); + fp = setmntent(_PATH_PROC_MOUNTS, "r"); if (unlikely(fp == NULL)) goto failed_dir; - while (fgets(line, sizeof(line), fp) != NULL) { - n = tokenize(line, mntent, NMNTFLDS); - assert(n == NMNTFLDS); - - if (strcmp(mntent[MNTFLD_TYPE], NILFS_FSTYPE) != 0) + while ((mntent = getmntent_r(fp, &mntbuf, buf, sizeof(buf))) != NULL) { + if (strcmp(mntent->mnt_type, NILFS_FSTYPE) != 0) continue; if (dir != NULL) { - mdir = mntent[MNTFLD_DIR]; + mdir = mntent->mnt_dir; if (myrealpath(mdir, canonical, sizeof(canonical))) mdir = canonical; if (strcmp(mdir, dir) != 0) @@ -219,16 +161,16 @@ static int nilfs_find_fs(struct nilfs *nilfs, const char *dev, const char *dir, } if (dev != NULL) { - mdev = mntent[MNTFLD_FS]; + mdev = mntent->mnt_fsname; if (myrealpath(mdev, canonical, sizeof(canonical))) mdev = canonical; if (strcmp(mdev, dev) != 0) continue; } - if (has_mntopt(mntent[MNTFLD_OPTS], opt)) { + if (hasmntopt(mntent, opt)) { free(nilfs->n_dev); - nilfs->n_dev = strdup(mntent[MNTFLD_FS]); + nilfs->n_dev = strdup(mntent->mnt_fsname); if (unlikely(nilfs->n_dev == NULL)) { free(nilfs->n_ioc); nilfs->n_ioc = NULL; @@ -236,7 +178,7 @@ static int nilfs_find_fs(struct nilfs *nilfs, const char *dev, const char *dir, goto failed_proc_mounts; } free(nilfs->n_ioc); - nilfs->n_ioc = strdup(mntent[MNTFLD_DIR]); + nilfs->n_ioc = strdup(mntent->mnt_dir); if (unlikely(nilfs->n_ioc == NULL)) { free(nilfs->n_dev); nilfs->n_dev = NULL; @@ -250,7 +192,7 @@ static int nilfs_find_fs(struct nilfs *nilfs, const char *dev, const char *dir, errno = ENXIO; failed_proc_mounts: - fclose(fp); + endmntent(fp); failed_dir: free(cdir);