Merge "Remove obsolete MTD support."

This commit is contained in:
Elliott Hughes
2016-06-15 21:55:15 +00:00
committed by Gerrit Code Review
16 changed files with 250 additions and 1498 deletions

View File

@@ -17,15 +17,23 @@ LOCAL_PATH := $(call my-dir)
# libfusesideload (static library) # libfusesideload (static library)
# =============================== # ===============================
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_SRC_FILES := fuse_sideload.cpp LOCAL_SRC_FILES := fuse_sideload.cpp
LOCAL_CLANG := true 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_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE := libfusesideload LOCAL_MODULE := libfusesideload
LOCAL_STATIC_LIBRARIES := libcutils libc libcrypto_static LOCAL_STATIC_LIBRARIES := libcutils libc libcrypto_static
include $(BUILD_STATIC_LIBRARY) 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) # recovery (static executable)
# =============================== # ===============================
include $(CLEAR_VARS) include $(CLEAR_VARS)
@@ -70,8 +78,8 @@ LOCAL_STATIC_LIBRARIES := \
libext4_utils_static \ libext4_utils_static \
libsparse_static \ libsparse_static \
libminzip \ libminzip \
libmounts \
libz \ libz \
libmtdutils \
libminadbd \ libminadbd \
libfusesideload \ libfusesideload \
libminui \ libminui \
@@ -89,11 +97,8 @@ LOCAL_STATIC_LIBRARIES := \
LOCAL_HAL_STATIC_LIBRARIES := libhealthd LOCAL_HAL_STATIC_LIBRARIES := libhealthd
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
LOCAL_CFLAGS += -DUSE_EXT4
LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_STATIC_LIBRARIES += libext4_utils_static libz LOCAL_STATIC_LIBRARIES += libext4_utils_static libz
endif
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
@@ -145,7 +150,6 @@ include $(BUILD_STATIC_LIBRARY)
include $(LOCAL_PATH)/minui/Android.mk \ include $(LOCAL_PATH)/minui/Android.mk \
$(LOCAL_PATH)/minzip/Android.mk \ $(LOCAL_PATH)/minzip/Android.mk \
$(LOCAL_PATH)/minadbd/Android.mk \ $(LOCAL_PATH)/minadbd/Android.mk \
$(LOCAL_PATH)/mtdutils/Android.mk \
$(LOCAL_PATH)/tests/Android.mk \ $(LOCAL_PATH)/tests/Android.mk \
$(LOCAL_PATH)/tools/Android.mk \ $(LOCAL_PATH)/tools/Android.mk \
$(LOCAL_PATH)/edify/Android.mk \ $(LOCAL_PATH)/edify/Android.mk \

View File

@@ -32,7 +32,6 @@ LOCAL_C_INCLUDES += \
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES += \ LOCAL_STATIC_LIBRARIES += \
libotafault \ libotafault \
libmtdutils \
libbase \ libbase \
libcrypto_static \ libcrypto_static \
libbz \ libbz \
@@ -79,7 +78,6 @@ LOCAL_STATIC_LIBRARIES += \
libedify \ libedify \
libotafault \ libotafault \
libminzip \ libminzip \
libmtdutils \
libcrypto_static \ libcrypto_static \
libbz libbz
LOCAL_SHARED_LIBRARIES += libz libcutils libc LOCAL_SHARED_LIBRARIES += libz libcutils libc

View File

@@ -32,7 +32,6 @@
#include "openssl/sha.h" #include "openssl/sha.h"
#include "applypatch/applypatch.h" #include "applypatch/applypatch.h"
#include "mtdutils/mtdutils.h"
#include "edify/expr.h" #include "edify/expr.h"
#include "ota_io.h" #include "ota_io.h"
#include "print_sha1.h" #include "print_sha1.h"
@@ -49,17 +48,14 @@ static int GenerateTarget(FileContents* source_file,
size_t target_size, size_t target_size,
const Value* bonus_data); const Value* bonus_data);
static bool mtd_partitions_scanned = false;
// Read a file into memory; store the file contents and associated // Read a file into memory; store the file contents and associated
// metadata in *file. // metadata in *file.
// //
// Return 0 on success. // Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file) { 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. // load the contents of a partition.
if (strncmp(filename, "MTD:", 4) == 0 || if (strncmp(filename, "EMMC:", 5) == 0) {
strncmp(filename, "EMMC:", 5) == 0) {
return LoadPartitionContents(filename, file); return LoadPartitionContents(filename, file);
} }
@@ -87,10 +83,9 @@ int LoadFileContents(const char* filename, FileContents* file) {
return 0; 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 // 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 // which that prefix of the partition contents has the corresponding
// sha1 hash will be loaded. It is acceptable for a size value to be // sha1 hash will be loaded. It is acceptable for a size value to be
// repeated with different sha1s. Will return 0 on success. // 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 // "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 // lengths and the hash of the data, and we'll do the load expecting
// to find one of those hashes. // to find one of those hashes.
enum PartitionType { MTD, EMMC };
static int LoadPartitionContents(const char* filename, FileContents* file) { static int LoadPartitionContents(const char* filename, FileContents* file) {
std::string copy(filename); std::string copy(filename);
std::vector<std::string> pieces = android::base::Split(copy, ":"); std::vector<std::string> pieces = android::base::Split(copy, ":");
@@ -112,12 +105,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
return -1; return -1;
} }
enum PartitionType type; if (pieces[0] != "EMMC") {
if (pieces[0] == "MTD") {
type = MTD;
} else if (pieces[0] == "EMMC") {
type = EMMC;
} else {
printf("LoadPartitionContents called with bad filename (%s)\n", filename); printf("LoadPartitionContents called with bad filename (%s)\n", filename);
return -1; return -1;
} }
@@ -145,37 +133,11 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
} }
); );
MtdReadContext* ctx = NULL; FILE* dev = ota_fopen(partition, "rb");
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");
if (dev == NULL) { if (dev == NULL) {
printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno));
return -1; return -1;
} }
}
SHA_CTX sha_ctx; SHA_CTX sha_ctx;
SHA1_Init(&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). // we're trying the possibilities in order of increasing size).
size_t next = size[index[i]] - data_size; size_t next = size[index[i]] - data_size;
if (next > 0) { if (next > 0) {
size_t read = 0; size_t read = ota_fread(p, 1, next, dev);
switch (type) {
case MTD:
read = mtd_read_data(ctx, p, next);
break;
case EMMC:
read = ota_fread(p, 1, next, dev);
break;
}
if (next != read) { if (next != read) {
printf("short read (%zu bytes of %zu) for partition \"%s\"\n", printf("short read (%zu bytes of %zu) for partition \"%s\"\n",
read, next, partition); 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); ota_fclose(dev);
break;
}
if (!found) { if (!found) {
// Ran off the end of the list of (size,sha1) pairs without finding a match. // 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 // 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 // might contain multiple colons, but WriteToPartition() only uses the first
// two and ignores the rest. Return 0 on success. // two and ignores the rest. Return 0 on success.
int WriteToPartition(const unsigned char* data, size_t len, const char* target) { 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; return -1;
} }
enum PartitionType type; if (pieces[0] != "EMMC") {
if (pieces[0] == "MTD") {
type = MTD;
} else if (pieces[0] == "EMMC") {
type = EMMC;
} else {
printf("WriteToPartition called with bad target (%s)\n", target); printf("WriteToPartition called with bad target (%s)\n", target);
return -1; return -1;
} }
const char* partition = pieces[1].c_str(); 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; size_t start = 0;
bool success = false; bool success = false;
int fd = ota_open(partition, O_RDWR | O_SYNC); 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; return -1;
} }
sync(); sync();
break;
}
}
return 0; return 0;
} }
@@ -729,7 +625,7 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
std::string target_str(target_filename); std::string target_str(target_filename);
std::vector<std::string> pieces = android::base::Split(target_str, ":"); 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); printf("invalid target name \"%s\"", target_filename);
return 1; return 1;
} }
@@ -778,8 +674,7 @@ static int GenerateTarget(FileContents* source_file,
FileContents* source_to_use; FileContents* source_to_use;
int made_copy = 0; int made_copy = 0;
bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 || bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0);
strncmp(target_filename, "EMMC:", 5) == 0);
const std::string tmp_target_filename = std::string(target_filename) + ".patch"; const std::string tmp_target_filename = std::string(target_filename) + ".patch";
// assume that target_filename (eg "/system/app/Foo.apk") is located // 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 // copy the source file to cache, then delete it from the original
// location. // location.
if (strncmp(source_filename, "MTD:", 4) == 0 || if (strncmp(source_filename, "EMMC:", 5) == 0) {
strncmp(source_filename, "EMMC:", 5) == 0) {
// It's impossible to free space on the target filesystem by // It's impossible to free space on the target filesystem by
// deleting the source if the source is a partition. If // deleting the source if the source is a partition. If
// we're ever in a state where we need to do this, fail. // we're ever in a state where we need to do this, fail.

View File

@@ -160,9 +160,9 @@ static int PatchMode(int argc, char** argv) {
// - otherwise, or if any error is encountered, exits with non-zero // - otherwise, or if any error is encountered, exits with non-zero
// status. // 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 // 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) { int main(int argc, char** argv) {
if (argc < 2) { if (argc < 2) {
@@ -175,8 +175,8 @@ int main(int argc, char** argv) {
" or %s -l\n" " or %s -l\n"
"\n" "\n"
"Filenames may be of the form\n" "Filenames may be of the form\n"
" MTD:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n" " EMMC:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
"to specify reading from or writing to an MTD partition.\n\n", "to specify reading from or writing to an EMMC partition.\n\n",
argv[0], argv[0], argv[0], argv[0]); argv[0], argv[0], argv[0], argv[0]);
return 2; return 2;
} }

View File

@@ -27,12 +27,9 @@
#include "bootloader.h" #include "bootloader.h"
#include "common.h" #include "common.h"
#include "mtdutils/mtdutils.h"
#include "roots.h" #include "roots.h"
#include <android-base/unique_fd.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 get_bootloader_message_block(bootloader_message* out, const Volume* v);
static int set_bootloader_message_block(const bootloader_message* in, 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"); LOGE("Cannot load volume /misc!\n");
return -1; return -1;
} }
if (strcmp(v->fs_type, "mtd") == 0) { if (strcmp(v->fs_type, "emmc") == 0) {
return get_bootloader_message_mtd(out, v);
} else if (strcmp(v->fs_type, "emmc") == 0) {
return get_bootloader_message_block(out, v); return get_bootloader_message_block(out, v);
} }
LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type); 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"); LOGE("Cannot load volume /misc!\n");
return -1; return -1;
} }
if (strcmp(v->fs_type, "mtd") == 0) { if (strcmp(v->fs_type, "emmc") == 0) {
return set_bootloader_message_mtd(in, v);
} else if (strcmp(v->fs_type, "emmc") == 0) {
return set_bootloader_message_block(in, v); return set_bootloader_message_block(in, v);
} }
LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type); LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
return -1; 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 // for misc partitions on block devices
// ------------------------------------ // ------------------------------------

View File

@@ -30,8 +30,6 @@
#include "minui/minui.h" #include "minui/minui.h"
#include "minzip/SysUtil.h" #include "minzip/SysUtil.h"
#include "minzip/Zip.h" #include "minzip/Zip.h"
#include "mtdutils/mounts.h"
#include "mtdutils/mtdutils.h"
#include "roots.h" #include "roots.h"
#include "ui.h" #include "ui.h"
#include "verifier.h" #include "verifier.h"

89
mounts.cpp Normal file
View 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);
}

View File

@@ -14,28 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef MTDUTILS_MOUNTS_H_ #ifndef MOUNTS_H_
#define MTDUTILS_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 #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_

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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_

View File

@@ -14,6 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
#include "roots.h"
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/mount.h> #include <sys/mount.h>
@@ -25,11 +27,9 @@
#include <fcntl.h> #include <fcntl.h>
#include <fs_mgr.h> #include <fs_mgr.h>
#include "mtdutils/mtdutils.h"
#include "mtdutils/mounts.h"
#include "roots.h"
#include "common.h" #include "common.h"
#include "make_ext4fs.h" #include "make_ext4fs.h"
#include "mounts.h"
#include "wipe.h" #include "wipe.h"
#include "cryptfs.h" #include "cryptfs.h"
@@ -82,9 +82,7 @@ int ensure_path_mounted_at(const char* path, const char* mount_point) {
return 0; return 0;
} }
int result; if (!scan_mounted_volumes()) {
result = scan_mounted_volumes();
if (result < 0) {
LOGE("failed to scan mounted volumes\n"); LOGE("failed to scan mounted volumes\n");
return -1; return -1;
} }
@@ -93,8 +91,7 @@ int ensure_path_mounted_at(const char* path, const char* mount_point) {
mount_point = v->mount_point; mount_point = v->mount_point;
} }
const MountedVolume* mv = MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
find_mounted_volume_by_mount_point(mount_point);
if (mv) { if (mv) {
// volume is already mounted // volume is already mounted
return 0; 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 mkdir(mount_point, 0755); // in case it doesn't already exist
if (strcmp(v->fs_type, "yaffs2") == 0) { if (strcmp(v->fs_type, "ext4") == 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 ||
strcmp(v->fs_type, "squashfs") == 0 || strcmp(v->fs_type, "squashfs") == 0 ||
strcmp(v->fs_type, "vfat") == 0) { strcmp(v->fs_type, "vfat") == 0) {
result = mount(v->blk_device, mount_point, v->fs_type, if (mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options) == -1) {
v->flags, v->fs_options);
if (result == 0) return 0;
LOGE("failed to mount %s (%s)\n", mount_point, strerror(errno)); LOGE("failed to mount %s (%s)\n", mount_point, strerror(errno));
return -1; return -1;
} }
return 0;
}
LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, mount_point); LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, mount_point);
return -1; return -1;
@@ -144,15 +129,12 @@ int ensure_path_unmounted(const char* path) {
return -1; return -1;
} }
int result; if (!scan_mounted_volumes()) {
result = scan_mounted_volumes();
if (result < 0) {
LOGE("failed to scan mounted volumes\n"); LOGE("failed to scan mounted volumes\n");
return -1; return -1;
} }
const MountedVolume* mv = MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);
find_mounted_volume_by_mount_point(v->mount_point);
if (mv == NULL) { if (mv == NULL) {
// volume is already unmounted // volume is already unmounted
return 0; return 0;
@@ -196,29 +178,6 @@ int format_volume(const char* volume) {
return -1; 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 (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 // if there's a key_loc that looks like a path, it should be a
// block device for storing encryption metadata. wipe it too. // block device for storing encryption metadata. wipe it too.

View File

@@ -40,8 +40,8 @@ LOCAL_STATIC_LIBRARIES += \
libbase \ libbase \
libotafault \ libotafault \
libedify \ libedify \
libmtdutils \
libminzip \ libminzip \
libmounts \
libz \ libz \
libbz \ libbz \
libcutils \ libcutils \
@@ -60,14 +60,11 @@ LOCAL_STATIC_LIBRARIES += \
libtune2fs \ libtune2fs \
$(tune2fs_static_libraries) $(tune2fs_static_libraries)
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
LOCAL_CFLAGS += -DUSE_EXT4
LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_STATIC_LIBRARIES += \ LOCAL_STATIC_LIBRARIES += \
libsparse_static \ libsparse_static \
libz libz
endif
LOCAL_C_INCLUDES += external/e2fsprogs/misc LOCAL_C_INCLUDES += external/e2fsprogs/misc
LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. LOCAL_C_INCLUDES += $(LOCAL_PATH)/..

View File

@@ -50,17 +50,14 @@
#include "edify/expr.h" #include "edify/expr.h"
#include "openssl/sha.h" #include "openssl/sha.h"
#include "minzip/DirUtil.h" #include "minzip/DirUtil.h"
#include "mtdutils/mounts.h" #include "mounts.h"
#include "mtdutils/mtdutils.h"
#include "ota_io.h" #include "ota_io.h"
#include "updater.h" #include "updater.h"
#include "install.h" #include "install.h"
#include "tune2fs.h" #include "tune2fs.h"
#ifdef USE_EXT4
#include "make_ext4fs.h" #include "make_ext4fs.h"
#include "wipe.h" #include "wipe.h"
#endif
// Send over the buffer to recovery though the command pipe. // Send over the buffer to recovery though the command pipe.
static void uiPrint(State* state, const std::string& buffer) { 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) // mount(fs_type, partition_type, location, mount_point)
// //
// fs_type="yaffs2" partition_type="MTD" location=partition
// fs_type="ext4" partition_type="EMMC" location=device // fs_type="ext4" partition_type="EMMC" location=device
Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL; 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, if (mount(location, mount_point, fs_type,
MS_NOATIME | MS_NODEV | MS_NODIRATIME, MS_NOATIME | MS_NODEV | MS_NODIRATIME,
has_mount_options ? mount_options : "") < 0) { has_mount_options ? mount_options : "") < 0) {
@@ -197,7 +175,6 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
} else { } else {
result = mount_point; result = mount_point;
} }
}
done: done:
free(fs_type); free(fs_type);
@@ -226,7 +203,7 @@ Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
scan_mounted_volumes(); 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) { if (vol == NULL) {
result = strdup(""); result = strdup("");
} else { } else {
@@ -256,7 +233,7 @@ Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
scan_mounted_volumes(); 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) { if (vol == NULL) {
uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point); uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point);
result = strdup(""); 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) // 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="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> // 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. // 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; goto done;
} }
if (strcmp(partition_type, "MTD") == 0) { if (strcmp(fs_type, "ext4") == 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) {
int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle); int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle);
if (status != 0) { if (status != 0) {
printf("%s: make_ext4fs failed (%d) on %s", 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; goto done;
} }
result = location; result = location;
#endif
} else { } else {
printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"", printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"",
name, fs_type, partition_type); name, fs_type, partition_type);
@@ -1059,98 +1006,6 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(result); 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) // apply_patch_space(bytes)
Value* ApplyPatchSpaceFn(const char* name, State* state, Value* ApplyPatchSpaceFn(const char* name, State* state,
int argc, Expr* argv[]) { int argc, Expr* argv[]) {
@@ -1607,7 +1462,6 @@ void RegisterInstallFunctions() {
RegisterFunction("getprop", GetPropFn); RegisterFunction("getprop", GetPropFn);
RegisterFunction("file_getprop", FileGetPropFn); RegisterFunction("file_getprop", FileGetPropFn);
RegisterFunction("write_raw_image", WriteRawImageFn);
RegisterFunction("apply_patch", ApplyPatchFn); RegisterFunction("apply_patch", ApplyPatchFn);
RegisterFunction("apply_patch_check", ApplyPatchCheckFn); RegisterFunction("apply_patch_check", ApplyPatchCheckFn);