android_bootable_recovery
android_bootable_recovery copied to clipboard
mmcutils_mtk.c
/*
- Copyright (c) 2010, Code Aurora Forum. All rights reserved. *
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- * Redistributions of source code must retain the above copyright
-
notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-
copyright notice, this list of conditions and the following
-
disclaimer in the documentation and/or other materials provided
-
with the distribution.
- * Neither the name of Code Aurora Forum, Inc. nor the names of its
-
contributors may be used to endorse or promote products derived
-
from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
include <stdlib.h>
include <stdio.h>
include <unistd.h>
include <dirent.h>
include <string.h>
include <errno.h>
include <sys/types.h>
include <sys/reboot.h>
include <sys/stat.h>
include <sys/wait.h>
include <sys/mount.h> // for _IOW, _IOR, mount()
include "mmcutils.h"
unsigned ext3_count = 0; char *ext3_partitions[] = {"system", "userdata", "cache", "NONE"};
unsigned vfat_count = 0; char *vfat_partitions[] = {"modem", "NONE"};
struct MmcPartition { char *device_index; char *filesystem; char *name; unsigned dstatus; unsigned dtype ; unsigned dfirstsec; unsigned dsize; };
typedef struct { MmcPartition *partitions; int partitions_allocd; int partition_count; } MmcState;
static MmcState g_mmc_state = { NULL, // partitions 0, // partitions_allocd -1 // partition_count };
define MMC_DEVICENAME "/dev/block/mmcblk0"
static void mmc_partition_name (MmcPartition *mbr, unsigned int type) { switch(type) { char name[64]; case MMC_BOOT_TYPE: sprintf(name,"boot"); mbr->name = strdup(name); break; case MMC_RECOVERY_TYPE: sprintf(name,"recovery"); mbr->name = strdup(name); break; case MMC_EXT3_TYPE: if (strcmp("NONE", ext3_partitions[ext3_count])) { strcpy((char *)name,(const char *)ext3_partitions[ext3_count]); mbr->name = strdup(name); ext3_count++; } mbr->filesystem = strdup("ext3"); break; case MMC_VFAT_TYPE: if (strcmp("NONE", vfat_partitions[vfat_count])) { strcpy((char *)name,(const char *)vfat_partitions[vfat_count]); mbr->name = strdup(name); vfat_count++; } mbr->filesystem = strdup("vfat"); break; }; }
static int mmc_read_mbr (const char *device, MmcPartition *mbr) { FILE *fd; unsigned char buffer[512]; int idx, i; unsigned mmc_partition_count = 0; unsigned int dtype; unsigned int dfirstsec; unsigned int EBR_first_sec; unsigned int EBR_current_sec; int ret = -1;
fd = fopen(device, "r");
if(fd == NULL)
{
printf("Can't open device: \"%s\"\n", device);
goto ERROR2;
}
if ((fread(buffer, 512, 1, fd)) != 1)
{
printf("Can't read device: \"%s\"\n", device);
goto ERROR1;
}
/* Check to see if signature exists */
if ((buffer[TABLE_SIGNATURE] != 0x55) || \
(buffer[TABLE_SIGNATURE + 1] != 0xAA))
{
printf("Incorrect mbr signatures!\n");
goto ERROR1;
}
idx = TABLE_ENTRY_0;
for (i = 0; i < 4; i++)
{
char device_index[128];
mbr[mmc_partition_count].dstatus = \
buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
mbr[mmc_partition_count].dtype = \
buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
mbr[mmc_partition_count].dfirstsec = \
GET_LWORD_FROM_BYTE(&buffer[idx + \
i * TABLE_ENTRY_SIZE + \
OFFSET_FIRST_SEC]);
mbr[mmc_partition_count].dsize = \
GET_LWORD_FROM_BYTE(&buffer[idx + \
i * TABLE_ENTRY_SIZE + \
OFFSET_SIZE]);
dtype = mbr[mmc_partition_count].dtype;
dfirstsec = mbr[mmc_partition_count].dfirstsec;
mmc_partition_name(&mbr[mmc_partition_count], \
mbr[mmc_partition_count].dtype);
sprintf(device_index, "%sp%d", device, (mmc_partition_count+1));
mbr[mmc_partition_count].device_index = strdup(device_index);
mmc_partition_count++;
if (mmc_partition_count == MAX_PARTITIONS)
goto SUCCESS;
}
/* See if the last partition is EBR, if not, parsing is done */
if (dtype != 0x05)
{
goto SUCCESS;
}
EBR_first_sec = dfirstsec;
EBR_current_sec = dfirstsec;
fseek (fd, (EBR_first_sec * 512), SEEK_SET);
if ((fread(buffer, 512, 1, fd)) != 1)
goto ERROR1;
/* Loop to parse the EBR */
for (i = 0;; i++)
{
char device_index[128];
if ((buffer[TABLE_SIGNATURE] != 0x55) || (buffer[TABLE_SIGNATURE + 1] != 0xAA))
{
break;
}
mbr[mmc_partition_count].dstatus = \
buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
mbr[mmc_partition_count].dtype = \
buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
mbr[mmc_partition_count].dfirstsec = \
GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
OFFSET_FIRST_SEC]) + \
EBR_current_sec;
mbr[mmc_partition_count].dsize = \
GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
OFFSET_SIZE]);
mmc_partition_name(&mbr[mmc_partition_count], \
mbr[mmc_partition_count].dtype);
sprintf(device_index, "%sp%d", device, (mmc_partition_count+1));
mbr[mmc_partition_count].device_index = strdup(device_index);
mmc_partition_count++;
if (mmc_partition_count == MAX_PARTITIONS)
goto SUCCESS;
dfirstsec = GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
if(dfirstsec == 0)
{
/* Getting to the end of the EBR tables */
break;
}
/* More EBR to follow - read in the next EBR sector */
fseek (fd, ((EBR_first_sec + dfirstsec) * 512), SEEK_SET);
if ((fread(buffer, 512, 1, fd)) != 1)
goto ERROR1;
EBR_current_sec = EBR_first_sec + dfirstsec;
}
SUCCESS: ret = mmc_partition_count; ERROR1: fclose(fd); ERROR2: return ret; }
int mmc_scan_partitions() { int i; ssize_t nbytes;
if (g_mmc_state.partitions == NULL) {
const int nump = MAX_PARTITIONS;
MmcPartition *partitions = malloc(nump * sizeof(*partitions));
if (partitions == NULL) {
errno = ENOMEM;
return -1;
}
g_mmc_state.partitions = partitions;
g_mmc_state.partitions_allocd = nump;
memset(partitions, 0, nump * sizeof(*partitions));
}
g_mmc_state.partition_count = 0;
ext3_count = 0;
vfat_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_mmc_state.partitions_allocd; i++) {
MmcPartition *p = &g_mmc_state.partitions[i];
if (p->device_index != NULL) {
free(p->device_index);
p->device_index = NULL;
}
if (p->name != NULL) {
free(p->name);
p->name = NULL;
}
if (p->filesystem != NULL) {
free(p->filesystem);
p->filesystem = NULL;
}
}
g_mmc_state.partition_count = mmc_read_mbr(MMC_DEVICENAME, g_mmc_state.partitions);
if(g_mmc_state.partition_count == -1)
{
printf("Error in reading mbr!\n");
// keep "partitions" around so we can free the names on a rescan.
g_mmc_state.partition_count = -1;
}
return g_mmc_state.partition_count;
}
static const MmcPartition * mmc_find_partition_by_device_index(const char *device_index) { if (g_mmc_state.partitions != NULL) { int i; for (i = 0; i < g_mmc_state.partitions_allocd; i++) { MmcPartition *p = &g_mmc_state.partitions[i]; if (p->device_index !=NULL && p->name != NULL) { if (strcmp(p->device_index, device_index) == 0) { return p; } } } } return NULL; }
const MmcPartition * mmc_find_partition_by_name(const char *name) { if (name[0] == '/') { return mmc_find_partition_by_device_index(name); }
if (g_mmc_state.partitions != NULL) {
int i;
for (i = 0; i < g_mmc_state.partitions_allocd; i++) {
MmcPartition *p = &g_mmc_state.partitions[i];
if (p->device_index !=NULL && p->name != NULL) {
if (strcmp(p->name, name) == 0) {
return p;
}
}
}
}
return NULL;
}
define MKE2FS_BIN "/sbin/mke2fs"
define TUNE2FS_BIN "/sbin/tune2fs"
define E2FSCK_BIN "/sbin/e2fsck"
int run_exec_process ( char **argv) { pid_t pid; int status; pid = fork(); if (pid == 0) { execv(argv[0], argv); fprintf(stderr, "E:Can't run (%s)\n",strerror(errno)); _exit(-1); }
waitpid(pid, &status, 0);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
return 1;
}
return 0;
}
int format_ext3_device (const char *device) { char *const mke2fs[] = {MKE2FS_BIN, "-j", "-q", device, NULL}; char *const tune2fs[] = {TUNE2FS_BIN, "-C", "1", device, NULL}; // Run mke2fs if(run_exec_process(mke2fs)) { printf("failure while running mke2fs\n"); return -1; }
// Run tune2fs
if(run_exec_process(tune2fs)) {
printf("failure while running mke2fs\n");
return -1;
}
// Run e2fsck
char *const e2fsck[] = {E2FSCK_BIN, "-fy", device, NULL};
if(run_exec_process(e2fsck)) {
printf("failure while running e2fsck\n");
return -1;
}
return 0;
}
int format_ext2_device (const char *device) { // Run mke2fs char *const mke2fs[] = {MKE2FS_BIN, device, NULL}; if(run_exec_process(mke2fs)) return -1;
// Run tune2fs
char *const tune2fs[] = {TUNE2FS_BIN, "-C", "1", device, NULL};
if(run_exec_process(tune2fs))
return -1;
// Run e2fsck
char *const e2fsck[] = {E2FSCK_BIN, "-fy", device, NULL};
if(run_exec_process(e2fsck))
return -1;
return 0;
}
int mmc_format_ext3 (MmcPartition *partition) { char device[128]; strcpy(device, partition->device_index); return format_ext3_device(device); }
int mmc_mount_partition(const MmcPartition *partition, const char *mount_point, int read_only) { const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME; char devname[128]; int rv = -1; strcpy(devname, partition->device_index); if (partition->filesystem == NULL) { printf("Null filesystem!\n"); return rv; } if (!read_only) { rv = mount(devname, mount_point, partition->filesystem, flags, NULL); } if (read_only || rv < 0) { rv = mount(devname, mount_point, partition->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); } } return rv; }
int mmc_raw_copy (const MmcPartition *partition, char *in_file) { int ch; FILE *in; FILE *out; int val = 0; char buf[512]; unsigned sz = 0; unsigned i; int ret = -1; char *out_file = partition->device_index;
in = fopen ( in_file, "r" );
if (in == NULL)
goto ERROR3;
out = fopen ( out_file, "w" );
if (out == NULL)
goto ERROR2;
fseek(in, 0L, SEEK_END);
sz = 1048576*20;//MTK 20MB
fseek(in, 0L, SEEK_SET);
if (sz % 512)
{
while ( ( ch = fgetc ( in ) ) != EOF )
fputc ( ch, out );
}
else
{
for (i=0; i< (sz/512); i++)
{
if ((fread(buf, 512, 1, in)) != 1)
goto ERROR1;
if ((fwrite(buf, 512, 1, out)) != 1)
goto ERROR1;
}
}
fsync(out);
ret = 0;
ERROR1: fclose ( out ); ERROR2: fclose ( in ); ERROR3: return ret;
}
int mmc_raw_dump_internal (const char* in_file, const char *out_file) { int ch; FILE *in; FILE *out; int val = 0; char buf[512]; unsigned sz = 0; unsigned i; int ret = -1;
in = fopen ( in_file, "r" );
if (in == NULL)
goto ERROR3;
out = fopen ( out_file, "w" );
if (out == NULL)
goto ERROR2;
fseek(in, 0L, SEEK_END);
sz = 1048576*20;//MTK 20MB
fseek(in, 0L, SEEK_SET);
if (sz % 512)
{
while ( ( ch = fgetc ( in ) ) != EOF )
fputc ( ch, out );
}
else
{
for (i=0; i< (sz/512); i++)
{
if ((fread(buf, 512, 1, in)) != 1)
goto ERROR1;
if ((fwrite(buf, 512, 1, out)) != 1)
goto ERROR1;
}
}
fsync(out);
ret = 0;
ERROR1: fclose ( out ); ERROR2: fclose ( in ); ERROR3: return ret;
}
// TODO: refactor this to not be a giant copy paste mess int mmc_raw_dump (const MmcPartition *partition, char *out_file) { return mmc_raw_dump_internal(partition->device_index, out_file); }
int mmc_raw_read (const MmcPartition *partition, char *data, int data_size) { int ch; FILE *in; int val = 0; char buf[512]; unsigned sz = 0; unsigned i; int ret = -1; char *in_file = partition->device_index;
in = fopen ( in_file, "r" );
if (in == NULL)
goto ERROR3;
fseek(in, 0L, SEEK_END);
sz = ftell(in);
fseek(in, 0L, SEEK_SET);
fread(data, data_size, 1, in);
ret = 0;
ERROR1: ERROR2: fclose ( in ); ERROR3: return ret;
}
int mmc_raw_write (const MmcPartition *partition, char *data, int data_size) { int ch; FILE *out; int val = 0; char buf[512]; unsigned sz = 0; unsigned i; int ret = -1; char *out_file = partition->device_index;
out = fopen ( out_file, "w" );
if (out == NULL)
goto ERROR3;
fwrite(data, data_size, 1, out);
ret = 0;
ERROR1: ERROR2: fclose ( out ); ERROR3: return ret;
}
int cmd_mmc_restore_raw_partition(const char *partition, const char *filename) { if (partition[0] != '/') { mmc_scan_partitions(); const MmcPartition *p; p = mmc_find_partition_by_name(partition); if (p == NULL) return -1; return mmc_raw_copy(p, filename); } else { return mmc_raw_dump_internal(filename, partition); } }
int cmd_mmc_backup_raw_partition(const char *partition, const char *filename) { if (partition[0] != '/') { mmc_scan_partitions(); const MmcPartition *p; p = mmc_find_partition_by_name(partition); if (p == NULL) return -1; return mmc_raw_dump(p, filename); } else { return mmc_raw_dump_internal(partition, filename); } }
int cmd_mmc_erase_raw_partition(const char *partition) { return 0; }
int cmd_mmc_erase_partition(const char *partition, const char *filesystem) { mmc_scan_partitions(); const MmcPartition *p; p = mmc_find_partition_by_name(partition); if (p == NULL) return -1; return mmc_format_ext3 (p); }
int cmd_mmc_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only) { mmc_scan_partitions(); const MmcPartition *p; p = mmc_find_partition_by_name(partition); if (p == NULL) return -1; return mmc_mount_partition(p, mount_point, read_only); }
int cmd_mmc_get_partition_device(const char *partition, char *device) { mmc_scan_partitions(); const MmcPartition *p; p = mmc_find_partition_by_name(partition); if (p == NULL) return -1; strcpy(device, p->device_index); return 0; }