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/export.h>
   8#include <linux/cmdline-parser.h>
   9
  10static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
  11{
  12        int ret = 0;
  13        struct cmdline_subpart *new_subpart;
  14
  15        *subpart = NULL;
  16
  17        new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
  18        if (!new_subpart)
  19                return -ENOMEM;
  20
  21        if (*partdef == '-') {
  22                new_subpart->size = (sector_t)(~0ULL);
  23                partdef++;
  24        } else {
  25                new_subpart->size = (sector_t)memparse(partdef, &partdef);
  26                if (new_subpart->size < (sector_t)PAGE_SIZE) {
  27                        pr_warn("cmdline partition size is invalid.");
  28                        ret = -EINVAL;
  29                        goto fail;
  30                }
  31        }
  32
  33        if (*partdef == '@') {
  34                partdef++;
  35                new_subpart->from = (sector_t)memparse(partdef, &partdef);
  36        } else {
  37                new_subpart->from = (sector_t)(~0ULL);
  38        }
  39
  40        if (*partdef == '(') {
  41                int length;
  42                char *next = strchr(++partdef, ')');
  43
  44                if (!next) {
  45                        pr_warn("cmdline partition format is invalid.");
  46                        ret = -EINVAL;
  47                        goto fail;
  48                }
  49
  50                length = min_t(int, next - partdef,
  51                               sizeof(new_subpart->name) - 1);
  52                strncpy(new_subpart->name, partdef, length);
  53                new_subpart->name[length] = '\0';
  54
  55                partdef = ++next;
  56        } else
  57                new_subpart->name[0] = '\0';
  58
  59        new_subpart->flags = 0;
  60
  61        if (!strncmp(partdef, "ro", 2)) {
  62                new_subpart->flags |= PF_RDONLY;
  63                partdef += 2;
  64        }
  65
  66        if (!strncmp(partdef, "lk", 2)) {
  67                new_subpart->flags |= PF_POWERUP_LOCK;
  68                partdef += 2;
  69        }
  70
  71        *subpart = new_subpart;
  72        return 0;
  73fail:
  74        kfree(new_subpart);
  75        return ret;
  76}
  77
  78static void free_subpart(struct cmdline_parts *parts)
  79{
  80        struct cmdline_subpart *subpart;
  81
  82        while (parts->subpart) {
  83                subpart = parts->subpart;
  84                parts->subpart = subpart->next_subpart;
  85                kfree(subpart);
  86        }
  87}
  88
  89static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
  90{
  91        int ret = -EINVAL;
  92        char *next;
  93        int length;
  94        struct cmdline_subpart **next_subpart;
  95        struct cmdline_parts *newparts;
  96        char buf[BDEVNAME_SIZE + 32 + 4];
  97
  98        *parts = NULL;
  99
 100        newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
 101        if (!newparts)
 102                return -ENOMEM;
 103
 104        next = strchr(bdevdef, ':');
 105        if (!next) {
 106                pr_warn("cmdline partition has no block device.");
 107                goto fail;
 108        }
 109
 110        length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1);
 111        strncpy(newparts->name, bdevdef, length);
 112        newparts->name[length] = '\0';
 113        newparts->nr_subparts = 0;
 114
 115        next_subpart = &newparts->subpart;
 116
 117        while (next && *(++next)) {
 118                bdevdef = next;
 119                next = strchr(bdevdef, ',');
 120
 121                length = (!next) ? (sizeof(buf) - 1) :
 122                        min_t(int, next - bdevdef, sizeof(buf) - 1);
 123
 124                strncpy(buf, bdevdef, length);
 125                buf[length] = '\0';
 126
 127                ret = parse_subpart(next_subpart, buf);
 128                if (ret)
 129                        goto fail;
 130
 131                newparts->nr_subparts++;
 132                next_subpart = &(*next_subpart)->next_subpart;
 133        }
 134
 135        if (!newparts->subpart) {
 136                pr_warn("cmdline partition has no valid partition.");
 137                ret = -EINVAL;
 138                goto fail;
 139        }
 140
 141        *parts = newparts;
 142
 143        return 0;
 144fail:
 145        free_subpart(newparts);
 146        kfree(newparts);
 147        return ret;
 148}
 149
 150void cmdline_parts_free(struct cmdline_parts **parts)
 151{
 152        struct cmdline_parts *next_parts;
 153
 154        while (*parts) {
 155                next_parts = (*parts)->next_parts;
 156                free_subpart(*parts);
 157                kfree(*parts);
 158                *parts = next_parts;
 159        }
 160}
 161EXPORT_SYMBOL(cmdline_parts_free);
 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}
 209EXPORT_SYMBOL(cmdline_parts_parse);
 210
 211struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
 212                                         const char *bdev)
 213{
 214        while (parts && strncmp(bdev, parts->name, sizeof(parts->name)))
 215                parts = parts->next_parts;
 216        return parts;
 217}
 218EXPORT_SYMBOL(cmdline_parts_find);
 219
 220/*
 221 *  add_part()
 222 *    0 success.
 223 *    1 can not add so many partitions.
 224 */
 225int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
 226                      int slot,
 227                      int (*add_part)(int, struct cmdline_subpart *, void *),
 228                      void *param)
 229{
 230        sector_t from = 0;
 231        struct cmdline_subpart *subpart;
 232
 233        for (subpart = parts->subpart; subpart;
 234             subpart = subpart->next_subpart, slot++) {
 235                if (subpart->from == (sector_t)(~0ULL))
 236                        subpart->from = from;
 237                else
 238                        from = subpart->from;
 239
 240                if (from >= disk_size)
 241                        break;
 242
 243                if (subpart->size > (disk_size - from))
 244                        subpart->size = disk_size - from;
 245
 246                from += subpart->size;
 247
 248                if (add_part(slot, subpart, param))
 249                        break;
 250        }
 251
 252        return slot;
 253}
 254EXPORT_SYMBOL(cmdline_parts_set);
 255