cmd_gpt.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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. /* name */
  195. val = extract_val(tok, "name");
  196. if (!val) { /* name is mandatory */
  197. errno = -4;
  198. goto err;
  199. }
  200. if (extract_env(val, &p))
  201. p = val;
  202. if (strlen(p) >= sizeof(parts[i].name)) {
  203. errno = -4;
  204. goto err;
  205. }
  206. strcpy((char *)parts[i].name, p);
  207. free(val);
  208. /* size */
  209. val = extract_val(tok, "size");
  210. if (!val) { /* 'size' is mandatory */
  211. errno = -4;
  212. goto err;
  213. }
  214. if (extract_env(val, &p))
  215. p = val;
  216. size_ll = ustrtoull(p, &p, 0);
  217. parts[i].size = lldiv(size_ll, dev_desc->blksz);
  218. free(val);
  219. /* start address */
  220. val = extract_val(tok, "start");
  221. if (val) { /* start address is optional */
  222. if (extract_env(val, &p))
  223. p = val;
  224. start_ll = ustrtoull(p, &p, 0);
  225. parts[i].start = lldiv(start_ll, dev_desc->blksz);
  226. free(val);
  227. }
  228. }
  229. *parts_count = p_count;
  230. *partitions = parts;
  231. free(str);
  232. return 0;
  233. err:
  234. free(str);
  235. free(*str_disk_guid);
  236. free(parts);
  237. return errno;
  238. }
  239. static int gpt_default(block_dev_desc_t *blk_dev_desc, const char *str_part)
  240. {
  241. int ret;
  242. char *str_disk_guid;
  243. u8 part_count = 0;
  244. disk_partition_t *partitions = NULL;
  245. if (!str_part)
  246. return -1;
  247. /* fill partitions */
  248. ret = set_gpt_info(blk_dev_desc, str_part,
  249. &str_disk_guid, &partitions, &part_count);
  250. if (ret) {
  251. if (ret == -1)
  252. printf("No partition list provided\n");
  253. if (ret == -2)
  254. printf("Missing disk guid\n");
  255. if ((ret == -3) || (ret == -4))
  256. printf("Partition list incomplete\n");
  257. return -1;
  258. }
  259. /* save partitions layout to disk */
  260. ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
  261. free(str_disk_guid);
  262. free(partitions);
  263. return ret;
  264. }
  265. /**
  266. * do_gpt(): Perform GPT operations
  267. *
  268. * @param cmdtp - command name
  269. * @param flag
  270. * @param argc
  271. * @param argv
  272. *
  273. * @return zero on success; otherwise error
  274. */
  275. static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  276. {
  277. int ret = CMD_RET_SUCCESS;
  278. int dev = 0;
  279. char *ep;
  280. block_dev_desc_t *blk_dev_desc;
  281. if (argc < 5)
  282. return CMD_RET_USAGE;
  283. /* command: 'write' */
  284. if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
  285. dev = (int)simple_strtoul(argv[3], &ep, 10);
  286. if (!ep || ep[0] != '\0') {
  287. printf("'%s' is not a number\n", argv[3]);
  288. return CMD_RET_USAGE;
  289. }
  290. blk_dev_desc = get_dev(argv[2], dev);
  291. if (!blk_dev_desc) {
  292. printf("%s: %s dev %d NOT available\n",
  293. __func__, argv[2], dev);
  294. return CMD_RET_FAILURE;
  295. }
  296. puts("Writing GPT: ");
  297. ret = gpt_default(blk_dev_desc, argv[4]);
  298. if (!ret) {
  299. puts("success!\n");
  300. return CMD_RET_SUCCESS;
  301. } else {
  302. puts("error!\n");
  303. return CMD_RET_FAILURE;
  304. }
  305. } else {
  306. return CMD_RET_USAGE;
  307. }
  308. return ret;
  309. }
  310. U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
  311. "GUID Partition Table",
  312. "<command> <interface> <dev> <partitions_list>\n"
  313. " - GUID partition table restoration\n"
  314. " Restore GPT information on a device connected\n"
  315. " to interface\n"
  316. );