mbr.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * cmd_mbr.c -- MBR (Master Boot Record) handling command
  4. *
  5. * Copyright (C) 2020 Samsung Electronics
  6. * author: Marek Szyprowski <m.szyprowski@samsung.com>
  7. *
  8. * based on the gpt command.
  9. */
  10. #include <common.h>
  11. #include <blk.h>
  12. #include <command.h>
  13. #include <malloc.h>
  14. #include <part.h>
  15. /**
  16. * extract_val() - Extract a value from the key=value pair list
  17. * @str: pointer to string with key=values pairs
  18. * @key: pointer to the key to search for
  19. *
  20. * The list of parameters is come separated, only a value for
  21. * the given key is returend.
  22. *
  23. * Function allocates memory for the value, remember to free!
  24. *
  25. * Return: Pointer to allocated string with the value.
  26. */
  27. static char *extract_val(const char *str, const char *key)
  28. {
  29. char *v, *k;
  30. char *s, *strcopy;
  31. char *new = NULL;
  32. strcopy = strdup(str);
  33. if (strcopy == NULL)
  34. return NULL;
  35. s = strcopy;
  36. while (s) {
  37. v = strsep(&s, ",");
  38. if (!v)
  39. break;
  40. k = strsep(&v, "=");
  41. if (!k)
  42. break;
  43. if (strcmp(k, key) == 0) {
  44. new = strdup(v);
  45. break;
  46. }
  47. }
  48. free(strcopy);
  49. return new;
  50. }
  51. /**
  52. * found_key() - Search for a key without a value in the parameter list
  53. * @str: pointer to string with key
  54. * @key: pointer to the key to search for
  55. *
  56. * The list of parameters is come separated.
  57. *
  58. * Return: True if key has been found.
  59. */
  60. static bool found_key(const char *str, const char *key)
  61. {
  62. char *k;
  63. char *s, *strcopy;
  64. bool result = false;
  65. strcopy = strdup(str);
  66. if (!strcopy)
  67. return NULL;
  68. s = strcopy;
  69. while (s) {
  70. k = strsep(&s, ",");
  71. if (!k)
  72. break;
  73. if (strcmp(k, key) == 0) {
  74. result = true;
  75. break;
  76. }
  77. }
  78. free(strcopy);
  79. return result;
  80. }
  81. static int str_to_partitions(const char *str_part, int blksz,
  82. unsigned long *disk_uuid, struct disk_partition **partitions,
  83. int *parts_count)
  84. {
  85. char *tok, *str, *s;
  86. int i;
  87. char *val, *p;
  88. int p_count;
  89. struct disk_partition *parts;
  90. int errno = 0;
  91. uint64_t size_ll, start_ll;
  92. if (str_part == NULL)
  93. return -1;
  94. str = strdup(str_part);
  95. if (str == NULL)
  96. return -ENOMEM;
  97. /* extract disk guid */
  98. s = str;
  99. val = extract_val(str, "uuid_disk");
  100. if (val) {
  101. val = strsep(&val, ";");
  102. p = val;
  103. *disk_uuid = ustrtoull(p, &p, 0);
  104. free(val);
  105. /* Move s to first partition */
  106. strsep(&s, ";");
  107. }
  108. if (s == NULL) {
  109. printf("Error: is the partitions string NULL-terminated?\n");
  110. return -EINVAL;
  111. }
  112. /* remove the optional semicolon at the end of the string */
  113. i = strlen(s) - 1;
  114. if (s[i] == ';')
  115. s[i] = '\0';
  116. /* calculate expected number of partitions */
  117. p_count = 1;
  118. p = s;
  119. while (*p) {
  120. if (*p++ == ';')
  121. p_count++;
  122. }
  123. /* allocate memory for partitions */
  124. parts = calloc(sizeof(struct disk_partition), p_count);
  125. if (parts == NULL)
  126. return -ENOMEM;
  127. /* retrieve partitions data from string */
  128. for (i = 0; i < p_count; i++) {
  129. tok = strsep(&s, ";");
  130. if (tok == NULL)
  131. break;
  132. /* size */
  133. val = extract_val(tok, "size");
  134. if (!val) { /* 'size' is mandatory */
  135. errno = -4;
  136. goto err;
  137. }
  138. p = val;
  139. if ((strcmp(p, "-") == 0)) {
  140. /* auto extend the size */
  141. parts[i].size = 0;
  142. } else {
  143. size_ll = ustrtoull(p, &p, 0);
  144. parts[i].size = size_ll / blksz;
  145. }
  146. free(val);
  147. /* start address */
  148. val = extract_val(tok, "start");
  149. if (val) { /* start address is optional */
  150. p = val;
  151. start_ll = ustrtoull(p, &p, 0);
  152. parts[i].start = start_ll / blksz;
  153. free(val);
  154. }
  155. /* system id */
  156. val = extract_val(tok, "id");
  157. if (!val) { /* '' is mandatory */
  158. errno = -4;
  159. goto err;
  160. }
  161. p = val;
  162. parts[i].sys_ind = ustrtoul(p, &p, 0);
  163. free(val);
  164. /* bootable */
  165. if (found_key(tok, "bootable"))
  166. parts[i].bootable = PART_BOOTABLE;
  167. }
  168. *parts_count = p_count;
  169. *partitions = parts;
  170. free(str);
  171. return 0;
  172. err:
  173. free(str);
  174. free(parts);
  175. return errno;
  176. }
  177. static int do_write_mbr(struct blk_desc *dev, const char *str)
  178. {
  179. unsigned long disk_uuid = 0;
  180. struct disk_partition *partitions;
  181. int blksz = dev->blksz;
  182. int count;
  183. if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) {
  184. printf("MBR: failed to setup partitions from \"%s\"\n", str);
  185. return -1;
  186. }
  187. if (layout_mbr_partitions(partitions, count, dev->lba)) {
  188. printf("MBR: failed to layout partitions on the device\n");
  189. free(partitions);
  190. return -1;
  191. }
  192. if (write_mbr_partitions(dev, partitions, count, disk_uuid)) {
  193. printf("MBR: failed to write partitions to the device\n");
  194. free(partitions);
  195. return -1;
  196. }
  197. return 0;
  198. }
  199. static int do_verify_mbr(struct blk_desc *dev, const char *str)
  200. {
  201. unsigned long disk_uuid = 0;
  202. struct disk_partition *partitions;
  203. int blksz = dev->blksz;
  204. int count, i, ret = 1;
  205. if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) {
  206. printf("MBR: failed to setup partitions from \"%s\"\n", str);
  207. return -1;
  208. }
  209. for (i = 0; i < count; i++) {
  210. struct disk_partition p;
  211. if (part_get_info(dev, i+1, &p))
  212. goto fail;
  213. if ((partitions[i].size && p.size < partitions[i].size) ||
  214. (partitions[i].start && p.start < partitions[i].start) ||
  215. (p.sys_ind != partitions[i].sys_ind))
  216. goto fail;
  217. }
  218. ret = 0;
  219. fail:
  220. free(partitions);
  221. return ret;
  222. }
  223. static int do_mbr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
  224. {
  225. const char *parts = NULL;
  226. int ret = CMD_RET_SUCCESS;
  227. int dev = 0;
  228. char *ep;
  229. struct blk_desc *blk_dev_desc = NULL;
  230. if (argc != 4 && argc != 5)
  231. return CMD_RET_USAGE;
  232. dev = (int)dectoul(argv[3], &ep);
  233. if (!ep || ep[0] != '\0') {
  234. printf("'%s' is not a number\n", argv[3]);
  235. return CMD_RET_USAGE;
  236. }
  237. blk_dev_desc = blk_get_dev(argv[2], dev);
  238. if (!blk_dev_desc) {
  239. printf("%s: %s dev %d NOT available\n",
  240. __func__, argv[2], dev);
  241. return CMD_RET_FAILURE;
  242. }
  243. if ((strcmp(argv[1], "write") == 0)) {
  244. parts = (argc == 5) ? argv[4] : env_get("mbr_parts");
  245. printf("MBR: write ");
  246. ret = do_write_mbr(blk_dev_desc, parts);
  247. } else if ((strcmp(argv[1], "verify") == 0)) {
  248. printf("MBR: verify ");
  249. parts = (argc == 5) ? argv[4] : env_get("mbr_parts");
  250. ret = do_verify_mbr(blk_dev_desc, parts);
  251. } else {
  252. return CMD_RET_USAGE;
  253. }
  254. if (ret) {
  255. printf("error!\n");
  256. return CMD_RET_FAILURE;
  257. }
  258. printf("success!\n");
  259. return CMD_RET_SUCCESS;
  260. }
  261. U_BOOT_CMD(mbr, CONFIG_SYS_MAXARGS, 1, do_mbr,
  262. "MBR (Master Boot Record)",
  263. "<command> <interface> <dev> <partitions_list>\n"
  264. " - MBR partition table restoration utility\n"
  265. " Restore or check partition information on a device connected\n"
  266. " to the given block interface\n"
  267. " Example usage:\n"
  268. " mbr write mmc 0 [\"${mbr_parts}\"]\n"
  269. " mbr verify mmc 0 [\"${partitions}\"]\n"
  270. );