]> err.no Git - util-linux/commitdiff
libmount: rewrite mountinfo/fstab parsers to use sscanf()
authorKarel Zak <kzak@redhat.com>
Fri, 1 Oct 2010 11:05:58 +0000 (13:05 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 3 Jan 2011 11:28:43 +0000 (12:28 +0100)
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>
include/mangle.h
lib/mangle.c
shlibs/mount/src/tab_parse.c

index 0ccd37768c2eb320aeb0cc9fceda3c1d9ab0dd8a..5dda902f7c433dfc0ee5532de6dbbdbdf2b73959 100644 (file)
@@ -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 */
 
index e320cfb7c63f9db8027cb3815780102697c8004c..938dd8e55e311c7b0366e91d110ff03e5a622671 100644 (file)
@@ -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;
index 062b9040ec671bea7bf8c1daf7b590797c71d944..603908f203314ea3fb794b80c17918c602effe0e 100644 (file)
@@ -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;
        }