summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--fuse_sdcard_provider.c141
-rw-r--r--fuse_sdcard_provider.h23
-rw-r--r--recovery.cpp110
4 files changed, 175 insertions, 102 deletions
diff --git a/Android.mk b/Android.mk
index f469182ef..1a91f0029 100644
--- a/Android.mk
+++ b/Android.mk
@@ -38,7 +38,8 @@ LOCAL_SRC_FILES := \
screen_ui.cpp \
asn1_decoder.cpp \
verifier.cpp \
- adb_install.cpp
+ adb_install.cpp \
+ fuse_sdcard_provider.c
LOCAL_MODULE := recovery
diff --git a/fuse_sdcard_provider.c b/fuse_sdcard_provider.c
new file mode 100644
index 000000000..19fb52df0
--- /dev/null
+++ b/fuse_sdcard_provider.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "fuse_sideload.h"
+
+struct file_data {
+ int fd; // the underlying sdcard file
+
+ uint64_t file_size;
+ uint32_t block_size;
+};
+
+static int read_block_file(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size) {
+ struct file_data* fd = (struct file_data*)cookie;
+
+ if (lseek(fd->fd, block * fd->block_size, SEEK_SET) < 0) {
+ printf("seek on sdcard failed: %s\n", strerror(errno));
+ return -EIO;
+ }
+
+ while (fetch_size > 0) {
+ ssize_t r = read(fd->fd, buffer, fetch_size);
+ if (r < 0) {
+ if (r != -EINTR) {
+ printf("read on sdcard failed: %s\n", strerror(errno));
+ return -EIO;
+ }
+ r = 0;
+ }
+ fetch_size -= r;
+ buffer += r;
+ }
+
+ return 0;
+}
+
+static void close_file(void* cookie) {
+ struct file_data* fd = (struct file_data*)cookie;
+ close(fd->fd);
+}
+
+struct token {
+ pthread_t th;
+ const char* path;
+ int result;
+};
+
+static void* run_sdcard_fuse(void* cookie) {
+ struct token* t = (struct token*)cookie;
+
+ struct stat sb;
+ if (stat(t->path, &sb) < 0) {
+ fprintf(stderr, "failed to stat %s: %s\n", t->path, strerror(errno));
+ t->result = -1;
+ return NULL;
+ }
+
+ struct file_data fd;
+ struct provider_vtab vtab;
+
+ fd.fd = open(t->path, O_RDONLY);
+ if (fd.fd < 0) {
+ fprintf(stderr, "failed to open %s: %s\n", t->path, strerror(errno));
+ t->result = -1;
+ return NULL;
+ }
+ fd.file_size = sb.st_size;
+ fd.block_size = 65536;
+
+ vtab.read_block = read_block_file;
+ vtab.close = close_file;
+
+ t->result = run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size);
+ return NULL;
+}
+
+// How long (in seconds) we wait for the fuse-provided package file to
+// appear, before timing out.
+#define SDCARD_INSTALL_TIMEOUT 10
+
+void* start_sdcard_fuse(const char* path) {
+ struct token* t = malloc(sizeof(struct token));
+
+ t->path = path;
+ pthread_create(&(t->th), NULL, run_sdcard_fuse, t);
+
+ struct stat st;
+ int i;
+ for (i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
+ if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
+ if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) {
+ sleep(1);
+ continue;
+ } else {
+ return NULL;
+ }
+ }
+ }
+
+ // The installation process expects to find the sdcard unmounted.
+ // Unmount it with MNT_DETACH so that our open file continues to
+ // work but new references see it as unmounted.
+ umount2("/sdcard", MNT_DETACH);
+
+ return t;
+}
+
+void finish_sdcard_fuse(void* cookie) {
+ if (cookie == NULL) return;
+ struct token* t = (struct token*)cookie;
+
+ // Calling stat() on this magic filename signals the fuse
+ // filesystem to shut down.
+ struct stat st;
+ stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
+
+ pthread_join(t->th, NULL);
+ free(t);
+}
diff --git a/fuse_sdcard_provider.h b/fuse_sdcard_provider.h
new file mode 100644
index 000000000..dc2982ca0
--- /dev/null
+++ b/fuse_sdcard_provider.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FUSE_SDCARD_PROVIDER_H
+#define __FUSE_SDCARD_PROVIDER_H
+
+void* start_sdcard_fuse(const char* path);
+void finish_sdcard_fuse(void* token);
+
+#endif
diff --git a/recovery.cpp b/recovery.cpp
index 1c7c0d6a4..d2d85e7c7 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -44,6 +44,8 @@
#include "adb_install.h"
extern "C" {
#include "minadbd/adb.h"
+#include "fuse_sideload.h"
+#include "fuse_sdcard_provider.h"
}
struct selabel_handle *sehandle;
@@ -73,7 +75,6 @@ static const char *CACHE_ROOT = "/cache";
static const char *SDCARD_ROOT = "/sdcard";
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
-static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
RecoveryUI* ui = NULL;
char* locale = NULL;
@@ -439,96 +440,6 @@ erase_volume(const char *volume) {
return result;
}
-static char*
-copy_sideloaded_package(const char* original_path) {
- if (ensure_path_mounted(original_path) != 0) {
- LOGE("Can't mount %s\n", original_path);
- return NULL;
- }
-
- if (ensure_path_mounted(SIDELOAD_TEMP_DIR) != 0) {
- LOGE("Can't mount %s\n", SIDELOAD_TEMP_DIR);
- return NULL;
- }
-
- if (mkdir(SIDELOAD_TEMP_DIR, 0700) != 0) {
- if (errno != EEXIST) {
- LOGE("Can't mkdir %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno));
- return NULL;
- }
- }
-
- // verify that SIDELOAD_TEMP_DIR is exactly what we expect: a
- // directory, owned by root, readable and writable only by root.
- struct stat st;
- if (stat(SIDELOAD_TEMP_DIR, &st) != 0) {
- LOGE("failed to stat %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno));
- return NULL;
- }
- if (!S_ISDIR(st.st_mode)) {
- LOGE("%s isn't a directory\n", SIDELOAD_TEMP_DIR);
- return NULL;
- }
- if ((st.st_mode & 0777) != 0700) {
- LOGE("%s has perms %o\n", SIDELOAD_TEMP_DIR, st.st_mode);
- return NULL;
- }
- if (st.st_uid != 0) {
- LOGE("%s owned by %lu; not root\n", SIDELOAD_TEMP_DIR, st.st_uid);
- return NULL;
- }
-
- char copy_path[PATH_MAX];
- strcpy(copy_path, SIDELOAD_TEMP_DIR);
- strcat(copy_path, "/package.zip");
-
- char* buffer = (char*)malloc(BUFSIZ);
- if (buffer == NULL) {
- LOGE("Failed to allocate buffer\n");
- return NULL;
- }
-
- size_t read;
- FILE* fin = fopen(original_path, "rb");
- if (fin == NULL) {
- LOGE("Failed to open %s (%s)\n", original_path, strerror(errno));
- return NULL;
- }
- FILE* fout = fopen(copy_path, "wb");
- if (fout == NULL) {
- LOGE("Failed to open %s (%s)\n", copy_path, strerror(errno));
- return NULL;
- }
-
- while ((read = fread(buffer, 1, BUFSIZ, fin)) > 0) {
- if (fwrite(buffer, 1, read, fout) != read) {
- LOGE("Short write of %s (%s)\n", copy_path, strerror(errno));
- return NULL;
- }
- }
-
- free(buffer);
-
- if (fclose(fout) != 0) {
- LOGE("Failed to close %s (%s)\n", copy_path, strerror(errno));
- return NULL;
- }
-
- if (fclose(fin) != 0) {
- LOGE("Failed to close %s (%s)\n", original_path, strerror(errno));
- return NULL;
- }
-
- // "adb push" is happy to overwrite read-only files when it's
- // running as root, but we'll try anyway.
- if (chmod(copy_path, 0400) != 0) {
- LOGE("Failed to chmod %s (%s)\n", copy_path, strerror(errno));
- return NULL;
- }
-
- return strdup(copy_path);
-}
-
static const char**
prepend_title(const char* const* headers) {
// count the number of lines in our title, plus the
@@ -812,17 +723,13 @@ prompt_and_wait(Device* device, int status) {
ui->Print("\n-- Install %s ...\n", path);
set_sdcard_update_bootloader_message();
- char* copy = copy_sideloaded_package(path);
- free(path);
- ensure_path_unmounted(SDCARD_ROOT);
+ void* token = start_sdcard_fuse(path);
- int status;
- if (copy) {
- status = install_package(copy, &wipe_cache, TEMPORARY_INSTALL_FILE, true);
- free(copy);
- } else {
- status = INSTALL_ERROR;
- }
+ int status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, &wipe_cache,
+ TEMPORARY_INSTALL_FILE, false);
+
+ finish_sdcard_fuse(token);
+ ensure_path_unmounted(SDCARD_ROOT);
if (status == INSTALL_SUCCESS && wipe_cache) {
ui->Print("\n-- Wiping cache (at package request)...\n");
@@ -832,6 +739,7 @@ prompt_and_wait(Device* device, int status) {
ui->Print("Cache wipe complete.\n");
}
}
+
if (status >= 0) {
if (status != INSTALL_SUCCESS) {
ui->SetBackground(RecoveryUI::ERROR);