ota_manifest.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * Copyright (c) 2012-2014 Wind River Systems, Inc.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <kernel.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <mem_manager.h>
  10. #include "ota_image.h"
  11. #include "ota_manifest.h"
  12. #include <os_common_api.h>
  13. /* the last byte reserved for '\0' */
  14. #define OTA_MANIFSET_FILE_MAX_SIZE (2048 - 1)
  15. #define XML_TAG_MAX_LEN 31
  16. static int xml_get_data(const char *buf, const char *tag, const char **start, const char **end)
  17. {
  18. char xml_tag[XML_TAG_MAX_LEN + 4];
  19. char *find;
  20. int tag_len;
  21. SYS_LOG_DBG("try to get tag %s \n",tag);
  22. tag_len = strlen(tag);
  23. if (tag_len > XML_TAG_MAX_LEN) {
  24. return -1;
  25. }
  26. /* find <tag> start postion */
  27. xml_tag[0] = '<';
  28. memcpy(&xml_tag[1], tag, tag_len);
  29. xml_tag[tag_len + 1] = '>';
  30. xml_tag[tag_len + 2] = '\0';
  31. find = strstr(buf, xml_tag);
  32. if (!find) {
  33. SYS_LOG_ERR("cant find tag start %s\n",tag);
  34. return -1;
  35. }
  36. find = find + tag_len + 2;
  37. if (start)
  38. *start = find;
  39. /* find </tag> end postion */
  40. xml_tag[0] = '<';
  41. xml_tag[1] = '/';
  42. memcpy(&xml_tag[2], tag, tag_len);
  43. xml_tag[tag_len + 2] = '>';
  44. xml_tag[tag_len + 3] = '\0';
  45. find = strstr(find, xml_tag);
  46. if (!find) {
  47. SYS_LOG_ERR("cant find tag end %s\n",tag);
  48. return -1;
  49. }
  50. if (end)
  51. *end = find;
  52. return 0;
  53. }
  54. static int xml_get_int(const char *buf, const char *tag, unsigned int *int_ptr)
  55. {
  56. const char *start, *stop;
  57. int err;
  58. err = xml_get_data(buf, tag, &start, &stop);
  59. if (err) {
  60. return err;
  61. }
  62. *int_ptr = strtoul(start, (char **)&stop, 0);
  63. return 0;
  64. }
  65. static int xml_get_str(const char *buf, const char *tag, char *str_ptr, int max_len)
  66. {
  67. const char *start, *stop;
  68. int err, len;
  69. err = xml_get_data(buf, tag, &start, &stop);
  70. if (err) {
  71. return err;
  72. }
  73. len = (unsigned int)stop - (unsigned int)start;
  74. if ((len + 1) > max_len)
  75. return -1;
  76. memcpy(str_ptr, start, len);
  77. str_ptr[len] = '\0';
  78. return 0;
  79. }
  80. const char *ota_file_type_strs[] = {
  81. "RESERVED",
  82. "BOOT",
  83. "SYSTEM",
  84. "RECOVERY",
  85. "DATA",
  86. "TEMP",
  87. "SYS_PARAM",
  88. };
  89. static int ota_get_file_type(const char *type)
  90. {
  91. int i;
  92. for (i = 0; i < ARRAY_SIZE(ota_file_type_strs); i++) {
  93. if (0 == memcmp(type, ota_file_type_strs[i], strlen(ota_file_type_strs[i]))) {
  94. return i;
  95. }
  96. }
  97. return -1;
  98. }
  99. int parse_fw_version(struct fw_version *ver, const char *xml, const char *ver_tag)
  100. {
  101. const char *ver_seg_start, *ver_seg_end;
  102. int err;
  103. err = xml_get_data(xml, ver_tag, &ver_seg_start, &ver_seg_end);
  104. if (err) {
  105. SYS_LOG_ERR("cannot found tag <%s>", ver_tag);
  106. goto failed;
  107. }
  108. err = xml_get_int(ver_seg_start, "version_code", &ver->version_code);
  109. if (err) {
  110. SYS_LOG_ERR("cannot found tag<version_code>");
  111. goto failed;
  112. }
  113. err = xml_get_int(ver_seg_start, "version_res", &ver->version_res);
  114. if (err) {
  115. SYS_LOG_ERR("cannot found tag<version_res>");
  116. ver->version_res = 0;
  117. }
  118. err = xml_get_str(ver_seg_start, "version_name", ver->version_name,
  119. sizeof(ver->version_name));
  120. if (err) {
  121. SYS_LOG_ERR("cannot found tag <version_name>");
  122. goto failed;
  123. }
  124. err = xml_get_str(ver_seg_start, "board_name", ver->board_name,
  125. sizeof(ver->board_name));
  126. if (err) {
  127. SYS_LOG_ERR("cannot found tag <board_name>");
  128. goto failed;
  129. }
  130. return 0;
  131. failed:
  132. return -ENOENT;
  133. }
  134. int ota_manifest_parse_partitions(struct ota_manifest *manifest, const char *xml)
  135. {
  136. const char *start, *stop, *part_seg_start, *part_seg_end;
  137. char file_name[13];
  138. int err, i, part_num, file_size, orig_size;
  139. uint32_t file_type, file_id, checksum;
  140. #ifdef CONFIG_OTA_MUTIPLE_STORAGE
  141. uint32_t storage_id = 0;
  142. #endif
  143. struct ota_file *wfile;
  144. err = xml_get_int(xml, "partitionsNum", &part_num);
  145. if (err) {
  146. SYS_LOG_ERR("cannot found partitionsNum tag");
  147. goto failed;
  148. }
  149. SYS_LOG_INF("part_num: %d\n", part_num);
  150. if (part_num > OTA_MANIFEST_MAX_FILE_CNT) {
  151. SYS_LOG_ERR("too many ota file cnt: %d\n", part_num);
  152. err = -EINVAL;
  153. goto failed;
  154. }
  155. err = xml_get_data(xml, "partitions", &part_seg_start, &part_seg_end);
  156. if (err) {
  157. SYS_LOG_ERR("cannot found partitions tag");
  158. goto failed;
  159. }
  160. for (i = 0; i < part_num; i++) {
  161. err = xml_get_data(part_seg_start, "partition", &part_seg_start, &part_seg_end);
  162. if (err) {
  163. SYS_LOG_ERR("cannot found partition tag");
  164. goto failed;
  165. }
  166. err = xml_get_data(part_seg_start, "type", &start, &stop);
  167. if (err) {
  168. SYS_LOG_ERR("cannot get <type> for part %d", i);
  169. goto failed;
  170. }
  171. file_type = ota_get_file_type(start);
  172. err = xml_get_int(part_seg_start, "file_id", &file_id);
  173. if (err) {
  174. SYS_LOG_ERR("cannot get <file_id> for part %d", i);
  175. goto failed;
  176. }
  177. #ifdef CONFIG_OTA_MUTIPLE_STORAGE
  178. err = xml_get_int(part_seg_start, "storage_id", &storage_id);
  179. if (err) {
  180. SYS_LOG_ERR("cannot get <storage_id> for part %d", i);
  181. goto failed;
  182. }
  183. #endif
  184. err = xml_get_str(part_seg_start, "file_name", file_name, sizeof(file_name));
  185. if (err) {
  186. SYS_LOG_ERR("cannot get <file_name> for part %d", i);
  187. goto failed;
  188. }
  189. err = xml_get_int(part_seg_start, "file_size", &file_size);
  190. if (err) {
  191. SYS_LOG_ERR("cannot get file <file_size> for part %d", i);
  192. goto failed;
  193. }
  194. err = xml_get_int(part_seg_start, "orig_size", &orig_size);
  195. if (err) {
  196. orig_size = file_size;
  197. }
  198. err = xml_get_int(part_seg_start, "checksum", &checksum);
  199. if (err) {
  200. SYS_LOG_ERR("cannot get <checksum> for part %d", i);
  201. goto failed;
  202. }
  203. SYS_LOG_INF("part file %s: type %d, file_id %d, checksum 0x%x",
  204. file_name, file_type, file_id, checksum);
  205. wfile = &manifest->wfiles[manifest->file_cnt];
  206. wfile->size = file_size;
  207. wfile->orig_size = orig_size;
  208. wfile->type = file_type;
  209. wfile->file_id = file_id;
  210. #ifdef CONFIG_OTA_MUTIPLE_STORAGE
  211. wfile->storage_id = storage_id;
  212. #endif
  213. wfile->checksum = checksum;
  214. strncpy(wfile->name, file_name, sizeof(wfile->name));
  215. manifest->file_cnt++;
  216. part_seg_start = part_seg_end;
  217. }
  218. return 0;
  219. failed:
  220. return err;
  221. }
  222. int ota_manifest_parse_data(struct ota_manifest *manifest, const char *xml)
  223. {
  224. int err;
  225. #if defined(CONFIG_OTA_FILE_PATCH) || defined(CONFIG_OTA_RES_PATCH)
  226. err = parse_fw_version(&manifest->old_fw_ver, xml, "old_firmware_version");
  227. if (err) {
  228. SYS_LOG_ERR("cannot found old_firmware_version, is not ota patch fw");
  229. /* clear old version code */
  230. memset(&manifest->old_fw_ver, 0x0, sizeof(struct fw_version));
  231. } else {
  232. SYS_LOG_INF("Is OTA patch fw, old fw version:");
  233. fw_version_dump(&manifest->old_fw_ver);
  234. }
  235. #endif
  236. err = parse_fw_version(&manifest->fw_ver, xml, "firmware_version");
  237. if (err) {
  238. SYS_LOG_ERR("parse fw version failed");
  239. goto failed;
  240. }
  241. SYS_LOG_INF("OTA new fw version:");
  242. fw_version_dump(&manifest->fw_ver);
  243. err = ota_manifest_parse_partitions(manifest, xml);
  244. if (err) {
  245. SYS_LOG_ERR("parse partitions failed");
  246. goto failed;
  247. }
  248. return 0;
  249. failed:
  250. return -1;
  251. }
  252. int ota_manifest_check_data(struct ota_image *img, const char *file_name,
  253. const char *xml, int size)
  254. {
  255. int err;
  256. if (memcmp(xml, "<?xml", 5)) {
  257. SYS_LOG_ERR("invalid manifest file");
  258. return -1;
  259. }
  260. err = ota_image_check_file(img, file_name, xml, size);
  261. if (err) {
  262. SYS_LOG_INF("manifest check err");
  263. return err;
  264. }
  265. return 0;
  266. }
  267. int ota_manifest_check_file_size(struct ota_manifest *manifest, struct ota_image *img)
  268. {
  269. #ifndef CONFIG_OTA_FILE_PATCH
  270. struct ota_file *file;
  271. int i, file_len;
  272. for (i = 0; i < manifest->file_cnt; i++) {
  273. file = &manifest->wfiles[i];
  274. file_len = ota_image_get_file_length(img, file->name);
  275. if (file_len != file->size) {
  276. SYS_LOG_ERR("file %s: file size 0x%x in manifest file is not equal to image dir 0x%x",
  277. file->name, file->size, file_len);
  278. return -EINVAL;
  279. }
  280. }
  281. #endif
  282. return 0;
  283. }
  284. int ota_manifest_parse_file(struct ota_manifest *manifest, struct ota_image *img,
  285. const char *file_name)
  286. {
  287. char *manifest_data;
  288. int file_size, img_file_offset;
  289. int err = 0;
  290. memset(manifest, 0x0, sizeof(struct ota_manifest));
  291. file_size = ota_image_get_file_length(img, file_name);
  292. if (file_size > OTA_MANIFSET_FILE_MAX_SIZE) {
  293. SYS_LOG_INF("cfg file is too big");
  294. return -1;
  295. }
  296. SYS_LOG_INF("manifest file %s length %d", file_name, file_size);
  297. manifest_data = mem_malloc(file_size + 1);
  298. if (!manifest_data) {
  299. SYS_LOG_ERR("failed to malloc %d bytes", file_size + 1);
  300. return -ENOMEM;
  301. }
  302. img_file_offset = ota_image_get_file_offset(img, file_name);
  303. if (img_file_offset < 0) {
  304. SYS_LOG_ERR("cannot found file %s in image", file_name);
  305. goto exit;
  306. }
  307. err = ota_image_read(img, img_file_offset, manifest_data, file_size);
  308. if (err) {
  309. SYS_LOG_INF("image read %d err %d", file_size, err);
  310. goto exit;
  311. }
  312. err = ota_manifest_check_data(img, file_name, manifest_data, file_size);
  313. if (err) {
  314. SYS_LOG_INF("manifest check failed");
  315. goto exit;
  316. }
  317. /* ensure data is string */
  318. manifest_data[file_size] = '\0';
  319. err = ota_manifest_parse_data(manifest, manifest_data);
  320. if (err) {
  321. SYS_LOG_ERR("failed to read manifest");
  322. goto exit;
  323. }
  324. err = ota_manifest_check_file_size(manifest, img);
  325. if (err) {
  326. SYS_LOG_ERR("failed to check file");
  327. goto exit;
  328. }
  329. exit:
  330. mem_free(manifest_data);
  331. return err;
  332. }