summaryrefslogtreecommitdiffstats
path: root/updater/install.c
diff options
context:
space:
mode:
Diffstat (limited to 'updater/install.c')
-rw-r--r--updater/install.c275
1 files changed, 272 insertions, 3 deletions
diff --git a/updater/install.c b/updater/install.c
index 2336f614d..2e965cee5 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -24,6 +24,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include "cutils/misc.h"
+#include "cutils/properties.h"
#include "edify/expr.h"
#include "minzip/DirUtil.h"
#include "mtdutils/mounts.h"
@@ -40,6 +42,7 @@ char* ErrorAbort(void* cookie, char* format, ...) {
return NULL;
}
+
// mount(type, location, mount_point)
//
// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
@@ -104,6 +107,36 @@ done:
return result;
}
+
+// is_mounted(mount_point)
+char* IsMountedFn(const char* name, void* cookie, int argc, Expr* argv[]) {
+ char* result = NULL;
+ if (argc != 1) {
+ return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc);
+ }
+ char* mount_point;
+ if (ReadArgs(cookie, argv, 1, &mount_point) < 0) {
+ return NULL;
+ }
+ if (strlen(mount_point) == 0) {
+ ErrorAbort(cookie, "mount_point argument to unmount() can't be empty");
+ goto done;
+ }
+
+ scan_mounted_volumes();
+ const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
+ if (vol == NULL) {
+ result = strdup("");
+ } else {
+ result = mount_point;
+ }
+
+done:
+ if (result != mount_point) free(mount_point);
+ return result;
+}
+
+
char* UnmountFn(const char* name, void* cookie, int argc, Expr* argv[]) {
char* result = NULL;
if (argc != 1) {
@@ -132,6 +165,8 @@ done:
if (result != mount_point) free(mount_point);
return result;
}
+
+
// format(type, location)
//
// type="MTD" location=partition
@@ -192,6 +227,7 @@ done:
return result;
}
+
char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) {
char** paths = malloc(argc * sizeof(char*));
int i;
@@ -222,6 +258,7 @@ char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) {
return strdup(buffer);
}
+
char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
@@ -243,8 +280,9 @@ char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) {
return strdup("");
}
-// package_extract package_path destination_path
-char* PackageExtractFn(const char* name, void* cookie, int argc, Expr* argv[]) {
+// package_extract_dir(package_path, destination_path)
+char* PackageExtractDirFn(const char* name, void* cookie,
+ int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
}
@@ -265,6 +303,42 @@ char* PackageExtractFn(const char* name, void* cookie, int argc, Expr* argv[]) {
return strdup(success ? "t" : "");
}
+
+// package_extract_file(package_path, destination_path)
+char* PackageExtractFileFn(const char* name, void* cookie,
+ int argc, Expr* argv[]) {
+ if (argc != 2) {
+ return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
+ }
+ char* zip_path;
+ char* dest_path;
+ if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL;
+
+ bool success = false;
+
+ ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip;
+ const ZipEntry* entry = mzFindZipEntry(za, zip_path);
+ if (entry == NULL) {
+ fprintf(stderr, "%s: no %s in package\n", name, zip_path);
+ goto done;
+ }
+
+ FILE* f = fopen(dest_path, "wb");
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open %s for write: %s\n",
+ name, dest_path, strerror(errno));
+ goto done;
+ }
+ success = mzExtractZipEntryToFile(za, entry, fileno(f));
+ fclose(f);
+
+ done:
+ free(zip_path);
+ free(dest_path);
+ return strdup(success ? "t" : "");
+}
+
+
// symlink target src1 src2 ...
char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) {
if (argc == 0) {
@@ -289,6 +363,7 @@ char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) {
return strdup("");
}
+
char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
char* result = NULL;
bool recursive = (strcmp(name, "set_perm_recursive") == 0);
@@ -356,15 +431,209 @@ done:
return result;
}
+
+char* GetPropFn(const char* name, void* cookie, int argc, Expr* argv[]) {
+ if (argc != 1) {
+ return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc);
+ }
+ char* key;
+ key = Evaluate(cookie, argv[0]);
+ if (key == NULL) return NULL;
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get(key, value, "");
+ free(key);
+
+ return strdup(value);
+}
+
+
+static bool write_raw_image_cb(const unsigned char* data,
+ int data_len, void* ctx) {
+ int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
+ if (r == data_len) return true;
+ fprintf(stderr, "%s\n", strerror(errno));
+ return false;
+}
+
+// write_raw_image(file, partition)
+char* WriteRawImageFn(const char* name, void* cookie, int argc, Expr* argv[]) {
+ char* result = NULL;
+
+ char* partition;
+ char* filename;
+ if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) {
+ return NULL;
+ }
+
+ if (strlen(partition) == 0) {
+ ErrorAbort(cookie, "partition argument to %s can't be empty", name);
+ goto done;
+ }
+ if (strlen(filename) == 0) {
+ ErrorAbort(cookie, "file argument to %s can't be empty", name);
+ goto done;
+ }
+
+ mtd_scan_partitions();
+ const MtdPartition* mtd = mtd_find_partition_by_name(partition);
+ if (mtd == NULL) {
+ fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
+ result = strdup("");
+ goto done;
+ }
+
+ MtdWriteContext* ctx = mtd_write_partition(mtd);
+ if (ctx == NULL) {
+ fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
+ name, partition);
+ result = strdup("");
+ goto done;
+ }
+
+ bool success;
+
+ FILE* f = fopen(filename, "rb");
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open %s: %s\n",
+ name, filename, strerror(errno));
+ result = strdup("");
+ goto done;
+ }
+
+ success = true;
+ char* buffer = malloc(BUFSIZ);
+ int read;
+ while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
+ int wrote = mtd_write_data(ctx, buffer, read);
+ success = success && (wrote == read);
+ if (!success) {
+ fprintf(stderr, "mtd_write_data to %s failed: %s\n",
+ partition, strerror(errno));
+ }
+ }
+ free(buffer);
+ fclose(f);
+
+ printf("%s %s partition from %s\n",
+ success ? "wrote" : "failed to write", partition, filename);
+
+ result = success ? partition : strdup("");
+
+done:
+ if (result != partition) free(partition);
+ free(filename);
+ return result;
+}
+
+// write_firmware_image(file, partition)
+//
+// partition is "radio" or "hboot"
+// file is not used until after updater exits
+//
+// TODO: this should live in some HTC-specific library
+char* WriteFirmwareImageFn(const char* name, void* cookie,
+ int argc, Expr* argv[]) {
+ char* result = NULL;
+
+ char* partition;
+ char* filename;
+ if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) {
+ return NULL;
+ }
+
+ if (strlen(partition) == 0) {
+ ErrorAbort(cookie, "partition argument to %s can't be empty", name);
+ goto done;
+ }
+ if (strlen(filename) == 0) {
+ ErrorAbort(cookie, "file argument to %s can't be empty", name);
+ goto done;
+ }
+
+ FILE* cmd = ((UpdaterInfo*)cookie)->cmd_pipe;
+ fprintf(cmd, "firmware %s %s\n", partition, filename);
+
+ printf("will write %s firmware from %s\n", partition, filename);
+ result = partition;
+
+done:
+ if (result != partition) free(partition);
+ free(filename);
+ return result;
+}
+
+
+extern int applypatch(int argc, char** argv);
+
+// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
+// apply_patch_check(file, sha1, ...)
+// apply_patch_space(bytes)
+char* ApplyPatchFn(const char* name, void* cookie, int argc, Expr* argv[]) {
+ printf("in applypatchfn (%s)\n", name);
+
+ char* prepend = NULL;
+ if (strstr(name, "check") != NULL) {
+ prepend = "-c";
+ } else if (strstr(name, "space") != NULL) {
+ prepend = "-s";
+ }
+
+ char** args = ReadVarArgs(cookie, argc, argv);
+ if (args == NULL) return NULL;
+
+ // insert the "program name" argv[0] and a copy of the "prepend"
+ // string (if any) at the start of the args.
+
+ int extra = 1 + (prepend != NULL ? 1 : 0);
+ char** temp = malloc((argc+extra) * sizeof(char*));
+ memcpy(temp+extra, args, argc * sizeof(char*));
+ temp[0] = strdup("updater");
+ if (prepend) {
+ temp[1] = strdup(prepend);
+ }
+ free(args);
+ args = temp;
+ argc += extra;
+
+ printf("calling applypatch\n");
+ fflush(stdout);
+ int result = applypatch(argc, args);
+ printf("applypatch returned %d\n", result);
+
+ int i;
+ for (i = 0; i < argc; ++i) {
+ free(args[i]);
+ }
+ free(args);
+
+ switch (result) {
+ case 0: return strdup("t");
+ case 1: return strdup("");
+ default: return ErrorAbort(cookie, "applypatch couldn't parse args");
+ }
+}
+
+
void RegisterInstallFunctions() {
RegisterFunction("mount", MountFn);
+ RegisterFunction("is_mounted", IsMountedFn);
RegisterFunction("unmount", UnmountFn);
RegisterFunction("format", FormatFn);
RegisterFunction("show_progress", ShowProgressFn);
RegisterFunction("delete", DeleteFn);
RegisterFunction("delete_recursive", DeleteFn);
- RegisterFunction("package_extract", PackageExtractFn);
+ RegisterFunction("package_extract_dir", PackageExtractDirFn);
+ RegisterFunction("package_extract_file", PackageExtractFileFn);
RegisterFunction("symlink", SymlinkFn);
RegisterFunction("set_perm", SetPermFn);
RegisterFunction("set_perm_recursive", SetPermFn);
+
+ RegisterFunction("getprop", GetPropFn);
+ RegisterFunction("write_raw_image", WriteRawImageFn);
+ RegisterFunction("write_firmware_image", WriteFirmwareImageFn);
+
+ RegisterFunction("apply_patch", ApplyPatchFn);
+ RegisterFunction("apply_patch_check", ApplyPatchFn);
+ RegisterFunction("apply_patch_space", ApplyPatchFn);
}