cmd_gpt.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. tok = strsep(&s, ";");
  137. val = extract_val(tok, "uuid_disk");
  138. if (!val) {
  139. free(str);
  140. return -2;
  141. }
  142. if (extract_env(val, &p))
  143. p = val;
  144. *str_disk_guid = strdup(p);
  145. free(val);
  146. if (strlen(s) == 0)
  147. return -3;
  148. i = strlen(s) - 1;
  149. if (s[i] == ';')
  150. s[i] = '\0';
  151. /* calculate expected number of partitions */
  152. p_count = 1;
  153. p = s;
  154. while (*p) {
  155. if (*p++ == ';')
  156. p_count++;
  157. }
  158. /* allocate memory for partitions */
  159. parts = calloc(sizeof(disk_partition_t), p_count);
  160. /* retrieve partitions data from string */
  161. for (i = 0; i < p_count; i++) {
  162. tok = strsep(&s, ";");
  163. if (tok == NULL)
  164. break;
  165. /* uuid */
  166. val = extract_val(tok, "uuid");
  167. if (!val) { /* 'uuid' is mandatory */
  168. errno = -4;
  169. goto err;
  170. }
  171. if (extract_env(val, &p))
  172. p = val;
  173. if (strlen(p) >= sizeof(parts[i].uuid)) {
  174. printf("Wrong uuid format for partition %d\n", i);
  175. errno = -4;
  176. goto err;
  177. }
  178. strcpy((char *)parts[i].uuid, p);
  179. free(val);
  180. /* name */
  181. val = extract_val(tok, "name");
  182. if (!val) { /* name is mandatory */
  183. errno = -4;
  184. goto err;
  185. }
  186. if (extract_env(val, &p))
  187. p = val;
  188. if (strlen(p) >= sizeof(parts[i].name)) {
  189. errno = -4;
  190. goto err;
  191. }
  192. strcpy((char *)parts[i].name, p);
  193. free(val);
  194. /* size */
  195. val = extract_val(tok, "size");
  196. if (!val) { /* 'size' is mandatory */
  197. errno = -4;
  198. goto err;
  199. }
  200. if (extract_env(val, &p))
  201. p = val;
  202. size_ll = ustrtoull(p, &p, 0);
  203. parts[i].size = lldiv(size_ll, dev_desc->blksz);
  204. free(val);
  205. /* start address */
  206. val = extract_val(tok, "start");
  207. if (val) { /* start address is optional */
  208. if (extract_env(val, &p))
  209. p = val;
  210. start_ll = ustrtoull(p, &p, 0);
  211. parts[i].start = lldiv(start_ll, dev_desc->blksz);
  212. free(val);
  213. }
  214. }
  215. *parts_count = p_count;
  216. *partitions = parts;
  217. free(str);
  218. return 0;
  219. err:
  220. free(str);
  221. free(*str_disk_guid);
  222. free(parts);
  223. return errno;
  224. }
  225. static int gpt_default(block_dev_desc_t *blk_dev_desc, const char *str_part)
  226. {
  227. int ret;
  228. char *str_disk_guid;
  229. u8 part_count = 0;
  230. disk_partition_t *partitions = NULL;
  231. if (!str_part)
  232. return -1;
  233. /* fill partitions */
  234. ret = set_gpt_info(blk_dev_desc, str_part,
  235. &str_disk_guid, &partitions, &part_count);
  236. if (ret) {
  237. if (ret == -1)
  238. printf("No partition list provided\n");
  239. if (ret == -2)
  240. printf("Missing disk guid\n");
  241. if ((ret == -3) || (ret == -4))
  242. printf("Partition list incomplete\n");
  243. return -1;
  244. }
  245. /* save partitions layout to disk */
  246. gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
  247. free(str_disk_guid);
  248. free(partitions);
  249. return 0;
  250. }
  251. /**
  252. * do_gpt(): Perform GPT operations
  253. *
  254. * @param cmdtp - command name
  255. * @param flag
  256. * @param argc
  257. * @param argv
  258. *
  259. * @return zero on success; otherwise error
  260. */
  261. static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  262. {
  263. int ret = CMD_RET_SUCCESS;
  264. int dev = 0;
  265. char *ep;
  266. block_dev_desc_t *blk_dev_desc;
  267. if (argc < 5)
  268. return CMD_RET_USAGE;
  269. /* command: 'write' */
  270. if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
  271. dev = (int)simple_strtoul(argv[3], &ep, 10);
  272. if (!ep || ep[0] != '\0') {
  273. printf("'%s' is not a number\n", argv[3]);
  274. return CMD_RET_USAGE;
  275. }
  276. blk_dev_desc = get_dev(argv[2], dev);
  277. if (!blk_dev_desc) {
  278. printf("%s: %s dev %d NOT available\n",
  279. __func__, argv[2], dev);
  280. return CMD_RET_FAILURE;
  281. }
  282. puts("Writing GPT: ");
  283. ret = gpt_default(blk_dev_desc, argv[4]);
  284. if (!ret) {
  285. puts("success!\n");
  286. return CMD_RET_SUCCESS;
  287. } else {
  288. puts("error!\n");
  289. return CMD_RET_FAILURE;
  290. }
  291. } else {
  292. return CMD_RET_USAGE;
  293. }
  294. return ret;
  295. }
  296. U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
  297. "GUID Partition Table",
  298. "<command> <interface> <dev> <partitions_list>\n"
  299. " - GUID partition table restoration\n"
  300. " Restore GPT information on a device connected\n"
  301. " to interface\n"
  302. );