linux/block/cmdline-parser.c
<<
>>
Prefs
   1/*
   2 * Parse command line, get partition information
   3 *
   4 * Written by Cai Zhiyong <caizhiyong@huawei.com>
   5 *
   6 */
   7#include <linux/buffer_head.h>
   8#include <linux/module.h>
   9#include <linux/cmdline-parser.h>
  10
  11static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
  12{
  13        int ret = 0;
  14        struct cmdline_subpart *new_subpart;
  15
  16        *subpart = NULL;
  17
  18        new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
  19        if (!new_subpart)
  20                return -ENOMEM;
  21
  22        if (*partdef == '-') {
  23                new_subpart->size = (sector_t)(~0ULL);
  24                partdef++;
  25        } else {
  26                new_subpart->size = (sector_t)memparse(partdef, &partdef);
  27                if (new_subpart->size < (sector_t)PAGE_SIZE) {
  28                        pr_warn("cmdline partition size is invalid.");
  29                        ret = -EINVAL;
  30                        goto fail;
  31                }
  32        }
  33
  34        if (*partdef == '@') {
  35                partdef++;
  36                new_subpart->from = (sector_t)memparse(partdef, &partdef);
  37        } else {
  38                new_subpart->from = (sector_t)(~0ULL);
  39        }
  40
  41        if (*partdef == '(') {
  42                int length;
  43                char *next = strchr(++partdef, ')');
  44
  45                if (!next) {
  46                        pr_warn("cmdline partition format is invalid.");
  47                        ret = -EINVAL;
  48                        goto fail;
  49                }
  50
  51                length = min_t(int, next - partdef,
  52                               sizeof(new_subpart->name) - 1);
  53                strncpy(new_subpart->name, partdef, length);
  54                new_subpart->name[length] = '\0';
  55
  56                partdef = ++next;
  57        } else
  58                new_subpart->name[0] = '\0';
  59
  60        new_subpart->flags = 0;
  61
  62        if (!strncmp(partdef, "ro", 2)) {
  63                new_subpart->flags |= PF_RDONLY;
  64                partdef += 2;
  65        }
  66
  67        if (!strncmp(partdef, "lk", 2)) {
  68                new_subpart->flags |= PF_POWERUP_LOCK;
  69                partdef += 2;
  70        }
  71
  72        *subpart = new_subpart;
  73        return 0;
  74fail:
  75        kfree(new_subpart);
  76        return ret;
  77}
  78
  79static void free_subpart(struct cmdline_parts *parts)
  80{
  81        struct cmdline_subpart *subpart;
  82
  83        while (parts->subpart) {
  84                subpart = parts->subpart;
  85                parts->subpart = subpart->next_subpart;
  86                kfree(subpart);
  87        }
  88}
  89
  90static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
  91{
  92        int ret = -EINVAL;
  93        char *next;
  94        int length;
  95        struct cmdline_subpart **next_subpart;
  96        struct cmdline_parts *newparts;
  97        char buf[BDEVNAME_SIZE + 32 + 4];
  98
  99        *parts = NULL;
 100
 101        newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
 102        if (!newparts)
 103                return -ENOMEM;
 104
 105        next = strchr(bdevdef, ':');
 106        if (!next) {
 107                pr_warn("cmdline partition has no block device.");
 108                goto fail;
 109        }
 110
 111        length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1);
 112        strncpy(newparts->name, bdevdef, length);
 113        newparts->name[length] = '\0';
 114        newparts->nr_subparts = 0;
 115
 116        next_subpart = &newparts->subpart;
 117
 118        while (next && *(++next)) {
 119                bdevdef = next;
 120                next = strchr(bdevdef, ',');
 121
 122                length = (!next) ? (sizeof(buf) - 1) :
 123                        min_t(int, next - bdevdef, sizeof(buf) - 1);
 124
 125                strncpy(buf, bdevdef, length);
 126                buf[length] = '\0';
 127
 128                ret = parse_subpart(next_subpart, buf);
 129                if (ret)
 130                        goto fail;
 131
 132                newparts->nr_subparts++;
 133                next_subpart = &(*next_subpart)->next_subpart;
 134        }
 135
 136        if (!newparts->subpart) {
 137                pr_warn("cmdline partition has no valid partition.");
 138                ret = -EINVAL;
 139                goto fail;
 140        }
 141
 142        *parts = newparts;
 143
 144        return 0;
 145fail:
 146        free_subpart(newparts);
 147        kfree(newparts);
 148        return ret;
 149}
 150
 151void cmdline_parts_free(struct cmdline_parts **parts)
 152{
 153        struct cmdline_parts *next_parts;
 154
 155        while (*parts) {
 156                next_parts = (*parts)->next_parts;
 157                free_subpart(*parts);
 158                kfree(*parts);
 159                *parts = next_parts;
 160        }
 161}
 162
 163int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline)
 164{
 165        int ret;
 166        char *buf;
 167        char *pbuf;
 168        char *next;
 169        struct cmdline_parts **next_parts;
 170
 171        *parts = NULL;
 172
 173        next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
 174        if (!buf)
 175                return -ENOMEM;
 176
 177        next_parts = parts;
 178
 179        while (next && *pbuf) {
 180                next = strchr(pbuf, ';');
 181                if (next)
 182                        *next = '\0';
 183
 184                ret = parse_parts(next_parts, pbuf);
 185                if (ret)
 186                        goto fail;
 187
 188                if (next)
 189                        pbuf = ++next;
 190
 191                next_parts = &(*next_parts)->next_parts;
 192        }
 193
 194        if (!*parts) {
 195                pr_warn("cmdline partition has no valid partition.");
 196                ret = -EINVAL;
 197                goto fail;
 198        }
 199
 200        ret = 0;
 201done:
 202        kfree(buf);
 203        return ret;
 204
 205fail:
 206        cmdline_parts_free(parts);
 207        goto done;
 208}
 209
 210struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
 211                                         const char *bdev)
 212{
 213        while (parts && strncmp(bdev, parts->name, sizeof(parts->name)))
 214                parts = parts->next_parts;
 215        return parts;
 216}
 217
 218/*
 219 *  add_part()
 220 *    0 success.
 221 *    1 can not add so many partitions.
 222 */
 223void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
 224                       int slot,
 225                       int (*add_part)(int, struct cmdline_subpart *, void *),
 226                       void *param)
 227
 228{
 229        sector_t from = 0;
 230        struct cmdline_subpart *subpart;
 231
 232        for (subpart = parts->subpart; subpart;
 233             subpart = subpart->next_subpart, slot++) {
 234                if (subpart->from == (sector_t)(~0ULL))
 235                        subpart->from = from;
 236                else
 237                        from = subpart->from;
 238
 239                if (from >= disk_size)
 240                        break;
 241
 242                if (subpart->size > (disk_size - from))
 243                        subpart->size = disk_size - from;
 244
 245                from += subpart->size;
 246
 247                if (add_part(slot, subpart, param))
 248                        break;
 249        }
 250}
 251
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.