cmd_gpt.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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 char extract_env(const char *str, char **env)
  30. {
  31. char *e, *s;
  32. if (!str || strlen(str) < 4)
  33. return -1;
  34. if ((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')) {
  35. s = strdup(str);
  36. if (s == NULL)
  37. return -1;
  38. memset(s + strlen(s) - 1, '\0', 1);
  39. memmove(s, s + 2, strlen(s) - 1);
  40. e = getenv(s);
  41. free(s);
  42. if (e == NULL) {
  43. printf("Environmental '%s' not set\n", str);
  44. return -1; /* env not set */
  45. }
  46. *env = e;
  47. return 0;
  48. }
  49. return -1;
  50. }
  51. /**
  52. * extract_val(): Extract value from a key=value pair list (comma separated).
  53. * Only value for the given key is returend.
  54. * Function allocates memory for the value, remember to free!
  55. *
  56. * @param str - pointer to string with key=values pairs
  57. * @param key - pointer to the key to search for
  58. *
  59. * @return - pointer to allocated string with the value
  60. */
  61. static char *extract_val(const char *str, const char *key)
  62. {
  63. char *v, *k;
  64. char *s, *strcopy;
  65. char *new = NULL;
  66. strcopy = strdup(str);
  67. if (strcopy == NULL)
  68. return NULL;
  69. s = strcopy;
  70. while (s) {
  71. v = strsep(&s, ",");
  72. if (!v)
  73. break;
  74. k = strsep(&v, "=");
  75. if (!k)
  76. break;
  77. if (strcmp(k, key) == 0) {
  78. new = strdup(v);
  79. break;
  80. }
  81. }
  82. free(strcopy);
  83. return new;
  84. }
  85. /**
  86. * set_gpt_info(): Fill partition information from string
  87. * function allocates memory, remember to free!
  88. *
  89. * @param dev_desc - pointer block device descriptor
  90. * @param str_part - pointer to string with partition information
  91. * @param str_disk_guid - pointer to pointer to allocated string with disk guid
  92. * @param partitions - pointer to pointer to allocated partitions array
  93. * @param parts_count - number of partitions
  94. *
  95. * @return - zero on success, otherwise error
  96. *
  97. */
  98. static int set_gpt_info(block_dev_desc_t *dev_desc,
  99. const char *str_part,
  100. char **str_disk_guid,
  101. disk_partition_t **partitions,
  102. u8 *parts_count)
  103. {
  104. char *tok, *str, *s;
  105. int i;
  106. char *val, *p;
  107. int p_count;
  108. disk_partition_t *parts;
  109. int errno = 0;
  110. uint64_t size_ll, start_ll;
  111. debug("%s: lba num: 0x%x %d\n", __func__,
  112. (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
  113. if (str_part == NULL)
  114. return -1;
  115. str = strdup(str_part);
  116. /* extract disk guid */
  117. s = str;
  118. tok = strsep(&s, ";");
  119. val = extract_val(tok, "uuid_disk");
  120. if (!val) {
  121. free(str);
  122. return -2;
  123. }
  124. if (extract_env(val, &p))
  125. p = val;
  126. *str_disk_guid = strdup(p);
  127. free(val);
  128. if (strlen(s) == 0)
  129. return -3;
  130. i = strlen(s) - 1;
  131. if (s[i] == ';')
  132. s[i] = '\0';
  133. /* calculate expected number of partitions */
  134. p_count = 1;
  135. p = s;
  136. while (*p) {
  137. if (*p++ == ';')
  138. p_count++;
  139. }
  140. /* allocate memory for partitions */
  141. parts = calloc(sizeof(disk_partition_t), p_count);
  142. /* retrieve partitions data from string */
  143. for (i = 0; i < p_count; i++) {
  144. tok = strsep(&s, ";");
  145. if (tok == NULL)
  146. break;
  147. /* uuid */
  148. val = extract_val(tok, "uuid");
  149. if (!val) { /* 'uuid' is mandatory */
  150. errno = -4;
  151. goto err;
  152. }
  153. if (extract_env(val, &p))
  154. p = val;
  155. if (strlen(p) >= sizeof(parts[i].uuid)) {
  156. printf("Wrong uuid format for partition %d\n", i);
  157. errno = -4;
  158. goto err;
  159. }
  160. strcpy((char *)parts[i].uuid, p);
  161. free(val);
  162. /* name */
  163. val = extract_val(tok, "name");
  164. if (!val) { /* name is mandatory */
  165. errno = -4;
  166. goto err;
  167. }
  168. if (extract_env(val, &p))
  169. p = val;
  170. if (strlen(p) >= sizeof(parts[i].name)) {
  171. errno = -4;
  172. goto err;
  173. }
  174. strcpy((char *)parts[i].name, p);
  175. free(val);
  176. /* size */
  177. val = extract_val(tok, "size");
  178. if (!val) { /* 'size' is mandatory */
  179. errno = -4;
  180. goto err;
  181. }
  182. if (extract_env(val, &p))
  183. p = val;
  184. size_ll = ustrtoull(p, &p, 0);
  185. parts[i].size = lldiv(size_ll, dev_desc->blksz);
  186. free(val);
  187. /* start address */
  188. val = extract_val(tok, "start");
  189. if (val) { /* start address is optional */
  190. if (extract_env(val, &p))
  191. p = val;
  192. start_ll = ustrtoull(p, &p, 0);
  193. parts[i].start = lldiv(start_ll, dev_desc->blksz);
  194. free(val);
  195. }
  196. }
  197. *parts_count = p_count;
  198. *partitions = parts;
  199. free(str);
  200. return 0;
  201. err:
  202. free(str);
  203. free(*str_disk_guid);
  204. free(parts);
  205. return errno;
  206. }
  207. static int gpt_default(block_dev_desc_t *blk_dev_desc, const char *str_part)
  208. {
  209. int ret;
  210. char *str_disk_guid;
  211. u8 part_count = 0;
  212. disk_partition_t *partitions = NULL;
  213. if (!str_part)
  214. return -1;
  215. /* fill partitions */
  216. ret = set_gpt_info(blk_dev_desc, str_part,
  217. &str_disk_guid, &partitions, &part_count);
  218. if (ret) {
  219. if (ret == -1)
  220. printf("No partition list provided\n");
  221. if (ret == -2)
  222. printf("Missing disk guid\n");
  223. if ((ret == -3) || (ret == -4))
  224. printf("Partition list incomplete\n");
  225. return -1;
  226. }
  227. /* save partitions layout to disk */
  228. gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
  229. free(str_disk_guid);
  230. free(partitions);
  231. return 0;
  232. }
  233. /**
  234. * do_gpt(): Perform GPT operations
  235. *
  236. * @param cmdtp - command name
  237. * @param flag
  238. * @param argc
  239. * @param argv
  240. *
  241. * @return zero on success; otherwise error
  242. */
  243. static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  244. {
  245. int ret = CMD_RET_SUCCESS;
  246. int dev = 0;
  247. char *ep;
  248. block_dev_desc_t *blk_dev_desc;
  249. if (argc < 5)
  250. return CMD_RET_USAGE;
  251. /* command: 'write' */
  252. if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
  253. dev = (int)simple_strtoul(argv[3], &ep, 10);
  254. if (!ep || ep[0] != '\0') {
  255. printf("'%s' is not a number\n", argv[3]);
  256. return CMD_RET_USAGE;
  257. }
  258. blk_dev_desc = get_dev(argv[2], dev);
  259. if (!blk_dev_desc) {
  260. printf("%s: %s dev %d NOT available\n",
  261. __func__, argv[2], dev);
  262. return CMD_RET_FAILURE;
  263. }
  264. if (gpt_default(blk_dev_desc, argv[4]))
  265. return CMD_RET_FAILURE;
  266. } else {
  267. return CMD_RET_USAGE;
  268. }
  269. return ret;
  270. }
  271. U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
  272. "GUID Partition Table",
  273. "<command> <interface> <dev> <partitions_list>\n"
  274. " - GUID partition table restoration\n"
  275. " Restore GPT information on a device connected\n"
  276. " to interface\n"
  277. );