diff options
Diffstat (limited to '')
-rw-r--r-- | commands.c | 1075 |
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, - ×tamp, extract_count_cb, (void *) &ctx) || - !mzExtractRecursive(package, src_path, dst_path, - MZ_EXTRACT_FILES_ONLY, - ×tamp, 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; -} |