From: Cai Zhiyong <caizhiy...@huawei.com>

move the command line parser to a separate module, and change it into
library-style code.

reference: https://lkml.org/lkml/2013/8/6/550

Signed-off-by: Cai Zhiyong <caizhiy...@huawei.com>
---
 block/Kconfig                  |   6 +
 block/Makefile                 |   1 +
 block/cmdline-parser.c         | 249 +++++++++++++++++++++++++++++++++
 block/partitions/Kconfig       |   1 +
 block/partitions/cmdline.c     | 311 ++++++-----------------------------------
 include/linux/cmdline-parser.h |  43 ++++++
 6 files changed, 342 insertions(+), 269 deletions(-)
 create mode 100644 block/cmdline-parser.c
 create mode 100644 include/linux/cmdline-parser.h

diff --git a/block/Kconfig b/block/Kconfig
index a7e40a7..7f38e40 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -99,6 +99,12 @@ config BLK_DEV_THROTTLING
 
        See Documentation/cgroups/blkio-controller.txt for more information.
 
+config CMDLINE_PARSER
+       bool "Block device command line partition parser"
+       default n
+       ---help---
+       Parsing command line, get the partitions information.
+
 menu "Partition Types"
 
 source "block/partitions/Kconfig"
diff --git a/block/Makefile b/block/Makefile
index 39b76ba..4fa4be5 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_IOSCHED_CFQ)     += cfq-iosched.o
 
 obj-$(CONFIG_BLOCK_COMPAT)     += compat_ioctl.o
 obj-$(CONFIG_BLK_DEV_INTEGRITY)        += blk-integrity.o
+obj-$(CONFIG_CMDLINE_PARSER)   += cmdline-parser.o
diff --git a/block/cmdline-parser.c b/block/cmdline-parser.c
new file mode 100644
index 0000000..18fb435
--- /dev/null
+++ b/block/cmdline-parser.c
@@ -0,0 +1,249 @@
+/*
+ * Parse command line, get partition information
+ *
+ * Written by Cai Zhiyong <caizhiy...@huawei.com>
+ *
+ */
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/cmdline-parser.h>
+
+static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
+{
+       int ret = 0;
+       struct cmdline_subpart *new_subpart;
+
+       *subpart = NULL;
+
+       new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
+       if (!new_subpart)
+               return -ENOMEM;
+
+       if (*partdef == '-') {
+               new_subpart->size = (sector_t)(~0ULL);
+               partdef++;
+       } else {
+               new_subpart->size = (sector_t)memparse(partdef, &partdef);
+               if (new_subpart->size < (sector_t)PAGE_SIZE) {
+                       pr_warn("cmdline partition size is invalid.");
+                       ret = -EINVAL;
+                       goto fail;
+               }
+       }
+
+       if (*partdef == '@') {
+               partdef++;
+               new_subpart->from = (sector_t)memparse(partdef, &partdef);
+       } else {
+               new_subpart->from = (sector_t)(~0ULL);
+       }
+
+       if (*partdef == '(') {
+               int length;
+               char *next = strchr(++partdef, ')');
+
+               if (!next) {
+                       pr_warn("cmdline partition format is invalid.");
+                       ret = -EINVAL;
+                       goto fail;
+               }
+
+               length = min_t(int, next - partdef,
+                              sizeof(new_subpart->name) - 1);
+               strncpy(new_subpart->name, partdef, length);
+               new_subpart->name[length] = '\0';
+
+               partdef = ++next;
+       } else
+               new_subpart->name[0] = '\0';
+
+       new_subpart->flags = 0;
+
+       if (!strncmp(partdef, "ro", 2)) {
+               new_subpart->flags |= PF_RDONLY;
+               partdef += 2;
+       }
+
+       if (!strncmp(partdef, "lk", 2)) {
+               new_subpart->flags |= PF_POWERUP_LOCK;
+               partdef += 2;
+       }
+
+       *subpart = new_subpart;
+       return 0;
+fail:
+       kfree(new_subpart);
+       return ret;
+}
+
+static void free_subpart(struct cmdline_parts *parts)
+{
+       struct cmdline_subpart *subpart;
+
+       while (parts->subpart) {
+               subpart = parts->subpart;
+               parts->subpart = subpart->next_subpart;
+               kfree(subpart);
+       }
+}
+
+static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
+{
+       int ret = -EINVAL;
+       char *next;
+       int length;
+       struct cmdline_subpart **next_subpart;
+       struct cmdline_parts *newparts;
+       char buf[BDEVNAME_SIZE + 32 + 4];
+
+       *parts = NULL;
+
+       newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
+       if (!newparts)
+               return -ENOMEM;
+
+       next = strchr(bdevdef, ':');
+       if (!next) {
+               pr_warn("cmdline partition has no block device.");
+               goto fail;
+       }
+
+       length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1);
+       strncpy(newparts->name, bdevdef, length);
+       newparts->name[length] = '\0';
+       newparts->nr_subparts = 0;
+
+       next_subpart = &newparts->subpart;
+
+       while (next && *(++next)) {
+               bdevdef = next;
+               next = strchr(bdevdef, ',');
+
+               length = (!next) ? (sizeof(buf) - 1) :
+                       min_t(int, next - bdevdef, sizeof(buf) - 1);
+
+               strncpy(buf, bdevdef, length);
+               buf[length] = '\0';
+
+               ret = parse_subpart(next_subpart, buf);
+               if (ret)
+                       goto fail;
+
+               newparts->nr_subparts++;
+               next_subpart = &(*next_subpart)->next_subpart;
+       }
+
+       if (!newparts->subpart) {
+               pr_warn("cmdline partition has no valid partition.");
+               goto fail;
+       }
+
+       *parts = newparts;
+
+       return 0;
+fail:
+       free_subpart(newparts);
+       kfree(newparts);
+       return ret;
+}
+
+void cmdline_parts_free(struct cmdline_parts **parts)
+{
+       struct cmdline_parts *next_parts;
+
+       while (*parts) {
+               next_parts = (*parts)->next_parts;
+               free_subpart(*parts);
+               kfree(*parts);
+               *parts = next_parts;
+       }
+}
+
+int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline)
+{
+       int ret;
+       char *buf;
+       char *pbuf;
+       char *next;
+       struct cmdline_parts **next_parts;
+
+       *parts = NULL;
+
+       next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       next_parts = parts;
+
+       while (next && *pbuf) {
+               next = strchr(pbuf, ';');
+               if (next)
+                       *next = '\0';
+
+               ret = parse_parts(next_parts, pbuf);
+               if (ret)
+                       goto fail;
+
+               if (next)
+                       pbuf = ++next;
+
+               next_parts = &(*next_parts)->next_parts;
+       }
+
+       if (!*parts) {
+               pr_warn("cmdline partition has no valid partition.");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       ret = 0;
+done:
+       kfree(buf);
+       return ret;
+
+fail:
+       cmdline_parts_free(parts);
+       goto done;
+}
+
+struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
+                                        const char *bdev)
+{
+       while (parts && strncmp(bdev, parts->name, sizeof(parts->name)))
+               parts = parts->next_parts;
+       return parts;
+}
+
+/*
+ *  add_part()
+ *    0 success.
+ *    1 can not add so many partitions.
+ */
+void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
+                      int slot,
+                      int (*add_part)(int, struct cmdline_subpart *, void *),
+                      void *param)
+
+{
+       sector_t from = 0;
+       struct cmdline_subpart *subpart;
+
+       for (subpart = parts->subpart; subpart;
+            subpart = subpart->next_subpart, slot++) {
+               if (subpart->from == (sector_t)(~0ULL))
+                       subpart->from = from;
+               else
+                       from = subpart->from;
+
+               if (from >= disk_size)
+                       break;
+
+               if (subpart->size > (disk_size - from))
+                       subpart->size = disk_size - from;
+
+               from += subpart->size;
+
+               if (add_part(slot, subpart, param))
+                       break;
+       }
+}
diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
index 2ebf251..87a3208 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -263,6 +263,7 @@ config SYSV68_PARTITION
 
 config CMDLINE_PARTITION
        bool "Command line partition support" if PARTITION_ADVANCED
+       select CMDLINE_PARSER
        help
          Say Y here if you would read the partitions table from bootargs.
          The format for the command line is just like mtdparts.
diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c
index 1a1eac7..56cf4ff 100644
--- a/block/partitions/cmdline.c
+++ b/block/partitions/cmdline.c
@@ -8,219 +8,54 @@
  * by absolute address of data on the block device.
  * Users can easily change the partition.
  *
- * This code reference MTD partition, source "drivers/mtd/cmdlinepart.c"
  * The format for the command line is just like mtdparts.
  *
  * Verbose config please reference "Documentation/block/cmdline-partition.txt"
  *
  */
 
-#include <linux/buffer_head.h>
-#include <linux/module.h>
-#include <linux/ctype.h>
+#include <linux/cmdline-parser.h>
 
 #include "check.h"
 #include "cmdline.h"
 
-struct cmdline_subpart {
-       char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */
-       sector_t from;
-       sector_t size;
-       struct cmdline_subpart *next_subpart;
-};
+static char *cmdline;
+static struct cmdline_parts *bdev_parts;
 
-struct cmdline_parts {
-       char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
-       struct cmdline_subpart *subpart;
-       struct cmdline_parts *next_parts;
-};
-
-static char *cmdline_string;
-static struct cmdline_parts *cmdline_parts;
-
-static int parse_subpart(struct cmdline_subpart **subpart, char *cmdline)
-{
-       int ret = 0;
-       struct cmdline_subpart *new_subpart;
-
-       *subpart = NULL;
-
-       new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
-       if (!new_subpart)
-               return -ENOMEM;
-
-       if (*cmdline == '-') {
-               new_subpart->size = (sector_t)(~0ULL);
-               cmdline++;
-       } else {
-               new_subpart->size = (sector_t)memparse(cmdline, &cmdline);
-               if (new_subpart->size < (sector_t)PAGE_SIZE) {
-                       pr_warn("cmdline partition size is invalid.");
-                       ret = -EINVAL;
-                       goto fail;
-               }
-       }
-
-       if (*cmdline == '@') {
-               cmdline++;
-               new_subpart->from = (sector_t)memparse(cmdline, &cmdline);
-       } else {
-               new_subpart->from = (sector_t)(~0ULL);
-       }
-
-       if (*cmdline == '(') {
-               int length;
-               char *next = strchr(++cmdline, ')');
-
-               if (!next) {
-                       pr_warn("cmdline partition format is invalid.");
-                       ret = -EINVAL;
-                       goto fail;
-               }
-
-               length = min_t(int, next - cmdline,
-                              sizeof(new_subpart->name) - 1);
-               strncpy(new_subpart->name, cmdline, length);
-               new_subpart->name[length] = '\0';
-
-               cmdline = ++next;
-       } else
-               new_subpart->name[0] = '\0';
-
-       *subpart = new_subpart;
-       return 0;
-fail:
-       kfree(new_subpart);
-       return ret;
-}
-
-static void free_subpart(struct cmdline_parts *parts)
-{
-       struct cmdline_subpart *subpart;
-
-       while (parts->subpart) {
-               subpart = parts->subpart;
-               parts->subpart = subpart->next_subpart;
-               kfree(subpart);
-       }
-}
-
-static void free_parts(struct cmdline_parts **parts)
-{
-       struct cmdline_parts *next_parts;
-
-       while (*parts) {
-               next_parts = (*parts)->next_parts;
-               free_subpart(*parts);
-               kfree(*parts);
-               *parts = next_parts;
-       }
-}
-
-static int parse_parts(struct cmdline_parts **parts, const char *cmdline)
+static int add_part(int slot, struct cmdline_subpart *subpart, void *param)
 {
-       int ret = -EINVAL;
-       char *next;
-       int length;
-       struct cmdline_subpart **next_subpart;
-       struct cmdline_parts *newparts;
-       char buf[BDEVNAME_SIZE + 32 + 4];
+       int label_min;
+       struct partition_meta_info *info;
+       char tmp[sizeof(info->volname) + 4];
+       struct parsed_partitions *state = (struct parsed_partitions *)param;
 
-       *parts = NULL;
+       if (slot >= state->limit)
+               return 1;
 
-       newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
-       if (!newparts)
-               return -ENOMEM;
+       put_partition(state, slot, subpart->from >> 9,
+                     subpart->size >> 9);
 
-       next = strchr(cmdline, ':');
-       if (!next) {
-               pr_warn("cmdline partition has no block device.");
-               goto fail;
-       }
-
-       length = min_t(int, next - cmdline, sizeof(newparts->name) - 1);
-       strncpy(newparts->name, cmdline, length);
-       newparts->name[length] = '\0';
-
-       next_subpart = &newparts->subpart;
+       info = &state->parts[slot].info;
 
-       while (next && *(++next)) {
-               cmdline = next;
-               next = strchr(cmdline, ',');
+       label_min = min_t(int, sizeof(info->volname) - 1,
+                         sizeof(subpart->name));
+       strncpy(info->volname, subpart->name, label_min);
+       info->volname[label_min] = '\0';
 
-               length = (!next) ? (sizeof(buf) - 1) :
-                       min_t(int, next - cmdline, sizeof(buf) - 1);
+       snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
+       strlcat(state->pp_buf, tmp, PAGE_SIZE);
 
-               strncpy(buf, cmdline, length);
-               buf[length] = '\0';
-
-               ret = parse_subpart(next_subpart, buf);
-               if (ret)
-                       goto fail;
-
-               next_subpart = &(*next_subpart)->next_subpart;
-       }
-
-       if (!newparts->subpart) {
-               pr_warn("cmdline partition has no valid partition.");
-               goto fail;
-       }
-
-       *parts = newparts;
+       state->parts[slot].has_info = true;
 
        return 0;
-fail:
-       free_subpart(newparts);
-       kfree(newparts);
-       return ret;
 }
 
-static int parse_cmdline(struct cmdline_parts **parts, const char *cmdline)
+static int __init cmdline_parts_setup(char *s)
 {
-       int ret;
-       char *buf;
-       char *pbuf;
-       char *next;
-       struct cmdline_parts **next_parts;
-
-       *parts = NULL;
-
-       next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       next_parts = parts;
-
-       while (next && *pbuf) {
-               next = strchr(pbuf, ';');
-               if (next)
-                       *next = '\0';
-
-               ret = parse_parts(next_parts, pbuf);
-               if (ret)
-                       goto fail;
-
-               if (next)
-                       pbuf = ++next;
-
-               next_parts = &(*next_parts)->next_parts;
-       }
-
-       if (!*parts) {
-               pr_warn("cmdline partition has no valid partition.");
-               ret = -EINVAL;
-               goto fail;
-       }
-
-       ret = 0;
-done:
-       kfree(buf);
-       return ret;
-
-fail:
-       free_parts(parts);
-       goto done;
+       cmdline = s;
+       return 1;
 }
+__setup("blkdevparts=", cmdline_parts_setup);
 
 /*
  * Purpose: allocate cmdline partitions.
@@ -229,98 +64,36 @@ fail:
  *  0 if this isn't our partition table
  *  1 if successful
  */
-static int parse_partitions(struct parsed_partitions *state,
-                           struct cmdline_parts *parts)
+int cmdline_partition(struct parsed_partitions *state)
 {
-       int slot;
-       sector_t from = 0;
        sector_t disk_size;
-       char buf[BDEVNAME_SIZE];
-       struct cmdline_subpart *subpart;
+       char bdev[BDEVNAME_SIZE];
+       struct cmdline_parts *parts;
+
+       if (cmdline) {
+               if (bdev_parts)
+                       cmdline_parts_free(&bdev_parts);
 
-       bdevname(state->bdev, buf);
+               if (cmdline_parts_parse(&bdev_parts, cmdline)) {
+                       cmdline = NULL;
+                       return -1;
+               }
+               cmdline = NULL;
+       }
 
-       while (parts && strncmp(buf, parts->name, BDEVNAME_SIZE))
-               parts = parts->next_parts;
+       if (!bdev_parts)
+               return 0;
 
+       bdevname(state->bdev, bdev);
+       parts = cmdline_parts_find(bdev_parts, bdev);
        if (!parts)
                return 0;
 
        disk_size = get_capacity(state->bdev->bd_disk) << 9;
 
-       for (slot = 1, subpart = parts->subpart;
-            subpart && slot < state->limit;
-            subpart = subpart->next_subpart, slot++) {
-               int label_min;
-               struct partition_meta_info *info;
-               char tmp[sizeof(info->volname) + 4];
-
-               if (subpart->from == (sector_t)(~0ULL))
-                       subpart->from = from;
-               else
-                       from = subpart->from;
-
-               if (from >= disk_size)
-                       break;
-
-               if (subpart->size > (disk_size - from))
-                       subpart->size = disk_size - from;
-
-               from += subpart->size;
-
-               put_partition(state, slot, subpart->from >> 9,
-                             subpart->size >> 9);
-
-               info = &state->parts[slot].info;
-
-               label_min = min_t(int, sizeof(info->volname) - 1,
-                                 sizeof(subpart->name));
-               strncpy(info->volname, subpart->name, label_min);
-               info->volname[label_min] = '\0';
-
-               snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
-               strlcat(state->pp_buf, tmp, PAGE_SIZE);
-
-               state->parts[slot].has_info = true;
-       }
+       cmdline_parts_set(parts, disk_size, 1, add_part, (void *)state);
 
        strlcat(state->pp_buf, "\n", PAGE_SIZE);
 
        return 1;
 }
-
-static int __init cmdline_parts_setup(char *s)
-{
-       cmdline_string = s;
-       return 1;
-}
-__setup("blkdevparts=", cmdline_parts_setup);
-
-/*
- * Purpose: allocate cmdline partitions.
- * Returns:
- * -1 if unable to read the partition table
- *  0 if this isn't our partition table
- *  1 if successful
- */
-int cmdline_partition(struct parsed_partitions *state)
-{
-       if (cmdline_string) {
-               if (cmdline_parts)
-                       free_parts(&cmdline_parts);
-
-               if (parse_cmdline(&cmdline_parts, cmdline_string))
-                       goto fail;
-
-               cmdline_string = NULL;
-       }
-
-       if (!cmdline_parts)
-               return 0;
-
-       return parse_partitions(state, cmdline_parts);
-
-fail:
-       cmdline_string = NULL;
-       return -1;
-}
diff --git a/include/linux/cmdline-parser.h b/include/linux/cmdline-parser.h
new file mode 100644
index 0000000..98e892e
--- /dev/null
+++ b/include/linux/cmdline-parser.h
@@ -0,0 +1,43 @@
+/*
+ * Parsing command line, get the partitions information.
+ *
+ * Written by Cai Zhiyong <caizhiy...@huawei.com>
+ *
+ */
+#ifndef CMDLINEPARSEH
+#define CMDLINEPARSEH
+
+#include <linux/blkdev.h>
+
+/* partition flags */
+#define PF_RDONLY                   0x01 /* Device is read only */
+#define PF_POWERUP_LOCK             0x02 /* Always locked after reset */
+
+struct cmdline_subpart {
+       char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */
+       sector_t from;
+       sector_t size;
+       int flags;
+       struct cmdline_subpart *next_subpart;
+};
+
+struct cmdline_parts {
+       char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
+       unsigned int nr_subparts;
+       struct cmdline_subpart *subpart;
+       struct cmdline_parts *next_parts;
+};
+
+void cmdline_parts_free(struct cmdline_parts **parts);
+
+int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline);
+
+struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
+                                        const char *bdev);
+
+void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
+                      int slot,
+                      int (*add_part)(int, struct cmdline_subpart *, void *),
+                      void *param);
+
+#endif /* CMDLINEPARSEH */
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to