#include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(PLATFORM_R16) || defined (PLATFORM_CPU) #include "log.h" #include "libuv_dbus.h" #include "crypto.h" #include "json_struct.h" #include "config_engine.h" #include "inet_api.h" #include "ota.h" #else #include #include #include #include #include #include #include #endif #define MAX_IPL_ITEM (4) #define IPL_PARAMS_PARTITION ("/dev/by-name/IPL3") #define IPL3_MAGIC_NAME ("R16IPL3\0") #define BOOT_IMG_FILE_NAME ("boot.img") #define ROOTFS_IMG_FILE_NAME ("rootfs.img") #define EXT_FS_UUID_FILE ("/etc/.extroot-uuid") #define OTA_TEMP_DIR ("/tmp/ota") #define OTA_FILE_DOWNLOAD_DIR ("/mnt/UDISK/ota") #define OTA_MEMORY_DOWNLOAD_DIR ("/tmp/UDISK/ota") typedef enum { OTA_PARTITION_BOOT = 0, OTA_PARTITION_ROOTFS, OTA_PARTITION_IPL_BOOT, OTA_PARTITION_IPL_ROOTFS, OTA_PARTITION_IPL_PARAMS, OTA_PARTITION_MAX } OTA_PARTITION_NAME; typedef struct { OTA_PARTITION_NAME partName; const char *pPartPath; unsigned int partSize; } OTA_PARTITION_INFO, *POTA_PARTITION_INFO; typedef struct { unsigned int fileSize; unsigned char md5sum[MD5_CHKSUM_LEN]; int reserved[4]; }IPL_DATA_ITEM, *PIPL_DATA_ITEM; typedef struct { char pMagicTag[8]; unsigned int setupStatus; SETUP_MODE setupMode; int curVersion; // int kernelVer; // char rfsVersion[1024]; IPL_DATA_ITEM iplItem[OTA_PARTITION_MAX - 1]; unsigned char md5sum[MD5_CHKSUM_LEN]; }IPL_DATA_INFO, *PIPL_DATA_INFO; typedef struct { OTA_FILE_INFO fileInfo; char pPath[MAX_PATH]; int dlStatus; int retCode; uv_barrier_t* puvBarrier; } DOWNLOAD_TASK_INFO, *PDOWNLOAD_TASK_INFO; static IPL_DATA_INFO g_iplInfo; static char g_otaDownloadPath[MAX_PATH]; static SETUP_MODE g_sSetupStatus = NORMAL_SETUP; static OTA_PARTITION_INFO g_otaPartInfo[] = { {OTA_PARTITION_BOOT, "/dev/by-name/boot", 0}, {OTA_PARTITION_ROOTFS, "/dev/by-name/rootfs", 0}, {OTA_PARTITION_IPL_BOOT, "/dev/by-name/IPL1", 0}, {OTA_PARTITION_IPL_ROOTFS, "/dev/by-name/IPL2", 0}, {OTA_PARTITION_IPL_PARAMS, "/dev/by-name/IPL3", 0}, }; static unsigned int g_IsOTAMode = 0; static uv_barrier_t g_otaBarrier; static uv_loop_t* g_pMainLoop = NULL; static int g_isDownloading = FALSE; static int g_isBackupMode = FALSE; static const char *g_umountPart[] = { "/usr", "/overlay", "/boot", "/rom", "/" }; static void __printfOTANotifyCmd(const char *pTags, POTA_DATA_INFO pInfo) { if(pTags && strlen(pTags) > 0) { LOG_EX2(LOG_Debug, "%s:\n", pTags); LOG_EX2(LOG_Debug, "**************************************************************\n"); } LOG_EX2(LOG_Debug, "Version : %d\n", pInfo->version); LOG_EX2(LOG_Debug, "OTA Command : %d(0x%08X)\n", pInfo->otaCmd, pInfo->otaCmd); LOG_EX2(LOG_Debug, "OTA Type : %d(0x%08X)\n", pInfo->otaMode, pInfo->otaMode); LOG_EX2(LOG_Debug, "---------------------------------------------------------\n"); LOG_EX2(LOG_Debug, "\tURL : %s\n", pInfo->otaFileInfo.url); LOG_EX2(LOG_Debug, "\tMD5 : %s\n", pInfo->otaFileInfo.md5); LOG_EX2(LOG_Debug, "\tsize : %u\n", pInfo->otaFileInfo.size); } static int __otaRspStatus(OTA_STATUS_TYPE type, int val) { int ret = 0; OTA_RSP_STATUS oStatus; if(OTA_ERR_CODE == type && val != 0) { g_IsOTAMode = FALSE; } memset(&oStatus, 0, sizeof(OTA_RSP_STATUS)); oStatus.status = type; oStatus.val = val; LOG_EX(LOG_Debug, "Rsponse: %d --> %d\n", type, val); if(type == OTA_UPGRADE_START || type == OTA_REBOOT_SYSTEM || type == OTA_RECOVERY_START) { ret = DBusJsonBoardcastCommand(NULL, 0xFFFFFFFF, CMD_OTA_STATUS, JSON_ENGINE_OTA_RSP, &oStatus, FALSE); } else { ret = DBusJsonSendToCommand(NULL, g_pModInfoTable[MODULE_CONTROLLER].modAliase, CMD_OTA_STATUS, JSON_ENGINE_OTA_RSP, &oStatus, FALSE); } return (ret); } #if 0 static void __dlThreadRuntimeCb(void *pParams) { PDOWNLOAD_TASK_INFO pDlInfo = (PDOWNLOAD_TASK_INFO)pParams; LOG_EX(LOG_Debug, "Cleanup barrier\n"); uv_barrier_wait(pDlInfo->puvBarrier); pthread_detach(pthread_self()); } #endif void __onHttpResponseCb(void *pData, unsigned int size, const char *pReqUrl, const char* pDlPath, const char *pTaskUuid, int iFinished, void *pUserData) { PDOWNLOAD_TASK_INFO pDlInfo = (PDOWNLOAD_TASK_INFO)pUserData; if(iFinished == 0) { LOG_EX(LOG_Debug, "Request(%s): [%s] --> [%s] Response: [%u] OK\n", pTaskUuid, pReqUrl, pDlPath, size); } else if(iFinished == 1) { LOG_EX(LOG_Error, "Request(%s): [%s] --> [%s] Response: [%u] Error\n", pTaskUuid, pReqUrl, pDlPath, size); } else { LOG_EX(LOG_Error, "Download Error Code: %d\n", iFinished); } if(pDlInfo) { // int err; uv_thread_t uvThread; pDlInfo->retCode = iFinished; // LOG_EX(LOG_Debug, "Cleanup barrier task start: %u\n", g_ThreadCnt); LOG_EX(LOG_Debug, "Cleanup barrier\n"); uv_barrier_wait(pDlInfo->puvBarrier); #if 0 g_ThreadCnt++; err = uv_thread_create(&uvThread, __dlThreadRuntimeCb, pDlInfo); if(err != 0) { LOG_EX(LOG_Error, "1:Create Thread Error: %d\n", err); } #endif } else { LOG_EX(LOG_Debug, "pDlInfo == NULL\n"); } } void __onProgressNotifyCb(const char *pReqUrl, const char *pTaskUuid, unsigned char uPercent, void* pUserData) { static unsigned char preCnt = 0; if(preCnt != uPercent && uPercent != 0) { preCnt = uPercent; __otaRspStatus(OTA_DOWNLOAD_PROGRESS, uPercent); LOG_EX(LOG_Debug, "[%s]: %u%%\n", pReqUrl, uPercent); } } static void __printIPLParams(PIPL_DATA_INFO pIPLInfo, const char* pTags) { int i; char md5[MD5_CHKSUM_STR_LEN]; if(pTags != NULL && strlen(pTags) > 0) { LOG_EX2(LOG_Debug, "%s\n", pTags); LOG_EX2(LOG_Debug, "------------------------------------------------\n"); } LOG_EX2(LOG_Debug, "Magic Tag : %s\n", pIPLInfo->pMagicTag); LOG_EX2(LOG_Debug, "Setup Status : %u\n", pIPLInfo->setupStatus); LOG_EX2(LOG_Debug, "Setup Module : %d(0x%08X)\n", pIPLInfo->setupMode, pIPLInfo->setupMode); LOG_EX2(LOG_Debug, "Version : %d\n", pIPLInfo->curVersion); memset(md5, 0, MD5_CHKSUM_STR_LEN); IHW_bin2hex(md5, pIPLInfo->md5sum, MD5_CHKSUM_LEN); LOG_EX2(LOG_Debug, "MD5 Checksum : %s\n", md5); LOG_EX2(LOG_Debug, "-------------------------------------------------------------------\n"); LOG_EX2(LOG_Debug, "| Partition | size | MD5 Checksum |\n"); LOG_EX2(LOG_Debug, "-------------------------------------------------------------------\n"); for(i = 0; i < sizeof(pIPLInfo->iplItem) / sizeof(pIPLInfo->iplItem[0]); i++) { char *pPartName = strdup(g_otaPartInfo[i].pPartPath); memset(md5, 0, MD5_CHKSUM_STR_LEN); IHW_bin2hex(md5, pIPLInfo->iplItem[i].md5sum, MD5_CHKSUM_LEN); LOG_EX2(LOG_Debug, "| %9s | %16u | %32s |\n", basename_v2(pPartName), pIPLInfo->iplItem[i].fileSize, md5); free(pPartName); } LOG_EX2(LOG_Debug, "-------------------------------------------------------------------\n"); } static int __ReadIPLParams(PIPL_DATA_INFO pIPLInfo) { uv_fs_t uvOpen, uvRead, uvClose; int ret, rdSize = 0; unsigned char md5Buf[MD5_CHKSUM_LEN]; uv_loop_t* pLoop = g_pMainLoop; uv_buf_t uvBuf = uv_buf_init((char*)pIPLInfo, sizeof(IPL_DATA_INFO)); if(pIPLInfo == NULL) { return (-ERR_INPUT_PARAMS); } memset(pIPLInfo, 0, sizeof(IPL_DATA_INFO)); ret = system("sync"); if(uv_fs_open(pLoop, &uvOpen, IPL_PARAMS_PARTITION, O_RDWR, 0, NULL) == -1) { LOG_EX(LOG_Error, "Open Partition %s Error\n", IPL_PARAMS_PARTITION); return (-ERR_OPEN_FILE); } if((rdSize = uv_fs_read(pLoop, &uvRead, uvOpen.result, &uvBuf, 1, -1, NULL)) != sizeof(IPL_DATA_INFO)) { LOG_EX(LOG_Error, "Read Partition Error: Read %d Bytes, Need Read %d Bytes %d\n", rdSize, sizeof(IPL_DATA_INFO)); return (-ERR_READ_FILE); } uv_fs_close(pLoop, &uvClose, uvOpen.result, NULL); if(memcmp(pIPLInfo->pMagicTag, IPL3_MAGIC_NAME, 8) != 0) { LOG_EX(LOG_Error, "Check Magic Head Error: [%s], need [%s]\n", pIPLInfo->pMagicTag, IPL3_MAGIC_NAME); return (-ERR_NO_INIT_IPL3); } EvpMD5HashBuf((const unsigned char *)pIPLInfo, sizeof(IPL_DATA_INFO) - MD5_CHKSUM_LEN, md5Buf, &rdSize); if(memcmp(pIPLInfo->md5sum, md5Buf, MD5_CHKSUM_LEN) != 0) { //print_hex_dump_bytes("CACL_", DUMP_PREFIX_ADDRESS, md5Buf, MD5_CHKSUM_LEN); //print_hex_dump_bytes("SAVE_", DUMP_PREFIX_ADDRESS, pIPLInfo->md5sum, MD5_CHKSUM_LEN); LOG_EX(LOG_Error, "Verify MD5 Error\n"); return (-ERR_BAD_IPL3); } //print_hex_dump_bytes("IPL3", DUMP_PREFIX_ADDRESS, pIPLInfo, sizeof(IPL_DATA_INFO)); return (0); } static int __Write2NandPartition(OTA_PARTITION_NAME partName, const char *pFilePath) { int fileSize = 0; char bufCmd[MAX_PATH]; if(partName < 0 || partName >= OTA_PARTITION_MAX || pFilePath == NULL || strlen(pFilePath) == 0) { LOG_EX(LOG_Error, "Input params error\n"); return (-ERR_INPUT_PARAMS); } if(access(pFilePath, F_OK) == -1) { LOG_EX(LOG_Error, "File %s not exist\n", pFilePath); return (-ERR_FILE_NOT_EXISTS); } GET_FILE_SIZE(pFilePath, fileSize); if(fileSize > g_otaPartInfo[partName].partSize || fileSize == -1) { LOG_EX(LOG_Error, "File %s size %d more than partition size %u\n", pFilePath, fileSize, g_otaPartInfo[partName].partSize); return (-ERR_BAD_FILE_SIZE); } memset(bufCmd, 0, MAX_PATH); if(partName == OTA_PARTITION_IPL_ROOTFS || partName == OTA_PARTITION_ROOTFS) { sprintf(bufCmd, "dd if=%s of=%s bs=128k conv=sync", pFilePath, g_otaPartInfo[partName].pPartPath); } else { sprintf(bufCmd, "dd if=%s of=%s bs=4k conv=sync", pFilePath, g_otaPartInfo[partName].pPartPath); } LOG_EX(LOG_Debug, "Run OTA: [%s]\n", bufCmd); fileSize = system(bufCmd); fileSize = system("sync"); return (0); } static int __SaveIPLParams(PIPL_DATA_INFO pIPLInfo) { int ret, wrSize = 0; uv_fs_t uvOpen, uvWrite, uvSync, uvClose; unsigned char md5Buf[MD5_CHKSUM_LEN]; unsigned char buf[MAX_PATH]; uv_loop_t* pLoop = g_pMainLoop; uv_buf_t uvBuf = uv_buf_init((char*)pIPLInfo, sizeof(IPL_DATA_INFO)); if(pIPLInfo == NULL) { return (-ERR_INPUT_PARAMS); } if(memcmp(pIPLInfo->pMagicTag, IPL3_MAGIC_NAME, 8) != 0) { memcpy(pIPLInfo->pMagicTag, IPL3_MAGIC_NAME, 8); LOG_EX(LOG_Error, "Check Magic Head Error: [%s], need [%s]\n", pIPLInfo->pMagicTag, IPL3_MAGIC_NAME); return (-ERR_NO_INIT_IPL3); } EvpMD5HashBuf((const unsigned char *)pIPLInfo, sizeof(IPL_DATA_INFO) - MD5_CHKSUM_LEN, md5Buf, &wrSize); if(wrSize != MD5_CHKSUM_LEN) { LOG_EX(LOG_Error, "Error MD5: size = %d, need %d\n", wrSize, MD5_CHKSUM_LEN); return (-ERR_BAD_IPL3); } memcpy(pIPLInfo->md5sum, md5Buf, MD5_CHKSUM_LEN); memset(buf, 0, MAX_PATH); ret = system("mkdir -p /tmp/ota_param/"); sprintf(buf, "/tmp/ota_param/ota_%d.params", pIPLInfo->curVersion); //print_hex_dump_bytes("IPL3", DUMP_PREFIX_ADDRESS, pIPLInfo, sizeof(IPL_DATA_INFO)); if(uv_fs_open(pLoop, &uvOpen, buf, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR, NULL) == -1) { LOG_EX(LOG_Error, "Open Partition %s Error\n", IPL_PARAMS_PARTITION); return (-ERR_OPEN_FILE); } if((wrSize = uv_fs_write(pLoop, &uvWrite, uvOpen.result, &uvBuf, 1, -1, NULL)) != sizeof(IPL_DATA_INFO)) { LOG_EX(LOG_Error, "Write Partition Error: Read %d Bytes, Need Read %d Bytes %d\n", wrSize, sizeof(IPL_DATA_INFO)); return (-ERR_READ_FILE); } uv_fs_fdatasync(pLoop, &uvSync, uvOpen.result, NULL); uv_fs_close(pLoop, &uvClose, uvOpen.result, NULL); ret = __Write2NandPartition(OTA_PARTITION_IPL_PARAMS, (const char*)buf); if(ret != 0) { LOG_EX(LOG_Error, "Write OTA Params Error: %d\n", ret); return (-ERR_OTA_WRITE_IPL3); } return (0); } static int __otaBackupWifi(int iBackup) { int ret = 0; if(iBackup == TRUE) { const char *pBackCmd = "mkdir -p /mnt/UDISK/ota/wifi_bak/ && rm -rf /mnt/UDISK/ota/wifi_bak/* \ && cp -rf /etc/wifi/* /mnt/UDISK/ota/wifi_bak/"; ret = system(pBackCmd); } else { const char *pBackCmd = "rm -rf /etc/wifi/*.* && cp -rf /mnt/UDISK/ota/wifi_bak/*.* /etc/wifi/"; ret = system(pBackCmd); } return ret; } static int __otaRunning(char* pCheckSumFile, int ver) { ssize_t rdRet; size_t rdSize; unsigned char strMD5[MD5_CHKSUM_STR_LEN]; char dirPath[MAX_PATH]; char basePath[MAX_PATH]; const char *pChkMD5 = NULL; char *pRdLine = NULL; char *pChkSumFile = pCheckSumFile; FILE *pFile = fopen(pChkSumFile, "r"); int ret, i = 0; int step = 0; if(pFile == NULL) { LOG_EX(LOG_Error, "Open File %s Error\n", pChkSumFile); return (-ERR_OPEN_FILE); } memset(dirPath, 0, MAX_PATH); dirname_v2(pChkSumFile, dirPath); LOG_EX(LOG_Debug, "Step %d: Check OTA image .......\n", step++); // check download ota file while((rdRet = getline(&pRdLine, &rdSize, pFile)) != -1) { char* pToken = NULL; char *pItem[2]; char pMD5Val[MD5_CHKSUM_LEN]; char pMD5Str[MD5_CHKSUM_STR_LEN]; int fileSize = 0; if(rdSize == 0 || pRdLine == NULL) { continue; } if(pRdLine[strlen(pRdLine) - 1] == '\n') { pRdLine[strlen(pRdLine) - 1] = 0; } i = 0; for(pToken = strtok(pRdLine, " "); pToken != NULL && i <= 1; pToken = strtok(NULL, " "), i++) { pItem[i] = pToken; } //fprintf(stdout, "md5 = %s, file = \'%s\'\n", pItem[0], pItem[1]); if(pItem[0] == NULL || pItem[1] == NULL || strlen(pItem[0]) != 32 || strlen(pItem[1]) == 0) { free(pRdLine); fclose(pFile); return (-ERR_MD5_CHECK_SUM); } memset(basePath, 0, MAX_PATH); sprintf(basePath, "%s/%s", dirPath, pItem[1]); LOG_EX(LOG_Debug, "OTA File: %s --> %s\n", basePath, pItem[0]); if((ret = EvpMD5HashFileV2(basePath, pMD5Val)) != 0) { free(pRdLine); fclose(pFile); LOG_EX(LOG_Error, "%s Check MD5 error: %d\n", ret); return (-ERR_MD5_FILE); } memset(pMD5Str, 0, MD5_CHKSUM_STR_LEN); IHW_bin2hex(pMD5Str, pMD5Val, MD5_CHKSUM_LEN); //LOG_EX(LOG_Debug, "%s Check MD5 Info: [%s] need [%s]\n", basePath, pMD5Str, pItem[0]); if(strcmp(pMD5Str, pItem[0]) != 0) { free(pRdLine); fclose(pFile); LOG_EX(LOG_Error, "%s Check MD5 error: [%s] need [%s]\n", basePath, pMD5Str, pItem[0]); return (-ERR_MD5_FILE); } if(strcmp(pItem[1], BOOT_IMG_FILE_NAME) == 0) { memcpy(g_iplInfo.iplItem[OTA_PARTITION_BOOT].md5sum, pMD5Val, MD5_CHKSUM_LEN); } else if(strcmp(pItem[1], ROOTFS_IMG_FILE_NAME) == 0) { GET_FILE_SIZE(basePath, fileSize); //fprintf(stdout, "fileSize = %lu\n", fileSize); memcpy(g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].md5sum, pMD5Val, MD5_CHKSUM_LEN); g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].fileSize = fileSize; } } if(pRdLine) { free(pRdLine); } fclose(pFile); LOG_EX(LOG_Debug, "Step %d: Remove EXT4 UUID File %s .......\n", step++, EXT_FS_UUID_FILE); remove(EXT_FS_UUID_FILE); __otaRspStatus(OTA_VERIFY_FILE, NO_OTA_STATUS_VAL_TAG); #if 0 for(i = 0; i < sizeof(g_umountPart) / sizeof(g_umountPart[0]); i++) { char *pRet = NULL; memset(cmdBuf, 0, MAX_PATH); sprintf(cmdBuf, "cat /proc/mounts | awk '{printf $2\"\\n\"}' | grep -Fx \"%s\" | wc -L", g_umountPart[i]); if(GetShellExecResult(cmdBuf, &pRet) == 0) { unsigned int tarLen = strtoul(pRet, NULL, 10); free(pRet); if(strlen(g_umountPart[i]) != tarLen) { continue; } } LOG_EX(LOG_Debug, "Step %d: Umount %s Partition .......\n", step++, g_umountPart[i]); memset(cmdBuf, 0, MAX_PATH); sprintf(cmdBuf, "umount %s", g_umountPart[i]); ret = system(cmdBuf); } #else ret = system("umount /rom"); #endif __otaRspStatus(OTA_UPGRADE_PARTITION, OTA_PARTITION_BOOT); // write to partition LOG_EX(LOG_Debug, "Step %d: OTA %s Partition .......\n", step++, g_otaPartInfo[OTA_PARTITION_BOOT].pPartPath); memset(basePath, 0, MAX_PATH); sprintf(basePath, "%s/%s", dirPath, BOOT_IMG_FILE_NAME); ret = __Write2NandPartition(OTA_PARTITION_BOOT, basePath); if(ret != 0) { LOG_EX(LOG_Error, "OTA OTA_PARTITION_BOOT Error: %d\n", ret); return (-ERR_OTA_WRITE_BOOT); } __otaRspStatus(OTA_UPGRADE_PARTITION, OTA_PARTITION_ROOTFS); LOG_EX(LOG_Debug, "Step %d: OTA %s Partition .......\n", step++, g_otaPartInfo[OTA_PARTITION_ROOTFS].pPartPath); memset(basePath, 0, MAX_PATH); sprintf(basePath, "%s/%s", dirPath, ROOTFS_IMG_FILE_NAME); ret = __Write2NandPartition(OTA_PARTITION_ROOTFS, basePath); if(ret != 0) { LOG_EX(LOG_Error, "OTA ROOTFS_IMG_FILE_NAME Error: %d\n", ret); return (-ERR_OTA_WRITE_ROOTFS); } LOG_EX(LOG_Debug, "Step %d: Verify Partition %d .......\n", step++, OTA_PARTITION_BOOT); __otaRspStatus(OTA_VERIFY_PARTITION, OTA_PARTITION_BOOT); pChkMD5 = EvpMD5HashFile(g_otaPartInfo[OTA_PARTITION_BOOT].pPartPath); IHW_bin2hex(strMD5, g_iplInfo.iplItem[OTA_PARTITION_BOOT].md5sum, MD5_CHKSUM_LEN); if(strcmp(pChkMD5, strMD5) != 0) { LOG_EX(LOG_Error, "Verify %s Partition MD5 Error: %s --> %s\n", g_otaPartInfo[OTA_PARTITION_BOOT].pPartPath, pChkMD5, strMD5); return (-ERR_VERIFY_PARTITION_MD5); } __otaRspStatus(OTA_VERIFY_PARTITION, OTA_PARTITION_ROOTFS); LOG_EX(LOG_Debug, "Step %d: Verify Partition %d .......\n", step++, OTA_PARTITION_ROOTFS); CopyFileWithSize(g_otaPartInfo[OTA_PARTITION_ROOTFS].pPartPath, "/tmp/dump_rootfs.img", g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].fileSize); pChkMD5 = EvpMD5HashFile("/tmp/dump_rootfs.img"); IHW_bin2hex(strMD5, g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].md5sum, MD5_CHKSUM_LEN); if(strcmp(pChkMD5, strMD5) != 0) { LOG_EX(LOG_Error, "Verify %s Partition MD5 Error: %s --> %s\n", g_otaPartInfo[OTA_PARTITION_ROOTFS].pPartPath, pChkMD5, strMD5); return (-ERR_VERIFY_PARTITION_MD5); } #if 0 LOG_EX(LOG_Debug, "Step %d: Upgrade Partition %d MD5 Checksum .......\n", step++, OTA_PARTITION_ROOTFS); EvpMD5HashFileV2(g_otaPartInfo[OTA_PARTITION_ROOTFS].pPartPath, g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].md5sum); g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].fileSize = g_otaPartInfo[OTA_PARTITION_ROOTFS].partSize; #endif LOG_EX(LOG_Debug, "Step %d: Save OTA Information .......\n", step++); g_iplInfo.curVersion = ver; g_iplInfo.setupStatus = 0; if(g_iplInfo.setupMode != RECOVERY_SETUP) { g_iplInfo.setupMode = SYSTEM_OTA; } ret = __SaveIPLParams(&g_iplInfo); if(ret != 0) { LOG_EX(LOG_Error, "Save IPL3 Error: %d\n", ret); return (-ERR_OTA_WRITE_PARAMS); } //print_hex_dump_bytes("IPL3", DUMP_PREFIX_ADDRESS, &g_iplInfo, sizeof(IPL_DATA_INFO)); __printIPLParams(&g_iplInfo, "OTA Succesed_____:"); LOG_EX(LOG_Debug, "Step %d: Waitting for reboot ......\n", step++); return (0); } static void __otaFromLocalImage(void *pParams) { int ret, reTry; int step = 0; char buf[MAX_PATH]; char *pFileName = NULL, *pMD5Val = NULL; const char *pMD5Chk = NULL; int version = (int)(intptr_t)pParams; LOG_EX(LOG_Debug, "Step %d: Get OTA information .......\n", step++); memset(buf, 0, MAX_PATH); sprintf(buf, "%s/ota.md5", g_otaDownloadPath); if(access(buf, F_OK) != 0) { __otaRspStatus(OTA_ERR_CODE, -ERR_FILE_NOT_EXISTS); g_IsOTAMode = FALSE; return; } memset(buf, 0, MAX_PATH); sprintf(buf, "cat %s/ota.md5 | awk '{print $2}'", g_otaDownloadPath); if(GetShellExecResult(buf, &pFileName) != 0) { LOG_EX(LOG_Error, "Get File Name Error: %s\n", buf); __otaRspStatus(OTA_ERR_CODE, -ERR_READ_FILE); g_IsOTAMode = FALSE; return; } memset(buf, 0, MAX_PATH); sprintf(buf, "cat %s/ota.md5 | awk '{print $1}'", g_otaDownloadPath); if(GetShellExecResult(buf, &pMD5Val) != 0) { LOG_EX(LOG_Error, "Get MD5 Value Error: %s\n", buf); free(pFileName); __otaRspStatus(OTA_ERR_CODE, -ERR_READ_FILE); g_IsOTAMode = FALSE; return; } LOG_EX(LOG_Debug, "Step %d: Verify OTA image .......\n", step++); memset(buf, 0, MAX_PATH); sprintf(buf, "%s/%s", g_otaDownloadPath, pFileName); pMD5Chk = EvpMD5HashFile(buf); if(strcmp(pMD5Chk, pMD5Val) != 0) { LOG_EX(LOG_Error, "Check %s MD5 Error: %s --> %s\n", buf, pMD5Chk, pMD5Val); __otaRspStatus(OTA_ERR_CODE, -ERR_MD5_CHECK_SUM); g_IsOTAMode = FALSE; return; } free(pMD5Val); free(pFileName); free((void *)pMD5Chk); LOG_EX(LOG_Debug, "Step %d: Decompress OTA file .......\n", step++); pFileName = strdup(buf); __otaRspStatus(OTA_DECOMPRESS_FILE, NO_OTA_STATUS_VAL_TAG); memset(buf, 0, MAX_PATH); sprintf(buf, "mkdir -p %s/%d/ && tar -C %s/%d -xvzf %s > /dev/null", OTA_TEMP_DIR, version, OTA_TEMP_DIR, version, pFileName); ret = system(buf); memset(buf, 0, MAX_PATH); sprintf(buf, "%s/%d/ota.md5", OTA_TEMP_DIR, version); SetHBLAutoExit(FALSE); __otaRspStatus(OTA_UPGRADE_START, NO_OTA_STATUS_VAL_TAG); LOG_EX(LOG_Debug, "Step %d: OTA write to partition .......\n", step++); //__otaBackupWifi(TRUE); //LOG_EX(LOG_Debug, "Step %d: OTA Backup WIFI .......\n", step++); LOG_EX(LOG_Debug, "System into mini ramfs mode\n"); ret = system("/sbin/ramfs.sh"); LOG_EX(LOG_Debug, "Ramfs ready......\n"); reTry = 3; while(reTry--) { if((ret = __otaRunning(buf, version)) == 0) { break; } } if(ret == ERR_OPEN_FILE || ret == ERR_MD5_FILE || ret == ERR_MD5_CHECK_SUM || ret == ERR_OTA_WRITE_BOOT || ret == ERR_OTA_WRITE_ROOTFS || ret == ERR_OTA_WRITE_PARAMS) { __otaRspStatus(OTA_ERR_CODE, -12345); } __otaRspStatus(OTA_REBOOT_SYSTEM, NO_OTA_STATUS_VAL_TAG); #if 0 LOG_EX(LOG_Debug, "Step %d: Clean resource and evn ......\n", step++); for(i = 0; i < sizeof(g_processName) / sizeof(g_processName[0]); i++) { memset(buf, 0, MAX_PATH); sprintf(buf, "killall -9 %s > /dev/null", g_processName[i]); ret = system(buf); } #endif #if 0 SysPointMarkUpload(); LogUploadCurLogFile(); ret = system("sync && ubus call system watchdog \'{\"stop\" : true}\'"); reTry = 3; do { sleep(1); } while(reTry--); reTry = 0; LOG_EX(LOG_Debug, "Reboot System By Power Control Chips\n"); sleep(1); ret = system("sync && echo 3140 > /sys/bus/platform/devices/axp22_board/axp22_reg"); sleep(10); while(TRUE) { LOG_EX(LOG_Debug, "Reboot System: %d times\n", reTry++); ret = system("reboot -f"); sleep(3); } #endif reTry = 300; while(reTry--) { LOG_EX(LOG_Debug, "System force reboot before %d seconds\n", reTry); sleep(1); } while(TRUE) { ret = system("reboot -f"); sleep(5); } return; } static int __isPreDownloader(POTA_DATA_INFO pInfo) { UT_string* pDlPath = NULL, *pChkPath = NULL; char *pFileName = NULL, *pMD5Val = NULL; const char *pMD5Chk = NULL; if(pInfo == NULL) { return (-ERR_FILE_NOT_EXISTS); } utstring_new(pDlPath); utstring_new(pChkPath); utstring_printf(pDlPath, "%s/tina_r16_ota_%d.tar.gz", g_otaDownloadPath, pInfo->version); utstring_printf(pChkPath, "%s/ota.md5", g_otaDownloadPath); if(access(utstring_body(pDlPath), F_OK) != 0 || access(utstring_body(pChkPath), F_OK) != 0) { utstring_free(pDlPath); utstring_free(pChkPath); return (-ERR_FILE_NOT_EXISTS); } utstring_renew(pChkPath); utstring_printf(pChkPath, "cat %s/ota.md5 | awk '{print $2}'", g_otaDownloadPath); if(GetShellExecResult(utstring_body(pChkPath), &pFileName) != 0) { LOG_EX(LOG_Error, "Get File Name Error: %s\n", utstring_body(pChkPath)); utstring_free(pDlPath); utstring_free(pChkPath); return -ERR_FILE_NOT_EXISTS; } utstring_renew(pChkPath); utstring_printf(pChkPath, "cat %s/ota.md5 | awk '{print $1}'", g_otaDownloadPath); if(GetShellExecResult(utstring_body(pChkPath), &pMD5Val) != 0) { LOG_EX(LOG_Error, "Get MD5 Value Error: %s\n", utstring_body(pChkPath)); free(pFileName); utstring_free(pDlPath); utstring_free(pChkPath); return -ERR_MD5_CHECK_SUM; } if(strcmp(pMD5Val, pInfo->otaFileInfo.md5) != 0) { LOG_EX(LOG_Debug, "Download File Chksum Diff: %s -> %s\n", pMD5Val, pInfo->otaFileInfo.md5); free(pFileName); free(pMD5Val); utstring_free(pDlPath); utstring_free(pChkPath); return -ERR_FILE_NOT_EXISTS; } utstring_renew(pChkPath); utstring_printf(pChkPath, "%s/%s", g_otaDownloadPath, pFileName); pMD5Chk = EvpMD5HashFile(utstring_body(pChkPath)); if(pMD5Chk == NULL || strcmp(pMD5Chk, pMD5Val) != 0) { LOG_EX(LOG_Error, "Check %s MD5 Error: %s --> %s\n", utstring_body(pChkPath), pMD5Chk, pMD5Val); free(pFileName); free(pMD5Val); utstring_free(pDlPath); utstring_free(pChkPath); if(pMD5Chk) { free((void *)pMD5Chk); } return -ERR_MD5_CHECK_SUM; } free(pMD5Val); free(pFileName); free((void *)pMD5Chk); utstring_free(pDlPath); utstring_free(pChkPath); return (0); } static void __otaDownloadImageCb(void *pParams) { POTA_DATA_INFO pInfo = (POTA_DATA_INFO)pParams; DOWNLOAD_TASK_INFO dlInfo; char buf[SIZE_1K]; int ret, reTry = 3; g_isDownloading = TRUE; // Notify CC Beging Download __otaRspStatus(OTA_DOWNLOAD_FILE, 2); if(__isPreDownloader(pInfo) == 0) { g_isDownloading = FALSE; g_IsOTAMode = FALSE; __otaRspStatus(OTA_DOWNLOAD_PROGRESS, 100); __otaRspStatus(OTA_DOWNLOAD_FILE, 0); if(pInfo->otaMode == OTA_MODE_FORCE_NOW) { g_IsOTAMode = TRUE; __otaFromLocalImage((void*)(intptr_t)pInfo->version); g_IsOTAMode = FALSE; } free(pInfo); pthread_detach(pthread_self()); return; } while(reTry--) { uv_barrier_t uvBarrier; uv_barrier_init(&uvBarrier, 2); memset(buf, 0, SIZE_1K); sprintf(buf, "rm -rf %s/*", g_otaDownloadPath); ret = system(buf); memset(&dlInfo, 0, sizeof(DOWNLOAD_TASK_INFO)); sprintf(dlInfo.pPath, "%s/tina_r16_ota_%d.tar.gz", g_otaDownloadPath, pInfo->version); memcpy(&dlInfo.fileInfo, &pInfo->otaFileInfo, sizeof(OTA_FILE_INFO)); dlInfo.dlStatus = 0; dlInfo.puvBarrier = &uvBarrier; InetHttpDlFileAsync(dlInfo.fileInfo.url, dlInfo.pPath, __onHttpResponseCb, __onProgressNotifyCb, &dlInfo); LOG_EX(LOG_Debug, ">>>>>>>>>>>>>>>>>>>Wait Download Finished.............\n"); uv_barrier_wait(&uvBarrier); uv_barrier_destroy(&uvBarrier); LOG_EX(LOG_Debug, "<<<<<<<<<<<<<<<<<<otaFileInfo.md5) != 0) { LOG_EX(LOG_Error, "Download File MD5 Error: %s --> %s\n", pChkVal, pInfo->otaFileInfo.md5); dlInfo.retCode = -ERR_MD5_CHECK_SUM; } else { break; } } } if(dlInfo.retCode != 0) { ret = system(buf); g_IsOTAMode = FALSE; g_isDownloading = FALSE; if(dlInfo.retCode > 0) { dlInfo.retCode = -dlInfo.retCode; } __otaRspStatus(OTA_DOWNLOAD_FILE, dlInfo.retCode); pthread_detach(pthread_self()); free(pInfo); return; } LOG_EX(LOG_Debug, "Step 1: Download File result: %d\n", dlInfo.retCode); memset(buf, 0, SIZE_1K); sprintf(buf, "echo \"%s %s\" > %s/ota.md5", dlInfo.fileInfo.md5, basename_v2(dlInfo.pPath), g_otaDownloadPath); ret = system(buf); LOG_EX(LOG_Debug, "Step 2: Save MD5 File; %d\n", ret); g_IsOTAMode = FALSE; __otaRspStatus(OTA_DOWNLOAD_FILE, 0); if(pInfo->otaMode == OTA_MODE_FORCE_NOW) { g_IsOTAMode = TRUE; __otaFromLocalImage((void*)(intptr_t)pInfo->version); g_IsOTAMode = FALSE; } free(pInfo); g_isDownloading = FALSE; pthread_detach(pthread_self()); } static void __dBusDeameonCb(MODULE_NAME modName, int status) { if(status) { LOG_EX(LOG_Error, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); } else { LOG_EX(LOG_Info, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); } if(modName == MODULE_CONTROLLER && status == 0) { __otaRspStatus(OTA_CURRENT_VERSION, g_iplInfo.curVersion); __otaRspStatus(OTA_CURRENT_SETUP_MODE, g_iplInfo.setupMode); __otaRspStatus(OTA_CURRENT_REBOOT_TIME, g_iplInfo.setupStatus); } } static PDBUS_MSG_PACK __dBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) { int err; uv_thread_t uvThread; POTA_DATA_INFO pInfo = NULL; if(!pMsg || !pLoop || !pConn) { return NULL; } //fprintf(stdout, "Recv: cmd = %u, Json = [%s]\n", pMsg->busCmd, (const char *)pMsg->pMsg); switch(pMsg->busCmd) { case CMD_OTA_RUNNOW: if(g_IsOTAMode == 1) { LOG_EX(LOG_Info, "Trigger OTA Now.......\n"); uv_barrier_wait(&g_otaBarrier); } else { __otaRspStatus(OTA_ERR_CODE, -ERR_OTA_NOT_READY); LOG_EX(LOG_Error, "Current Not In OTA Mode\n"); } break; case CMD_MISC_QUERY_DL_STATUS: if(g_isDownloading) { __otaRspStatus(OTA_DOWNLOAD_FILE, 1); } else { __otaRspStatus(OTA_DOWNLOAD_FILE, 0); } break; case CMD_MISC_QUERY_OTA_STATUS: if(g_sSetupStatus == SYSTEM_OTA_OK) { __otaRspStatus(OTA_SUCCESED, 0); } else if(g_sSetupStatus == RECOVERY_SETUP) { __otaRspStatus(OTA_SUCCESED, -1); } else if(g_sSetupStatus == NORMAL_SETUP) { __otaRspStatus(OTA_SUCCESED, 1); } break; case CMD_SYSTEM_STANDBY: LOG_EX(LOG_Debug, "System Ready ....\n"); break; case CMD_OTA_NOTIFY: if(g_IsOTAMode == 0) { if(g_iplInfo.setupMode == SYSTEM_OTA) { LOG_EX(LOG_Debug, "Current System Mode: SYSTEM_OTA\n"); } else if(g_iplInfo.setupMode == RECOVERY_SETUP) { LOG_EX(LOG_Debug, "Current System Mode: RECOVERY_SETUP\n"); } else if(g_iplInfo.setupMode == SYSTEM_OTA_OK) { LOG_EX(LOG_Debug, "Current System Mode: SYSTEM_OTA_OK\n"); } else { LOG_EX(LOG_Debug, "Current System Mode: NORMAL_SETUP\n"); } if(g_isDownloading) { __otaRspStatus(OTA_DOWNLOAD_FILE, 1); break; } pInfo = (POTA_DATA_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_OTA_REQ, TRUE, &err); if(pInfo == NULL) { __otaRspStatus(OTA_ERR_CODE, -ERR_INPUT_PARAMS); } else { //unsigned long long uDiskFreeSize = GetPartitionFreeSize("/mnt/UDISK/"); unsigned long long uMemFreeSize = GetPartitionFreeSize("/tmp/"); unsigned long long uUsedSize = 0; g_IsOTAMode = TRUE; #if TEST_OTA_SERVER memset(&pInfo->otaFileInfo, 0, sizeof(OTA_FILE_INFO)); strcpy(pInfo->otaFileInfo.md5, "78bcf3236f54543301ee1a2f74282917"); strcpy(pInfo->otaFileInfo.url, "http://10.240.84.163/tina_r16_ota_2.tar.gz"); pInfo->otaFileInfo.size = 57106052; #endif __printfOTANotifyCmd("On OTA Notify Command++", pInfo); uUsedSize = pInfo->otaFileInfo.size + (1024 * 1024 * 10); if(g_isBackupMode) { LOG_EX(LOG_Debug, "OTA on recovery mode\n"); pInfo->otaMode == OTA_MODE_FORCE_NOW; } else { LOG_EX(LOG_Debug, "OTA on normal mode\n"); } #if 0 if(uUsedSize > uDiskFreeSize) { LOG_EX(LOG_Error, "Error: File Size = %u bytes, Need %llu bytes, UDISK Free %llu bytes\n", pInfo->otaFileInfo.size, uUsedSize, uDiskFreeSize); if(uUsedSize > uMemFreeSize) { LOG_EX(LOG_Error, "Error: Not Enought Space, Memory Free %llu bytes\n", uMemFreeSize); __otaRspStatus(OTA_DISK_FULL, pInfo->otaCmd); break; } else { memset(g_otaDownloadPath, 0, MAX_PATH); strcpy(g_otaDownloadPath, OTA_MEMORY_DOWNLOAD_DIR); LOG_EX(LOG_Warn, "Warnning: Storage OTA File To Memory: %s\n", g_otaDownloadPath); } } #else if(uUsedSize > uMemFreeSize) { g_IsOTAMode = FALSE; LOG_EX(LOG_Error, "Error: Not Enought Space, Memory Free %llu bytes\n", uMemFreeSize); __otaRspStatus(OTA_DISK_FULL, pInfo->otaCmd); free(pInfo); break; } else { memset(g_otaDownloadPath, 0, MAX_PATH); strcpy(g_otaDownloadPath, OTA_MEMORY_DOWNLOAD_DIR); LOG_EX(LOG_Warn, "Warnning: Storage OTA File To Memory: %s\n", g_otaDownloadPath); } #endif switch(pInfo->otaCmd) { case OTA_CMD_DOWNLOAD: if(strlen(pInfo->otaFileInfo.md5) == 0 || strlen(pInfo->otaFileInfo.url) == 0) { g_IsOTAMode = FALSE; LOG_EX(LOG_Error, "OTA Information Error\n"); } else { err = uv_thread_create(&uvThread, __otaDownloadImageCb, pInfo); if(err != 0) { LOG_EX(LOG_Error, "Create Thread Error: %d\n", err); } } break; case OTA_CMD_USED_LOCAL_IMAGE: case OTA_CMD_EXEC: err = uv_thread_create(&uvThread, __otaFromLocalImage, (void*)(intptr_t)pInfo->version); if(err != 0) { LOG_EX(LOG_Error, "Create Thread Error: %d\n", err); } free(pInfo); break; default: __otaRspStatus(OTA_UNKNOWN_CMD, pInfo->otaCmd); free(pInfo); break; } } } else { __otaRspStatus(OTA_ERR_CODE, -ERR_OTA_PRE_STATR); } break; default: break; } return NULL; } int main(int argc, char **argv) { int i, ret = 0; char buf[256]; DBusConnection* pBus; //struct tm *pTm = NULL; g_pMainLoop = GetDBusDefaultLoop(); pBus = DBusWithLibuvInit(g_pMainLoop, g_pModInfoTable[MODULE_OTA].modAliase, __dBusOnMessage, __dBusDeameonCb, NULL, &ret); if(pBus == NULL) { fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); return (-1); } g_IsOTAMode = 0; strcpy(g_otaDownloadPath, OTA_FILE_DOWNLOAD_DIR); memset(buf, 0, 256); sprintf(buf, "mkdir -p %s", OTA_FILE_DOWNLOAD_DIR); ret = system(buf); memset(buf, 0, 256); sprintf(buf, "mkdir -p %s", OTA_MEMORY_DOWNLOAD_DIR); ret = system(buf); for(i = 0; i < OTA_PARTITION_MAX; i++) { char *pCmdRet = NULL; memset(buf, 0, 256); sprintf(buf, "cat /proc/partitions | grep `readlink %s | xargs basename` | awk '{print $3}'", g_otaPartInfo[i].pPartPath); if((ret = GetShellExecResult((const char *)buf, &pCmdRet)) == 0) { g_otaPartInfo[i].partSize = strtoul(pCmdRet, NULL, 10); if(errno == ERANGE || errno == EINVAL) { g_otaPartInfo[i].partSize = 0; } g_otaPartInfo[i].partSize *= 1024; //fprintf(stdout, "%d: %s --> %s\n", i, g_otaPartInfo[i].pPartPath, pCmdRet); free(pCmdRet); } } LOG_EX(LOG_Debug, "__ReadIPLParams: %d\n", __ReadIPLParams(&g_iplInfo)); if(ret == 0) { __printIPLParams(&g_iplInfo, "Current OTA Information:"); } g_sSetupStatus = g_iplInfo.setupMode; if(g_iplInfo.setupMode == SYSTEM_OTA) { LOG_EX(LOG_Debug, "System setup on OTA mode\n"); if(g_iplInfo.setupStatus > 3 && g_iplInfo.setupStatus != 0xFFFFFFFF) { LOG_EX(LOG_Error, "Check OTA error more than 3 times, Ask server todo next step.....\n"); __otaRspStatus(OTA_SUCCESED, -1); } else if(g_iplInfo.setupStatus <= 3) { LOG_EX(LOG_Error, "Check OTA error less than 3 times, Redo OTA used last image.....\n"); g_IsOTAMode = 1; __otaFromLocalImage(&g_iplInfo.curVersion); g_IsOTAMode = 0; } } else if(g_iplInfo.setupMode == RECOVERY_SETUP) { g_isBackupMode = TRUE; LOG_EX(LOG_Error, "System on recovery mode\n"); __otaRspStatus(OTA_CURRENT_SETUP_MODE, RECOVERY_SETUP); } else if(g_iplInfo.setupMode == SYSTEM_OTA_OK) { LOG_EX(LOG_Info, "System OTA OK\n"); __otaRspStatus(OTA_CURRENT_SETUP_MODE, SYSTEM_OTA_OK); } else { LOG_EX(LOG_Debug, "System setup on normal mode\n"); } if(g_iplInfo.setupStatus != 0) { if(g_iplInfo.setupMode == SYSTEM_OTA_OK) { g_iplInfo.setupMode = NORMAL_SETUP; } g_iplInfo.setupStatus = 0; __SaveIPLParams(&g_iplInfo); } // Make sure continue last download task __otaRspStatus(OTA_DOWNLOAD_FILE, -28); RunUVLoop(g_pMainLoop); while(TRUE) { usleep(1000); } return (0); }