android_bootable_recovery icon indicating copy to clipboard operation
android_bootable_recovery copied to clipboard

mmcutils_mtk.c

Open WhyMeta opened this issue 10 years ago • 0 comments

/*

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

WhyMeta avatar Sep 03 '14 10:09 WhyMeta