summaryrefslogtreecommitdiffstats
path: root/commands.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--commands.c1075
1 files changed, 0 insertions, 1075 deletions
diff --git a/commands.c b/commands.c
deleted file mode 100644
index b4678ba6f..000000000
--- a/commands.c
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef NDEBUG
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <unistd.h>
-
-#include "amend/commands.h"
-#include "commands.h"
-#include "common.h"
-#include "cutils/misc.h"
-#include "cutils/properties.h"
-#include "firmware.h"
-#include "minzip/DirUtil.h"
-#include "minzip/Zip.h"
-#include "roots.h"
-
-static int gDidShowProgress = 0;
-
-#define UNUSED(p) ((void)(p))
-
-#define CHECK_BOOL() \
- do { \
- assert(argv == NULL); \
- if (argv != NULL) return -1; \
- assert(argc == true || argc == false); \
- if (argc != true && argc != false) return -1; \
- } while (false)
-
-#define CHECK_WORDS() \
- do { \
- assert(argc >= 0); \
- if (argc < 0) return -1; \
- assert(argc == 0 || argv != NULL); \
- if (argc != 0 && argv == NULL) return -1; \
- } while (false)
-
-#define CHECK_FN() \
- do { \
- CHECK_WORDS(); \
- assert(result != NULL); \
- if (result == NULL) return -1; \
- } while (false)
-
-/*
- * Command definitions
- */
-
-/* assert <boolexpr>
- */
-static int
-cmd_assert(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_BOOL();
-
- /* If our argument is false, return non-zero (failure)
- * If our argument is true, return zero (success)
- */
- if (argc) {
- return 0;
- } else {
- return 1;
- }
-}
-
-/* format <root>
- */
-static int
-cmd_format(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_WORDS();
-
- if (argc != 1) {
- LOGE("Command %s requires exactly one argument\n", name);
- return 1;
- }
- const char *root = argv[0];
- ui_print("Formatting %s...\n", root);
-
- int ret = format_root_device(root);
- if (ret != 0) {
- LOGE("Can't format %s\n", root);
- return 1;
- }
-
- return 0;
-}
-
-/* delete <file1> [<fileN> ...]
- * delete_recursive <file-or-dir1> [<file-or-dirN> ...]
- *
- * Like "rm -f", will try to delete every named file/dir, even if
- * earlier ones fail. Recursive deletes that fail halfway through
- * give up early.
- */
-static int
-cmd_delete(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(cookie);
- CHECK_WORDS();
- int nerr = 0;
- bool recurse;
-
- if (argc < 1) {
- LOGE("Command %s requires at least one argument\n", name);
- return 1;
- }
-
- recurse = (strcmp(name, "delete_recursive") == 0);
- ui_print("Deleting files...\n");
-
- int i;
- for (i = 0; i < argc; i++) {
- const char *root_path = argv[i];
- char pathbuf[PATH_MAX];
- const char *path;
-
- /* This guarantees that all paths use "SYSTEM:"-style roots;
- * plain paths won't make it through translate_root_path().
- */
- path = translate_root_path(root_path, pathbuf, sizeof(pathbuf));
- if (path != NULL) {
- int ret = ensure_root_path_mounted(root_path);
- if (ret < 0) {
- LOGW("Can't mount volume to delete \"%s\"\n", root_path);
- nerr++;
- continue;
- }
- if (recurse) {
- ret = dirUnlinkHierarchy(path);
- } else {
- ret = unlink(path);
- }
- if (ret != 0 && errno != ENOENT) {
- LOGW("Can't delete %s\n(%s)\n", path, strerror(errno));
- nerr++;
- }
- } else {
- nerr++;
- }
- }
-//TODO: add a way to fail if a delete didn't work
-
- return 0;
-}
-
-typedef struct {
- int num_done;
- int num_total;
-} ExtractContext;
-
-static void extract_count_cb(const char *fn, void *cookie)
-{
- ++((ExtractContext*) cookie)->num_total;
-}
-
-static void extract_cb(const char *fn, void *cookie)
-{
- // minzip writes the filename to the log, so we don't need to
- ExtractContext *ctx = (ExtractContext*) cookie;
- ui_set_progress((float) ++ctx->num_done / ctx->num_total);
-}
-
-/* copy_dir <src-dir> <dst-dir> [<timestamp>]
- *
- * The contents of <src-dir> will become the contents of <dst-dir>.
- * The original contents of <dst-dir> are preserved unless something
- * in <src-dir> overwrote them.
- *
- * e.g., for "copy_dir PKG:system SYSTEM:", the file "PKG:system/a"
- * would be copied to "SYSTEM:a".
- *
- * The specified timestamp (in decimal seconds since 1970) will be used,
- * or a fixed default timestamp will be supplied otherwise.
- */
-static int
-cmd_copy_dir(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_WORDS();
-
- // To create a consistent system image, never use the clock for timestamps.
- struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
- if (argc == 3) {
- char *end;
- time_t value = strtoul(argv[2], &end, 0);
- if (value == 0 || end[0] != '\0') {
- LOGE("Command %s: invalid timestamp \"%s\"\n", name, argv[2]);
- return 1;
- } else if (value < timestamp.modtime) {
- LOGE("Command %s: timestamp \"%s\" too early\n", name, argv[2]);
- return 1;
- }
- timestamp.modtime = timestamp.actime = value;
- } else if (argc != 2) {
- LOGE("Command %s requires exactly two arguments\n", name);
- return 1;
- }
-
- // Use 40% of the progress bar (80% post-verification) by default
- ui_print("Copying files...\n");
- if (!gDidShowProgress) ui_show_progress(DEFAULT_FILES_PROGRESS_FRACTION, 0);
-
- /* Mount the destination volume if it isn't already.
- */
- const char *dst_root_path = argv[1];
- int ret = ensure_root_path_mounted(dst_root_path);
- if (ret < 0) {
- LOGE("Can't mount %s\n", dst_root_path);
- return 1;
- }
-
- /* Get the real target path.
- */
- char dstpathbuf[PATH_MAX];
- const char *dst_path;
- dst_path = translate_root_path(dst_root_path,
- dstpathbuf, sizeof(dstpathbuf));
- if (dst_path == NULL) {
- LOGE("Command %s: bad destination path \"%s\"\n", name, dst_root_path);
- return 1;
- }
-
- /* Try to copy the directory. The source may be inside a package.
- */
- const char *src_root_path = argv[0];
- char srcpathbuf[PATH_MAX];
- const char *src_path;
- if (is_package_root_path(src_root_path)) {
- const ZipArchive *package;
- src_path = translate_package_root_path(src_root_path,
- srcpathbuf, sizeof(srcpathbuf), &package);
- if (src_path == NULL) {
- LOGE("Command %s: bad source path \"%s\"\n", name, src_root_path);
- return 1;
- }
-
- /* Extract the files. Set MZ_EXTRACT_FILES_ONLY, because only files
- * are validated by the signature. Do a dry run first to count how
- * many there are (and find some errors early).
- */
- ExtractContext ctx;
- ctx.num_done = 0;
- ctx.num_total = 0;
-
- if (!mzExtractRecursive(package, src_path, dst_path,
- MZ_EXTRACT_FILES_ONLY | MZ_EXTRACT_DRY_RUN,
- &timestamp, extract_count_cb, (void *) &ctx) ||
- !mzExtractRecursive(package, src_path, dst_path,
- MZ_EXTRACT_FILES_ONLY,
- &timestamp, extract_cb, (void *) &ctx)) {
- LOGW("Command %s: couldn't extract \"%s\" to \"%s\"\n",
- name, src_root_path, dst_root_path);
- return 1;
- }
- } else {
- LOGE("Command %s: non-package source path \"%s\" not yet supported\n",
- name, src_root_path);
-//xxx mount the src volume
-//xxx
- return 255;
- }
-
- return 0;
-}
-
-/* run_program <program-file> [<args> ...]
- *
- * Run an external program included in the update package.
- */
-static int
-cmd_run_program(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(cookie);
- CHECK_WORDS();
-
- if (argc < 1) {
- LOGE("Command %s requires at least one argument\n", name);
- return 1;
- }
-
- // Copy the program file to temporary storage.
- if (!is_package_root_path(argv[0])) {
- LOGE("Command %s: non-package program file \"%s\" not supported\n",
- name, argv[0]);
- return 1;
- }
-
- char path[PATH_MAX];
- const ZipArchive *package;
- if (!translate_package_root_path(argv[0], path, sizeof(path), &package)) {
- LOGE("Command %s: bad source path \"%s\"\n", name, argv[0]);
- return 1;
- }
-
- const ZipEntry *entry = mzFindZipEntry(package, path);
- if (entry == NULL) {
- LOGE("Can't find %s\n", path);
- return 1;
- }
-
- static const char *binary = "/tmp/run_program_binary";
- unlink(binary); // just to be sure
- int fd = creat(binary, 0755);
- if (fd < 0) {
- LOGE("Can't make %s\n", binary);
- return 1;
- }
- bool ok = mzExtractZipEntryToFile(package, entry, fd);
- close(fd);
-
- if (!ok) {
- LOGE("Can't copy %s\n", path);
- return 1;
- }
-
- // Create a copy of argv to NULL-terminate it, as execv requires
- char **args = (char **) malloc(sizeof(char*) * (argc + 1));
- memcpy(args, argv, sizeof(char*) * argc);
- args[argc] = NULL;
-
- pid_t pid = fork();
- if (pid == 0) {
- execv(binary, args);
- fprintf(stderr, "E:Can't run %s\n(%s)\n", binary, strerror(errno));
- _exit(-1);
- }
-
- int status;
- waitpid(pid, &status, 0);
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
- return 0;
- } else {
- LOGE("Error in %s\n(Status %d)\n", path, status);
- return 1;
- }
-}
-
-/* set_perm <uid> <gid> <mode> <path> [... <pathN>]
- * set_perm_recursive <uid> <gid> <dir-mode> <file-mode> <path> [... <pathN>]
- *
- * Like "chmod", "chown" and "chgrp" all in one, set ownership and permissions
- * of single files or entire directory trees. Any error causes failure.
- * User, group, and modes must all be integer values (hex or octal OK).
- */
-static int
-cmd_set_perm(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(cookie);
- CHECK_WORDS();
- bool recurse = !strcmp(name, "set_perm_recursive");
-
- int min_args = 4 + (recurse ? 1 : 0);
- if (argc < min_args) {
- LOGE("Command %s requires at least %d args\n", name, min_args);
- return 1;
- }
-
- // All the arguments except the path(s) are numeric.
- int i, n[min_args - 1];
- for (i = 0; i < min_args - 1; ++i) {
- char *end;
- n[i] = strtoul(argv[i], &end, 0);
- if (end[0] != '\0' || argv[i][0] == '\0') {
- LOGE("Command %s: invalid argument \"%s\"\n", name, argv[i]);
- return 1;
- }
- }
-
- for (i = min_args - 1; i < min_args; ++i) {
- char path[PATH_MAX];
- if (translate_root_path(argv[i], path, sizeof(path)) == NULL) {
- LOGE("Command %s: bad path \"%s\"\n", name, argv[i]);
- return 1;
- }
-
- if (ensure_root_path_mounted(argv[i])) {
- LOGE("Can't mount %s\n", argv[i]);
- return 1;
- }
-
- if (recurse
- ? dirSetHierarchyPermissions(path, n[0], n[1], n[2], n[3])
- : (chown(path, n[0], n[1]) || chmod(path, n[2]))) {
- LOGE("Can't chown/mod %s\n(%s)\n", path, strerror(errno));
- return 1;
- }
- }
-
- return 0;
-}
-
-/* show_progress <fraction> <duration>
- *
- * Use <fraction> of the on-screen progress meter for the next operation,
- * automatically advancing the meter over <duration> seconds (or more rapidly
- * if the actual rate of progress can be determined).
- */
-static int
-cmd_show_progress(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(cookie);
- CHECK_WORDS();
-
- if (argc != 2) {
- LOGE("Command %s requires exactly two arguments\n", name);
- return 1;
- }
-
- char *end;
- double fraction = strtod(argv[0], &end);
- if (end[0] != '\0' || argv[0][0] == '\0' || fraction < 0 || fraction > 1) {
- LOGE("Command %s: invalid fraction \"%s\"\n", name, argv[0]);
- return 1;
- }
-
- int duration = strtoul(argv[1], &end, 0);
- if (end[0] != '\0' || argv[0][0] == '\0') {
- LOGE("Command %s: invalid duration \"%s\"\n", name, argv[1]);
- return 1;
- }
-
- // Half of the progress bar is taken by verification,
- // so everything that happens during installation is scaled.
- ui_show_progress(fraction * (1 - VERIFICATION_PROGRESS_FRACTION), duration);
- gDidShowProgress = 1;
- return 0;
-}
-
-/* symlink <link-target> <link-path>
- *
- * Create a symlink, like "ln -s". The link path must not exist already.
- * Note that <link-path> is in root:path format, but <link-target> is
- * for the target filesystem (and may be relative).
- */
-static int
-cmd_symlink(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(cookie);
- CHECK_WORDS();
-
- if (argc != 2) {
- LOGE("Command %s requires exactly two arguments\n", name);
- return 1;
- }
-
- char path[PATH_MAX];
- if (translate_root_path(argv[1], path, sizeof(path)) == NULL) {
- LOGE("Command %s: bad path \"%s\"\n", name, argv[1]);
- return 1;
- }
-
- if (ensure_root_path_mounted(argv[1])) {
- LOGE("Can't mount %s\n", argv[1]);
- return 1;
- }
-
- if (symlink(argv[0], path)) {
- LOGE("Can't symlink %s\n", path);
- return 1;
- }
-
- return 0;
-}
-
-struct FirmwareContext {
- size_t total_bytes, done_bytes;
- char *data;
-};
-
-static bool firmware_fn(const unsigned char *data, int data_len, void *cookie)
-{
- struct FirmwareContext *context = (struct FirmwareContext*) cookie;
- if (context->done_bytes + data_len > context->total_bytes) {
- LOGE("Data overrun in firmware\n");
- return false; // Should not happen, but let's be safe.
- }
-
- memcpy(context->data + context->done_bytes, data, data_len);
- context->done_bytes += data_len;
- ui_set_progress(context->done_bytes * 1.0 / context->total_bytes);
- return true;
-}
-
-/* write_radio_image <src-image>
- * write_hboot_image <src-image>
- * Doesn't actually take effect until the rest of installation finishes.
- */
-static int
-cmd_write_firmware_image(const char *name, void *cookie,
- int argc, const char *argv[])
-{
- UNUSED(cookie);
- CHECK_WORDS();
-
- if (argc != 1) {
- LOGE("Command %s requires exactly one argument\n", name);
- return 1;
- }
-
- const char *type;
- if (!strcmp(name, "write_radio_image")) {
- type = "radio";
- } else if (!strcmp(name, "write_hboot_image")) {
- type = "hboot";
- } else {
- LOGE("Unknown firmware update command %s\n", name);
- return 1;
- }
-
- if (!is_package_root_path(argv[0])) {
- LOGE("Command %s: non-package image file \"%s\" not supported\n",
- name, argv[0]);
- return 1;
- }
-
- ui_print("Extracting %s image...\n", type);
- char path[PATH_MAX];
- const ZipArchive *package;
- if (!translate_package_root_path(argv[0], path, sizeof(path), &package)) {
- LOGE("Command %s: bad source path \"%s\"\n", name, argv[0]);
- return 1;
- }
-
- const ZipEntry *entry = mzFindZipEntry(package, path);
- if (entry == NULL) {
- LOGE("Can't find %s\n", path);
- return 1;
- }
-
- // Load the update image into RAM.
- struct FirmwareContext context;
- context.total_bytes = mzGetZipEntryUncompLen(entry);
- context.done_bytes = 0;
- context.data = malloc(context.total_bytes);
- if (context.data == NULL) {
- LOGE("Can't allocate %d bytes for %s\n", context.total_bytes, argv[0]);
- return 1;
- }
-
- if (!mzProcessZipEntryContents(package, entry, firmware_fn, &context) ||
- context.done_bytes != context.total_bytes) {
- LOGE("Can't read %s\n", argv[0]);
- free(context.data);
- return 1;
- }
-
- if (remember_firmware_update(type, context.data, context.total_bytes)) {
- LOGE("Can't store %s image\n", type);
- free(context.data);
- return 1;
- }
-
- return 0;
-}
-
-static bool write_raw_image_process_fn(
- 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;
- LOGE("%s\n", strerror(errno));
- return false;
-}
-
-/* write_raw_image <src-image> <dest-root>
- */
-static int
-cmd_write_raw_image(const char *name, void *cookie,
- int argc, const char *argv[])
-{
- UNUSED(cookie);
- CHECK_WORDS();
-
- if (argc != 2) {
- LOGE("Command %s requires exactly two arguments\n", name);
- return 1;
- }
-
- // Use 10% of the progress bar (20% post-verification) by default
- const char *src_root_path = argv[0];
- const char *dst_root_path = argv[1];
- ui_print("Writing %s...\n", dst_root_path);
- if (!gDidShowProgress) ui_show_progress(DEFAULT_IMAGE_PROGRESS_FRACTION, 0);
-
- /* Find the source image, which is probably in a package.
- */
- if (!is_package_root_path(src_root_path)) {
- LOGE("Command %s: non-package source path \"%s\" not yet supported\n",
- name, src_root_path);
- return 255;
- }
-
- /* Get the package.
- */
- char srcpathbuf[PATH_MAX];
- const char *src_path;
- const ZipArchive *package;
- src_path = translate_package_root_path(src_root_path,
- srcpathbuf, sizeof(srcpathbuf), &package);
- if (src_path == NULL) {
- LOGE("Command %s: bad source path \"%s\"\n", name, src_root_path);
- return 1;
- }
-
- /* Get the entry.
- */
- const ZipEntry *entry = mzFindZipEntry(package, src_path);
- if (entry == NULL) {
- LOGE("Missing file %s\n", src_path);
- return 1;
- }
-
- /* Unmount the destination root if it isn't already.
- */
- int ret = ensure_root_path_unmounted(dst_root_path);
- if (ret < 0) {
- LOGE("Can't unmount %s\n", dst_root_path);
- return 1;
- }
-
- /* Open the partition for writing.
- */
- const MtdPartition *partition = get_root_mtd_partition(dst_root_path);
- if (partition == NULL) {
- LOGE("Can't find %s\n", dst_root_path);
- return 1;
- }
- MtdWriteContext *context = mtd_write_partition(partition);
- if (context == NULL) {
- LOGE("Can't open %s\n", dst_root_path);
- return 1;
- }
-
- /* Extract and write the image.
- */
- bool ok = mzProcessZipEntryContents(package, entry,
- write_raw_image_process_fn, context);
- if (!ok) {
- LOGE("Error writing %s\n", dst_root_path);
- mtd_write_close(context);
- return 1;
- }
-
- if (mtd_erase_blocks(context, -1) == (off_t) -1) {
- LOGE("Error finishing %s\n", dst_root_path);
- mtd_write_close(context);
- return -1;
- }
-
- if (mtd_write_close(context)) {
- LOGE("Error closing %s\n", dst_root_path);
- return -1;
- }
- return 0;
-}
-
-/* mark <resource> dirty|clean
- */
-static int
-cmd_mark(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_WORDS();
-//xxx when marking, save the top-level hash at the mark point
-// so we can retry on failure. Otherwise the hashes won't match,
-// or someone could intentionally dirty the FS to force a downgrade
-//xxx
- return -1;
-}
-
-/* done
- */
-static int
-cmd_done(const char *name, void *cookie, int argc, const char *argv[])
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_WORDS();
-//xxx
- return -1;
-}
-
-
-/*
- * Function definitions
- */
-
-/* compatible_with(<version>)
- *
- * Returns "true" if this version of the script parser and command
- * set supports the named version.
- */
-static int
-fn_compatible_with(const char *name, void *cookie, int argc, const char *argv[],
- char **result, size_t *resultLen)
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_FN();
-
- if (argc != 1) {
- fprintf(stderr, "%s: wrong number of arguments (%d)\n",
- name, argc);
- return 1;
- }
-
- if (!strcmp(argv[0], "0.1") || !strcmp(argv[0], "0.2")) {
- *result = strdup("true");
- } else {
- *result = strdup("");
- }
- if (resultLen != NULL) {
- *resultLen = strlen(*result);
- }
- return 0;
-}
-
-/* update_forced()
- *
- * Returns "true" if some system setting has determined that
- * the update should happen no matter what.
- */
-static int
-fn_update_forced(const char *name, void *cookie, int argc, const char *argv[],
- char **result, size_t *resultLen)
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_FN();
-
- if (argc != 0) {
- fprintf(stderr, "%s: wrong number of arguments (%d)\n",
- name, argc);
- return 1;
- }
-
- //xxx check some global or property
- bool force = true;
- if (force) {
- *result = strdup("true");
- } else {
- *result = strdup("");
- }
- if (resultLen != NULL) {
- *resultLen = strlen(*result);
- }
-
- return 0;
-}
-
-/* get_mark(<resource>)
- *
- * Returns the current mark associated with the provided resource.
- */
-static int
-fn_get_mark(const char *name, void *cookie, int argc, const char *argv[],
- char **result, size_t *resultLen)
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_FN();
-
- if (argc != 1) {
- fprintf(stderr, "%s: wrong number of arguments (%d)\n",
- name, argc);
- return 1;
- }
-
- //xxx look up the value
- *result = strdup("");
- if (resultLen != NULL) {
- *resultLen = strlen(*result);
- }
-
- return 0;
-}
-
-/* hash_dir(<path-to-directory>)
- */
-static int
-fn_hash_dir(const char *name, void *cookie, int argc, const char *argv[],
- char **result, size_t *resultLen)
-{
- int ret = -1;
-
- UNUSED(name);
- UNUSED(cookie);
- CHECK_FN();
-
- const char *dir;
- if (argc != 1) {
- fprintf(stderr, "%s: wrong number of arguments (%d)\n",
- name, argc);
- return 1;
- } else {
- dir = argv[0];
- }
-
- return ret;
-}
-
-/* matches(<str>, <str1> [, <strN>...])
- * If <str> matches (strcmp) any of <str1>...<strN>, returns <str>,
- * otherwise returns "".
- *
- * E.g., assert matches(hash_dir("/path"), "hash1", "hash2")
- */
-static int
-fn_matches(const char *name, void *cookie, int argc, const char *argv[],
- char **result, size_t *resultLen)
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_FN();
-
- if (argc < 2) {
- fprintf(stderr, "%s: not enough arguments (%d < 2)\n",
- name, argc);
- return 1;
- }
-
- int i;
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[0], argv[i]) == 0) {
- *result = strdup(argv[0]);
- if (resultLen != NULL) {
- *resultLen = strlen(*result);
- }
- return 0;
- }
- }
-
- *result = strdup("");
- if (resultLen != NULL) {
- *resultLen = 1;
- }
- return 0;
-}
-
-/* concat(<str>, <str1> [, <strN>...])
- * Returns the concatenation of all strings.
- */
-static int
-fn_concat(const char *name, void *cookie, int argc, const char *argv[],
- char **result, size_t *resultLen)
-{
- UNUSED(name);
- UNUSED(cookie);
- CHECK_FN();
-
- size_t totalLen = 0;
- int i;
- for (i = 0; i < argc; i++) {
- totalLen += strlen(argv[i]);
- }
-
- char *s = (char *)malloc(totalLen + 1);
- if (s == NULL) {
- return -1;
- }
- s[totalLen] = '\0';
- for (i = 0; i < argc; i++) {
- //TODO: keep track of the end to avoid walking the string each time
- strcat(s, argv[i]);
- }
- *result = s;
- if (resultLen != NULL) {
- *resultLen = strlen(s);
- }
-
- return 0;
-}
-
-/* getprop(<property>)
- * Returns the named Android system property value, or "" if not set.
- */
-static int
-fn_getprop(const char *name, void *cookie, int argc, const char *argv[],
- char **result, size_t *resultLen)
-{
- UNUSED(cookie);
- CHECK_FN();
-
- if (argc != 1) {
- LOGE("Command %s requires exactly one argument\n", name);
- return 1;
- }
-
- char value[PROPERTY_VALUE_MAX];
- property_get(argv[0], value, "");
-
- *result = strdup(value);
- if (resultLen != NULL) {
- *resultLen = strlen(*result);
- }
-
- return 0;
-}
-
-/* file_contains(<filename>, <substring>)
- * Returns "true" if the file exists and contains the specified substring.
- */
-static int
-fn_file_contains(const char *name, void *cookie, int argc, const char *argv[],
- char **result, size_t *resultLen)
-{
- UNUSED(cookie);
- CHECK_FN();
-
- if (argc != 2) {
- LOGE("Command %s requires exactly two arguments\n", name);
- return 1;
- }
-
- char pathbuf[PATH_MAX];
- const char *root_path = argv[0];
- const char *path = translate_root_path(root_path, pathbuf, sizeof(pathbuf));
- if (path == NULL) {
- LOGE("Command %s: bad path \"%s\"\n", name, root_path);
- return 1;
- }
-
- if (ensure_root_path_mounted(root_path)) {
- LOGE("Can't mount %s\n", root_path);
- return 1;
- }
-
- const char *needle = argv[1];
- char *haystack = (char*) load_file(path, NULL);
- if (haystack == NULL) {
- LOGI("%s: Can't read \"%s\" (%s)\n", name, path, strerror(errno));
- *result = ""; /* File not found is not an error. */
- } else if (strstr(haystack, needle) == NULL) {
- LOGI("%s: Can't find \"%s\" in \"%s\"\n", name, needle, path);
- *result = strdup("");
- free(haystack);
- } else {
- *result = strdup("true");
- free(haystack);
- }
-
- if (resultLen != NULL) {
- *resultLen = strlen(*result);
- }
- return 0;
-}
-
-int
-register_update_commands(RecoveryCommandContext *ctx)
-{
- int ret;
-
- ret = commandInit();
- if (ret < 0) return ret;
-
- /*
- * Commands
- */
-
- ret = registerCommand("assert", CMD_ARGS_BOOLEAN, cmd_assert, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("delete", CMD_ARGS_WORDS, cmd_delete, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("delete_recursive", CMD_ARGS_WORDS, cmd_delete,
- (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("copy_dir", CMD_ARGS_WORDS,
- cmd_copy_dir, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("run_program", CMD_ARGS_WORDS,
- cmd_run_program, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("set_perm", CMD_ARGS_WORDS,
- cmd_set_perm, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("set_perm_recursive", CMD_ARGS_WORDS,
- cmd_set_perm, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("show_progress", CMD_ARGS_WORDS,
- cmd_show_progress, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("symlink", CMD_ARGS_WORDS, cmd_symlink, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("format", CMD_ARGS_WORDS, cmd_format, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("write_radio_image", CMD_ARGS_WORDS,
- cmd_write_firmware_image, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("write_hboot_image", CMD_ARGS_WORDS,
- cmd_write_firmware_image, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("write_raw_image", CMD_ARGS_WORDS,
- cmd_write_raw_image, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("mark", CMD_ARGS_WORDS, cmd_mark, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerCommand("done", CMD_ARGS_WORDS, cmd_done, (void *)ctx);
- if (ret < 0) return ret;
-
- /*
- * Functions
- */
-
- ret = registerFunction("compatible_with", fn_compatible_with, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerFunction("update_forced", fn_update_forced, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerFunction("get_mark", fn_get_mark, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerFunction("hash_dir", fn_hash_dir, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerFunction("matches", fn_matches, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerFunction("concat", fn_concat, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerFunction("getprop", fn_getprop, (void *)ctx);
- if (ret < 0) return ret;
-
- ret = registerFunction("file_contains", fn_file_contains, (void *)ctx);
- if (ret < 0) return ret;
-
- return 0;
-}