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