Merge "Remove obsolete MTD support."
This commit is contained in:
22
Android.mk
22
Android.mk
@@ -17,15 +17,23 @@ LOCAL_PATH := $(call my-dir)
|
||||
# libfusesideload (static library)
|
||||
# ===============================
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := fuse_sideload.cpp
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
|
||||
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror
|
||||
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
|
||||
LOCAL_MODULE := libfusesideload
|
||||
LOCAL_STATIC_LIBRARIES := libcutils libc libcrypto_static
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libmounts (static library)
|
||||
# ===============================
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := mounts.cpp
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
|
||||
LOCAL_MODULE := libmounts
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# recovery (static executable)
|
||||
# ===============================
|
||||
include $(CLEAR_VARS)
|
||||
@@ -70,8 +78,8 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
libext4_utils_static \
|
||||
libsparse_static \
|
||||
libminzip \
|
||||
libmounts \
|
||||
libz \
|
||||
libmtdutils \
|
||||
libminadbd \
|
||||
libfusesideload \
|
||||
libminui \
|
||||
@@ -89,11 +97,8 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
|
||||
LOCAL_HAL_STATIC_LIBRARIES := libhealthd
|
||||
|
||||
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
|
||||
LOCAL_CFLAGS += -DUSE_EXT4
|
||||
LOCAL_C_INCLUDES += system/extras/ext4_utils
|
||||
LOCAL_STATIC_LIBRARIES += libext4_utils_static libz
|
||||
endif
|
||||
LOCAL_C_INCLUDES += system/extras/ext4_utils
|
||||
LOCAL_STATIC_LIBRARIES += libext4_utils_static libz
|
||||
|
||||
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
|
||||
|
||||
@@ -145,7 +150,6 @@ include $(BUILD_STATIC_LIBRARY)
|
||||
include $(LOCAL_PATH)/minui/Android.mk \
|
||||
$(LOCAL_PATH)/minzip/Android.mk \
|
||||
$(LOCAL_PATH)/minadbd/Android.mk \
|
||||
$(LOCAL_PATH)/mtdutils/Android.mk \
|
||||
$(LOCAL_PATH)/tests/Android.mk \
|
||||
$(LOCAL_PATH)/tools/Android.mk \
|
||||
$(LOCAL_PATH)/edify/Android.mk \
|
||||
|
||||
@@ -32,7 +32,6 @@ LOCAL_C_INCLUDES += \
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libotafault \
|
||||
libmtdutils \
|
||||
libbase \
|
||||
libcrypto_static \
|
||||
libbz \
|
||||
@@ -79,7 +78,6 @@ LOCAL_STATIC_LIBRARIES += \
|
||||
libedify \
|
||||
libotafault \
|
||||
libminzip \
|
||||
libmtdutils \
|
||||
libcrypto_static \
|
||||
libbz
|
||||
LOCAL_SHARED_LIBRARIES += libz libcutils libc
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include "openssl/sha.h"
|
||||
#include "applypatch/applypatch.h"
|
||||
#include "mtdutils/mtdutils.h"
|
||||
#include "edify/expr.h"
|
||||
#include "ota_io.h"
|
||||
#include "print_sha1.h"
|
||||
@@ -49,17 +48,14 @@ static int GenerateTarget(FileContents* source_file,
|
||||
size_t target_size,
|
||||
const Value* bonus_data);
|
||||
|
||||
static bool mtd_partitions_scanned = false;
|
||||
|
||||
// Read a file into memory; store the file contents and associated
|
||||
// metadata in *file.
|
||||
//
|
||||
// Return 0 on success.
|
||||
int LoadFileContents(const char* filename, FileContents* file) {
|
||||
// A special 'filename' beginning with "MTD:" or "EMMC:" means to
|
||||
// A special 'filename' beginning with "EMMC:" means to
|
||||
// load the contents of a partition.
|
||||
if (strncmp(filename, "MTD:", 4) == 0 ||
|
||||
strncmp(filename, "EMMC:", 5) == 0) {
|
||||
if (strncmp(filename, "EMMC:", 5) == 0) {
|
||||
return LoadPartitionContents(filename, file);
|
||||
}
|
||||
|
||||
@@ -87,10 +83,9 @@ int LoadFileContents(const char* filename, FileContents* file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load the contents of an MTD or EMMC partition into the provided
|
||||
// Load the contents of an EMMC partition into the provided
|
||||
// FileContents. filename should be a string of the form
|
||||
// "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:..." (or
|
||||
// "EMMC:<partition_device>:..."). The smallest size_n bytes for
|
||||
// "EMMC:<partition_device>:...". The smallest size_n bytes for
|
||||
// which that prefix of the partition contents has the corresponding
|
||||
// sha1 hash will be loaded. It is acceptable for a size value to be
|
||||
// repeated with different sha1s. Will return 0 on success.
|
||||
@@ -102,8 +97,6 @@ int LoadFileContents(const char* filename, FileContents* file) {
|
||||
// "end-of-file" marker), so the caller must specify the possible
|
||||
// lengths and the hash of the data, and we'll do the load expecting
|
||||
// to find one of those hashes.
|
||||
enum PartitionType { MTD, EMMC };
|
||||
|
||||
static int LoadPartitionContents(const char* filename, FileContents* file) {
|
||||
std::string copy(filename);
|
||||
std::vector<std::string> pieces = android::base::Split(copy, ":");
|
||||
@@ -112,12 +105,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum PartitionType type;
|
||||
if (pieces[0] == "MTD") {
|
||||
type = MTD;
|
||||
} else if (pieces[0] == "EMMC") {
|
||||
type = EMMC;
|
||||
} else {
|
||||
if (pieces[0] != "EMMC") {
|
||||
printf("LoadPartitionContents called with bad filename (%s)\n", filename);
|
||||
return -1;
|
||||
}
|
||||
@@ -145,37 +133,11 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
|
||||
}
|
||||
);
|
||||
|
||||
MtdReadContext* ctx = NULL;
|
||||
FILE* dev = NULL;
|
||||
|
||||
switch (type) {
|
||||
case MTD: {
|
||||
if (!mtd_partitions_scanned) {
|
||||
mtd_scan_partitions();
|
||||
mtd_partitions_scanned = true;
|
||||
}
|
||||
|
||||
const MtdPartition* mtd = mtd_find_partition_by_name(partition);
|
||||
if (mtd == NULL) {
|
||||
printf("mtd partition \"%s\" not found (loading %s)\n", partition, filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx = mtd_read_partition(mtd);
|
||||
if (ctx == NULL) {
|
||||
printf("failed to initialize read of mtd partition \"%s\"\n", partition);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EMMC:
|
||||
dev = ota_fopen(partition, "rb");
|
||||
FILE* dev = ota_fopen(partition, "rb");
|
||||
if (dev == NULL) {
|
||||
printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
SHA_CTX sha_ctx;
|
||||
SHA1_Init(&sha_ctx);
|
||||
@@ -192,16 +154,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
|
||||
// we're trying the possibilities in order of increasing size).
|
||||
size_t next = size[index[i]] - data_size;
|
||||
if (next > 0) {
|
||||
size_t read = 0;
|
||||
switch (type) {
|
||||
case MTD:
|
||||
read = mtd_read_data(ctx, p, next);
|
||||
break;
|
||||
|
||||
case EMMC:
|
||||
read = ota_fread(p, 1, next, dev);
|
||||
break;
|
||||
}
|
||||
size_t read = ota_fread(p, 1, next, dev);
|
||||
if (next != read) {
|
||||
printf("short read (%zu bytes of %zu) for partition \"%s\"\n",
|
||||
read, next, partition);
|
||||
@@ -234,16 +187,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case MTD:
|
||||
mtd_read_close(ctx);
|
||||
break;
|
||||
|
||||
case EMMC:
|
||||
ota_fclose(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!found) {
|
||||
// Ran off the end of the list of (size,sha1) pairs without finding a match.
|
||||
@@ -302,7 +246,7 @@ int SaveFileContents(const char* filename, const FileContents* file) {
|
||||
}
|
||||
|
||||
// Write a memory buffer to 'target' partition, a string of the form
|
||||
// "MTD:<partition>[:...]" or "EMMC:<partition_device>[:...]". The target name
|
||||
// "EMMC:<partition_device>[:...]". The target name
|
||||
// might contain multiple colons, but WriteToPartition() only uses the first
|
||||
// two and ignores the rest. Return 0 on success.
|
||||
int WriteToPartition(const unsigned char* data, size_t len, const char* target) {
|
||||
@@ -314,57 +258,12 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum PartitionType type;
|
||||
if (pieces[0] == "MTD") {
|
||||
type = MTD;
|
||||
} else if (pieces[0] == "EMMC") {
|
||||
type = EMMC;
|
||||
} else {
|
||||
if (pieces[0] != "EMMC") {
|
||||
printf("WriteToPartition called with bad target (%s)\n", target);
|
||||
return -1;
|
||||
}
|
||||
const char* partition = pieces[1].c_str();
|
||||
|
||||
switch (type) {
|
||||
case MTD: {
|
||||
if (!mtd_partitions_scanned) {
|
||||
mtd_scan_partitions();
|
||||
mtd_partitions_scanned = true;
|
||||
}
|
||||
|
||||
const MtdPartition* mtd = mtd_find_partition_by_name(partition);
|
||||
if (mtd == NULL) {
|
||||
printf("mtd partition \"%s\" not found for writing\n", partition);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtdWriteContext* ctx = mtd_write_partition(mtd);
|
||||
if (ctx == NULL) {
|
||||
printf("failed to init mtd partition \"%s\" for writing\n", partition);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t written = mtd_write_data(ctx, reinterpret_cast<const char*>(data), len);
|
||||
if (written != len) {
|
||||
printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition);
|
||||
mtd_write_close(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mtd_erase_blocks(ctx, -1) < 0) {
|
||||
printf("error finishing mtd write of %s\n", partition);
|
||||
mtd_write_close(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mtd_write_close(ctx)) {
|
||||
printf("error closing mtd write of %s\n", partition);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EMMC: {
|
||||
size_t start = 0;
|
||||
bool success = false;
|
||||
int fd = ota_open(partition, O_RDWR | O_SYNC);
|
||||
@@ -469,9 +368,6 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
|
||||
return -1;
|
||||
}
|
||||
sync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -729,7 +625,7 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
|
||||
std::string target_str(target_filename);
|
||||
|
||||
std::vector<std::string> pieces = android::base::Split(target_str, ":");
|
||||
if (pieces.size() != 2 || (pieces[0] != "MTD" && pieces[0] != "EMMC")) {
|
||||
if (pieces.size() != 2 || pieces[0] != "EMMC") {
|
||||
printf("invalid target name \"%s\"", target_filename);
|
||||
return 1;
|
||||
}
|
||||
@@ -778,8 +674,7 @@ static int GenerateTarget(FileContents* source_file,
|
||||
FileContents* source_to_use;
|
||||
int made_copy = 0;
|
||||
|
||||
bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 ||
|
||||
strncmp(target_filename, "EMMC:", 5) == 0);
|
||||
bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0);
|
||||
const std::string tmp_target_filename = std::string(target_filename) + ".patch";
|
||||
|
||||
// assume that target_filename (eg "/system/app/Foo.apk") is located
|
||||
@@ -860,8 +755,7 @@ static int GenerateTarget(FileContents* source_file,
|
||||
// copy the source file to cache, then delete it from the original
|
||||
// location.
|
||||
|
||||
if (strncmp(source_filename, "MTD:", 4) == 0 ||
|
||||
strncmp(source_filename, "EMMC:", 5) == 0) {
|
||||
if (strncmp(source_filename, "EMMC:", 5) == 0) {
|
||||
// It's impossible to free space on the target filesystem by
|
||||
// deleting the source if the source is a partition. If
|
||||
// we're ever in a state where we need to do this, fail.
|
||||
|
||||
@@ -160,9 +160,9 @@ static int PatchMode(int argc, char** argv) {
|
||||
// - otherwise, or if any error is encountered, exits with non-zero
|
||||
// status.
|
||||
//
|
||||
// <src-file> (or <file> in check mode) may refer to an MTD partition
|
||||
// <src-file> (or <file> in check mode) may refer to an EMMC partition
|
||||
// to read the source data. See the comments for the
|
||||
// LoadMTDContents() function above for the format of such a filename.
|
||||
// LoadPartitionContents() function for the format of such a filename.
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
@@ -175,8 +175,8 @@ int main(int argc, char** argv) {
|
||||
" or %s -l\n"
|
||||
"\n"
|
||||
"Filenames may be of the form\n"
|
||||
" MTD:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
|
||||
"to specify reading from or writing to an MTD partition.\n\n",
|
||||
" EMMC:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
|
||||
"to specify reading from or writing to an EMMC partition.\n\n",
|
||||
argv[0], argv[0], argv[0], argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -27,12 +27,9 @@
|
||||
|
||||
#include "bootloader.h"
|
||||
#include "common.h"
|
||||
#include "mtdutils/mtdutils.h"
|
||||
#include "roots.h"
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
static int get_bootloader_message_mtd(bootloader_message* out, const Volume* v);
|
||||
static int set_bootloader_message_mtd(const bootloader_message* in, const Volume* v);
|
||||
static int get_bootloader_message_block(bootloader_message* out, const Volume* v);
|
||||
static int set_bootloader_message_block(const bootloader_message* in, const Volume* v);
|
||||
|
||||
@@ -42,9 +39,7 @@ int get_bootloader_message(bootloader_message* out) {
|
||||
LOGE("Cannot load volume /misc!\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(v->fs_type, "mtd") == 0) {
|
||||
return get_bootloader_message_mtd(out, v);
|
||||
} else if (strcmp(v->fs_type, "emmc") == 0) {
|
||||
if (strcmp(v->fs_type, "emmc") == 0) {
|
||||
return get_bootloader_message_block(out, v);
|
||||
}
|
||||
LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
|
||||
@@ -57,93 +52,13 @@ int set_bootloader_message(const bootloader_message* in) {
|
||||
LOGE("Cannot load volume /misc!\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(v->fs_type, "mtd") == 0) {
|
||||
return set_bootloader_message_mtd(in, v);
|
||||
} else if (strcmp(v->fs_type, "emmc") == 0) {
|
||||
if (strcmp(v->fs_type, "emmc") == 0) {
|
||||
return set_bootloader_message_block(in, v);
|
||||
}
|
||||
LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// for misc partitions on MTD
|
||||
// ------------------------------
|
||||
|
||||
static const int MISC_PAGES = 3; // number of pages to save
|
||||
static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
|
||||
|
||||
static int get_bootloader_message_mtd(bootloader_message* out,
|
||||
const Volume* v) {
|
||||
size_t write_size;
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
|
||||
if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
|
||||
LOGE("failed to find \"%s\"\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtdReadContext* read = mtd_read_partition(part);
|
||||
if (read == nullptr) {
|
||||
LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const ssize_t size = write_size * MISC_PAGES;
|
||||
char data[size];
|
||||
ssize_t r = mtd_read_data(read, data, size);
|
||||
if (r != size) LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
|
||||
mtd_read_close(read);
|
||||
if (r != size) return -1;
|
||||
|
||||
memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
|
||||
return 0;
|
||||
}
|
||||
static int set_bootloader_message_mtd(const bootloader_message* in,
|
||||
const Volume* v) {
|
||||
size_t write_size;
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
|
||||
if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
|
||||
LOGE("failed to find \"%s\"\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtdReadContext* read = mtd_read_partition(part);
|
||||
if (read == nullptr) {
|
||||
LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t size = write_size * MISC_PAGES;
|
||||
char data[size];
|
||||
ssize_t r = mtd_read_data(read, data, size);
|
||||
if (r != size) LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
|
||||
mtd_read_close(read);
|
||||
if (r != size) return -1;
|
||||
|
||||
memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
|
||||
|
||||
MtdWriteContext* write = mtd_write_partition(part);
|
||||
if (write == nullptr) {
|
||||
LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (mtd_write_data(write, data, size) != size) {
|
||||
LOGE("failed to write \"%s\": %s\n", v->blk_device, strerror(errno));
|
||||
mtd_write_close(write);
|
||||
return -1;
|
||||
}
|
||||
if (mtd_write_close(write)) {
|
||||
LOGE("failed to finish \"%s\": %s\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------
|
||||
// for misc partitions on block devices
|
||||
// ------------------------------------
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
#include "minui/minui.h"
|
||||
#include "minzip/SysUtil.h"
|
||||
#include "minzip/Zip.h"
|
||||
#include "mtdutils/mounts.h"
|
||||
#include "mtdutils/mtdutils.h"
|
||||
#include "roots.h"
|
||||
#include "ui.h"
|
||||
#include "verifier.h"
|
||||
|
||||
89
mounts.cpp
Normal file
89
mounts.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mounts.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <mntent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct MountedVolume {
|
||||
std::string device;
|
||||
std::string mount_point;
|
||||
std::string filesystem;
|
||||
std::string flags;
|
||||
};
|
||||
|
||||
std::vector<MountedVolume*> g_mounts_state;
|
||||
|
||||
bool scan_mounted_volumes() {
|
||||
for (size_t i = 0; i < g_mounts_state.size(); ++i) {
|
||||
delete g_mounts_state[i];
|
||||
}
|
||||
g_mounts_state.clear();
|
||||
|
||||
// Open and read mount table entries.
|
||||
FILE* fp = setmntent("/proc/mounts", "re");
|
||||
if (fp == NULL) {
|
||||
return false;
|
||||
}
|
||||
mntent* e;
|
||||
while ((e = getmntent(fp)) != NULL) {
|
||||
MountedVolume* v = new MountedVolume;
|
||||
v->device = e->mnt_fsname;
|
||||
v->mount_point = e->mnt_dir;
|
||||
v->filesystem = e->mnt_type;
|
||||
v->flags = e->mnt_opts;
|
||||
g_mounts_state.push_back(v);
|
||||
}
|
||||
endmntent(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
MountedVolume* find_mounted_volume_by_device(const char* device) {
|
||||
for (size_t i = 0; i < g_mounts_state.size(); ++i) {
|
||||
if (g_mounts_state[i]->device == device) return g_mounts_state[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MountedVolume* find_mounted_volume_by_mount_point(const char* mount_point) {
|
||||
for (size_t i = 0; i < g_mounts_state.size(); ++i) {
|
||||
if (g_mounts_state[i]->mount_point == mount_point) return g_mounts_state[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int unmount_mounted_volume(MountedVolume* volume) {
|
||||
// Intentionally pass the empty string to umount if the caller tries
|
||||
// to unmount a volume they already unmounted using this
|
||||
// function.
|
||||
std::string mount_point = volume->mount_point;
|
||||
volume->mount_point.clear();
|
||||
return umount(mount_point.c_str());
|
||||
}
|
||||
|
||||
int remount_read_only(MountedVolume* volume) {
|
||||
return mount(volume->device.c_str(), volume->mount_point.c_str(), volume->filesystem.c_str(),
|
||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME | MS_RDONLY | MS_REMOUNT, 0);
|
||||
}
|
||||
@@ -14,28 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MTDUTILS_MOUNTS_H_
|
||||
#define MTDUTILS_MOUNTS_H_
|
||||
#ifndef MOUNTS_H_
|
||||
#define MOUNTS_H_
|
||||
|
||||
struct MountedVolume;
|
||||
|
||||
bool scan_mounted_volumes();
|
||||
|
||||
MountedVolume* find_mounted_volume_by_device(const char* device);
|
||||
|
||||
MountedVolume* find_mounted_volume_by_mount_point(const char* mount_point);
|
||||
|
||||
int unmount_mounted_volume(MountedVolume* volume);
|
||||
|
||||
int remount_read_only(MountedVolume* volume);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct MountedVolume MountedVolume;
|
||||
|
||||
int scan_mounted_volumes(void);
|
||||
|
||||
const MountedVolume *find_mounted_volume_by_device(const char *device);
|
||||
|
||||
const MountedVolume *
|
||||
find_mounted_volume_by_mount_point(const char *mount_point);
|
||||
|
||||
int unmount_mounted_volume(const MountedVolume *volume);
|
||||
|
||||
int remount_read_only(const MountedVolume* volume);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MTDUTILS_MOUNTS_H_
|
||||
@@ -1,20 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
mtdutils.c \
|
||||
mounts.c
|
||||
|
||||
LOCAL_MODULE := libmtdutils
|
||||
LOCAL_CLANG := true
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_SRC_FILES := flash_image.c
|
||||
LOCAL_MODULE := flash_image
|
||||
LOCAL_MODULE_TAGS := eng
|
||||
LOCAL_STATIC_LIBRARIES := libmtdutils
|
||||
LOCAL_SHARED_LIBRARIES := libcutils liblog libc
|
||||
include $(BUILD_EXECUTABLE)
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cutils/log.h"
|
||||
#include "mtdutils.h"
|
||||
|
||||
#ifdef LOG_TAG
|
||||
#undef LOG_TAG
|
||||
#endif
|
||||
#define LOG_TAG "flash_image"
|
||||
|
||||
#define HEADER_SIZE 2048 // size of header to compare for equality
|
||||
|
||||
void die(const char *msg, ...) {
|
||||
int err = errno;
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
char buf[1024];
|
||||
vsnprintf(buf, sizeof(buf), msg, args);
|
||||
va_end(args);
|
||||
|
||||
if (err != 0) {
|
||||
strlcat(buf, ": ", sizeof(buf));
|
||||
strlcat(buf, strerror(err), sizeof(buf));
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
ALOGE("%s\n", buf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read an image file and write it to a flash partition. */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const MtdPartition *ptn;
|
||||
MtdWriteContext *write;
|
||||
void *data;
|
||||
unsigned sz;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (mtd_scan_partitions() <= 0) die("error scanning partitions");
|
||||
const MtdPartition *partition = mtd_find_partition_by_name(argv[1]);
|
||||
if (partition == NULL) die("can't find %s partition", argv[1]);
|
||||
|
||||
// If the first part of the file matches the partition, skip writing
|
||||
|
||||
int fd = open(argv[2], O_RDONLY);
|
||||
if (fd < 0) die("error opening %s", argv[2]);
|
||||
|
||||
char header[HEADER_SIZE];
|
||||
int headerlen = TEMP_FAILURE_RETRY(read(fd, header, sizeof(header)));
|
||||
if (headerlen <= 0) die("error reading %s header", argv[2]);
|
||||
|
||||
MtdReadContext *in = mtd_read_partition(partition);
|
||||
if (in == NULL) {
|
||||
ALOGW("error opening %s: %s\n", argv[1], strerror(errno));
|
||||
// just assume it needs re-writing
|
||||
} else {
|
||||
char check[HEADER_SIZE];
|
||||
int checklen = mtd_read_data(in, check, sizeof(check));
|
||||
if (checklen <= 0) {
|
||||
ALOGW("error reading %s: %s\n", argv[1], strerror(errno));
|
||||
// just assume it needs re-writing
|
||||
} else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
|
||||
ALOGI("header is the same, not flashing %s\n", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
mtd_read_close(in);
|
||||
}
|
||||
|
||||
// Skip the header (we'll come back to it), write everything else
|
||||
ALOGI("flashing %s from %s\n", argv[1], argv[2]);
|
||||
|
||||
MtdWriteContext *out = mtd_write_partition(partition);
|
||||
if (out == NULL) die("error writing %s", argv[1]);
|
||||
|
||||
char buf[HEADER_SIZE];
|
||||
memset(buf, 0, headerlen);
|
||||
int wrote = mtd_write_data(out, buf, headerlen);
|
||||
if (wrote != headerlen) die("error writing %s", argv[1]);
|
||||
|
||||
int len;
|
||||
while ((len = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)))) > 0) {
|
||||
wrote = mtd_write_data(out, buf, len);
|
||||
if (wrote != len) die("error writing %s", argv[1]);
|
||||
}
|
||||
if (len < 0) die("error reading %s", argv[2]);
|
||||
|
||||
if (mtd_write_close(out)) die("error closing %s", argv[1]);
|
||||
|
||||
// Now come back and write the header last
|
||||
|
||||
out = mtd_write_partition(partition);
|
||||
if (out == NULL) die("error re-opening %s", argv[1]);
|
||||
|
||||
wrote = mtd_write_data(out, header, headerlen);
|
||||
if (wrote != headerlen) die("error re-writing %s", argv[1]);
|
||||
|
||||
// Need to write a complete block, so write the rest of the first block
|
||||
size_t block_size;
|
||||
if (mtd_partition_info(partition, NULL, &block_size, NULL))
|
||||
die("error getting %s block size", argv[1]);
|
||||
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, headerlen, SEEK_SET)) != headerlen)
|
||||
die("error rewinding %s", argv[2]);
|
||||
|
||||
int left = block_size - headerlen;
|
||||
while (left < 0) left += block_size;
|
||||
while (left > 0) {
|
||||
len = TEMP_FAILURE_RETRY(read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left));
|
||||
if (len <= 0) die("error reading %s", argv[2]);
|
||||
if (mtd_write_data(out, buf, len) != len)
|
||||
die("error writing %s", argv[1]);
|
||||
left -= len;
|
||||
}
|
||||
|
||||
if (mtd_write_close(out)) die("error closing %s", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <mntent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "mounts.h"
|
||||
|
||||
struct MountedVolume {
|
||||
const char *device;
|
||||
const char *mount_point;
|
||||
const char *filesystem;
|
||||
const char *flags;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
MountedVolume *volumes;
|
||||
int volumes_allocd;
|
||||
int volume_count;
|
||||
} MountsState;
|
||||
|
||||
static MountsState g_mounts_state = {
|
||||
NULL, // volumes
|
||||
0, // volumes_allocd
|
||||
0 // volume_count
|
||||
};
|
||||
|
||||
static inline void
|
||||
free_volume_internals(const MountedVolume *volume, int zero)
|
||||
{
|
||||
free((char *)volume->device);
|
||||
free((char *)volume->mount_point);
|
||||
free((char *)volume->filesystem);
|
||||
free((char *)volume->flags);
|
||||
if (zero) {
|
||||
memset((void *)volume, 0, sizeof(*volume));
|
||||
}
|
||||
}
|
||||
|
||||
#define PROC_MOUNTS_FILENAME "/proc/mounts"
|
||||
|
||||
int
|
||||
scan_mounted_volumes()
|
||||
{
|
||||
FILE* fp;
|
||||
struct mntent* mentry;
|
||||
|
||||
if (g_mounts_state.volumes == NULL) {
|
||||
const int numv = 32;
|
||||
MountedVolume *volumes = malloc(numv * sizeof(*volumes));
|
||||
if (volumes == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
g_mounts_state.volumes = volumes;
|
||||
g_mounts_state.volumes_allocd = numv;
|
||||
memset(volumes, 0, numv * sizeof(*volumes));
|
||||
} else {
|
||||
/* Free the old volume strings.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < g_mounts_state.volume_count; i++) {
|
||||
free_volume_internals(&g_mounts_state.volumes[i], 1);
|
||||
}
|
||||
}
|
||||
g_mounts_state.volume_count = 0;
|
||||
|
||||
/* Open and read mount table entries. */
|
||||
fp = setmntent(PROC_MOUNTS_FILENAME, "r");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
while ((mentry = getmntent(fp)) != NULL) {
|
||||
MountedVolume* v = &g_mounts_state.volumes[g_mounts_state.volume_count++];
|
||||
v->device = strdup(mentry->mnt_fsname);
|
||||
v->mount_point = strdup(mentry->mnt_dir);
|
||||
v->filesystem = strdup(mentry->mnt_type);
|
||||
v->flags = strdup(mentry->mnt_opts);
|
||||
}
|
||||
endmntent(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const MountedVolume *
|
||||
find_mounted_volume_by_device(const char *device)
|
||||
{
|
||||
if (g_mounts_state.volumes != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < g_mounts_state.volume_count; i++) {
|
||||
MountedVolume *v = &g_mounts_state.volumes[i];
|
||||
/* May be null if it was unmounted and we haven't rescanned.
|
||||
*/
|
||||
if (v->device != NULL) {
|
||||
if (strcmp(v->device, device) == 0) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const MountedVolume *
|
||||
find_mounted_volume_by_mount_point(const char *mount_point)
|
||||
{
|
||||
if (g_mounts_state.volumes != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < g_mounts_state.volume_count; i++) {
|
||||
MountedVolume *v = &g_mounts_state.volumes[i];
|
||||
/* May be null if it was unmounted and we haven't rescanned.
|
||||
*/
|
||||
if (v->mount_point != NULL) {
|
||||
if (strcmp(v->mount_point, mount_point) == 0) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
unmount_mounted_volume(const MountedVolume *volume)
|
||||
{
|
||||
/* Intentionally pass NULL to umount if the caller tries
|
||||
* to unmount a volume they already unmounted using this
|
||||
* function.
|
||||
*/
|
||||
int ret = umount(volume->mount_point);
|
||||
if (ret == 0) {
|
||||
free_volume_internals(volume, 1);
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
remount_read_only(const MountedVolume* volume)
|
||||
{
|
||||
return mount(volume->device, volume->mount_point, volume->filesystem,
|
||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME |
|
||||
MS_RDONLY | MS_REMOUNT, 0);
|
||||
}
|
||||
@@ -1,561 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mount.h> // for _IOW, _IOR, mount()
|
||||
#include <sys/stat.h>
|
||||
#include <mtd/mtd-user.h>
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
#include "mtdutils.h"
|
||||
|
||||
struct MtdPartition {
|
||||
int device_index;
|
||||
unsigned int size;
|
||||
unsigned int erase_size;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct MtdReadContext {
|
||||
const MtdPartition *partition;
|
||||
char *buffer;
|
||||
size_t consumed;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct MtdWriteContext {
|
||||
const MtdPartition *partition;
|
||||
char *buffer;
|
||||
size_t stored;
|
||||
int fd;
|
||||
|
||||
off_t* bad_block_offsets;
|
||||
int bad_block_alloc;
|
||||
int bad_block_count;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
MtdPartition *partitions;
|
||||
int partitions_allocd;
|
||||
int partition_count;
|
||||
} MtdState;
|
||||
|
||||
static MtdState g_mtd_state = {
|
||||
NULL, // partitions
|
||||
0, // partitions_allocd
|
||||
-1 // partition_count
|
||||
};
|
||||
|
||||
#define MTD_PROC_FILENAME "/proc/mtd"
|
||||
|
||||
int
|
||||
mtd_scan_partitions()
|
||||
{
|
||||
char buf[2048];
|
||||
const char *bufp;
|
||||
int fd;
|
||||
int i;
|
||||
ssize_t nbytes;
|
||||
|
||||
if (g_mtd_state.partitions == NULL) {
|
||||
const int nump = 32;
|
||||
MtdPartition *partitions = malloc(nump * sizeof(*partitions));
|
||||
if (partitions == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
g_mtd_state.partitions = partitions;
|
||||
g_mtd_state.partitions_allocd = nump;
|
||||
memset(partitions, 0, nump * sizeof(*partitions));
|
||||
}
|
||||
g_mtd_state.partition_count = 0;
|
||||
|
||||
/* Initialize all of the entries to make things easier later.
|
||||
* (Lets us handle sparsely-numbered partitions, which
|
||||
* may not even be possible.)
|
||||
*/
|
||||
for (i = 0; i < g_mtd_state.partitions_allocd; i++) {
|
||||
MtdPartition *p = &g_mtd_state.partitions[i];
|
||||
if (p->name != NULL) {
|
||||
free(p->name);
|
||||
p->name = NULL;
|
||||
}
|
||||
p->device_index = -1;
|
||||
}
|
||||
|
||||
/* Open and read the file contents.
|
||||
*/
|
||||
fd = open(MTD_PROC_FILENAME, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
goto bail;
|
||||
}
|
||||
nbytes = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf) - 1));
|
||||
close(fd);
|
||||
if (nbytes < 0) {
|
||||
goto bail;
|
||||
}
|
||||
buf[nbytes] = '\0';
|
||||
|
||||
/* Parse the contents of the file, which looks like:
|
||||
*
|
||||
* # cat /proc/mtd
|
||||
* dev: size erasesize name
|
||||
* mtd0: 00080000 00020000 "bootloader"
|
||||
* mtd1: 00400000 00020000 "mfg_and_gsm"
|
||||
* mtd2: 00400000 00020000 "0000000c"
|
||||
* mtd3: 00200000 00020000 "0000000d"
|
||||
* mtd4: 04000000 00020000 "system"
|
||||
* mtd5: 03280000 00020000 "userdata"
|
||||
*/
|
||||
bufp = buf;
|
||||
while (nbytes > 0) {
|
||||
int mtdnum, mtdsize, mtderasesize;
|
||||
int matches;
|
||||
char mtdname[64];
|
||||
mtdname[0] = '\0';
|
||||
mtdnum = -1;
|
||||
|
||||
matches = sscanf(bufp, "mtd%d: %x %x \"%63[^\"]",
|
||||
&mtdnum, &mtdsize, &mtderasesize, mtdname);
|
||||
/* This will fail on the first line, which just contains
|
||||
* column headers.
|
||||
*/
|
||||
if (matches == 4) {
|
||||
MtdPartition *p = &g_mtd_state.partitions[mtdnum];
|
||||
p->device_index = mtdnum;
|
||||
p->size = mtdsize;
|
||||
p->erase_size = mtderasesize;
|
||||
p->name = strdup(mtdname);
|
||||
if (p->name == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto bail;
|
||||
}
|
||||
g_mtd_state.partition_count++;
|
||||
}
|
||||
|
||||
/* Eat the line.
|
||||
*/
|
||||
while (nbytes > 0 && *bufp != '\n') {
|
||||
bufp++;
|
||||
nbytes--;
|
||||
}
|
||||
if (nbytes > 0) {
|
||||
bufp++;
|
||||
nbytes--;
|
||||
}
|
||||
}
|
||||
|
||||
return g_mtd_state.partition_count;
|
||||
|
||||
bail:
|
||||
// keep "partitions" around so we can free the names on a rescan.
|
||||
g_mtd_state.partition_count = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const MtdPartition *
|
||||
mtd_find_partition_by_name(const char *name)
|
||||
{
|
||||
if (g_mtd_state.partitions != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < g_mtd_state.partitions_allocd; i++) {
|
||||
MtdPartition *p = &g_mtd_state.partitions[i];
|
||||
if (p->device_index >= 0 && p->name != NULL) {
|
||||
if (strcmp(p->name, name) == 0) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
mtd_mount_partition(const MtdPartition *partition, const char *mount_point,
|
||||
const char *filesystem, int read_only)
|
||||
{
|
||||
const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME;
|
||||
char devname[64];
|
||||
int rv = -1;
|
||||
|
||||
sprintf(devname, "/dev/block/mtdblock%d", partition->device_index);
|
||||
if (!read_only) {
|
||||
rv = mount(devname, mount_point, filesystem, flags, NULL);
|
||||
}
|
||||
if (read_only || rv < 0) {
|
||||
rv = mount(devname, mount_point, filesystem, flags | MS_RDONLY, 0);
|
||||
if (rv < 0) {
|
||||
printf("Failed to mount %s on %s: %s\n",
|
||||
devname, mount_point, strerror(errno));
|
||||
} else {
|
||||
printf("Mount %s on %s read-only\n", devname, mount_point);
|
||||
}
|
||||
}
|
||||
#if 1 //TODO: figure out why this is happening; remove include of stat.h
|
||||
if (rv >= 0) {
|
||||
/* For some reason, the x bits sometimes aren't set on the root
|
||||
* of mounted volumes.
|
||||
*/
|
||||
struct stat st;
|
||||
rv = stat(mount_point, &st);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
mode_t new_mode = st.st_mode | S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
if (new_mode != st.st_mode) {
|
||||
printf("Fixing execute permissions for %s\n", mount_point);
|
||||
rv = chmod(mount_point, new_mode);
|
||||
if (rv < 0) {
|
||||
printf("Couldn't fix permissions for %s: %s\n",
|
||||
mount_point, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
mtd_partition_info(const MtdPartition *partition,
|
||||
size_t *total_size, size_t *erase_size, size_t *write_size)
|
||||
{
|
||||
char mtddevname[32];
|
||||
sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
|
||||
int fd = open(mtddevname, O_RDONLY);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
struct mtd_info_user mtd_info;
|
||||
int ret = ioctl(fd, MEMGETINFO, &mtd_info);
|
||||
close(fd);
|
||||
if (ret < 0) return -1;
|
||||
|
||||
if (total_size != NULL) *total_size = mtd_info.size;
|
||||
if (erase_size != NULL) *erase_size = mtd_info.erasesize;
|
||||
if (write_size != NULL) *write_size = mtd_info.writesize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
MtdReadContext *mtd_read_partition(const MtdPartition *partition)
|
||||
{
|
||||
MtdReadContext *ctx = (MtdReadContext*) malloc(sizeof(MtdReadContext));
|
||||
if (ctx == NULL) return NULL;
|
||||
|
||||
ctx->buffer = malloc(partition->erase_size);
|
||||
if (ctx->buffer == NULL) {
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char mtddevname[32];
|
||||
sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
|
||||
ctx->fd = open(mtddevname, O_RDONLY);
|
||||
if (ctx->fd < 0) {
|
||||
free(ctx->buffer);
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->partition = partition;
|
||||
ctx->consumed = partition->erase_size;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static int read_block(const MtdPartition *partition, int fd, char *data)
|
||||
{
|
||||
struct mtd_ecc_stats before, after;
|
||||
if (ioctl(fd, ECCGETSTATS, &before)) {
|
||||
printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
loff_t pos = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
|
||||
if (pos == -1) {
|
||||
printf("mtd: read_block: couldn't SEEK_CUR: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t size = partition->erase_size;
|
||||
int mgbb;
|
||||
|
||||
while (pos + size <= (int) partition->size) {
|
||||
if (TEMP_FAILURE_RETRY(lseek64(fd, pos, SEEK_SET)) != pos ||
|
||||
TEMP_FAILURE_RETRY(read(fd, data, size)) != size) {
|
||||
printf("mtd: read error at 0x%08llx (%s)\n",
|
||||
(long long)pos, strerror(errno));
|
||||
} else if (ioctl(fd, ECCGETSTATS, &after)) {
|
||||
printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
} else if (after.failed != before.failed) {
|
||||
printf("mtd: ECC errors (%d soft, %d hard) at 0x%08llx\n",
|
||||
after.corrected - before.corrected,
|
||||
after.failed - before.failed, (long long)pos);
|
||||
// copy the comparison baseline for the next read.
|
||||
memcpy(&before, &after, sizeof(struct mtd_ecc_stats));
|
||||
} else if ((mgbb = ioctl(fd, MEMGETBADBLOCK, &pos))) {
|
||||
fprintf(stderr,
|
||||
"mtd: MEMGETBADBLOCK returned %d at 0x%08llx: %s\n",
|
||||
mgbb, (long long)pos, strerror(errno));
|
||||
} else {
|
||||
return 0; // Success!
|
||||
}
|
||||
|
||||
pos += partition->erase_size;
|
||||
}
|
||||
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t mtd_read_data(MtdReadContext *ctx, char *data, size_t len)
|
||||
{
|
||||
size_t read = 0;
|
||||
while (read < len) {
|
||||
if (ctx->consumed < ctx->partition->erase_size) {
|
||||
size_t avail = ctx->partition->erase_size - ctx->consumed;
|
||||
size_t copy = len - read < avail ? len - read : avail;
|
||||
memcpy(data + read, ctx->buffer + ctx->consumed, copy);
|
||||
ctx->consumed += copy;
|
||||
read += copy;
|
||||
}
|
||||
|
||||
// Read complete blocks directly into the user's buffer
|
||||
while (ctx->consumed == ctx->partition->erase_size &&
|
||||
len - read >= ctx->partition->erase_size) {
|
||||
if (read_block(ctx->partition, ctx->fd, data + read)) return -1;
|
||||
read += ctx->partition->erase_size;
|
||||
}
|
||||
|
||||
if (read >= len) {
|
||||
return read;
|
||||
}
|
||||
|
||||
// Read the next block into the buffer
|
||||
if (ctx->consumed == ctx->partition->erase_size && read < len) {
|
||||
if (read_block(ctx->partition, ctx->fd, ctx->buffer)) return -1;
|
||||
ctx->consumed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
void mtd_read_close(MtdReadContext *ctx)
|
||||
{
|
||||
close(ctx->fd);
|
||||
free(ctx->buffer);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
MtdWriteContext *mtd_write_partition(const MtdPartition *partition)
|
||||
{
|
||||
MtdWriteContext *ctx = (MtdWriteContext*) malloc(sizeof(MtdWriteContext));
|
||||
if (ctx == NULL) return NULL;
|
||||
|
||||
ctx->bad_block_offsets = NULL;
|
||||
ctx->bad_block_alloc = 0;
|
||||
ctx->bad_block_count = 0;
|
||||
|
||||
ctx->buffer = malloc(partition->erase_size);
|
||||
if (ctx->buffer == NULL) {
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char mtddevname[32];
|
||||
sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
|
||||
ctx->fd = open(mtddevname, O_RDWR);
|
||||
if (ctx->fd < 0) {
|
||||
free(ctx->buffer);
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->partition = partition;
|
||||
ctx->stored = 0;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void add_bad_block_offset(MtdWriteContext *ctx, off_t pos) {
|
||||
if (ctx->bad_block_count + 1 > ctx->bad_block_alloc) {
|
||||
ctx->bad_block_alloc = (ctx->bad_block_alloc*2) + 1;
|
||||
ctx->bad_block_offsets = realloc(ctx->bad_block_offsets,
|
||||
ctx->bad_block_alloc * sizeof(off_t));
|
||||
}
|
||||
ctx->bad_block_offsets[ctx->bad_block_count++] = pos;
|
||||
}
|
||||
|
||||
static int write_block(MtdWriteContext *ctx, const char *data)
|
||||
{
|
||||
const MtdPartition *partition = ctx->partition;
|
||||
int fd = ctx->fd;
|
||||
|
||||
off_t pos = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_CUR));
|
||||
if (pos == (off_t) -1) {
|
||||
printf("mtd: write_block: couldn't SEEK_CUR: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t size = partition->erase_size;
|
||||
while (pos + size <= (int) partition->size) {
|
||||
loff_t bpos = pos;
|
||||
int ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
|
||||
if (ret != 0 && !(ret == -1 && errno == EOPNOTSUPP)) {
|
||||
add_bad_block_offset(ctx, pos);
|
||||
fprintf(stderr,
|
||||
"mtd: not writing bad block at 0x%08lx (ret %d): %s\n",
|
||||
pos, ret, strerror(errno));
|
||||
pos += partition->erase_size;
|
||||
continue; // Don't try to erase known factory-bad blocks.
|
||||
}
|
||||
|
||||
struct erase_info_user erase_info;
|
||||
erase_info.start = pos;
|
||||
erase_info.length = size;
|
||||
int retry;
|
||||
for (retry = 0; retry < 2; ++retry) {
|
||||
if (ioctl(fd, MEMERASE, &erase_info) < 0) {
|
||||
printf("mtd: erase failure at 0x%08lx (%s)\n",
|
||||
pos, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, pos, SEEK_SET)) != pos ||
|
||||
TEMP_FAILURE_RETRY(write(fd, data, size)) != size) {
|
||||
printf("mtd: write error at 0x%08lx (%s)\n",
|
||||
pos, strerror(errno));
|
||||
}
|
||||
|
||||
char verify[size];
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, pos, SEEK_SET)) != pos ||
|
||||
TEMP_FAILURE_RETRY(read(fd, verify, size)) != size) {
|
||||
printf("mtd: re-read error at 0x%08lx (%s)\n",
|
||||
pos, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (memcmp(data, verify, size) != 0) {
|
||||
printf("mtd: verification error at 0x%08lx (%s)\n",
|
||||
pos, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (retry > 0) {
|
||||
printf("mtd: wrote block after %d retries\n", retry);
|
||||
}
|
||||
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);
|
||||
printf("mtd: skipping write block at 0x%08lx\n", pos);
|
||||
ioctl(fd, MEMERASE, &erase_info);
|
||||
pos += partition->erase_size;
|
||||
}
|
||||
|
||||
// Ran out of space on the device
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t mtd_write_data(MtdWriteContext *ctx, const char *data, size_t len)
|
||||
{
|
||||
size_t wrote = 0;
|
||||
while (wrote < len) {
|
||||
// Coalesce partial writes into complete blocks
|
||||
if (ctx->stored > 0 || len - wrote < ctx->partition->erase_size) {
|
||||
size_t avail = ctx->partition->erase_size - ctx->stored;
|
||||
size_t copy = len - wrote < avail ? len - wrote : avail;
|
||||
memcpy(ctx->buffer + ctx->stored, data + wrote, copy);
|
||||
ctx->stored += copy;
|
||||
wrote += copy;
|
||||
}
|
||||
|
||||
// If a complete block was accumulated, write it
|
||||
if (ctx->stored == ctx->partition->erase_size) {
|
||||
if (write_block(ctx, ctx->buffer)) return -1;
|
||||
ctx->stored = 0;
|
||||
}
|
||||
|
||||
// Write complete blocks directly from the user's buffer
|
||||
while (ctx->stored == 0 && len - wrote >= ctx->partition->erase_size) {
|
||||
if (write_block(ctx, data + wrote)) return -1;
|
||||
wrote += ctx->partition->erase_size;
|
||||
}
|
||||
}
|
||||
|
||||
return wrote;
|
||||
}
|
||||
|
||||
off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks)
|
||||
{
|
||||
// Zero-pad and write any pending data to get us to a block boundary
|
||||
if (ctx->stored > 0) {
|
||||
size_t zero = ctx->partition->erase_size - ctx->stored;
|
||||
memset(ctx->buffer + ctx->stored, 0, zero);
|
||||
if (write_block(ctx, ctx->buffer)) return -1;
|
||||
ctx->stored = 0;
|
||||
}
|
||||
|
||||
off_t pos = TEMP_FAILURE_RETRY(lseek(ctx->fd, 0, SEEK_CUR));
|
||||
if ((off_t) pos == (off_t) -1) {
|
||||
printf("mtd_erase_blocks: couldn't SEEK_CUR: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int total = (ctx->partition->size - pos) / ctx->partition->erase_size;
|
||||
if (blocks < 0) blocks = total;
|
||||
if (blocks > total) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Erase the specified number of blocks
|
||||
while (blocks-- > 0) {
|
||||
loff_t bpos = pos;
|
||||
if (ioctl(ctx->fd, MEMGETBADBLOCK, &bpos) > 0) {
|
||||
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.
|
||||
}
|
||||
|
||||
struct erase_info_user erase_info;
|
||||
erase_info.start = pos;
|
||||
erase_info.length = ctx->partition->erase_size;
|
||||
if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) {
|
||||
printf("mtd: erase failure at 0x%08lx\n", pos);
|
||||
}
|
||||
pos += ctx->partition->erase_size;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
int mtd_write_close(MtdWriteContext *ctx)
|
||||
{
|
||||
int r = 0;
|
||||
// Make sure any pending data gets written
|
||||
if (mtd_erase_blocks(ctx, 0) == (off_t) -1) r = -1;
|
||||
if (close(ctx->fd)) r = -1;
|
||||
free(ctx->bad_block_offsets);
|
||||
free(ctx->buffer);
|
||||
free(ctx);
|
||||
return r;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MTDUTILS_H_
|
||||
#define MTDUTILS_H_
|
||||
|
||||
#include <sys/types.h> // for size_t, etc.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct MtdPartition MtdPartition;
|
||||
|
||||
int mtd_scan_partitions(void);
|
||||
|
||||
const MtdPartition *mtd_find_partition_by_name(const char *name);
|
||||
|
||||
/* mount_point is like "/system"
|
||||
* filesystem is like "yaffs2"
|
||||
*/
|
||||
int mtd_mount_partition(const MtdPartition *partition, const char *mount_point,
|
||||
const char *filesystem, int read_only);
|
||||
|
||||
/* get the partition and the minimum erase/write block size. NULL is ok.
|
||||
*/
|
||||
int mtd_partition_info(const MtdPartition *partition,
|
||||
size_t *total_size, size_t *erase_size, size_t *write_size);
|
||||
|
||||
/* read or write raw data from a partition, starting at the beginning.
|
||||
* skips bad blocks as best we can.
|
||||
*/
|
||||
typedef struct MtdReadContext MtdReadContext;
|
||||
typedef struct MtdWriteContext MtdWriteContext;
|
||||
|
||||
MtdReadContext *mtd_read_partition(const MtdPartition *);
|
||||
ssize_t mtd_read_data(MtdReadContext *, char *data, size_t data_len);
|
||||
void mtd_read_close(MtdReadContext *);
|
||||
|
||||
MtdWriteContext *mtd_write_partition(const MtdPartition *);
|
||||
ssize_t mtd_write_data(MtdWriteContext *, const char *data, size_t data_len);
|
||||
off_t mtd_erase_blocks(MtdWriteContext *, int blocks); /* 0 ok, -1 for all */
|
||||
int mtd_write_close(MtdWriteContext *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MTDUTILS_H_
|
||||
63
roots.cpp
63
roots.cpp
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "roots.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mount.h>
|
||||
@@ -25,11 +27,9 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <fs_mgr.h>
|
||||
#include "mtdutils/mtdutils.h"
|
||||
#include "mtdutils/mounts.h"
|
||||
#include "roots.h"
|
||||
#include "common.h"
|
||||
#include "make_ext4fs.h"
|
||||
#include "mounts.h"
|
||||
#include "wipe.h"
|
||||
#include "cryptfs.h"
|
||||
|
||||
@@ -82,9 +82,7 @@ int ensure_path_mounted_at(const char* path, const char* mount_point) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int result;
|
||||
result = scan_mounted_volumes();
|
||||
if (result < 0) {
|
||||
if (!scan_mounted_volumes()) {
|
||||
LOGE("failed to scan mounted volumes\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -93,8 +91,7 @@ int ensure_path_mounted_at(const char* path, const char* mount_point) {
|
||||
mount_point = v->mount_point;
|
||||
}
|
||||
|
||||
const MountedVolume* mv =
|
||||
find_mounted_volume_by_mount_point(mount_point);
|
||||
MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
|
||||
if (mv) {
|
||||
// volume is already mounted
|
||||
return 0;
|
||||
@@ -102,27 +99,15 @@ int ensure_path_mounted_at(const char* path, const char* mount_point) {
|
||||
|
||||
mkdir(mount_point, 0755); // in case it doesn't already exist
|
||||
|
||||
if (strcmp(v->fs_type, "yaffs2") == 0) {
|
||||
// mount an MTD partition as a YAFFS2 filesystem.
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* partition;
|
||||
partition = mtd_find_partition_by_name(v->blk_device);
|
||||
if (partition == NULL) {
|
||||
LOGE("failed to find \"%s\" partition to mount at \"%s\"\n",
|
||||
v->blk_device, mount_point);
|
||||
return -1;
|
||||
}
|
||||
return mtd_mount_partition(partition, mount_point, v->fs_type, 0);
|
||||
} else if (strcmp(v->fs_type, "ext4") == 0 ||
|
||||
if (strcmp(v->fs_type, "ext4") == 0 ||
|
||||
strcmp(v->fs_type, "squashfs") == 0 ||
|
||||
strcmp(v->fs_type, "vfat") == 0) {
|
||||
result = mount(v->blk_device, mount_point, v->fs_type,
|
||||
v->flags, v->fs_options);
|
||||
if (result == 0) return 0;
|
||||
|
||||
if (mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options) == -1) {
|
||||
LOGE("failed to mount %s (%s)\n", mount_point, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, mount_point);
|
||||
return -1;
|
||||
@@ -144,15 +129,12 @@ int ensure_path_unmounted(const char* path) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result;
|
||||
result = scan_mounted_volumes();
|
||||
if (result < 0) {
|
||||
if (!scan_mounted_volumes()) {
|
||||
LOGE("failed to scan mounted volumes\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const MountedVolume* mv =
|
||||
find_mounted_volume_by_mount_point(v->mount_point);
|
||||
MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);
|
||||
if (mv == NULL) {
|
||||
// volume is already unmounted
|
||||
return 0;
|
||||
@@ -196,29 +178,6 @@ int format_volume(const char* volume) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) {
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* partition = mtd_find_partition_by_name(v->blk_device);
|
||||
if (partition == NULL) {
|
||||
LOGE("format_volume: no MTD partition \"%s\"\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtdWriteContext *write = mtd_write_partition(partition);
|
||||
if (write == NULL) {
|
||||
LOGW("format_volume: can't open MTD \"%s\"\n", v->blk_device);
|
||||
return -1;
|
||||
} else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
|
||||
LOGW("format_volume: can't erase MTD \"%s\"\n", v->blk_device);
|
||||
mtd_write_close(write);
|
||||
return -1;
|
||||
} else if (mtd_write_close(write)) {
|
||||
LOGW("format_volume: can't close MTD \"%s\"\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "f2fs") == 0) {
|
||||
// if there's a key_loc that looks like a path, it should be a
|
||||
// block device for storing encryption metadata. wipe it too.
|
||||
|
||||
@@ -40,8 +40,8 @@ LOCAL_STATIC_LIBRARIES += \
|
||||
libbase \
|
||||
libotafault \
|
||||
libedify \
|
||||
libmtdutils \
|
||||
libminzip \
|
||||
libmounts \
|
||||
libz \
|
||||
libbz \
|
||||
libcutils \
|
||||
@@ -60,14 +60,11 @@ LOCAL_STATIC_LIBRARIES += \
|
||||
libtune2fs \
|
||||
$(tune2fs_static_libraries)
|
||||
|
||||
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
|
||||
LOCAL_CFLAGS += -DUSE_EXT4
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter
|
||||
LOCAL_C_INCLUDES += system/extras/ext4_utils
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libsparse_static \
|
||||
libz
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES += external/e2fsprogs/misc
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
|
||||
|
||||
@@ -50,17 +50,14 @@
|
||||
#include "edify/expr.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "minzip/DirUtil.h"
|
||||
#include "mtdutils/mounts.h"
|
||||
#include "mtdutils/mtdutils.h"
|
||||
#include "mounts.h"
|
||||
#include "ota_io.h"
|
||||
#include "updater.h"
|
||||
#include "install.h"
|
||||
#include "tune2fs.h"
|
||||
|
||||
#ifdef USE_EXT4
|
||||
#include "make_ext4fs.h"
|
||||
#include "wipe.h"
|
||||
#endif
|
||||
|
||||
// Send over the buffer to recovery though the command pipe.
|
||||
static void uiPrint(State* state, const std::string& buffer) {
|
||||
@@ -109,7 +106,6 @@ char* PrintSha1(const uint8_t* digest) {
|
||||
|
||||
// mount(fs_type, partition_type, location, mount_point)
|
||||
//
|
||||
// fs_type="yaffs2" partition_type="MTD" location=partition
|
||||
// fs_type="ext4" partition_type="EMMC" location=device
|
||||
Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
char* result = NULL;
|
||||
@@ -170,24 +166,6 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(partition_type, "MTD") == 0) {
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* mtd;
|
||||
mtd = mtd_find_partition_by_name(location);
|
||||
if (mtd == NULL) {
|
||||
uiPrintf(state, "%s: no mtd partition named \"%s\"\n",
|
||||
name, location);
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
|
||||
uiPrintf(state, "mtd mount of %s failed: %s\n",
|
||||
location, strerror(errno));
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
result = mount_point;
|
||||
} else {
|
||||
if (mount(location, mount_point, fs_type,
|
||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME,
|
||||
has_mount_options ? mount_options : "") < 0) {
|
||||
@@ -197,7 +175,6 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
} else {
|
||||
result = mount_point;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
free(fs_type);
|
||||
@@ -226,7 +203,7 @@ Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
|
||||
scan_mounted_volumes();
|
||||
{
|
||||
const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
|
||||
MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
|
||||
if (vol == NULL) {
|
||||
result = strdup("");
|
||||
} else {
|
||||
@@ -256,7 +233,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);
|
||||
MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
|
||||
if (vol == NULL) {
|
||||
uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point);
|
||||
result = strdup("");
|
||||
@@ -292,7 +269,6 @@ static int exec_cmd(const char* path, char* const argv[]) {
|
||||
|
||||
// format(fs_type, partition_type, location, fs_size, mount_point)
|
||||
//
|
||||
// fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes> mount_point=<location>
|
||||
// fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location>
|
||||
// fs_type="f2fs" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location>
|
||||
// if fs_size == 0, then make fs uses the entire partition.
|
||||
@@ -332,35 +308,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (strcmp(partition_type, "MTD") == 0) {
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* mtd = mtd_find_partition_by_name(location);
|
||||
if (mtd == NULL) {
|
||||
printf("%s: no mtd partition named \"%s\"",
|
||||
name, location);
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
MtdWriteContext* ctx = mtd_write_partition(mtd);
|
||||
if (ctx == NULL) {
|
||||
printf("%s: can't write \"%s\"", name, location);
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
if (mtd_erase_blocks(ctx, -1) == -1) {
|
||||
mtd_write_close(ctx);
|
||||
printf("%s: failed to erase \"%s\"", name, location);
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
if (mtd_write_close(ctx) != 0) {
|
||||
printf("%s: failed to close \"%s\"", name, location);
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
result = location;
|
||||
#ifdef USE_EXT4
|
||||
} else if (strcmp(fs_type, "ext4") == 0) {
|
||||
if (strcmp(fs_type, "ext4") == 0) {
|
||||
int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle);
|
||||
if (status != 0) {
|
||||
printf("%s: make_ext4fs failed (%d) on %s",
|
||||
@@ -387,7 +335,6 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
goto done;
|
||||
}
|
||||
result = location;
|
||||
#endif
|
||||
} else {
|
||||
printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"",
|
||||
name, fs_type, partition_type);
|
||||
@@ -1059,98 +1006,6 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
return StringValue(result);
|
||||
}
|
||||
|
||||
// write_raw_image(filename_or_blob, partition)
|
||||
Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
char* result = NULL;
|
||||
|
||||
Value* partition_value;
|
||||
Value* contents;
|
||||
if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* partition = NULL;
|
||||
if (partition_value->type != VAL_STRING) {
|
||||
ErrorAbort(state, "partition argument to %s must be string", name);
|
||||
goto done;
|
||||
}
|
||||
partition = partition_value->data;
|
||||
if (strlen(partition) == 0) {
|
||||
ErrorAbort(state, "partition argument to %s can't be empty", name);
|
||||
goto done;
|
||||
}
|
||||
if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
|
||||
ErrorAbort(state, "file argument to %s can't be empty", name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* mtd;
|
||||
mtd = mtd_find_partition_by_name(partition);
|
||||
if (mtd == NULL) {
|
||||
printf("%s: no mtd partition named \"%s\"\n", name, partition);
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
|
||||
MtdWriteContext* ctx;
|
||||
ctx = mtd_write_partition(mtd);
|
||||
if (ctx == NULL) {
|
||||
printf("%s: can't write mtd partition \"%s\"\n",
|
||||
name, partition);
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
|
||||
bool success;
|
||||
|
||||
if (contents->type == VAL_STRING) {
|
||||
// we're given a filename as the contents
|
||||
char* filename = contents->data;
|
||||
FILE* f = ota_fopen(filename, "rb");
|
||||
if (f == NULL) {
|
||||
printf("%s: can't open %s: %s\n", name, filename, strerror(errno));
|
||||
result = strdup("");
|
||||
goto done;
|
||||
}
|
||||
|
||||
success = true;
|
||||
char* buffer = reinterpret_cast<char*>(malloc(BUFSIZ));
|
||||
int read;
|
||||
while (success && (read = ota_fread(buffer, 1, BUFSIZ, f)) > 0) {
|
||||
int wrote = mtd_write_data(ctx, buffer, read);
|
||||
success = success && (wrote == read);
|
||||
}
|
||||
free(buffer);
|
||||
ota_fclose(f);
|
||||
} else {
|
||||
// we're given a blob as the contents
|
||||
ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size);
|
||||
success = (wrote == contents->size);
|
||||
}
|
||||
if (!success) {
|
||||
printf("mtd_write_data to %s failed: %s\n",
|
||||
partition, strerror(errno));
|
||||
}
|
||||
|
||||
if (mtd_erase_blocks(ctx, -1) == -1) {
|
||||
printf("%s: error erasing blocks of %s\n", name, partition);
|
||||
}
|
||||
if (mtd_write_close(ctx) != 0) {
|
||||
printf("%s: error closing write of %s\n", name, partition);
|
||||
}
|
||||
|
||||
printf("%s %s partition\n",
|
||||
success ? "wrote" : "failed to write", partition);
|
||||
|
||||
result = success ? partition : strdup("");
|
||||
|
||||
done:
|
||||
if (result != partition) FreeValue(partition_value);
|
||||
FreeValue(contents);
|
||||
return StringValue(result);
|
||||
}
|
||||
|
||||
// apply_patch_space(bytes)
|
||||
Value* ApplyPatchSpaceFn(const char* name, State* state,
|
||||
int argc, Expr* argv[]) {
|
||||
@@ -1607,7 +1462,6 @@ void RegisterInstallFunctions() {
|
||||
|
||||
RegisterFunction("getprop", GetPropFn);
|
||||
RegisterFunction("file_getprop", FileGetPropFn);
|
||||
RegisterFunction("write_raw_image", WriteRawImageFn);
|
||||
|
||||
RegisterFunction("apply_patch", ApplyPatchFn);
|
||||
RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
|
||||
|
||||
Reference in New Issue
Block a user