cmd_gpt.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * cmd_gpt.c -- GPT (GUID Partition Table) handling command
  3. *
  4. * Copyright (C) 2012 Samsung Electronics
  5. * author: Lukasz Majewski <l.majewski@samsung.com>
  6. * author: Piotr Wilczek <p.wilczek@samsung.com>
  7. *
  8. * SPDX-License-Identifier: GPL-2.0+
  9. */
  10. #include <common.h>
  11. #include <malloc.h>
  12. #include <command.h>
  13. #include <part_efi.h>
  14. #include <exports.h>
  15. #include <linux/ctype.h>
  16. #include <div64.h>
  17. #ifndef CONFIG_PARTITION_UUIDS
  18. #error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled
  19. #endif
  20. /**
  21. * extract_env(): Expand env name from string format '&{env_name}'
  22. * and return pointer to the env (if the env is set)
  23. *
  24. * @param str - pointer to string
  25. * @param env - pointer to pointer to extracted env
  26. *
  27. * @return - zero on successful expand and env is set
  28. */
  29. static int extract_env(const char *str, char **env)
  30. {
  31. int ret = -1;
  32. char *e, *s;
  33. #ifdef CONFIG_RANDOM_UUID
  34. char uuid_str[UUID_STR_LEN + 1];
  35. #endif
  36. if (!str || strlen(str) < 4)
  37. return -1;
  38. if (!((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')))
  39. return -1;
  40. s = strdup(str);
  41. if (s == NULL)
  42. return -1;
  43. memset(s + strlen(s) - 1, '\0', 1);
  44. memmove(s, s + 2, strlen(s) - 1);
  45. e = getenv(s);
  46. if (e == NULL) {
  47. #ifdef CONFIG_RANDOM_UUID
  48. debug("%s unset. ", str);
  49. gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_STD);
  50. setenv(s, uuid_str);
  51. e = getenv(s);
  52. if (e) {
  53. debug("Set to random.\n");
  54. ret = 0;
  55. } else {
  56. debug("Can't get random UUID.\n");
  57. }
  58. #else
  59. debug("%s unset.\n", str);
  60. #endif
  61. } else {
  62. debug("%s get from environment.\n", str);
  63. ret = 0;
  64. }
  65. *env = e;
  66. free(s);
  67. return ret;
  68. }
  69. /**
  70. * extract_val(): Extract value from a key=value pair list (comma separated).
  71. * Only value for the given key is returend.
  72. * Function allocates memory for the value, remember to free!
  73. *
  74. * @param str - pointer to string with key=values pairs
  75. * @param key - pointer to the key to search for
  76. *
  77. * @return - pointer to allocated string with the value
  78. */
  79. static char *extract_val(const char *str, const char *key)
  80. {
  81. char *v, *k;
  82. char *s, *strcopy;
  83. char *new = NULL;
  84. strcopy = strdup(str);
  85. if (strcopy == NULL)
  86. return NULL;
  87. s = strcopy;
  88. while (s) {
  89. v = strsep(&s, ",");
  90. if (!v)
  91. break;
  92. k = strsep(&v, "=");
  93. if (!k)
  94. break;
  95. if (strcmp(k, key) == 0) {
  96. new = strdup(v);
  97. break;
  98. }
  99. }
  100. free(strcopy);
  101. return new;
  102. }
  103. /**
  104. * set_gpt_info(): Fill partition information from string
  105. * function allocates memory, remember to free!
  106. *
  107. * @param dev_desc - pointer block device descriptor
  108. * @param str_part - pointer to string with partition information
  109. * @param str_disk_guid - pointer to pointer to allocated string with disk guid
  110. * @param partitions - pointer to pointer to allocated partitions array
  111. * @param parts_count - number of partitions
  112. *
  113. * @return - zero on success, otherwise error
  114. *
  115. */
  116. static int set_gpt_info(block_dev_desc_t *dev_desc,
  117. const char *str_part,
  118. char **str_disk_guid,
  119. disk_partition_t **partitions,
  120. u8 *parts_count)
  121. {
  122. char *tok, *str, *s;
  123. int i;
  124. char *val, *p;
  125. int p_count;
  126. disk_partition_t *parts;
  127. int errno = 0;
  128. uint64_t size_ll, start_ll;
  129. debug("%s: lba num: 0x%x %d\n", __func__,
  130. (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
  131. if (str_part == NULL)
  132. return -1;
  133. str = strdup(str_part);
  134. /* extract disk guid */
  135. s = str;
  136. val = extract_val(str, "uuid_disk");
  137. if (!val) {
  138. #ifdef CONFIG_RANDOM_UUID
  139. *str_disk_guid = malloc(UUID_STR_LEN + 1);
  140. gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
  141. #else
  142. free(str);
  143. return -2;
  144. #endif
  145. } else {
  146. val = strsep(&val, ";");
  147. if (extract_env(val, &p))
  148. p = val;
  149. *str_disk_guid = strdup(p);
  150. free(val);
  151. /* Move s to first partition */
  152. strsep(&s, ";");
  153. }
  154. if (strlen(s) == 0)
  155. return -3;
  156. i = strlen(s) - 1;
  157. if (s[i] == ';')
  158. s[i] = '\0';
  159. /* calculate expected number of partitions */
  160. p_count = 1;
  161. p = s;
  162. while (*p) {
  163. if (*p++ == ';')
  164. p_count++;
  165. }
  166. /* allocate memory for partitions */
  167. parts = calloc(sizeof(disk_partition_t), p_count);
  168. /* retrieve partitions data from string */
  169. for (i = 0; i < p_count; i++) {
  170. tok = strsep(&s, ";");
  171. if (tok == NULL)
  172. break;
  173. /* uuid */
  174. val = extract_val(tok, "uuid");
  175. if (!val) {
  176. /* 'uuid' is optional if random uuid's are enabled */
  177. #ifdef CONFIG_RANDOM_UUID
  178. gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD);
  179. #else
  180. errno = -4;
  181. goto err;
  182. #endif
  183. } else {
  184. if (extract_env(val, &p))
  185. p = val;
  186. if (strlen(p) >= sizeof(parts[i].uuid)) {
  187. printf("Wrong uuid format for partition %d\n", i);
  188. errno = -4;
  189. goto err;
  190. }
  191. strcpy((char *)parts[i].uuid, p);
  192. free(val);
  193. }
  194. #ifdef CONFIG_PARTITION_TYPE_GUID
  195. /* guid */
  196. val = extract_val(tok, "type");
  197. if (val) {
  198. /* 'type' is optional */
  199. if (extract_env(val, &p))
  200. p = val;
  201. if (strlen(p) >= sizeof(parts[i].type_guid)) {
  202. printf("Wrong type guid format for partition %d\n",
  203. i);
  204. errno = -4;
  205. goto err;
  206. }
  207. strcpy((char *)parts[i].type_guid, p);
  208. free(val);
  209. }
  210. #endif
  211. /* name */
  212. val = extract_val(tok, "name");
  213. if (!val) { /* name is mandatory */
  214. errno = -4;
  215. goto err;
  216. }
  217. if (extract_env(val, &p))
  218. p = val;
  219. if (strlen(p) >= sizeof(parts[i].name)) {
  220. errno = -4;
  221. goto err;
  222. }
  223. strcpy((char *)parts[i].name, p);
  224. free(val);
  225. /* size */
  226. val = extract_val(tok, "size");
  227. if (!val) { /* 'size' is mandatory */
  228. errno = -4;
  229. goto err;
  230. }
  231. if (extract_env(val, &p))
  232. p = val;
  233. size_ll = ustrtoull(p, &p, 0);
  234. parts[i].size = lldiv(size_ll, dev_desc->blksz);
  235. free(val);
  236. /* start address */
  237. val = extract_val(tok, "start");
  238. if (val) { /* start address is optional */
  239. if (extract_env(val, &p))
  240. p = val;
  241. start_ll = ustrtoull(p, &p, 0);
  242. parts[i].start = lldiv(start_ll, dev_desc->blksz);
  243. free(val);
  244. }
  245. }
  246. *parts_count = p_count;
  247. *partitions = parts;
  248. free(str);
  249. return 0;
  250. err:
  251. free(str);
  252. free(*str_disk_guid);
  253. free(parts);
  254. return errno;
  255. }
  256. static int gpt_default(block_dev_desc_t *blk_dev_desc, const char *str_part)
  257. {
  258. int ret;
  259. char *str_disk_guid;
  260. u8 part_count = 0;
  261. disk_partition_t *partitions = NULL;
  262. /* fill partitions */
  263. ret = set_gpt_info(blk_dev_desc, str_part,
  264. &str_disk_guid, &partitions, &part_count);
  265. if (ret) {
  266. if (ret == -1)
  267. printf("No partition list provided\n");
  268. if (ret == -2)
  269. printf("Missing disk guid\n");
  270. if ((ret == -3) || (ret == -4))
  271. printf("Partition list incomplete\n");
  272. return -1;
  273. }
  274. /* save partitions layout to disk */
  275. ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
  276. free(str_disk_guid);
  277. free(partitions);
  278. return ret;
  279. }
  280. /**
  281. * do_gpt(): Perform GPT operations
  282. *
  283. * @param cmdtp - command name
  284. * @param flag
  285. * @param argc
  286. * @param argv
  287. *
  288. * @return zero on success; otherwise error
  289. */
  290. static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  291. {
  292. int ret = CMD_RET_SUCCESS;
  293. int dev = 0;
  294. char *ep;
  295. block_dev_desc_t *blk_dev_desc;
  296. if (argc < 5)
  297. return CMD_RET_USAGE;
  298. /* command: 'write' */
  299. if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
  300. dev = (int)simple_strtoul(argv[3], &ep, 10);
  301. if (!ep || ep[0] != '\0') {
  302. printf("'%s' is not a number\n", argv[3]);
  303. return CMD_RET_USAGE;
  304. }
  305. blk_dev_desc = get_dev(argv[2], dev);
  306. if (!blk_dev_desc) {
  307. printf("%s: %s dev %d NOT available\n",
  308. __func__, argv[2], dev);
  309. return CMD_RET_FAILURE;
  310. }
  311. puts("Writing GPT: ");
  312. ret = gpt_default(blk_dev_desc, argv[4]);
  313. if (!ret) {
  314. puts("success!\n");
  315. return CMD_RET_SUCCESS;
  316. } else {
  317. puts("error!\n");
  318. return CMD_RET_FAILURE;
  319. }
  320. } else {
  321. return CMD_RET_USAGE;
  322. }
  323. return ret;
  324. }
  325. U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
  326. "GUID Partition Table",
  327. "<command> <interface> <dev> <partitions_list>\n"
  328. " - GUID partition table restoration and validity check\n"
  329. " Restore or verify GPT information on a device connected\n"
  330. " to interface\n"
  331. " Example usage:\n"
  332. " gpt write mmc 0 $partitions\n"
  333. " gpt verify mmc 0 $partitions\n"
  334. );