allow OTA package to provide binary instead of script

Allow installation of OTA packages which do not contain an
update-script, but instead contain an update-binary.
This commit is contained in:
Doug Zongker 2009-06-04 10:24:53 -07:00
parent f28c916e73
commit b2ee9201be

170
install.c
View file

@ -14,10 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include "amend/amend.h" #include "amend/amend.h"
#include "common.h" #include "common.h"
@ -30,8 +33,10 @@
#include "mtdutils/mtdutils.h" #include "mtdutils/mtdutils.h"
#include "roots.h" #include "roots.h"
#include "verifier.h" #include "verifier.h"
#include "firmware.h"
#define ASSUMED_UPDATE_SCRIPT_NAME "META-INF/com/google/android/update-script" #define ASSUMED_UPDATE_SCRIPT_NAME "META-INF/com/google/android/update-script"
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
#define PUBLIC_KEYS_FILE "/res/keys" #define PUBLIC_KEYS_FILE "/res/keys"
static const ZipEntry * static const ZipEntry *
@ -95,7 +100,7 @@ handle_update_script(ZipArchive *zip, const ZipEntry *update_script_entry)
int ret = execCommandList((ExecContext *)1, commands); int ret = execCommandList((ExecContext *)1, commands);
if (ret != 0) { if (ret != 0) {
int num = ret; int num = ret;
char *line, *next = script_data; char *line = NULL, *next = script_data;
while (next != NULL && ret-- > 0) { while (next != NULL && ret-- > 0) {
line = next; line = next;
next = memchr(line, '\n', script_data + script_len - line); next = memchr(line, '\n', script_data + script_len - line);
@ -109,6 +114,159 @@ handle_update_script(ZipArchive *zip, const ZipEntry *update_script_entry)
return INSTALL_SUCCESS; return INSTALL_SUCCESS;
} }
// The update binary ask us to install a firmware file on reboot. Set
// that up. Takes ownership of type and filename.
static int
handle_firmware_update(char* type, char* filename) {
struct stat st_data;
if (stat(filename, &st_data) < 0) {
LOGE("Error stat'ing %s: %s\n", filename, strerror(errno));
return INSTALL_ERROR;
}
LOGI("type is [%s]\n", type);
char* data = malloc(st_data.st_size);
if (data == NULL) {
LOGE("Can't allocate %d bytes for firmware data\n", st_data.st_size);
return INSTALL_ERROR;
}
FILE* f = fopen(filename, "rb");
if (f == NULL) {
LOGE("Failed to open %s: %s\n", filename, strerror(errno));
return INSTALL_ERROR;
}
if (fread(data, 1, st_data.st_size, f) != st_data.st_size) {
LOGE("Failed to read firmware data: %s\n", strerror(errno));
return INSTALL_ERROR;
}
fclose(f);
if (remember_firmware_update(type, data, st_data.st_size)) {
LOGE("Can't store %s image\n", type);
free(data);
return INSTALL_ERROR;
}
free(filename);
return INSTALL_SUCCESS;
}
// If the package contains an update binary, extract it and run it.
static int
try_update_binary(const char *path, ZipArchive *zip) {
const ZipEntry* binary_entry =
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
if (binary_entry == NULL) {
return INSTALL_CORRUPT;
}
char* binary = "/tmp/update_binary";
unlink(binary);
int fd = creat(binary, 0755);
if (fd < 0) {
LOGE("Can't make %s\n", binary);
return 1;
}
bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
close(fd);
if (!ok) {
LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
return 1;
}
int pipefd[2];
pipe(pipefd);
// When executing the update binary contained in the package, the
// arguments passed are:
//
// - the version number for this interface (currently 1)
//
// - an fd to which the program can write in order to update the
// progress bar. The program can write single-line commands:
//
// progress <frac> <secs>
// fill up <frac> of the progress bar over <secs> seconds.
//
// firmware <"hboot"|"radio"> <filename>
// arrange to install the contents of <filename> in the
// given partition on reboot.
//
// - the name of the package zip file.
//
char** args = malloc(sizeof(char*) * 5);
args[0] = binary;
args[1] = "1";
args[2] = malloc(10);
sprintf(args[2], "%d", pipefd[1]);
args[3] = (char*)path;
args[4] = NULL;
pid_t pid = fork();
if (pid == 0) {
close(pipefd[0]);
execv(binary, args);
fprintf(stderr, "E:Can't run %s (%s)\n", binary, strerror(errno));
_exit(-1);
}
close(pipefd[1]);
char* firmware_type = NULL;
char* firmware_filename = NULL;
char buffer[81];
FILE* from_child = fdopen(pipefd[0], "r");
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
LOGI("read: %s", buffer);
char* command = strtok(buffer, " \n");
if (command == NULL) {
continue;
} else if (strcmp(command, "progress") == 0) {
char* fraction_s = strtok(NULL, " \n");
char* seconds_s = strtok(NULL, " \n");
float fraction = strtof(fraction_s, NULL);
int seconds = strtol(seconds_s, NULL, 10);
ui_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACTION),
seconds);
} else if (strcmp(command, "firmware") == 0) {
char* type = strtok(NULL, " \n");
char* filename = strtok(NULL, " \n");
if (type != NULL && filename != NULL) {
if (firmware_type != NULL) {
LOGE("ignoring attempt to do multiple firmware updates");
} else {
firmware_type = strdup(type);
firmware_filename = strdup(filename);
}
}
} else {
LOGE("unknown command [%s]\n", command);
}
}
fclose(from_child);
int status;
waitpid(pid, &status, 0);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
LOGE("Error in %s\n(Status %d)\n", path, status);
return INSTALL_ERROR;
}
if (firmware_type != NULL) {
return handle_firmware_update(firmware_type, firmware_filename);
} else {
return INSTALL_SUCCESS;
}
}
static int static int
handle_update_package(const char *path, ZipArchive *zip, handle_update_package(const char *path, ZipArchive *zip,
const RSAPublicKey *keys, int numKeys) const RSAPublicKey *keys, int numKeys)
@ -127,6 +285,16 @@ handle_update_package(const char *path, ZipArchive *zip,
// Update should take the rest of the progress bar. // Update should take the rest of the progress bar.
ui_print("Installing update...\n"); ui_print("Installing update...\n");
int result = try_update_binary(path, zip);
if (result == INSTALL_SUCCESS || result == INSTALL_ERROR) {
register_package_root(NULL, NULL); // Unregister package root
return result;
}
// if INSTALL_CORRUPT is returned, this package doesn't have an
// update binary. Fall back to the older mechanism of looking for
// an update script.
const ZipEntry *script_entry; const ZipEntry *script_entry;
script_entry = find_update_script(zip); script_entry = find_update_script(zip);
if (script_entry == NULL) { if (script_entry == NULL) {