#include <assert.h>
+#include <alloca.h>
#include <linux/limits.h>
+#include <stdlib.h>
#include "../common/common.h"
#include "fota-manager.h"
#define FOTA_TRIGGER_PATH FOTA_DIR "/" FOTA_TRIGGER_FILE
/* Empty string here is intentional */
-#define FOTA_TRIGGER_MODE_RO_UPDATE_AND_FINISH_UPDATE ""
+#define FOTA_TRIGGER_MODE_RO_UPDATE_AND_FINISH_UPDATE "--ro-update-and-finish"
#define FOTA_TRIGGER_MODE_RO_UPDATE "--ro-update"
#define FOTA_TRIGGER_MODE_FINISH_UPDATE "--finish"
return result;
}
-static char *check_delta_exist(char *base_dir)
+bool check_delta_exist(const char *base_dir, struct deltas *deltas)
{
+ assert(deltas);
assert(base_dir);
- char *client_delta_path = NULL;
- const char *delta_files[] = {FOTA_DELTA_COMPRESSED_FILENAME,
- FOTA_DELTA_FILENAME};
+ #define I_DELTA 0
+ #define I_DELTA_BOOT 1
+ #define I_DELTA_PLATFORM 2
+ const char *delta_files[] = {FOTA_DELTA_BASENAME,
+ FOTA_DELTA_BOOT_BASENAME,
+ FOTA_DELTA_PLATFORM_BASENAME};
+ const char *extensions[] = {".tar", ".tar.gz"};
+ bool delta_found = false;
+ char *delta_table[3] = {NULL, NULL, NULL};
+ deltas->first_delta = NULL;
+ deltas->second_delta = NULL;
+
+ // Collect info about existing delta files
for (size_t n = 0; n < G_N_ELEMENTS(delta_files); n++) {
- gchar *tmp_file_name = g_strconcat(base_dir, "/", delta_files[n], NULL);
- if (tmp_file_name == NULL) {
- _FLOGE("Out of memory error");
- break;
+ for (size_t e = 0; e < G_N_ELEMENTS(extensions); e++) {
+ gchar *tmp_file_name = g_strconcat(base_dir, "/", delta_files[n], extensions[e], NULL);
+ if (tmp_file_name == NULL) {
+ _FLOGE("Out of memory error");
+ break;
+ }
+
+ _FLOGD("Checking: %s", tmp_file_name);
+ if (g_file_test(tmp_file_name, G_FILE_TEST_EXISTS)) {
+ // If there is a two version of the same delta
+ // (tar and tar.gz), we treat it as an error
+ if (delta_table[n]) {
+ _FLOGE("There are a tar and tar.gz version of delta file in %s", base_dir);
+ free(tmp_file_name);
+ goto error;
+ }
+ delta_table[n] = tmp_file_name;
+
+ delta_found = true;
+ } else {
+ free(tmp_file_name);
+ }
}
+ }
- _FLOGD("Checking: %s", tmp_file_name);
- if (g_file_test(tmp_file_name, G_FILE_TEST_EXISTS)) {
- client_delta_path = tmp_file_name;
- break;
+ if (!delta_found)
+ goto error;
+
+ // Check if there is complete delta and delta-boot or deta-platform
+ if (delta_table[I_DELTA]) {
+ if (delta_table[I_DELTA_BOOT] || delta_table[I_DELTA_PLATFORM]) {
+ _FLOGE("There are complete delta (delta.tar(.gz)) and partial delta (delta-boot or delta-platform) in %s", base_dir);
+ goto error;
}
- free(tmp_file_name);
}
- return client_delta_path;
+ // Check if there is only delta-boot
+ if (delta_table[I_DELTA_BOOT] && delta_table[I_DELTA_PLATFORM] == NULL) {
+ _FLOGE("There is only delta-boot file, and this is not enough to perfrom the upgrade");
+ goto error;
+ }
+
+ if (delta_table[I_DELTA]) {
+ deltas->first_delta = delta_table[I_DELTA];
+ _FLOGD("Found complete delta: %s", deltas->first_delta);
+ }
+
+ if (delta_table[I_DELTA_PLATFORM]) {
+ deltas->first_delta = delta_table[I_DELTA_PLATFORM];
+ _FLOGD("Found platform delta: %s", deltas->first_delta);
+ }
+
+ if (delta_table[I_DELTA_BOOT]) {
+ deltas->second_delta = delta_table[I_DELTA_BOOT];
+ _FLOGD("Found boot delta: %s", deltas->second_delta);
+ }
+
+ return true;
+error:
+ for (size_t i = 0; i < G_N_ELEMENTS(delta_table); i++)
+ free(delta_table[i]);
+ return false;
+
+ #undef I_DELTA
+ #undef I_DELTA_BOOT
+ #undef I_DELTA_PLATFORM
}
-static char *find_delta_dir(const char *appid)
+static char *find_delta_dir(const char *appid, struct deltas *deltas)
{
- char *client_delta_path = NULL;
+ char *client_delta_dir = NULL;
if (appid != NULL) {
+ // Check if delta exists in app dir
char *dir_path = g_strjoin("/", APP_SHARED_DIR, appid, APP_SHARED_DATA, NULL);
- client_delta_path = check_delta_exist(dir_path);
- free(dir_path);
+ if (check_delta_exist(dir_path, deltas)) {
+ client_delta_dir = dir_path;
+ } else {
+ free(dir_path);
+ }
}
- if (client_delta_path == NULL)
- client_delta_path = check_delta_exist(FOTA_DIR);
+ // If not - check if delta exists in FOTA_DIR
+ if (client_delta_dir == NULL && check_delta_exist(FOTA_DIR, deltas)) {
+ client_delta_dir = strdup(FOTA_DIR);
+ if (client_delta_dir == NULL) {
+ _FLOGE("Out of memory error");
+ }
+ }
- return client_delta_path;
+ return client_delta_dir;
}
-int find_delta_and_prepare_script(pid_t sender_pid, gchar **client_delta_path)
+int find_delta_and_prepare_script(pid_t sender_pid, struct deltas *deltas)
{
int ret = 0;
char *appid = NULL;
appid = get_sender_appid(sender_pid);
/* Find the delta file path */
- *client_delta_path = find_delta_dir(appid);
+ char *delta_dir = find_delta_dir(appid, deltas);
if (appid != NULL) {
free(appid);
appid = NULL;
}
- if (*client_delta_path == NULL) {
+ if (delta_dir == NULL) {
_FLOGE("Delta file not found");
return -1;
}
- _FLOGI("Delta found: %s", *client_delta_path);
+ _FLOGI("Delta directory found: %s", delta_dir);
/* Prepare fota dir */
ret = util_file_mkdir(FOTA_DIR);
}
/* Check client have appropriate delta */
- if (check_is_delta_appropriate(*client_delta_path, &check_sha) != 0) {
+ if (deltas->second_delta && check_is_delta_appropriate(deltas->second_delta, deltas->first_delta, &check_sha) != 0) {
+ return -1;
+ }
+ if (check_is_delta_appropriate(deltas->first_delta, deltas->first_delta, &check_sha) != 0) {
return -1;
}
}
/* Trigger update */
- ret = util_file_untar(*client_delta_path, FOTA_DIR, FOTA_TRIGGER_FILE);
+ ret = util_file_untar(deltas->first_delta, FOTA_DIR, FOTA_TRIGGER_FILE);
if (ret < 0) {
return -1;
}
return 0;
}
+int execute_upgrade_trigger(struct deltas *deltas, char *mode)
+{
+ assert(mode);
+ #define MAX_ARGS 5
+
+ char **args = alloca(sizeof(char*)*MAX_ARGS);
+ size_t arg = 0;
+ args[arg++] = FOTA_TRIGGER_PATH;
+ if (deltas && deltas->first_delta)
+ args[arg++] = deltas->first_delta;
+ if (deltas && deltas->second_delta)
+ args[arg++] = deltas->second_delta;
+ args[arg++] = mode;
+ args[arg] = NULL;
+
+ return execv(FOTA_TRIGGER_PATH, args);
+ #undef MAX_ARGS
+}
+
int fota_installer_ro_update_and_finish_update(pid_t sender_pid)
{
int ret = 0, status = 0, exec_status = 0;
- gchar *client_delta_path = NULL;
+
pid_t pid;
- ret = find_delta_and_prepare_script(sender_pid, &client_delta_path);
+ struct deltas deltas;
+ ret = find_delta_and_prepare_script(sender_pid, &deltas);
+
if (ret < 0) {
status = ret;
goto execute_destroy;
}
- /* This shouldn't fail. Added to make compiler happy */
- assert(client_delta_path);
-
/* All basic checks succeeded, following is what happens next: We
* double-fork() the process and run actual upgrade script in the child
* process. We do this so that we can at least inform API client that
exit(EXIT_SUCCESS);
}
- ret = execl(FOTA_TRIGGER_PATH, FOTA_TRIGGER_PATH, client_delta_path,
- FOTA_TRIGGER_MODE_RO_UPDATE_AND_FINISH_UPDATE, NULL);
+ ret = execute_upgrade_trigger(&deltas,
+ FOTA_TRIGGER_MODE_RO_UPDATE_AND_FINISH_UPDATE);
if (ret == -1)
- _FLOGE("Failed to execl(%s %s %s)", FOTA_TRIGGER_PATH, client_delta_path,
+ _FLOGE("Failed to execl(%s %s %s %s)", FOTA_TRIGGER_PATH, deltas.first_delta, deltas.second_delta,
FOTA_TRIGGER_MODE_RO_UPDATE_AND_FINISH_UPDATE);
exit(EXIT_FAILURE);
}
execute_destroy:
- if (client_delta_path)
- free(client_delta_path);
+ if (deltas.first_delta)
+ free(deltas.first_delta);
+ if (deltas.second_delta)
+ free(deltas.second_delta);
return status;
}
int fota_installer_ro_update(pid_t sender_pid)
{
int ret = 0, status = 0, exec_status = 0;
- gchar *client_delta_path = NULL;
pid_t pid;
- ret = find_delta_and_prepare_script(sender_pid, &client_delta_path);
+ struct deltas deltas;
+ ret = find_delta_and_prepare_script(sender_pid, &deltas);
+
if (ret < 0) {
status = ret;
goto execute_destroy;
}
- /* This shouldn't fail. Added to make compiler happy */
- assert(client_delta_path);
-
/*
* This is supposed to bo called asynchronously, so we do
* care if and when the script finishes.
status = -1;
goto execute_destroy;
} else if (pid == 0) {
- ret = execl(FOTA_TRIGGER_PATH, FOTA_TRIGGER_PATH, client_delta_path,
- FOTA_TRIGGER_MODE_RO_UPDATE, NULL);
+
+ ret = execute_upgrade_trigger(&deltas,
+ FOTA_TRIGGER_MODE_RO_UPDATE);
if (ret == -1)
- _FLOGE("Failed to execl(%s %s %s)", FOTA_TRIGGER_PATH, client_delta_path,
- FOTA_TRIGGER_MODE_RO_UPDATE);
+ _FLOGE("Failed to execl(%s %s %s %s)", FOTA_TRIGGER_PATH, deltas.first_delta,
+ deltas.second_delta, FOTA_TRIGGER_MODE_RO_UPDATE);
exit(EXIT_FAILURE);
}
status = exec_status > 0 ? -exec_status : exec_status;
execute_destroy:
- if (client_delta_path)
- free(client_delta_path);
+ if (deltas.first_delta)
+ free(deltas.first_delta);
+ if (deltas.second_delta)
+ free(deltas.second_delta);
return status;
}
_FLOGE("Failed to fork");
return -1;
} else if (pid == 0) {
- ret = execl(FOTA_TRIGGER_PATH, FOTA_TRIGGER_PATH, FOTA_TRIGGER_MODE_FINISH_UPDATE, NULL);
+ ret = execute_upgrade_trigger(NULL, FOTA_TRIGGER_MODE_FINISH_UPDATE);
if (ret == -1)
_FLOGE("Failed to execl(%s %s)", FOTA_TRIGGER_PATH, FOTA_TRIGGER_MODE_FINISH_UPDATE);
exec_status = WEXITSTATUS(exec_status);
return exec_status > 0 ? -exec_status : exec_status;
-}
\ No newline at end of file
+}
static int fota_storage_id = -1;
-gchar *fota_storage_find_delta(const char* mount_path, const char *folder_name)
+int fota_storage_find_delta(const char* mount_path, const char *folder_name, struct deltas *deltas)
{
int ret = 0;
bool is_appropriate = false;
- gchar *storage_delta_path = NULL;
+ gchar *storage_delta_dir = NULL;
- /* Check storage have delta.tar */
- storage_delta_path = g_strjoin("/", mount_path, folder_name, FOTA_DELTA_FILENAME, NULL);
- if (storage_delta_path == NULL) {
- _FLOGI("Memory allocation error for storage delta path.");
+ storage_delta_dir = g_strjoin("/", mount_path, folder_name, NULL);
+ if (storage_delta_dir == NULL) {
+ _FLOGE("Out of memory");
goto verify_destroy;
}
- if (!g_file_test(storage_delta_path, G_FILE_TEST_EXISTS)) {
- gchar *tmp_storage_delta_path = storage_delta_path;
- storage_delta_path = g_strconcat(tmp_storage_delta_path, ".gz", NULL);
- free(tmp_storage_delta_path);
-
- if (!g_file_test(storage_delta_path, G_FILE_TEST_EXISTS)) {
- _FLOGI("Storage doesn't have %s", storage_delta_path);
- goto verify_destroy;
- }
+
+ if (!check_delta_exist(storage_delta_dir, deltas)) {
+ _FLOGI("Storage doesn't have %s", storage_delta_dir);
+ goto verify_destroy;
}
/* Prepare fota dir */
}
/* Check storage have appropriate delta */
- if (check_is_delta_appropriate(storage_delta_path, NULL) != 0)
+ if (deltas->second_delta && check_is_delta_appropriate(deltas->second_delta, deltas->first_delta, NULL) != 0)
goto verify_destroy;
- _FLOGI("Success to find delta from storage(%s)", storage_delta_path);
+ if (check_is_delta_appropriate(deltas->first_delta, deltas->first_delta, NULL) != 0)
+ goto verify_destroy;
+
+ _FLOGI("Success to find delta from storage(%s)", storage_delta_dir);
is_appropriate = true;
verify_destroy:
- if (!is_appropriate && storage_delta_path) {
- free(storage_delta_path);
- storage_delta_path = NULL;
+ if (!is_appropriate) {
+ if (storage_delta_dir) {
+ free(storage_delta_dir);
+ }
+ ret = -1;
}
- return storage_delta_path;
+ return ret;
}
-gchar *fota_storage_search_delta_path(const char *mount_path)
+int fota_storage_search_delta_path(const char *mount_path, struct deltas *deltas)
{
GFile *mount = NULL;
GFileEnumerator *enumerator = NULL;
GFileInfo *info = NULL;
GError* error = NULL;
- gchar* delta_path = NULL;
+ int result = -1;
mount = g_file_new_for_path(mount_path);
enumerator = g_file_enumerate_children(mount, G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
while ((info = g_file_enumerator_next_file(enumerator, NULL, NULL)) != NULL) {
if (g_file_info_get_file_type(info) == G_FILE_TYPE_DIRECTORY) {
- delta_path = fota_storage_find_delta(mount_path, g_file_info_get_name(info));
- if (delta_path != NULL)
+ result = fota_storage_find_delta(mount_path,
+ g_file_info_get_name(info),
+ deltas);
+ if (result >= 0)
break;
}
g_object_unref(mount);
- return delta_path;
+ return result;
}
void fota_storage_checker_plug(int storage_id, const char *mount_path)
gchar *delta_path = NULL;
_FLOGI("Storage mounted with %s, start process to check local delta", mount_path);
- delta_path = fota_storage_search_delta_path(mount_path);
- if (delta_path == NULL) {
+
+ struct deltas deltas;
+ if (fota_storage_search_delta_path(mount_path, &deltas) < 0) {
_FLOGI("Failed to search delta path from %s", mount_path);
goto plug_destroy;
}
+ delta_path = g_strjoin(" ",
+ deltas.first_delta,
+ deltas.second_delta,
+ NULL);
+ free(deltas.first_delta);
+ free(deltas.second_delta);
+
+ if (delta_path == NULL) {
+ _FLOGE("Out of memory");
+ goto plug_destroy;
+ }
+
+
ret = fota_client_controller_add_event(FOTA_EVENT_PLUG, delta_path);
if (ret < 0) {
_FLOGE("Failed to add fota client event : %d, idx : %d, value : %s",