/* 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;
}
Exemple #3
0
static int
cmd_restore_rom(const char *name, void *cookie, int argc, const char *argv[],
        PermissionRequestList *permissions)
{
    UNUSED(cookie);
    CHECK_WORDS();

    int restoreboot = 1;
    int restoresystem = 1;
    int restoredata = 1;
    int restorecache = 1;
    int restoresdext = 1;
    int i;
    for (i = 0; i < argc; i++)
    {
        if (strcmp(argv[i], "noboot") == 0)
            restoreboot = 0;
        else if (strcmp(argv[i], "nosystem") == 0)
            restoresystem = 0;
        else if (strcmp(argv[i], "nodata") == 0)
            restoredata = 0;
        else if (strcmp(argv[i], "nocache") == 0)
            restorecache = 0;
        else if (strcmp(argv[i], "nosd-ext") == 0)
            restorecache = 0;
    }

    return nandroid_restore(argv[0], restoreboot, restoresystem, restoredata, restorecache, restoresdext);
}
Exemple #4
0
static int
cmd_backup_rom(const char *name, void *cookie, int argc, const char *argv[],
        PermissionRequestList *permissions)
{
    UNUSED(cookie);
    CHECK_WORDS();

    char* backup_name = NULL;
    char backup_path[PATH_MAX];
    switch(argc)
    {
        case 0:
            {
                char backup_path[PATH_MAX];
                nandroid_generate_timestamp_path(backup_path);
                backup_name = backup_path;
            }
            break;
        case 1:
            backup_name = argv[0];
            break;
        default:
            LOGE("Command %s requires zero or one argument\n", name);
            return 1;
    }

    return nandroid_backup(backup_name);
}
Exemple #5
0
/* format <root>
 */
static int
cmd_format(const char *name, void *cookie, int argc, const char *argv[],
        PermissionRequestList *permissions)
{
    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;
    }
#ifdef BOARD_HAS_DATADATA
    if (0 == strcmp(root, "DATA:")) {
        ret = format_root_device("DATADATA:");
        if (ret != 0) {
            LOGE("Can't format %s\n", root);
            return 1;
        }
    }
#endif
    return 0;
}
/* done
 */
static int
cmd_done(const char *name, void *cookie, int argc, const char *argv[])
{
    UNUSED(name);
    UNUSED(cookie);
    CHECK_WORDS();
//xxx
    return -1;
}
Exemple #7
0
/* done
 */
static int
cmd_done(const char *name, void *cookie, int argc, const char *argv[],
        PermissionRequestList *permissions)
{
    UNUSED(name);
    UNUSED(cookie);
    CHECK_WORDS();
//xxx
    return -1;
}
/* 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;
}
Exemple #9
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[],
        PermissionRequestList *permissions)
{
    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");
//xxx permissions

    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;
}
Exemple #10
0
static int
cmd_install_zip(const char *name, void *cookie, int argc, const char *argv[],
            PermissionRequestList *permissions)
{
    UNUSED(cookie);
    CHECK_WORDS();
    
    if (argc != 1) {
        LOGE("Command %s requires exactly one argument\n", name);
        return 1;
    }

    return install_zip(argv[0]);
}
Exemple #11
0
/* 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[],
        PermissionRequestList *permissions)
{
    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;
}
Exemple #12
0
static int
cmd_sleep(const char *name, void *cookie, int argc, const char *argv[],
            PermissionRequestList *permissions)
{
    UNUSED(cookie);
    CHECK_WORDS();

    if (argc != 1) {
        LOGE("Command %s requires exactly one argument\n", name);
        return 1;
    }
    
    int seconds = atoi(argv[0]);
    sleep(seconds);

    return 0;
}
Exemple #13
0
static int
cmd_print(const char *name, void *cookie, int argc, const char *argv[],
            PermissionRequestList *permissions)
{
    UNUSED(cookie);
    CHECK_WORDS();
    
    char message[1024];
    message[0] = NULL;
    int i;
    for (i = 0; i < argc; i++)
    {
        strcat(message, argv[i]);
        strcat(message, " ");
    }
    strcat(message, "\n");
    
    ui_print(message);
    return 0;
}
/* 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..", root);

    int ret = format_root_device(root);
    if (ret != 0) {
        LOGE("Can't format %s\n", root);
        return 1;
    }

    return 0;
}
/* 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;
}
/* 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;
}
/* 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;
    }
}
/* 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;
}