diff options
-rw-r--r-- | edify/expr.c | 4 | ||||
-rw-r--r-- | edify/main.c | 10 | ||||
-rw-r--r-- | etc/init.rc | 8 | ||||
-rw-r--r-- | install.cpp | 16 | ||||
-rw-r--r-- | minui/graphics.c | 4 | ||||
-rw-r--r-- | minzip/DirUtil.c | 58 | ||||
-rw-r--r-- | minzip/DirUtil.h | 8 | ||||
-rw-r--r-- | mtdutils/mtdutils.c | 26 | ||||
-rw-r--r-- | recovery.cpp | 128 | ||||
-rw-r--r-- | roots.cpp | 19 | ||||
-rw-r--r-- | roots.h | 4 | ||||
-rw-r--r-- | screen_ui.cpp | 51 | ||||
-rw-r--r-- | screen_ui.h | 9 | ||||
-rw-r--r-- | ui.cpp | 41 | ||||
-rw-r--r-- | ui.h | 21 | ||||
-rw-r--r-- | updater/install.c | 370 | ||||
-rw-r--r-- | updater/updater.c | 24 |
17 files changed, 559 insertions, 242 deletions
diff --git a/edify/expr.c b/edify/expr.c index 07a8ceb6a..a2f1f99d7 100644 --- a/edify/expr.c +++ b/edify/expr.c @@ -287,13 +287,13 @@ Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) { long l_int = strtol(left, &end, 10); if (left[0] == '\0' || *end != '\0') { - fprintf(stderr, "[%s] is not an int\n", left); + printf("[%s] is not an int\n", left); goto done; } long r_int = strtol(right, &end, 10); if (right[0] == '\0' || *end != '\0') { - fprintf(stderr, "[%s] is not an int\n", right); + printf("[%s] is not an int\n", right); goto done; } diff --git a/edify/main.c b/edify/main.c index 855704385..9e6bab7ca 100644 --- a/edify/main.c +++ b/edify/main.c @@ -34,8 +34,8 @@ int expect(const char* expr_str, const char* expected, int* errors) { int error_count = 0; error = yyparse(&e, &error_count); if (error > 0 || error_count > 0) { - fprintf(stderr, "error parsing \"%s\" (%d errors)\n", - expr_str, error_count); + printf("error parsing \"%s\" (%d errors)\n", + expr_str, error_count); ++*errors; return 0; } @@ -49,7 +49,7 @@ int expect(const char* expr_str, const char* expected, int* errors) { free(state.errmsg); free(state.script); if (result == NULL && expected != NULL) { - fprintf(stderr, "error evaluating \"%s\"\n", expr_str); + printf("error evaluating \"%s\"\n", expr_str); ++*errors; return 0; } @@ -59,8 +59,8 @@ int expect(const char* expr_str, const char* expected, int* errors) { } if (strcmp(result, expected) != 0) { - fprintf(stderr, "evaluating \"%s\": expected \"%s\", got \"%s\"\n", - expr_str, expected, result); + printf("evaluating \"%s\": expected \"%s\", got \"%s\"\n", + expr_str, expected, result); ++*errors; free(result); return 0; diff --git a/etc/init.rc b/etc/init.rc index abc7b318b..175489066 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -2,6 +2,7 @@ import /init.recovery.${ro.hardware}.rc on early-init start ueventd + start healthd on init export PATH /sbin @@ -37,13 +38,20 @@ on boot class_start default +on property:sys.powerctl=* + powerctl ${sys.powerctl} + service ueventd /sbin/ueventd critical +service healthd /sbin/healthd -n + critical + service recovery /sbin/recovery service adbd /sbin/adbd recovery disabled + socket adbd stream 660 system system # Always start adbd on userdebug and eng builds on property:ro.debuggable=1 diff --git a/install.cpp b/install.cpp index 0cb5cc7df..797a525fd 100644 --- a/install.cpp +++ b/install.cpp @@ -154,6 +154,7 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) { } else { ui->Print("\n"); } + fflush(stdout); } else if (strcmp(command, "wipe_cache") == 0) { *wipe_cache = 1; } else if (strcmp(command, "clear_display") == 0) { @@ -179,7 +180,9 @@ really_install_package(const char *path, int* wipe_cache) { ui->SetBackground(RecoveryUI::INSTALLING_UPDATE); ui->Print("Finding update package...\n"); - ui->SetProgressType(RecoveryUI::INDETERMINATE); + // Give verification half the progress bar... + ui->SetProgressType(RecoveryUI::DETERMINATE); + ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); LOGI("Update location: %s\n", path); if (ensure_path_mounted(path) != 0) { @@ -197,10 +200,7 @@ really_install_package(const char *path, int* wipe_cache) } LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE); - // Give verification half the progress bar... ui->Print("Verifying update package...\n"); - ui->SetProgressType(RecoveryUI::DETERMINATE); - ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); int err; err = verify_file(path, loadedKeys, numKeys); @@ -236,7 +236,13 @@ install_package(const char* path, int* wipe_cache, const char* install_file) } else { LOGE("failed to open last_install: %s\n", strerror(errno)); } - int result = really_install_package(path, wipe_cache); + int result; + if (setup_install_mounts() != 0) { + LOGE("failed to set up expected mounts for install; aborting\n"); + result = INSTALL_ERROR; + } else { + result = really_install_package(path, wipe_cache); + } if (install_log) { fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log); fputc('\n', install_log); diff --git a/minui/graphics.c b/minui/graphics.c index 4968eac7a..d75716531 100644 --- a/minui/graphics.c +++ b/minui/graphics.c @@ -385,8 +385,8 @@ int gr_init(void) get_memory_surface(&gr_mem_surface); - fprintf(stderr, "framebuffer: fd %d (%d x %d)\n", - gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height); + printf("framebuffer: fd %d (%d x %d)\n", + gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height); /* start with 0 as front (displayed) and 1 as back (drawing) */ gr_active_fb = 0; diff --git a/minzip/DirUtil.c b/minzip/DirUtil.c index 8dd5da1da..fe2c880ac 100644 --- a/minzip/DirUtil.c +++ b/minzip/DirUtil.c @@ -234,61 +234,3 @@ dirUnlinkHierarchy(const char *path) /* delete target directory */ return rmdir(path); } - -int -dirSetHierarchyPermissions(const char *path, - int uid, int gid, int dirMode, int fileMode) -{ - struct stat st; - if (lstat(path, &st)) { - return -1; - } - - /* ignore symlinks */ - if (S_ISLNK(st.st_mode)) { - return 0; - } - - /* directories and files get different permissions */ - if (chown(path, uid, gid) || - chmod(path, S_ISDIR(st.st_mode) ? dirMode : fileMode)) { - return -1; - } - - /* recurse over directory components */ - if (S_ISDIR(st.st_mode)) { - DIR *dir = opendir(path); - if (dir == NULL) { - return -1; - } - - errno = 0; - const struct dirent *de; - while (errno == 0 && (de = readdir(dir)) != NULL) { - if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) { - continue; - } - - char dn[PATH_MAX]; - snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); - if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode)) { - errno = 0; - } else if (errno == 0) { - errno = -1; - } - } - - if (errno != 0) { - int save = errno; - closedir(dir); - errno = save; - return -1; - } - - if (closedir(dir)) { - return -1; - } - } - - return 0; -} diff --git a/minzip/DirUtil.h b/minzip/DirUtil.h index a5cfa761b..85a00128b 100644 --- a/minzip/DirUtil.h +++ b/minzip/DirUtil.h @@ -48,14 +48,6 @@ int dirCreateHierarchy(const char *path, int mode, */ int dirUnlinkHierarchy(const char *path); -/* chown -R <uid>:<gid> <path> - * chmod -R <mode> <path> - * - * Sets directories to <dirMode> and files to <fileMode>. Skips symlinks. - */ -int dirSetHierarchyPermissions(const char *path, - int uid, int gid, int dirMode, int fileMode); - #ifdef __cplusplus } #endif diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c index 107cbb9a8..d04b26efa 100644 --- a/mtdutils/mtdutils.c +++ b/mtdutils/mtdutils.c @@ -289,7 +289,7 @@ static int read_block(const MtdPartition *partition, int fd, char *data) { struct mtd_ecc_stats before, after; if (ioctl(fd, ECCGETSTATS, &before)) { - fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno)); + printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno)); return -1; } @@ -300,13 +300,13 @@ static int read_block(const MtdPartition *partition, int fd, char *data) while (pos + size <= (int) partition->size) { if (lseek64(fd, pos, SEEK_SET) != pos || read(fd, data, size) != size) { - fprintf(stderr, "mtd: read error at 0x%08llx (%s)\n", + printf("mtd: read error at 0x%08llx (%s)\n", pos, strerror(errno)); } else if (ioctl(fd, ECCGETSTATS, &after)) { - fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno)); + printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno)); return -1; } else if (after.failed != before.failed) { - fprintf(stderr, "mtd: ECC errors (%d soft, %d hard) at 0x%08llx\n", + printf("mtd: ECC errors (%d soft, %d hard) at 0x%08llx\n", after.corrected - before.corrected, after.failed - before.failed, pos); // copy the comparison baseline for the next read. @@ -431,39 +431,39 @@ static int write_block(MtdWriteContext *ctx, const char *data) int retry; for (retry = 0; retry < 2; ++retry) { if (ioctl(fd, MEMERASE, &erase_info) < 0) { - fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", + printf("mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (lseek(fd, pos, SEEK_SET) != pos || write(fd, data, size) != size) { - fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n", + printf("mtd: write error at 0x%08lx (%s)\n", pos, strerror(errno)); } char verify[size]; if (lseek(fd, pos, SEEK_SET) != pos || read(fd, verify, size) != size) { - fprintf(stderr, "mtd: re-read error at 0x%08lx (%s)\n", + printf("mtd: re-read error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (memcmp(data, verify, size) != 0) { - fprintf(stderr, "mtd: verification error at 0x%08lx (%s)\n", + printf("mtd: verification error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (retry > 0) { - fprintf(stderr, "mtd: wrote block after %d retries\n", retry); + printf("mtd: wrote block after %d retries\n", retry); } - fprintf(stderr, "mtd: successfully wrote block at %lx\n", pos); + printf("mtd: successfully wrote block at %lx\n", pos); return 0; // Success! } // Try to erase it once more as we give up on this block add_bad_block_offset(ctx, pos); - fprintf(stderr, "mtd: skipping write block at 0x%08lx\n", pos); + printf("mtd: skipping write block at 0x%08lx\n", pos); ioctl(fd, MEMERASE, &erase_info); pos += partition->erase_size; } @@ -526,7 +526,7 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks) while (blocks-- > 0) { loff_t bpos = pos; if (ioctl(ctx->fd, MEMGETBADBLOCK, &bpos) > 0) { - fprintf(stderr, "mtd: not erasing bad block at 0x%08lx\n", pos); + printf("mtd: not erasing bad block at 0x%08lx\n", pos); pos += ctx->partition->erase_size; continue; // Don't try to erase known factory-bad blocks. } @@ -535,7 +535,7 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks) erase_info.start = pos; erase_info.length = ctx->partition->erase_size; if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) { - fprintf(stderr, "mtd: erase failure at 0x%08lx\n", pos); + printf("mtd: erase failure at 0x%08lx\n", pos); } pos += ctx->partition->erase_size; } diff --git a/recovery.cpp b/recovery.cpp index c82844d25..d803cadf1 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -61,6 +61,7 @@ static const struct option OPTIONS[] = { #define LAST_LOG_FILE "/cache/recovery/last_log" +static const char *CACHE_LOG_DIR = "/cache/recovery"; static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *INTENT_FILE = "/cache/recovery/intent"; static const char *LOG_FILE = "/cache/recovery/log"; @@ -74,6 +75,7 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; RecoveryUI* ui = NULL; char* locale = NULL; +char recovery_version[PROPERTY_VALUE_MAX+1]; /* * The recovery tool communicates with the main system through /cache files. @@ -283,6 +285,19 @@ rotate_last_logs(int max) { } } +static void +copy_logs() { + // Copy logs to cache so the system can find out what happened. + copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); + copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); + copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); + chmod(LOG_FILE, 0600); + chown(LOG_FILE, 1000, 1000); // system user + chmod(LAST_LOG_FILE, 0640); + chmod(LAST_INSTALL_FILE, 0644); + sync(); +} + // clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and // record any intent we were asked to communicate back to the system. @@ -312,14 +327,7 @@ finish_recovery(const char *send_intent) { check_and_fclose(fp, LOCALE_FILE); } - // Copy logs to cache so the system can find out what happened. - copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); - copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); - copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); - chmod(LOG_FILE, 0600); - chown(LOG_FILE, 1000, 1000); // system user - chmod(LAST_LOG_FILE, 0640); - chmod(LAST_INSTALL_FILE, 0644); + copy_logs(); // Reset to normal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; @@ -336,22 +344,95 @@ finish_recovery(const char *send_intent) { sync(); // For good measure. } +typedef struct _saved_log_file { + char* name; + struct stat st; + unsigned char* data; + struct _saved_log_file* next; +} saved_log_file; + static int erase_volume(const char *volume) { + bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); + ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); + + saved_log_file* head = NULL; + + if (is_cache) { + // If we're reformatting /cache, we load any + // "/cache/recovery/last*" files into memory, so we can restore + // them after the reformat. + + ensure_path_mounted(volume); + + DIR* d; + struct dirent* de; + d = opendir(CACHE_LOG_DIR); + if (d) { + char path[PATH_MAX]; + strcpy(path, CACHE_LOG_DIR); + strcat(path, "/"); + int path_len = strlen(path); + while ((de = readdir(d)) != NULL) { + if (strncmp(de->d_name, "last", 4) == 0) { + saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file)); + strcpy(path+path_len, de->d_name); + p->name = strdup(path); + if (stat(path, &(p->st)) == 0) { + // truncate files to 512kb + if (p->st.st_size > (1 << 19)) { + p->st.st_size = 1 << 19; + } + p->data = (unsigned char*) malloc(p->st.st_size); + FILE* f = fopen(path, "rb"); + fread(p->data, 1, p->st.st_size, f); + fclose(f); + p->next = head; + head = p; + } else { + free(p); + } + } + } + closedir(d); + } else { + if (errno != ENOENT) { + printf("opendir failed: %s\n", strerror(errno)); + } + } + } + ui->Print("Formatting %s...\n", volume); ensure_path_unmounted(volume); + int result = format_volume(volume); + + if (is_cache) { + while (head) { + FILE* f = fopen_path(head->name, "wb"); + if (f) { + fwrite(head->data, 1, head->st.st_size, f); + fclose(f); + chmod(head->name, head->st.st_mode); + chown(head->name, head->st.st_uid, head->st.st_gid); + } + free(head->name); + free(head->data); + saved_log_file* temp = head->next; + free(head); + head = temp; + } - if (strcmp(volume, "/cache") == 0) { // Any part of the log we'd copied to cache is now gone. // Reset the pointer so we copy from the beginning of the temp // log. tmplog_offset = 0; + copy_logs(); } - return format_volume(volume); + return result; } static char* @@ -446,21 +527,17 @@ copy_sideloaded_package(const char* original_path) { static const char** prepend_title(const char* const* headers) { - const char* title[] = { "Android system recovery <" - EXPAND(RECOVERY_API_VERSION) "e>", - "", - NULL }; - // count the number of lines in our title, plus the // caller-provided headers. - int count = 0; + int count = 3; // our title has 3 lines const char* const* p; - for (p = title; *p; ++p, ++count); for (p = headers; *p; ++p, ++count); const char** new_headers = (const char**)malloc((count+1) * sizeof(char*)); const char** h = new_headers; - for (p = title; *p; ++p, ++h) *h = *p; + *(h++) = "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>"; + *(h++) = recovery_version; + *(h++) = ""; for (p = headers; *p; ++p, ++h) *h = *p; *h = NULL; @@ -734,10 +811,6 @@ prompt_and_wait(Device* device, int status) { break; case Device::APPLY_EXT: - // Some packages expect /cache to be mounted (eg, - // standard incremental packages expect to use /cache - // as scratch space). - ensure_path_mounted(CACHE_ROOT); status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device); if (status == INSTALL_SUCCESS && wipe_cache) { ui->Print("\n-- Wiping cache (at package request)...\n"); @@ -783,12 +856,12 @@ prompt_and_wait(Device* device, int status) { break; case Device::APPLY_ADB_SIDELOAD: - ensure_path_mounted(CACHE_ROOT); status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE); if (status >= 0) { if (status != INSTALL_SUCCESS) { ui->SetBackground(RecoveryUI::ERROR); ui->Print("Installation aborted.\n"); + copy_logs(); } else if (!ui->IsTextVisible()) { return; // reboot if logs aren't visible } else { @@ -866,7 +939,7 @@ main(int argc, char **argv) { load_volume_table(); ensure_path_mounted(LAST_LOG_FILE); - rotate_last_logs(5); + rotate_last_logs(10); get_args(&argc, &argv); int previous_runs = 0; @@ -913,8 +986,7 @@ main(int argc, char **argv) { sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { - fprintf(stderr, "Warning: No file_contexts\n"); - ui->Print("Warning: No file_contexts\n"); + ui->Print("Warning: No file_contexts\n"); } device->StartRecovery(); @@ -942,6 +1014,7 @@ main(int argc, char **argv) { printf("\n"); property_list(print_property, NULL); + property_get("ro.build.display.id", recovery_version, ""); printf("\n"); int status = INSTALL_SUCCESS; @@ -979,6 +1052,7 @@ main(int argc, char **argv) { } if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) { + copy_logs(); ui->SetBackground(RecoveryUI::ERROR); } if (status != INSTALL_SUCCESS || ui->IsTextVisible()) { @@ -988,6 +1062,6 @@ main(int argc, char **argv) { // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui->Print("Rebooting...\n"); - android_reboot(ANDROID_RB_RESTART, 0, 0); + property_set(ANDROID_RB_PROPERTY, "reboot,"); return EXIT_SUCCESS; } @@ -202,3 +202,22 @@ int format_volume(const char* volume) { LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; } + +int setup_install_mounts() { + if (fstab == NULL) { + LOGE("can't set up install mounts: no fstab loaded\n"); + return -1; + } + for (int i = 0; i < fstab->num_entries; ++i) { + Volume* v = fstab->recs + i; + + if (strcmp(v->mount_point, "/tmp") == 0 || + strcmp(v->mount_point, "/cache") == 0) { + if (ensure_path_mounted(v->mount_point) != 0) return -1; + + } else { + if (ensure_path_unmounted(v->mount_point) != 0) return -1; + } + } + return 0; +} @@ -42,6 +42,10 @@ int ensure_path_unmounted(const char* path); // it is mounted. int format_volume(const char* volume); +// Ensure that all and only the volumes that packages expect to find +// mounted (/tmp and /cache) are mounted. Returns 0 on success. +int setup_install_mounts(); + #ifdef __cplusplus } #endif diff --git a/screen_ui.cpp b/screen_ui.cpp index 93e260936..8376341c3 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -196,9 +196,29 @@ void ScreenRecoveryUI::draw_progress_locked() } } -#define C_HEADER 247,0,6 -#define C_MENU 0,106,157 -#define C_LOG 249,194,0 +void ScreenRecoveryUI::SetColor(UIElement e) { + switch (e) { + case HEADER: + gr_color(247, 0, 6, 255); + break; + case MENU: + case MENU_SEL_BG: + gr_color(0, 106, 157, 255); + break; + case MENU_SEL_FG: + gr_color(255, 255, 255, 255); + break; + case LOG: + gr_color(249, 194, 0, 255); + break; + case TEXT_FILL: + gr_color(0, 0, 0, 160); + break; + default: + gr_color(255, 255, 255, 255); + break; + } +} // Redraw everything on the screen. Does not flip pages. // Should only be called with updateMutex locked. @@ -208,37 +228,38 @@ void ScreenRecoveryUI::draw_screen_locked() draw_progress_locked(); if (show_text) { - gr_color(0, 0, 0, 160); + SetColor(TEXT_FILL); gr_fill(0, 0, gr_fb_width(), gr_fb_height()); int y = 0; int i = 0; if (show_menu) { - gr_color(C_HEADER, 255); + SetColor(HEADER); for (; i < menu_top + menu_items; ++i) { - if (i == menu_top) gr_color(C_MENU, 255); + if (i == menu_top) SetColor(MENU); if (i == menu_top + menu_sel) { // draw the highlight bar + SetColor(MENU_SEL_BG); gr_fill(0, y-2, gr_fb_width(), y+char_height+2); // white text of selected item - gr_color(255, 255, 255, 255); + SetColor(MENU_SEL_FG); if (menu[i][0]) gr_text(4, y, menu[i], 1); - gr_color(C_MENU, 255); + SetColor(MENU); } else { if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top); } y += char_height+4; } - gr_color(C_MENU, 255); + SetColor(MENU); y += 4; gr_fill(0, y, gr_fb_width(), y+2); y += 4; ++i; } - gr_color(C_LOG, 255); + SetColor(LOG); // display from the bottom up, until we hit the top of the // screen, the bottom of the menu, or we've displayed the @@ -446,10 +467,11 @@ void ScreenRecoveryUI::SetProgressType(ProgressType type) pthread_mutex_lock(&updateMutex); if (progressBarType != type) { progressBarType = type; - update_progress_locked(); } progressScopeStart = 0; + progressScopeSize = 0; progress = 0; + update_progress_locked(); pthread_mutex_unlock(&updateMutex); } @@ -585,3 +607,10 @@ void ScreenRecoveryUI::ShowText(bool visible) update_screen_locked(); pthread_mutex_unlock(&updateMutex); } + +void ScreenRecoveryUI::Redraw() +{ + pthread_mutex_lock(&updateMutex); + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} diff --git a/screen_ui.h b/screen_ui.h index fe0de46e8..fc35d95b6 100644 --- a/screen_ui.h +++ b/screen_ui.h @@ -53,6 +53,14 @@ class ScreenRecoveryUI : public RecoveryUI { int SelectMenu(int sel); void EndMenu(); + void Redraw(); + + enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL }; + virtual void SetColor(UIElement e); + + protected: + int install_overlay_offset_x, install_overlay_offset_y; + private: Icon currentIcon; int installingFrame; @@ -94,7 +102,6 @@ class ScreenRecoveryUI : public RecoveryUI { int animation_fps; int indeterminate_frames; int installing_frames; - int install_overlay_offset_x, install_overlay_offset_y; int overlay_offset_x, overlay_offset_y; void draw_install_overlay_locked(int frame); @@ -46,7 +46,8 @@ static RecoveryUI* self = NULL; RecoveryUI::RecoveryUI() : key_queue_len(0), key_last_down(-1), - key_down_time(0) { + key_long_press(false), + key_down_count(0) { pthread_mutex_init(&key_queue_mutex, NULL); pthread_cond_init(&key_queue_cond, NULL); self = this; @@ -112,19 +113,22 @@ void RecoveryUI::process_key(int key_code, int updown) { bool register_key = false; bool long_press = false; - const long long_threshold = CLOCKS_PER_SEC * 750 / 1000; - pthread_mutex_lock(&key_queue_mutex); key_pressed[key_code] = updown; if (updown) { + ++key_down_count; key_last_down = key_code; - key_down_time = clock(); + key_long_press = false; + pthread_t th; + key_timer_t* info = new key_timer_t; + info->ui = this; + info->key_code = key_code; + info->count = key_down_count; + pthread_create(&th, NULL, &RecoveryUI::time_key_helper, info); + pthread_detach(th); } else { if (key_last_down == key_code) { - long duration = clock() - key_down_time; - if (duration > long_threshold) { - long_press = true; - } + long_press = key_long_press; register_key = true; } key_last_down = -1; @@ -152,6 +156,24 @@ void RecoveryUI::process_key(int key_code, int updown) { } } +void* RecoveryUI::time_key_helper(void* cookie) { + key_timer_t* info = (key_timer_t*) cookie; + info->ui->time_key(info->key_code, info->count); + delete info; + return NULL; +} + +void RecoveryUI::time_key(int key_code, int count) { + usleep(750000); // 750 ms == "long" + bool long_press = false; + pthread_mutex_lock(&key_queue_mutex); + if (key_last_down == key_code && key_down_count == count) { + long_press = key_long_press = true; + } + pthread_mutex_unlock(&key_queue_mutex); + if (long_press) KeyLongPress(key_code); +} + void RecoveryUI::EnqueueKey(int key_code) { pthread_mutex_lock(&key_queue_mutex); const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]); @@ -242,3 +264,6 @@ RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) { void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) { } + +void RecoveryUI::KeyLongPress(int key) { +} @@ -80,8 +80,17 @@ class RecoveryUI { enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE }; virtual KeyAction CheckKey(int key); + // Called immediately before each call to CheckKey(), tell you if + // the key was long-pressed. virtual void NextCheckKeyIsLong(bool is_long_press); + // Called when a key is held down long enough to have been a + // long-press (but before the key is released). This means that + // if the key is eventually registered (released without any other + // keys being pressed in the meantime), NextCheckKeyIsLong() will + // be called with "true". + virtual void KeyLongPress(int key); + // --- menu display --- // Display some header text followed by a menu of items, which appears @@ -108,15 +117,25 @@ private: int key_queue[256], key_queue_len; char key_pressed[KEY_MAX + 1]; // under key_queue_mutex int key_last_down; // under key_queue_mutex - clock_t key_down_time; // under key_queue_mutex + bool key_long_press; // under key_queue_mutex + int key_down_count; // under key_queue_mutex int rel_sum; + typedef struct { + RecoveryUI* ui; + int key_code; + int count; + } key_timer_t; + pthread_t input_t; static void* input_thread(void* cookie); static int input_callback(int fd, short revents, void* data); void process_key(int key_code, int updown); bool usb_connected(); + + static void* time_key_helper(void* cookie); + void time_key(int key_code, int count); }; #endif // RECOVERY_UI_H diff --git a/updater/install.c b/updater/install.c index 1fc4fd394..061aa7b5b 100644 --- a/updater/install.c +++ b/updater/install.c @@ -27,6 +27,12 @@ #include <unistd.h> #include <fcntl.h> #include <time.h> +#include <selinux/selinux.h> +#include <ftw.h> +#include <sys/capability.h> +#include <sys/xattr.h> +#include <linux/xattr.h> +#include <inttypes.h> #include "cutils/misc.h" #include "cutils/properties.h" @@ -97,13 +103,13 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { const MtdPartition* mtd; mtd = mtd_find_partition_by_name(location); if (mtd == NULL) { - fprintf(stderr, "%s: no mtd partition named \"%s\"", + printf("%s: no mtd partition named \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) { - fprintf(stderr, "mtd mount of %s failed: %s\n", + printf("mtd mount of %s failed: %s\n", location, strerror(errno)); result = strdup(""); goto done; @@ -112,7 +118,7 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { } else { if (mount(location, mount_point, fs_type, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { - fprintf(stderr, "%s: failed to mount %s at %s: %s\n", + printf("%s: failed to mount %s at %s: %s\n", name, location, mount_point, strerror(errno)); result = strdup(""); } else { @@ -175,7 +181,7 @@ Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { scan_mounted_volumes(); const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); if (vol == NULL) { - fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point); + printf("unmount of %s failed; no such volume\n", mount_point); result = strdup(""); } else { unmount_mounted_volume(vol); @@ -233,25 +239,25 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(location); if (mtd == NULL) { - fprintf(stderr, "%s: no mtd partition named \"%s\"", + printf("%s: no mtd partition named \"%s\"", name, location); result = strdup(""); goto done; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { - fprintf(stderr, "%s: can't write \"%s\"", name, location); + printf("%s: can't write \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_erase_blocks(ctx, -1) == -1) { mtd_write_close(ctx); - fprintf(stderr, "%s: failed to erase \"%s\"", name, location); + printf("%s: failed to erase \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_write_close(ctx) != 0) { - fprintf(stderr, "%s: failed to close \"%s\"", name, location); + printf("%s: failed to close \"%s\"", name, location); result = strdup(""); goto done; } @@ -260,7 +266,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { } else if (strcmp(fs_type, "ext4") == 0) { int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle); if (status != 0) { - fprintf(stderr, "%s: make_ext4fs failed (%d) on %s", + printf("%s: make_ext4fs failed (%d) on %s", name, status, location); result = strdup(""); goto done; @@ -268,7 +274,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { result = location; #endif } else { - fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"", + printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"", name, fs_type, partition_type); } @@ -394,13 +400,13 @@ Value* PackageExtractFileFn(const char* name, State* state, ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; const ZipEntry* entry = mzFindZipEntry(za, zip_path); if (entry == NULL) { - fprintf(stderr, "%s: no %s in package\n", name, zip_path); + printf("%s: no %s in package\n", name, zip_path); goto done2; } FILE* f = fopen(dest_path, "wb"); if (f == NULL) { - fprintf(stderr, "%s: can't open %s for write: %s\n", + printf("%s: can't open %s for write: %s\n", name, dest_path, strerror(errno)); goto done2; } @@ -426,14 +432,14 @@ Value* PackageExtractFileFn(const char* name, State* state, ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; const ZipEntry* entry = mzFindZipEntry(za, zip_path); if (entry == NULL) { - fprintf(stderr, "%s: no %s in package\n", name, zip_path); + printf("%s: no %s in package\n", name, zip_path); goto done1; } v->size = mzGetZipEntryUncompLen(entry); v->data = malloc(v->size); if (v->data == NULL) { - fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n", + printf("%s: failed to allocate %ld bytes for %s\n", name, (long)v->size, zip_path); goto done1; } @@ -460,13 +466,13 @@ static int make_parents(char* name) { *p = '\0'; if (make_parents(name) < 0) return -1; int result = mkdir(name, 0700); - if (result == 0) fprintf(stderr, "symlink(): created [%s]\n", name); + if (result == 0) printf("symlink(): created [%s]\n", name); *p = '/'; if (result == 0 || errno == EEXIST) { // successfully created or already existed; we're done return 0; } else { - fprintf(stderr, "failed to mkdir %s: %s\n", name, strerror(errno)); + printf("failed to mkdir %s: %s\n", name, strerror(errno)); return -1; } } @@ -494,18 +500,18 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { for (i = 0; i < argc-1; ++i) { if (unlink(srcs[i]) < 0) { if (errno != ENOENT) { - fprintf(stderr, "%s: failed to remove %s: %s\n", + printf("%s: failed to remove %s: %s\n", name, srcs[i], strerror(errno)); ++bad; } } if (make_parents(srcs[i])) { - fprintf(stderr, "%s: failed to symlink %s to %s: making parents failed\n", + printf("%s: failed to symlink %s to %s: making parents failed\n", name, srcs[i], target); ++bad; } if (symlink(target, srcs[i]) < 0) { - fprintf(stderr, "%s: failed to symlink %s to %s: %s\n", + printf("%s: failed to symlink %s to %s: %s\n", name, srcs[i], target, strerror(errno)); ++bad; } @@ -518,74 +524,247 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(strdup("")); } - -Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = NULL; - bool recursive = (strcmp(name, "set_perm_recursive") == 0); - - int min_args = 4 + (recursive ? 1 : 0); - if (argc < min_args) { - return ErrorAbort(state, "%s() expects %d+ args, got %d", - name, min_args, argc); +struct perm_parsed_args { + bool has_uid; + uid_t uid; + bool has_gid; + gid_t gid; + bool has_mode; + mode_t mode; + bool has_fmode; + mode_t fmode; + bool has_dmode; + mode_t dmode; + bool has_selabel; + char* selabel; + bool has_capabilities; + uint64_t capabilities; +}; + +static struct perm_parsed_args ParsePermArgs(int argc, char** args) { + int i; + struct perm_parsed_args parsed; + int bad = 0; + static int max_warnings = 20; + + memset(&parsed, 0, sizeof(parsed)); + + for (i = 1; i < argc; i += 2) { + if (strcmp("uid", args[i]) == 0) { + int64_t uid; + if (sscanf(args[i+1], "%" SCNd64, &uid) == 1) { + parsed.uid = uid; + parsed.has_uid = true; + } else { + printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("gid", args[i]) == 0) { + int64_t gid; + if (sscanf(args[i+1], "%" SCNd64, &gid) == 1) { + parsed.gid = gid; + parsed.has_gid = true; + } else { + printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("mode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.mode = mode; + parsed.has_mode = true; + } else { + printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("dmode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.dmode = mode; + parsed.has_dmode = true; + } else { + printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("fmode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.fmode = mode; + parsed.has_fmode = true; + } else { + printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("capabilities", args[i]) == 0) { + int64_t capabilities; + if (sscanf(args[i+1], "%" SCNi64, &capabilities) == 1) { + parsed.capabilities = capabilities; + parsed.has_capabilities = true; + } else { + printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("selabel", args[i]) == 0) { + if (args[i+1][0] != '\0') { + parsed.selabel = args[i+1]; + parsed.has_selabel = true; + } else { + printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (max_warnings != 0) { + printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i]); + max_warnings--; + if (max_warnings == 0) { + printf("ParsedPermArgs: suppressing further warnings\n"); + } + } } + return parsed; +} - char** args = ReadVarArgs(state, argc, argv); - if (args == NULL) return NULL; - - char* end; - int i; +static int ApplyParsedPerms( + const char* filename, + const struct stat *statptr, + struct perm_parsed_args parsed) +{ int bad = 0; - int uid = strtoul(args[0], &end, 0); - if (*end != '\0' || args[0][0] == 0) { - ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]); - goto done; + /* ignore symlinks */ + if (S_ISLNK(statptr->st_mode)) { + return 0; } - int gid = strtoul(args[1], &end, 0); - if (*end != '\0' || args[1][0] == 0) { - ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]); - goto done; + if (parsed.has_uid) { + if (chown(filename, parsed.uid, -1) < 0) { + printf("ApplyParsedPerms: chown of %s to %d failed: %s\n", + filename, parsed.uid, strerror(errno)); + bad++; + } } - if (recursive) { - int dir_mode = strtoul(args[2], &end, 0); - if (*end != '\0' || args[2][0] == 0) { - ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]); - goto done; + if (parsed.has_gid) { + if (chown(filename, -1, parsed.gid) < 0) { + printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n", + filename, parsed.gid, strerror(errno)); + bad++; } + } - int file_mode = strtoul(args[3], &end, 0); - if (*end != '\0' || args[3][0] == 0) { - ErrorAbort(state, "%s: \"%s\" not a valid filemode", - name, args[3]); - goto done; + if (parsed.has_mode) { + if (chmod(filename, parsed.mode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.mode, strerror(errno)); + bad++; } + } - for (i = 4; i < argc; ++i) { - dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode); + if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { + if (chmod(filename, parsed.dmode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.dmode, strerror(errno)); + bad++; } - } else { - int mode = strtoul(args[2], &end, 0); - if (*end != '\0' || args[2][0] == 0) { - ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]); - goto done; + } + + if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { + if (chmod(filename, parsed.fmode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.fmode, strerror(errno)); + bad++; } + } - for (i = 3; i < argc; ++i) { - if (chown(args[i], uid, gid) < 0) { - fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n", - name, args[i], uid, gid, strerror(errno)); - ++bad; + if (parsed.has_selabel) { + // TODO: Don't silently ignore ENOTSUP + if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) { + printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", + filename, parsed.selabel, strerror(errno)); + bad++; + } + } + + if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { + if (parsed.capabilities == 0) { + if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { + // Report failure unless it's ENODATA (attribute not set) + printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", + filename, parsed.capabilities, strerror(errno)); + bad++; } - if (chmod(args[i], mode) < 0) { - fprintf(stderr, "%s: chmod of %s to %o failed: %s\n", - name, args[i], mode, strerror(errno)); - ++bad; + } else { + struct vfs_cap_data cap_data; + memset(&cap_data, 0, sizeof(cap_data)); + cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; + cap_data.data[0].permitted = (uint32_t) (parsed.capabilities & 0xffffffff); + cap_data.data[0].inheritable = 0; + cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32); + cap_data.data[1].inheritable = 0; + if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { + printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", + filename, parsed.capabilities, strerror(errno)); + bad++; } } } - result = strdup(""); + + return bad; +} + +// nftw doesn't allow us to pass along context, so we need to use +// global variables. *sigh* +static struct perm_parsed_args recursive_parsed_args; + +static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr, + int fileflags, struct FTW *pfwt) { + return ApplyParsedPerms(filename, statptr, recursive_parsed_args); +} + +static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { + int i; + int bad = 0; + static int nwarnings = 0; + struct stat sb; + Value* result = NULL; + + bool recursive = (strcmp(name, "set_metadata_recursive") == 0); + + if ((argc % 2) != 1) { + return ErrorAbort(state, "%s() expects an odd number of arguments, got %d", + name, argc); + } + + char** args = ReadVarArgs(state, argc, argv); + if (args == NULL) return NULL; + + if (lstat(args[0], &sb) == -1) { + result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno)); + goto done; + } + + struct perm_parsed_args parsed = ParsePermArgs(argc, args); + + if (recursive) { + recursive_parsed_args = parsed; + bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); + memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); + } else { + bad += ApplyParsedPerms(args[0], &sb, parsed); + } done: for (i = 0; i < argc; ++i) { @@ -593,13 +772,16 @@ done: } free(args); - if (bad) { - free(result); + if (result != NULL) { + return result; + } + + if (bad > 0) { return ErrorAbort(state, "%s: some changes failed", name); } - return StringValue(result); -} + return StringValue(strdup("")); +} Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 1) { @@ -720,7 +902,7 @@ 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)); + printf("%s\n", strerror(errno)); return false; } @@ -752,14 +934,14 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { 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); + printf("%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", + printf("%s: can't write mtd partition \"%s\"\n", name, partition); result = strdup(""); goto done; @@ -772,7 +954,7 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { char* filename = contents->data; FILE* f = fopen(filename, "rb"); if (f == NULL) { - fprintf(stderr, "%s: can't open %s: %s\n", + printf("%s: can't open %s: %s\n", name, filename, strerror(errno)); result = strdup(""); goto done; @@ -793,15 +975,15 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { success = (wrote == contents->size); } if (!success) { - fprintf(stderr, "mtd_write_data to %s failed: %s\n", + printf("mtd_write_data to %s failed: %s\n", partition, strerror(errno)); } if (mtd_erase_blocks(ctx, -1) == -1) { - fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition); + printf("%s: error erasing blocks of %s\n", name, partition); } if (mtd_write_close(ctx) != 0) { - fprintf(stderr, "%s: error closing write of %s\n", name, partition); + printf("%s: error closing write of %s\n", name, partition); } printf("%s %s partition\n", @@ -988,23 +1170,23 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { memcpy(args2, args, sizeof(char*) * argc); args2[argc] = NULL; - fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc); + printf("about to run program [%s] with %d args\n", args2[0], argc); pid_t child = fork(); if (child == 0) { execv(args2[0], args2); - fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno)); + printf("run_program: execv failed: %s\n", strerror(errno)); _exit(1); } int status; waitpid(child, &status, 0); if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { - fprintf(stderr, "run_program: child exited with status %d\n", + printf("run_program: child exited with status %d\n", WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { - fprintf(stderr, "run_program: child terminated by signal %d\n", + printf("run_program: child terminated by signal %d\n", WTERMSIG(status)); } @@ -1053,7 +1235,7 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { } if (args[0]->size < 0) { - fprintf(stderr, "%s(): no file contents received", name); + printf("%s(): no file contents received", name); return StringValue(strdup("")); } uint8_t digest[SHA_DIGEST_SIZE]; @@ -1068,12 +1250,12 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE); for (i = 1; i < argc; ++i) { if (args[i]->type != VAL_STRING) { - fprintf(stderr, "%s(): arg %d is not a string; skipping", + printf("%s(): arg %d is not a string; skipping", name, i); } else if (ParseSha1(args[i]->data, arg_digest) != 0) { // Warn about bad args and skip them. - fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping", - name, args[i]->data); + printf("%s(): error parsing \"%s\" as sha-1; skipping", + name, args[i]->data); } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) { break; } @@ -1133,8 +1315,18 @@ void RegisterInstallFunctions() { RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_file", PackageExtractFileFn); RegisterFunction("symlink", SymlinkFn); - RegisterFunction("set_perm", SetPermFn); - RegisterFunction("set_perm_recursive", SetPermFn); + + // Usage: + // set_metadata("filename", "key1", "value1", "key2", "value2", ...) + // Example: + // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); + RegisterFunction("set_metadata", SetMetadataFn); + + // Usage: + // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) + // Example: + // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); + RegisterFunction("set_metadata_recursive", SetMetadataFn); RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); diff --git a/updater/updater.c b/updater/updater.c index 58ac27f9e..c7009feac 100644 --- a/updater/updater.c +++ b/updater/updater.c @@ -36,13 +36,14 @@ struct selabel_handle *sehandle; int main(int argc, char** argv) { // Various things log information to stdout or stderr more or less - // at random. The log file makes more sense if buffering is - // turned off so things appear in the right order. + // at random (though we've tried to standardize on stdout). The + // log file makes more sense if buffering is turned off so things + // appear in the right order. setbuf(stdout, NULL); setbuf(stderr, NULL); if (argc != 4) { - fprintf(stderr, "unexpected number of arguments (%d)\n", argc); + printf("unexpected number of arguments (%d)\n", argc); return 1; } @@ -50,7 +51,7 @@ int main(int argc, char** argv) { if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || version[1] != '\0') { // We support version 1, 2, or 3. - fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; " + printf("wrong updater binary API; expected 1, 2, or 3; " "got %s\n", argv[1]); return 2; @@ -69,20 +70,20 @@ int main(int argc, char** argv) { int err; err = mzOpenZipArchive(package_data, &za); if (err != 0) { - fprintf(stderr, "failed to open package %s: %s\n", + printf("failed to open package %s: %s\n", package_data, strerror(err)); return 3; } const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); if (script_entry == NULL) { - fprintf(stderr, "failed to find %s in %s\n", SCRIPT_NAME, package_data); + printf("failed to find %s in %s\n", SCRIPT_NAME, package_data); return 4; } char* script = malloc(script_entry->uncompLen+1); if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) { - fprintf(stderr, "failed to read script from package\n"); + printf("failed to read script from package\n"); return 5; } script[script_entry->uncompLen] = '\0'; @@ -101,7 +102,7 @@ int main(int argc, char** argv) { yy_scan_string(script); int error = yyparse(&root, &error_count); if (error != 0 || error_count > 0) { - fprintf(stderr, "%d parse errors\n", error_count); + printf("%d parse errors\n", error_count); return 6; } @@ -112,7 +113,6 @@ int main(int argc, char** argv) { sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { - fprintf(stderr, "Warning: No file_contexts\n"); fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); } @@ -131,10 +131,10 @@ int main(int argc, char** argv) { char* result = Evaluate(&state, root); if (result == NULL) { if (state.errmsg == NULL) { - fprintf(stderr, "script aborted (no error message)\n"); + printf("script aborted (no error message)\n"); fprintf(cmd_pipe, "ui_print script aborted (no error message)\n"); } else { - fprintf(stderr, "script aborted: %s\n", state.errmsg); + printf("script aborted: %s\n", state.errmsg); char* line = strtok(state.errmsg, "\n"); while (line) { fprintf(cmd_pipe, "ui_print %s\n", line); @@ -145,7 +145,7 @@ int main(int argc, char** argv) { free(state.errmsg); return 7; } else { - fprintf(stderr, "script result was [%s]\n", result); + fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result); free(result); } |