summaryrefslogtreecommitdiffstats
path: root/updater/install.c
diff options
context:
space:
mode:
Diffstat (limited to 'updater/install.c')
-rw-r--r--updater/install.c134
1 files changed, 103 insertions, 31 deletions
diff --git a/updater/install.c b/updater/install.c
index 872cbf857..dad0d08c9 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -45,11 +45,26 @@
#include "mtdutils/mounts.h"
#include "mtdutils/mtdutils.h"
#include "updater.h"
+#include "install.h"
#ifdef USE_EXT4
#include "make_ext4fs.h"
+#include "wipe.h"
#endif
+// Take a sha-1 digest and return it as a newly-allocated hex string.
+char* PrintSha1(const uint8_t* digest) {
+ char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
+ int i;
+ const char* alphabet = "0123456789abcdef";
+ for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
+ buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
+ buffer[i*2+1] = alphabet[digest[i] & 0xf];
+ }
+ buffer[i*2] = '\0';
+ return buffer;
+}
+
// mount(fs_type, partition_type, location, mount_point)
//
// fs_type="yaffs2" partition_type="MTD" location=partition
@@ -195,14 +210,29 @@ done:
return StringValue(result);
}
+static int exec_cmd(const char* path, char* const argv[]) {
+ int status;
+ pid_t child;
+ if ((child = vfork()) == 0) {
+ execv(path, argv);
+ _exit(-1);
+ }
+ waitpid(child, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ printf("%s failed with status %d\n", path, WEXITSTATUS(status));
+ }
+ return WEXITSTATUS(status);
+}
+
// format(fs_type, partition_type, location, fs_size, mount_point)
//
// fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes> mount_point=<location>
// fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location>
-// if fs_size == 0, then make_ext4fs uses the entire partition.
+// fs_type="f2fs" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location>
+// if fs_size == 0, then make fs uses the entire partition.
// if fs_size > 0, that is the size to use
-// if fs_size < 0, then reserve that many bytes at the end of the partition
+// if fs_size < 0, then reserve that many bytes at the end of the partition (not for "f2fs")
Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
if (argc != 5) {
@@ -274,6 +304,24 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
result = location;
+ } else if (strcmp(fs_type, "f2fs") == 0) {
+ char *num_sectors;
+ if (asprintf(&num_sectors, "%lld", atoll(fs_size) / 512) <= 0) {
+ printf("format_volume: failed to create %s command for %s\n", fs_type, location);
+ result = strdup("");
+ goto done;
+ }
+ const char *f2fs_path = "/sbin/mkfs.f2fs";
+ const char* const f2fs_argv[] = {"mkfs.f2fs", "-t", "-d1", location, num_sectors, NULL};
+ int status = exec_cmd(f2fs_path, (char* const*)f2fs_argv);
+ free(num_sectors);
+ if (status != 0) {
+ printf("%s: mkfs.f2fs failed (%d) on %s",
+ name, status, location);
+ result = strdup("");
+ goto done;
+ }
+ result = location;
#endif
} else {
printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"",
@@ -304,13 +352,14 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
if (strlen(dst_name) == 0) {
- ErrorAbort(state, "dst_name argument to %s() can't be empty",
- name);
+ ErrorAbort(state, "dst_name argument to %s() can't be empty", name);
goto done;
}
-
- if (rename(src_name, dst_name) != 0) {
- ErrorAbort(state, "Rename of %s() to %s() failed, error %s()",
+ if (make_parents(dst_name) != 0) {
+ ErrorAbort(state, "Creating parent of %s failed, error %s",
+ dst_name, strerror(errno));
+ } else if (rename(src_name, dst_name) != 0) {
+ ErrorAbort(state, "Rename of %s to %s failed, error %s",
src_name, dst_name, strerror(errno));
} else {
result = dst_name;
@@ -421,19 +470,23 @@ Value* PackageExtractDirFn(const char* name, State* state,
// function (the char* returned is actually a FileContents*).
Value* PackageExtractFileFn(const char* name, State* state,
int argc, Expr* argv[]) {
- if (argc != 1 && argc != 2) {
+ if (argc < 1 || argc > 2) {
return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
name, argc);
}
bool success = false;
+
+ UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
+
if (argc == 2) {
// The two-argument version extracts to a file.
+ ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
+
char* zip_path;
char* dest_path;
if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
- ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
if (entry == NULL) {
printf("%s: no %s in package\n", name, zip_path);
@@ -502,7 +555,7 @@ static int make_parents(char* name) {
*p = '\0';
if (make_parents(name) < 0) return -1;
int result = mkdir(name, 0700);
- if (result == 0) printf("symlink(): created [%s]\n", name);
+ if (result == 0) printf("created [%s]\n", name);
*p = '/';
if (result == 0 || errno == EEXIST) {
// successfully created or already existed; we're done
@@ -838,8 +891,8 @@ Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
// file_getprop(file, key)
//
// interprets 'file' as a getprop-style file (key=value pairs, one
-// per line, # comment lines and blank lines okay), and returns the value
-// for 'key' (or "" if it isn't defined).
+// per line. # comment lines,blank lines, lines without '=' ignored),
+// and returns the value for 'key' (or "" if it isn't defined).
Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
char* buffer = NULL;
@@ -897,9 +950,7 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
char* equal = strchr(line, '=');
if (equal == NULL) {
- ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
- name, line, filename);
- goto done;
+ continue;
}
// trim whitespace between key and '='
@@ -1053,8 +1104,8 @@ Value* ApplyPatchSpaceFn(const char* name, State* state,
return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
}
+// apply_patch(file, size, init_sha1, tgt_sha1, patch)
-// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc < 6 || (argc % 2) == 1) {
return ErrorAbort(state, "%s(): expected at least 6 args and an "
@@ -1239,19 +1290,6 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(strdup(buffer));
}
-// Take a sha-1 digest and return it as a newly-allocated hex string.
-static char* PrintSha1(uint8_t* digest) {
- char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
- int i;
- const char* alphabet = "0123456789abcdef";
- for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
- buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
- buffer[i*2+1] = alphabet[digest[i] & 0xf];
- }
- buffer[i*2] = '\0';
- return buffer;
-}
-
// sha1_check(data)
// to return the sha1 of the data (given in the format returned by
// read_file).
@@ -1322,7 +1360,7 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
v->type = VAL_BLOB;
FileContents fc;
- if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
+ if (LoadFileContents(filename, &fc) != 0) {
free(filename);
v->size = -1;
v->data = NULL;
@@ -1419,7 +1457,7 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
// Return the value most recently saved with SetStageFn. The argument
// is the block device for the misc partition.
Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
- if (argc != 2) {
+ if (argc != 1) {
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
}
@@ -1436,6 +1474,36 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(strdup(buffer));
}
+Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) {
+ if (argc != 2) {
+ return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+ }
+
+ char* filename;
+ char* len_str;
+ if (ReadArgs(state, argv, 2, &filename, &len_str) < 0) return NULL;
+
+ size_t len = strtoull(len_str, NULL, 0);
+ int fd = open(filename, O_WRONLY, 0644);
+ int success = wipe_block_device(fd, len);
+
+ free(filename);
+ free(len_str);
+
+ close(fd);
+
+ return StringValue(strdup(success ? "t" : ""));
+}
+
+Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) {
+ if (argc != 0) {
+ return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
+ }
+ UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
+ fprintf(ui->cmd_pipe, "enable_reboot\n");
+ return StringValue(strdup("t"));
+}
+
void RegisterInstallFunctions() {
RegisterFunction("mount", MountFn);
RegisterFunction("is_mounted", IsMountedFn);
@@ -1469,6 +1537,8 @@ void RegisterInstallFunctions() {
RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
+ RegisterFunction("wipe_block_device", WipeBlockDeviceFn);
+
RegisterFunction("read_file", ReadFileFn);
RegisterFunction("sha1_check", Sha1CheckFn);
RegisterFunction("rename", RenameFn);
@@ -1482,4 +1552,6 @@ void RegisterInstallFunctions() {
RegisterFunction("reboot_now", RebootNowFn);
RegisterFunction("get_stage", GetStageFn);
RegisterFunction("set_stage", SetStageFn);
+
+ RegisterFunction("enable_reboot", EnableRebootFn);
}