summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak2010-10-01 13:05:58 +0200
committerKarel Zak2011-01-03 12:28:43 +0100
commit8f3f6383a581e64d5dbe9a13130e078f45babf07 (patch)
tree323304a71688a9fc157dceaee666ea0a449650ba
parentlibmount: fix mount helpers call (diff)
downloadkernel-qcow2-util-linux-8f3f6383a581e64d5dbe9a13130e078f45babf07.tar.gz
kernel-qcow2-util-linux-8f3f6383a581e64d5dbe9a13130e078f45babf07.tar.xz
kernel-qcow2-util-linux-8f3f6383a581e64d5dbe9a13130e078f45babf07.zip
libmount: rewrite mountinfo/fstab parsers to use sscanf()
The old solution (without scanf()) was based on old code from mount(8). It seems that the modern libc is able to provide all necessary functionality by sscanf() and %ms directive. Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--include/mangle.h5
-rw-r--r--lib/mangle.c15
-rw-r--r--shlibs/mount/src/tab_parse.c285
3 files changed, 93 insertions, 212 deletions
diff --git a/include/mangle.h b/include/mangle.h
index 0ccd37768..5dda902f7 100644
--- a/include/mangle.h
+++ b/include/mangle.h
@@ -10,5 +10,10 @@ extern char *mangle(const char *s);
extern void unmangle_to_buffer(const char *s, char *buf, size_t len);
extern char *unmangle(const char *s);
+static inline void unmangle_string(char *s)
+{
+ unmangle_to_buffer(s, s, strlen(s) + 1);
+}
+
#endif /* UTIL_LINUX_MANGLE_H */
diff --git a/lib/mangle.c b/lib/mangle.c
index e320cfb7c..938dd8e55 100644
--- a/lib/mangle.c
+++ b/lib/mangle.c
@@ -115,10 +115,19 @@ int main(int argc, char *argv[])
else if (!strcmp(argv[1], "--unmangle")) {
char *x = unmangle(argv[2]);
- if (x)
+
+ if (x) {
printf("unmangled: '%s'\n", x);
- else
- err(EXIT_FAILURE, "unmangle failed");
+ free(x);
+ }
+
+ x = strdup(argv[2]);
+ unmangle_to_buffer(x, x, strlen(x) + 1);
+
+ if (x) {
+ printf("self-unmangled: '%s'\n", x);
+ free(x);
+ }
}
return EXIT_SUCCESS;
diff --git a/shlibs/mount/src/tab_parse.c b/shlibs/mount/src/tab_parse.c
index 062b9040e..603908f20 100644
--- a/shlibs/mount/src/tab_parse.c
+++ b/shlibs/mount/src/tab_parse.c
@@ -29,138 +29,44 @@ static inline char *skip_spaces(char *s)
return s;
}
-static inline char *skip_nonspaces(char *s)
-{
- assert(s);
-
- while (*s && !(*s == ' ' || *s == '\t'))
- s++;
- return s;
-}
-
-static size_t next_word_size(char *s, char **start, char **end)
-{
- char *e;
-
- assert(s);
-
- s = skip_spaces(s);
- if (!*s)
- return 0;
- e = skip_nonspaces(s);
-
- if (start)
- *start = s;
- if (end)
- *end = e;
-
- return e - s;
-}
-
-static int next_word(char **s, char **next)
-{
- size_t sz;
- char *end;
-
- assert(s);
-
- sz = next_word_size(*s, s, &end) + 1;
- if (sz == 1)
- return -EINVAL;
-
- *next = malloc(sz);
- if (!*next)
- return -ENOMEM;
-
- unmangle_to_buffer(*s, *next, sz);
- *s = end + 1;
- return 0;
-}
-
-static int next_word_skip(char **s)
-{
- *s = skip_spaces(*s);
- if (!**s)
- return -EINVAL;
- *s = skip_nonspaces(*s);
- return 0;
-}
-
-static int next_number(char **s, int *num)
-{
- char *end = NULL;
-
- assert(num);
- assert(s);
-
- *s = skip_spaces(*s);
- if (!**s)
- return -EINVAL;
-
- *num = strtol(*s, &end, 10);
- if (end == NULL || *s == end)
- return -EINVAL;
-
- *s = end;
-
- /* valid end of number is space or terminator */
- if (*end == ' ' || *end == '\t' || *end == '\0')
- return 0;
-
- return -EINVAL;
-}
-
/*
* Parses one line from {fs,m}tab
*/
static int mnt_tab_parse_file_line(mnt_fs *fs, char *s)
{
- int rc = 0, col;
-
- fs->passno = fs->freq = 0; /* default */
-
- for (col = 0; rc == 0 && col < 4; col++) {
- char *p = NULL;
-
- rc = next_word(&s, &p);
- if (rc)
- goto done;
-
- switch(col) {
- /* SOURCE */
- case 0:
- rc =__mnt_fs_set_source_ptr(fs, p);
- break;
- /* TARGET */
- case 1:
- fs->target = p;
- break;
- /* TYPE */
- case 2:
- rc = __mnt_fs_set_fstype_ptr(fs, p);
- break;
- /* OPTS */
- case 3:
- rc = __mnt_fs_set_optstr_ptr(fs, p, TRUE);
- break;
- }
- if (rc) {
- free(p);
- goto done;
- }
+ int rc;
+ char *src, *fstype, *optstr;
+
+ rc = sscanf(s, "%ms " /* (1) source */
+ "%ms " /* (2) target */
+ "%ms " /* (3) FS type */
+ "%ms " /* (4) options */
+ "%u " /* (5) freq */
+ "%u ", /* (6) passno */
+
+ &src,
+ &fs->target,
+ &fstype,
+ &optstr,
+ &fs->freq,
+ &fs->passno);
+
+ if (rc >= 4 && rc <= 6) {
+ unmangle_string(src);
+ unmangle_string(fs->target);
+ unmangle_string(fstype);
+ unmangle_string(optstr);
+
+ rc = __mnt_fs_set_source_ptr(fs, src);
+ if (!rc)
+ rc = __mnt_fs_set_fstype_ptr(fs, fstype);
+ if (!rc)
+ rc = __mnt_fs_set_optstr_ptr(fs, optstr, TRUE);
+ } else {
+ DBG(TAB, mnt_debug( "parse error: [field=%d]: '%s'", rc, s));
+ rc = -EINVAL;
}
- /* FREQ (optional) */
- rc = next_number(&s, &fs->freq);
- if (rc && !*s)
- rc = 0; /* no error, end of line, freq is optional */
-
- else {
- rc = next_number(&s, &fs->passno);
- if (rc && !*s)
- rc = 0;
- }
-done:
return rc;
}
@@ -169,85 +75,55 @@ done:
*/
static int mnt_parse_mountinfo_line(mnt_fs *fs, char *s)
{
- int rc = 0, col;
+ int rc;
unsigned int maj, min;
- char *p = NULL;
-
- /* ID */
- rc = next_number(&s, &fs->id);
- if (rc)
- goto done;
-
- /* PARENT */
- rc = next_number(&s, &fs->parent);
- if (rc)
- goto done;
-
- /* <maj>:<min> */
- s = skip_spaces(s);
- if (!*s || sscanf(s, "%u:%u", &maj, &min) != 2)
- rc = -EINVAL;
- else {
+ char *fstype, *src;
+
+ rc = sscanf(s, "%u " /* (1) id */
+ "%u " /* (2) parent */
+ "%u:%u " /* (3) maj:min */
+ "%ms " /* (4) mountroot */
+ "%ms " /* (5) target */
+ "%ms" /* (6) vfs options (fs-independent) */
+ "%*[^-]" /* (7) optional fields */
+ "- " /* (8) separator */
+ "%ms " /* (9) FS type */
+ "%ms " /* (10) source */
+ "%ms", /* (11) fs options (fs specific) */
+
+ &fs->id,
+ &fs->parent,
+ &maj, &min,
+ &fs->root,
+ &fs->target,
+ &fs->vfs_optstr,
+ &fstype,
+ &src,
+ &fs->fs_optstr);
+
+ if (rc == 10) {
fs->devno = makedev(maj, min);
- next_word_skip(&s);
- }
-
- for (col = 3; rc == 0 && col < 9; col++) {
- rc = next_word(&s, &p);
- if (rc)
- break;
-
- switch(col) {
- /* MOUNTROOT */
- case 3:
- fs->root = p;
- break;
-
- /* TARGET (mountpoit) */
- case 4:
- fs->target = p;
- break;
-
- /* OPTIONS (fs-independent) */
- case 5:
- fs->vfs_optstr = p;
-
- /* ignore optional fields behind options */
- do {
- s = skip_spaces(s);
- if (s && *s == '-' &&
- (*(s + 1) == ' ' || *(s + 1) == '\t')) {
- s++;
- break;
- }
- next_word_skip(&s);
- } while (s);
- break;
- /* FSTYPE */
- case 6:
- rc =__mnt_fs_set_fstype_ptr(fs, p);
- break;
+ unmangle_string(fs->root);
+ unmangle_string(fs->target);
+ unmangle_string(fs->vfs_optstr);
+ unmangle_string(fstype);
- /* SOURCE or "none" */
- case 7:
- rc = __mnt_fs_set_source_ptr(fs, p);
- break;
+ if (!strcmp(src, "none")) {
+ free(src);
+ src = NULL;
+ } else
+ unmangle_string(src);
- /* OPTIONS (fs-dependent) */
- case 8:
- fs->fs_optstr = p;
+ unmangle_string(fs->fs_optstr);
- if (!strcmp(fs->fs_optstr, "none")) {
- free(fs->fs_optstr);
- fs->fs_optstr = NULL;
- }
- break;
- }
+ rc = __mnt_fs_set_fstype_ptr(fs, fstype);
+ if (!rc)
+ rc = __mnt_fs_set_source_ptr(fs, src);
+ } else {
+ DBG(TAB, mnt_debug("parse error [field=%d]: '%s'", rc, s));
+ rc = -EINVAL;
}
- if (rc)
- free(p);
-done:
return rc;
}
@@ -258,17 +134,10 @@ done:
*/
static int detect_fmt(char *line)
{
- int num;
-
- /* ID */
- if (next_number(&line, &num) != 0)
- return MNT_FMT_FSTAB;
-
- /* PARENT */
- if (next_number(&line, &num) != 0)
- return MNT_FMT_FSTAB;
+ unsigned int a, b;
- return MNT_FMT_MOUNTINFO;
+ return sscanf(line, "%u %u", &a, &b) == 2 ?
+ MNT_FMT_MOUNTINFO : MNT_FMT_FSTAB;
}
@@ -374,12 +243,10 @@ static int mnt_tab_parse_next(mnt_tab *tb, FILE *f, mnt_fs *fs,
tb->fmt = detect_fmt(s);
if (tb->fmt == MNT_FMT_FSTAB) {
- /* parse /etc/{fs,m}tab */
if (mnt_tab_parse_file_line(fs, s) != 0)
goto err;
} else if (tb->fmt == MNT_FMT_MOUNTINFO) {
- /* parse /proc/self/mountinfo */
if (mnt_parse_mountinfo_line(fs, s) != 0)
goto err;
}