summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--applypatch/applypatch.c107
-rw-r--r--applypatch/applypatch.h2
-rw-r--r--edify/expr.c4
-rw-r--r--edify/main.c10
-rw-r--r--install.cpp1
-rw-r--r--minui/graphics.c4
-rw-r--r--minzip/DirUtil.c9
-rw-r--r--minzip/DirUtil.h2
-rw-r--r--mtdutils/mtdutils.c26
-rw-r--r--recovery.cpp107
-rw-r--r--screen_ui.cpp4
-rw-r--r--updater/install.c101
-rw-r--r--updater/updater.c24
13 files changed, 302 insertions, 99 deletions
diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c
index 259fa581e..6b8da2a8a 100644
--- a/applypatch/applypatch.c
+++ b/applypatch/applypatch.c
@@ -421,18 +421,111 @@ int WriteToPartition(unsigned char* data, size_t len,
break;
case EMMC:
- ;
- FILE* f = fopen(partition, "wb");
- if (fwrite(data, 1, len, f) != len) {
- printf("short write writing to %s (%s)\n",
- partition, strerror(errno));
+ {
+ size_t start = 0;
+ int success = 0;
+ int fd = open(partition, O_RDWR | O_SYNC);
+ if (fd < 0) {
+ printf("failed to open %s: %s\n", partition, strerror(errno));
return -1;
}
- if (fclose(f) != 0) {
+ int attempt;
+
+ for (attempt = 0; attempt < 10; ++attempt) {
+ size_t next_sync = start + (1<<20);
+ printf("raw O_SYNC write %s attempt %d start at %d\n", partition, attempt+1, start);
+ lseek(fd, start, SEEK_SET);
+ while (start < len) {
+ size_t to_write = len - start;
+ if (to_write > 4096) to_write = 4096;
+
+ ssize_t written = write(fd, data+start, to_write);
+ if (written < 0) {
+ if (errno == EINTR) {
+ written = 0;
+ } else {
+ printf("failed write writing to %s (%s)\n",
+ partition, strerror(errno));
+ return -1;
+ }
+ }
+ start += written;
+ if (start >= next_sync) {
+ fsync(fd);
+ next_sync = start + (1<<20);
+ }
+ }
+ fsync(fd);
+
+ // drop caches so our subsequent verification read
+ // won't just be reading the cache.
+ sync();
+ int dc = open("/proc/sys/vm/drop_caches", O_WRONLY);
+ write(dc, "3\n", 2);
+ close(dc);
+ sleep(1);
+ printf(" caches dropped\n");
+
+ // verify
+ lseek(fd, 0, SEEK_SET);
+ unsigned char buffer[4096];
+ start = len;
+ size_t p;
+ for (p = 0; p < len; p += sizeof(buffer)) {
+ size_t to_read = len - p;
+ if (to_read > sizeof(buffer)) to_read = sizeof(buffer);
+
+ size_t so_far = 0;
+ while (so_far < to_read) {
+ ssize_t read_count = read(fd, buffer+so_far, to_read-so_far);
+ if (read_count < 0) {
+ if (errno == EINTR) {
+ read_count = 0;
+ } else {
+ printf("verify read error %s at %d: %s\n",
+ partition, p, strerror(errno));
+ return -1;
+ }
+ }
+ if ((size_t)read_count < to_read) {
+ printf("short verify read %s at %d: %d %d %s\n",
+ partition, p, read_count, to_read, strerror(errno));
+ }
+ so_far += read_count;
+ }
+
+ if (memcmp(buffer, data+p, to_read)) {
+ printf("verification failed starting at %d\n", p);
+ start = p;
+ break;
+ }
+ }
+
+ if (start == len) {
+ printf("verification read succeeded (attempt %d)\n", attempt+1);
+ success = true;
+ break;
+ }
+
+ sleep(2);
+ }
+
+ if (!success) {
+ printf("failed to verify after all attempts\n");
+ return -1;
+ }
+
+ if (close(fd) != 0) {
printf("error closing %s (%s)\n", partition, strerror(errno));
return -1;
}
+ // hack: sync and sleep after closing in hopes of getting
+ // the data actually onto flash.
+ printf("sleeping after close\n");
+ sync();
+ sleep(5);
break;
+ }
}
free(copy);
@@ -473,7 +566,7 @@ int ParseSha1(const char* str, uint8_t* digest) {
// Search an array of sha1 strings for one matching the given sha1.
// Return the index of the match on success, or -1 if no match is
// found.
-int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str,
+int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
int num_patches) {
int i;
uint8_t patch_sha1[SHA_DIGEST_SIZE];
diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h
index d1a023293..f1f13a100 100644
--- a/applypatch/applypatch.h
+++ b/applypatch/applypatch.h
@@ -65,7 +65,7 @@ int LoadFileContents(const char* filename, FileContents* file,
int retouch_flag);
int SaveFileContents(const char* filename, const FileContents* file);
void FreeFileContents(FileContents* file);
-int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str,
+int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
int num_patches);
// bsdiff.c
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/install.cpp b/install.cpp
index 0cb5cc7df..e1ab848f6 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) {
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..c120fa3cd 100644
--- a/minzip/DirUtil.c
+++ b/minzip/DirUtil.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <dirent.h>
#include <limits.h>
+#include <selinux/selinux.h>
#include "DirUtil.h"
@@ -237,7 +238,7 @@ dirUnlinkHierarchy(const char *path)
int
dirSetHierarchyPermissions(const char *path,
- int uid, int gid, int dirMode, int fileMode)
+ int uid, int gid, int dirMode, int fileMode, const char* secontext)
{
struct stat st;
if (lstat(path, &st)) {
@@ -255,6 +256,10 @@ dirSetHierarchyPermissions(const char *path,
return -1;
}
+ if ((secontext != NULL) && lsetfilecon(path, secontext) && (errno != ENOTSUP)) {
+ return -1;
+ }
+
/* recurse over directory components */
if (S_ISDIR(st.st_mode)) {
DIR *dir = opendir(path);
@@ -271,7 +276,7 @@ dirSetHierarchyPermissions(const char *path,
char dn[PATH_MAX];
snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name);
- if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode)) {
+ if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode, secontext)) {
errno = 0;
} else if (errno == 0) {
errno = -1;
diff --git a/minzip/DirUtil.h b/minzip/DirUtil.h
index a5cfa761b..3e12a0bf5 100644
--- a/minzip/DirUtil.h
+++ b/minzip/DirUtil.h
@@ -54,7 +54,7 @@ int dirUnlinkHierarchy(const char *path);
* Sets directories to <dirMode> and files to <fileMode>. Skips symlinks.
*/
int dirSetHierarchyPermissions(const char *path,
- int uid, int gid, int dirMode, int fileMode);
+ int uid, int gid, int dirMode, int fileMode, const char* secontext);
#ifdef __cplusplus
}
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..c5a589cc6 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";
@@ -283,6 +284,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 +326,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 +343,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*
@@ -789,6 +869,7 @@ prompt_and_wait(Device* device, int status) {
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 +947,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 +994,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();
@@ -979,6 +1059,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()) {
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 222de00ee..93e260936 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -82,6 +82,10 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
install_overlay_offset_y(190),
overlay_offset_x(-1),
overlay_offset_y(-1) {
+
+ for (int i = 0; i < 5; i++)
+ backgroundIcon[i] = NULL;
+
pthread_mutex_init(&updateMutex, NULL);
self = this;
}
diff --git a/updater/install.c b/updater/install.c
index 1fc4fd394..c81bbb59d 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
+#include <selinux/selinux.h>
#include "cutils/misc.h"
#include "cutils/properties.h"
@@ -97,13 +98,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 +113,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 +176,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 +234,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 +261,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 +269,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 +395,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 +427,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 +461,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 +495,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;
}
@@ -521,9 +522,10 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
- bool recursive = (strcmp(name, "set_perm_recursive") == 0);
+ bool recursive = (strcmp(name, "set_perm_recursive") == 0) || (strcmp(name, "set_perm2_recursive") == 0);
+ bool has_selabel = (strcmp(name, "set_perm2") == 0) || (strcmp(name, "set_perm2_recursive") == 0);
- int min_args = 4 + (recursive ? 1 : 0);
+ int min_args = 4 + (has_selabel ? 1 : 0) + (recursive ? 1 : 0);
if (argc < min_args) {
return ErrorAbort(state, "%s() expects %d+ args, got %d",
name, min_args, argc);
@@ -562,8 +564,13 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
- for (i = 4; i < argc; ++i) {
- dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
+ char* secontext = NULL;
+ if (has_selabel) {
+ secontext = args[4];
+ }
+
+ for (i = 4 + (has_selabel ? 1 : 0); i < argc; ++i) {
+ dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode, secontext);
}
} else {
int mode = strtoul(args[2], &end, 0);
@@ -572,17 +579,27 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
- for (i = 3; i < argc; ++i) {
+ char* secontext = NULL;
+ if (has_selabel) {
+ secontext = args[3];
+ }
+
+ for (i = 3 + (has_selabel ? 1 : 0); i < argc; ++i) {
if (chown(args[i], uid, gid) < 0) {
- fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
+ printf("%s: chown of %s to %d %d failed: %s\n",
name, args[i], uid, gid, strerror(errno));
++bad;
}
if (chmod(args[i], mode) < 0) {
- fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
+ printf("%s: chmod of %s to %o failed: %s\n",
name, args[i], mode, strerror(errno));
++bad;
}
+ if (has_selabel && lsetfilecon(args[i], secontext) && (errno != ENOTSUP)) {
+ printf("%s: lsetfilecon of %s to %s failed: %s\n",
+ name, args[i], secontext, strerror(errno));
+ ++bad;
+ }
}
}
result = strdup("");
@@ -720,7 +737,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 +769,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 +789,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 +810,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 +1005,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 +1070,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 +1085,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;
}
@@ -1135,6 +1152,8 @@ void RegisterInstallFunctions() {
RegisterFunction("symlink", SymlinkFn);
RegisterFunction("set_perm", SetPermFn);
RegisterFunction("set_perm_recursive", SetPermFn);
+ RegisterFunction("set_perm2", SetPermFn);
+ RegisterFunction("set_perm2_recursive", SetPermFn);
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);
}