Beispiel #1
0
static bool write_raw_image_cb(const unsigned char* data,
                               int data_len, void* ctx) {
    int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
    if (r == data_len) return true;
    fprintf(stderr, "%s\n", strerror(errno));
    return false;
}
static int
set_bootloader_message_mtd (const struct bootloader_message *in,
			    const Volume * v)
{
  size_t write_size;

  mtd_scan_partitions ();
  const MtdPartition *part = mtd_find_partition_by_name (v->device);

  if (part == NULL || mtd_partition_info (part, NULL, NULL, &write_size))
	  {
	    LOGE ("Can't find %s\n", v->device);
	    return -1;
	  }

  MtdReadContext *read = mtd_read_partition (part);

  if (read == NULL)
	  {
	    LOGE ("Can't open %s\n(%s)\n", v->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 ("Can't read %s\n(%s)\n", v->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 == NULL)
	  {
	    LOGE ("Can't open %s\n(%s)\n", v->device, strerror (errno));
	    return -1;
	  }
  if (mtd_write_data (write, data, size) != size)
	  {
	    LOGE ("Can't write %s\n(%s)\n", v->device, strerror (errno));
	    mtd_write_close (write);
	    return -1;
	  }
  if (mtd_write_close (write))
	  {
	    LOGE ("Can't finish %s\n(%s)\n", v->device, strerror (errno));
	    return -1;
	  }

  LOGI ("Set boot command \"%s\"\n",
	in->command[0] != 255 ? in->command : "");
  return 0;
}
Beispiel #3
0
// Write a memory buffer to target_mtd partition, a string of the form
// "MTD:<partition>[:...]".  Return 0 on success.
int WriteToMTDPartition(unsigned char* data, size_t len,
                        const char* target_mtd) {
  char* partition = strchr(target_mtd, ':');
  if (partition == NULL) {
    fprintf(stderr, "bad MTD target name \"%s\"\n", target_mtd);
    return -1;
  }
  ++partition;
  // Trim off anything after a colon, eg "MTD:boot:blah:blah:blah...".
  // We want just the partition name "boot".
  partition = strdup(partition);
  char* end = strchr(partition, ':');
  if (end != NULL)
    *end = '\0';

  if (!mtd_partitions_scanned) {
    mtd_scan_partitions();
    mtd_partitions_scanned = 1;
  }

  const MtdPartition* mtd = mtd_find_partition_by_name(partition);
  if (mtd == NULL) {
    fprintf(stderr, "mtd partition \"%s\" not found for writing\n", partition);
    return -1;
  }

  MtdWriteContext* ctx = mtd_write_partition(mtd);
  if (ctx == NULL) {
    fprintf(stderr, "failed to init mtd partition \"%s\" for writing\n",
            partition);
    return -1;
  }

  size_t written = mtd_write_data(ctx, (char*)data, len);
  if (written != len) {
    fprintf(stderr, "only wrote %d of %d bytes to MTD %s\n",
            written, len, partition);
    mtd_write_close(ctx);
    return -1;
  }

  if (mtd_erase_blocks(ctx, -1) < 0) {
    fprintf(stderr, "error finishing mtd write of %s\n", partition);
    mtd_write_close(ctx);
    return -1;
  }

  if (mtd_write_close(ctx)) {
    fprintf(stderr, "error closing mtd write of %s\n", partition);
    return -1;
  }

  free(partition);
  return 0;
}
// FOTA cookie indicates that an android or modem image package
// is available for delta update
int set_fota_cookie_mtd(void)
{
    size_t write_size;

    mtd_scan_partitions();
    const MtdPartition *part = mtd_find_partition_by_name("FOTA");

    if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
        LOGE("Can't find FOTA\n");
        return -1;
    }

    MtdReadContext *read = mtd_read_partition(part);
    if (read == NULL) {
        LOGE("Can't open FOTA\n(%s)\n", strerror(errno));
        return -1;
    }

    ssize_t size = write_size; //writing 1 page is enough
    char data[size];
    ssize_t r = mtd_read_data(read, data, size);
    if (r != size) LOGE("Can't read FOTA\n(%s)\n", strerror(errno));
    mtd_read_close(read);
    if (r != size) return -1;

    //setting FOTA cookie value, 0x64645343
    memset(data, 0x0, sizeof(data));
    data[0] = 0x43;
    data[1] = 0x53;
    data[2] = 0x64;
    data[3] = 0x64;

    MtdWriteContext *write = mtd_write_partition(part);
    if (write == NULL) {
        LOGE("Can't open FOTA\n(%s)\n", strerror(errno));
        return -1;
    }
    if (mtd_write_data(write, data, size) != size) {
        LOGE("Can't write FOTA\n(%s)\n", strerror(errno));
        mtd_write_close(write);
        return -1;
    }
    if (mtd_write_close(write)) {
        LOGE("Can't finish FOTA\n(%s)\n", strerror(errno));
        return -1;
    }

    LOGI("Set FOTA cookie done.\n");
    return 0;
}
int set_bootloader_message(const struct bootloader_message *in) {
    size_t write_size;
    const MtdPartition *part = get_root_mtd_partition(MISC_NAME);
    if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
        LOGE("Can't find %s\n", MISC_NAME);
        return -1;
    }

    MtdReadContext *read = mtd_read_partition(part);
    if (read == NULL) {
        LOGE("Can't open %s\n(%s)\n", MISC_NAME, 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("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno));
    mtd_read_close(read);
    if (r != size) return -1;

    memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));

#ifdef LOG_VERBOSE
    printf("\n--- set_bootloader_message ---\n");
    dump_data(data, size);
    printf("\n");
#endif

    MtdWriteContext *write = mtd_write_partition(part);
    if (write == NULL) {
        LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
        return -1;
    }
    if (mtd_write_data(write, data, size) != size) {
        LOGE("Can't write %s\n(%s)\n", MISC_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }
    if (mtd_write_close(write)) {
        LOGE("Can't finish %s\n(%s)\n", MISC_NAME, strerror(errno));
        return -1;
    }

    LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
    return 0;
}
Beispiel #6
0
int cmd_mtd_restore_raw_partition(const char *partition_name, const char *filename)
{
    const MtdPartition *ptn;
    MtdWriteContext *write;
    void *data;

    FILE* f = fopen(filename, "rb");
    if (f == NULL) {
        fprintf(stderr, "error opening %s", filename);
        return -1;
    }

    if (mtd_scan_partitions() <= 0)
    {
        fprintf(stderr, "error scanning partitions");
        return -1;
    }
    const MtdPartition *mtd = mtd_find_partition_by_name(partition_name);
    if (mtd == NULL)
    {
        fprintf(stderr, "can't find %s partition", partition_name);
        return -1;
    }

    int fd = open(filename, O_RDONLY);
    if (fd < 0)
    {
        printf("error opening %s", filename);
        return -1;
    }
    
    MtdWriteContext* ctx = mtd_write_partition(mtd);
    if (ctx == NULL) {
        printf("error writing %s", partition_name);
        return -1;
    }

    int success = 1;
    char* buffer = malloc(BUFSIZ);
    int read;
    while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
        int wrote = mtd_write_data(ctx, buffer, read);
        success = success && (wrote == read);
    }
    free(buffer);
    fclose(f);

    if (!success) {
        fprintf(stderr, "error writing %s", partition_name);
        return -1;
    }

    if (mtd_erase_blocks(ctx, -1) == -1) {
        fprintf(stderr, "error erasing blocks of %s\n", partition_name);
    }
    if (mtd_write_close(ctx) != 0) {
        fprintf(stderr, "error closing write of %s\n", partition_name);
    }
    printf("%s %s partition\n", success ? "wrote" : "failed to write", partition_name);
    return 0;
}
// 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_find_partition_by_name(partition);
    if (mtd == NULL) {
        fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
        result = strdup("");
        goto done;
    }

    MtdWriteContext* ctx = mtd_write_partition(mtd);
    if (ctx == NULL) {
        fprintf(stderr, "%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 = fopen(filename, "rb");
        if (f == NULL) {
            fprintf(stderr, "%s: can't open %s: %s\n",
                    name, filename, strerror(errno));
            result = strdup("");
            goto done;
        }

        success = true;
        char* buffer = malloc(BUFSIZ);
        int read;
        while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
            int wrote = mtd_write_data(ctx, buffer, read);
            success = success && (wrote == read);
        }
        free(buffer);
        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) {
        fprintf(stderr, "mtd_write_data to %s failed: %s\n",
                partition, strerror(errno));
    }

    if (mtd_erase_blocks(ctx, -1) == -1) {
        fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
    }
    if (mtd_write_close(ctx) != 0) {
        fprintf(stderr, "%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);
}
int
cmd_mtd_restore_raw_partition (const char *partition_name,
			       const char *filename)
{
  const MtdPartition *ptn;
  MtdWriteContext *write;
  void *data;
  unsigned sz;

  if (mtd_scan_partitions () <= 0)
	  {
	    printf ("error scanning partitions");
	    return -1;
	  }
  const MtdPartition *partition = mtd_find_partition_by_name (partition_name);

  if (partition == NULL)
	  {
	    printf ("can't find %s partition", partition_name);
	    return -1;
	  }

  // If the first part of the file matches the partition, skip writing

  int fd = open (filename, O_RDONLY);

  if (fd < 0)
	  {
	    printf ("error opening %s", filename);
	    return -1;
	  }

  char header[HEADER_SIZE];
  int headerlen = read (fd, header, sizeof (header));

  if (headerlen <= 0)
	  {
	    printf ("error reading %s header", filename);
	    return -1;
	  }

  MtdReadContext *in = mtd_read_partition (partition);

  if (in == NULL)
	  {
	    printf ("error opening %s: %s\n", partition, 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)
		    {
		      printf ("error reading %s: %s\n", partition_name,
			      strerror (errno));
		      // just assume it needs re-writing
		    }
	    else if (checklen == headerlen
		     && !memcmp (header, check, headerlen))
		    {
		      printf ("header is the same, not flashing %s\n",
			      partition_name);
		      return 0;
		    }
	    mtd_read_close (in);
	  }

  // Skip the header (we'll come back to it), write everything else
  printf ("flashing %s from %s\n", partition_name, filename);

  MtdWriteContext *out = mtd_write_partition (partition);

  if (out == NULL)
	  {
	    printf ("error writing %s", partition_name);
	    return -1;
	  }

  char buf[HEADER_SIZE];

  memset (buf, 0, headerlen);
  int wrote = mtd_write_data (out, buf, headerlen);

  if (wrote != headerlen)
	  {
	    printf ("error writing %s", partition_name);
	    return -1;
	  }

  int len;

  while ((len = read (fd, buf, sizeof (buf))) > 0)
	  {
	    wrote = mtd_write_data (out, buf, len);
	    if (wrote != len)
		    {
		      printf ("error writing %s", partition_name);
		      return -1;
		    }
	  }
  if (len < 0)
	  {
	    printf ("error reading %s", filename);
	    return -1;
	  }

  if (mtd_write_close (out))
	  {
	    printf ("error closing %s", partition_name);
	    return -1;
	  }

  // Now come back and write the header last

  out = mtd_write_partition (partition);
  if (out == NULL)
	  {
	    printf ("error re-opening %s", partition_name);
	    return -1;
	  }

  wrote = mtd_write_data (out, header, headerlen);
  if (wrote != headerlen)
	  {
	    printf ("error re-writing %s", partition_name);
	    return -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))
	  {
	    printf ("error getting %s block size", partition_name);
	    return -1;
	  }

  if (lseek (fd, headerlen, SEEK_SET) != headerlen)
	  {
	    printf ("error rewinding %s", filename);
	    return -1;
	  }

  int left = block_size - headerlen;

  while (left < 0)
    left += block_size;
  while (left > 0)
	  {
	    len =
	      read (fd, buf,
		    left > (int) sizeof (buf) ? (int) sizeof (buf) : left);
	    if (len <= 0)
		    {
		      printf ("error reading %s", filename);
		      return -1;
		    }
	    if (mtd_write_data (out, buf, len) != len)
		    {
		      printf ("error writing %s", partition_name);
		      return -1;
		    }

	    left -= len;
	  }

  if (mtd_write_close (out))
	  {
	    printf ("error closing %s", partition_name);
	    return -1;
	  }
  return 0;
}
int write_update_for_bootloader(
        const char *update, int update_length,
        int bitmap_width, int bitmap_height, int bitmap_bpp,
        const char *busy_bitmap, const char *fail_bitmap) {
    if (ensure_root_path_unmounted(CACHE_NAME)) {
        LOGE("Can't unmount %s\n", CACHE_NAME);
        return -1;
    }

    const MtdPartition *part = get_root_mtd_partition(CACHE_NAME);
    if (part == NULL) {
        LOGE("Can't find %s\n", CACHE_NAME);
        return -1;
    }

    MtdWriteContext *write = mtd_write_partition(part);
    if (write == NULL) {
        LOGE("Can't open %s\n(%s)\n", CACHE_NAME, strerror(errno));
        return -1;
    }

    /* Write an invalid (zero) header first, to disable any previous
     * update and any other structured contents (like a filesystem),
     * and as a placeholder for the amount of space required.
     */

    struct update_header header;
    memset(&header, 0, sizeof(header));
    const ssize_t header_size = sizeof(header);
    if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
        LOGE("Can't write header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }

    /* Write each section individually block-aligned, so we can write
     * each block independently without complicated buffering.
     */

    memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE);
    header.version = UPDATE_VERSION;
    header.size = header_size;

    off_t image_start_pos = mtd_erase_blocks(write, 0);
    header.image_length = update_length;
    if ((int) header.image_offset == -1 ||
        mtd_write_data(write, update, update_length) != update_length) {
        LOGE("Can't write update to %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }
    off_t busy_start_pos = mtd_erase_blocks(write, 0);
    header.image_offset = mtd_find_write_start(write, image_start_pos);

    header.bitmap_width = bitmap_width;
    header.bitmap_height = bitmap_height;
    header.bitmap_bpp = bitmap_bpp;

    int bitmap_length = (bitmap_bpp + 7) / 8 * bitmap_width * bitmap_height;

    header.busy_bitmap_length = busy_bitmap != NULL ? bitmap_length : 0;
    if ((int) header.busy_bitmap_offset == -1 ||
        mtd_write_data(write, busy_bitmap, bitmap_length) != bitmap_length) {
        LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }
    off_t fail_start_pos = mtd_erase_blocks(write, 0);
    header.busy_bitmap_offset = mtd_find_write_start(write, busy_start_pos);

    header.fail_bitmap_length = fail_bitmap != NULL ? bitmap_length : 0;
    if ((int) header.fail_bitmap_offset == -1 ||
        mtd_write_data(write, fail_bitmap, bitmap_length) != bitmap_length) {
        LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }
    mtd_erase_blocks(write, 0);
    header.fail_bitmap_offset = mtd_find_write_start(write, fail_start_pos);

    /* Write the header last, after all the blocks it refers to, so that
     * when the magic number is installed everything is valid.
     */

    if (mtd_write_close(write)) {
        LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno));
        return -1;
    }

    write = mtd_write_partition(part);
    if (write == NULL) {
        LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno));
        return -1;
    }

    if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
        LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }

    if (mtd_erase_blocks(write, 0) != image_start_pos) {
        LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }

    if (mtd_write_close(write)) {
        LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno));
        return -1;
    }

    return 0;
}
int main(int argc, char **argv) {
    const MtdPartition *ptn;
    MtdWriteContext *write;
    void *data;
    unsigned sz;

    if (argc != 4) {
        fprintf(stderr, "usage: %s type [partition|device] [image_file_path]\n", argv[0]);
        return 2;
    }

	if (0 == strcmp("MTD", argv[1])) {
        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 = read(fd, header, sizeof(header));
        if (headerlen <= 0) die("error reading %s header", argv[2]);

        MtdReadContext *in = mtd_read_partition(partition);
        if (in == NULL) {
            LOGW("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) {
                LOGW("error reading %s: %s\n", argv[1], strerror(errno));
                // just assume it needs re-writing
            } else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
                LOGI("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
        LOGI("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 = 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 (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 = read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left);
            if (len == 0) break;
            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 there is more to write, input data was less than block_size, so pad
        // with nulls.
        memset(buf, 0, sizeof(buf));
        while (left > 0) {
            int pad_len = left > (int)sizeof(buf) ? (int)sizeof(buf) : left;
            if (mtd_write_data(out, buf, pad_len) != pad_len)
                die("error writing %s", argv[1]);
            left -= pad_len;
        }

        if (mtd_write_close(out)) die("error closing %s", argv[1]);
        return 0;
	} else if (0 == strcmp("EMMC", argv[1]) || 0 == strcmp("INAND",argv[1])) {

		int fd = open(argv[3], O_RDONLY);
	    if (fd < 0) die("error opening %s", argv[3]);

	    char header[HEADER_SIZE];
	    int headerlen = read(fd, header, sizeof(header));
	    if (headerlen != sizeof(header)) die("error reading %s header", argv[3]);

		FILE* f = fopen(argv[2], "rb");
	    if (f == NULL ) die("error opening %s", argv[2]);
		char check[HEADER_SIZE];
		int checklen = fread(&check, 1, sizeof(check), f);
	    if (checklen != sizeof(check)) die("error reading %s header", argv[3]);

		fclose(f);
		if(!memcmp(header, check, headerlen)) {
			printf("header is the same, not flashing %s\n", argv[2]);
			close(fd);
	        return 0;
	    }
        	
    	f = fopen(argv[2], "wb");
		
		char buf[HEADER_SIZE];
	    int wrote = fwrite(header, sizeof(header), 1, f);
	    if (wrote != 1) {
			close(fd);
			fclose(f);
			die("error writing %s", argv[2]);
	    }

	    int len;
	    while ((len = read(fd, buf, sizeof(buf))) > 0) {
	        wrote = fwrite(buf, sizeof(buf), 1, f); 
	        if (wrote != 1) {
				close(fd);
				fclose(f);
				die("error writing %s", argv[2]);
	        }
	    }
	    if (len < 0) {
			close(fd);
			fclose(f);
			die("error reading %s", argv[3]);
		}
		close(fd);
		fclose(f);
        
	}
	else {
		die("wrong type %s, it should be MTD or EMMC", argv[1]);
	}

	printf("flash image %s to %s successfully\n",  argv[3], argv[2] );
	
	return 0;	

}
// Write a memory buffer to 'target' partition, a string of the form
// "MTD:<partition>[:...]" or "EMMC:<partition_device>:".  Return 0 on
// success.
int WriteToPartition(unsigned char* data, size_t len,
                        const char* target) {
    char* copy = strdup(target);
    const char* magic = strtok(copy, ":");

    enum PartitionType type;
    if (strcmp(magic, "MTD") == 0) {
        type = MTD;
    } else if (strcmp(magic, "EMMC") == 0) {
        type = EMMC;
    } else {
        printf("WriteToPartition called with bad target (%s)\n", target);
        return -1;
    }
    const char* partition = strtok(NULL, ":");

    if (partition == NULL) {
        printf("bad partition target name \"%s\"\n", target);
        return -1;
    }

    switch (type) {
        case MTD:
            if (!mtd_partitions_scanned) {
                mtd_scan_partitions();
                mtd_partitions_scanned = 1;
            }

            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, (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;
            int success = 0;
            int fd = open(partition, O_RDWR);
            if (fd < 0) {
                printf("failed to open %s: %s\n", partition, strerror(errno));
                return -1;
            }
            int attempt;

            for (attempt = 0; attempt < 2; ++attempt) {
                lseek(fd, start, SEEK_SET);
                while (start < len) {
                    size_t to_write = len - start;
                    if (to_write > 1<<20) to_write = 1<<20;

                    ssize_t written = write(fd, data+start, to_write);
                    if (written < 0) {
                        if (errno == EINTR) {
                            written = 0;
                        } else {
                            printf("failed write writing to %s (%s)\n",
                                   partition, strerror(errno));
                            return -1;
                        }
                    }
                    start += written;
                }
                fsync(fd);

                // drop caches so our subsequent verification read
                // won't just be reading the cache.
                sync();
                int dc = open("/proc/sys/vm/drop_caches", O_WRONLY);
                write(dc, "3\n", 2);
                close(dc);
                sleep(1);
                printf("  caches dropped\n");

                // verify
                lseek(fd, 0, SEEK_SET);
                unsigned char buffer[4096];
                start = len;
                size_t p;
                for (p = 0; p < len; p += sizeof(buffer)) {
                    size_t to_read = len - p;
                    if (to_read > sizeof(buffer)) to_read = sizeof(buffer);

                    size_t so_far = 0;
                    while (so_far < to_read) {
                        ssize_t read_count = read(fd, buffer+so_far, to_read-so_far);
                        if (read_count < 0) {
                            if (errno == EINTR) {
                                read_count = 0;
                            } else {
                                printf("verify read error %s at %zu: %s\n",
                                       partition, p, strerror(errno));
                                return -1;
                            }
                        }
                        if ((size_t)read_count < to_read) {
                            printf("short verify read %s at %zu: %zd %zu %s\n",
                                   partition, p, read_count, to_read, strerror(errno));
                        }
                        so_far += read_count;
                    }

                    if (memcmp(buffer, data+p, to_read)) {
                        printf("verification failed starting at %zu\n", p);
                        start = p;
                        break;
                    }
                }

                if (start == len) {
                    printf("verification read succeeded (attempt %d)\n", attempt+1);
                    success = true;
                    break;
                }
            }

            if (!success) {
                printf("failed to verify after all attempts\n");
                return -1;
            }

            if (close(fd) != 0) {
                printf("error closing %s (%s)\n", partition, strerror(errno));
                return -1;
            }
            sync();
            break;
        }
    }

    free(copy);
    return 0;
}
Beispiel #12
0
// write_raw_image(file, partition)
Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
    char* result = NULL;

    char* partition;
    char* filename;
    if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
        return NULL;
    }

    if (strlen(partition) == 0) {
        ErrorAbort(state, "partition argument to %s can't be empty", name);
        goto done;
    }
    if (strlen(filename) == 0) {
        ErrorAbort(state, "file argument to %s can't be empty", name);
        goto done;
    }

#ifdef BOARD_USES_BMLUTILS
    if (0 == write_raw_image(name, filename)) {
        result = partition;
    }
    result = strdup("Failure");
#else
    mtd_scan_partitions();
    const MtdPartition* mtd = mtd_find_partition_by_name(partition);
    if (mtd == NULL) {
        fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
        result = strdup("");
        goto MMC;
    }

    MtdWriteContext* ctx = mtd_write_partition(mtd);
    if (ctx == NULL) {
        fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
                name, partition);
        result = strdup("");
        goto done;
    }

    bool success;

    FILE* f = fopen(filename, "rb");
    if (f == NULL) {
        fprintf(stderr, "%s: can't open %s: %s\n",
                name, filename, strerror(errno));
        result = strdup("");
        goto done;
    }

    success = true;
    char* buffer = malloc(BUFSIZ);
    int read;
    while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
        int wrote = mtd_write_data(ctx, buffer, read);
        success = success && (wrote == read);
        if (!success) {
            fprintf(stderr, "mtd_write_data to %s failed: %s\n",
                    partition, strerror(errno));
        }
    }
    free(buffer);
    fclose(f);

    if (mtd_erase_blocks(ctx, -1) == -1) {
        fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
    }
    if (mtd_write_close(ctx) != 0) {
        fprintf(stderr, "%s: error closing write of %s\n", name, partition);
    }

    printf("%s %s partition from %s\n",
           success ? "wrote" : "failed to write", partition, filename);

    result = success ? partition : strdup("");
    goto done;

MMC:
    mmc_scan_partitions();
    const MmcPartition* mmc = mmc_find_partition_by_name(partition);
    if (mmc == NULL) {
        fprintf(stderr, "%s: no mmc partition named \"%s\"\n", name, partition);
        result = strdup("");
        goto done;
    }
    if (mmc_raw_copy(mmc, filename)) {
        fprintf(stderr, "%s: error erasing mmc partition named \"%s\"\n", name, partition);
        result = strdup("");
        goto done;
    }
    result = partition;
#endif

done:
    if (result != partition) free(partition);
    free(filename);
    return StringValue(result);
}
/* 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;
    int i;
    char *partitionName = NULL, *imageFile = NULL;
    int deleteImage = 0;

    if (argc < 3) {
		printUsage(argv[0]);
        return 2;
    }

	partitionName = argv[1];
	imageFile = argv[2];

	if (partitionName == NULL || imageFile == NULL) {
		printUsage(argv[0]);
		return 2;
	}



    if (mtd_scan_partitions() <= 0) die("error scanning partitions");
    const MtdPartition *partition = mtd_find_partition_by_name(partitionName);
    if (partition == NULL) die("can't find %s partition", partitionName);

    // If the first part of the file matches the partition, skip writing

    int fd = open(imageFile, O_RDONLY);
    if (fd < 0) die("error opening %s", imageFile);

    char header[HEADER_SIZE];
    int headerlen = read(fd, header, sizeof(header));
    if (headerlen <= 0) die("error reading %s header", imageFile);

    MtdReadContext *in = mtd_read_partition(partition);
    if (in == NULL) {
        LOGW("error opening %s: %s\n", partitionName, 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) {
            LOGW("error reading %s: %s\n", partitionName, strerror(errno));
            // just assume it needs re-writing
        } else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
            LOGI("header is the same, not flashing %s\n", argv[1]);
            if (deleteImage)
				unlink(imageFile);
            return 0;
        }
        mtd_read_close(in);
    }

    // Skip the header (we'll come back to it), write everything else
    LOGI("flashing %s from %s\n", partitionName, imageFile);

    MtdWriteContext *out = mtd_write_partition(partition);
    if (out == NULL) die("error writing %s", partitionName);

    char buf[HEADER_SIZE];
    memset(buf, 0, headerlen);
    int wrote = mtd_write_data(out, buf, headerlen);
    if (wrote != headerlen) die("error writing %s", partitionName);

    int len;
    while ((len = read(fd, buf, sizeof(buf))) > 0) {
        wrote = mtd_write_data(out, buf, len);
        if (wrote != len) die("error writing %s", partitionName);
    }
    if (len < 0) die("error reading %s", imageFile);

    if (mtd_write_close(out)) die("error closing %s", partitionName);

    // Now come back and write the header last

    out = mtd_write_partition(partition);
    if (out == NULL) die("error re-opening %s", partitionName);

    wrote = mtd_write_data(out, header, headerlen);
    if (wrote != headerlen) die("error re-writing %s", partitionName);

    // 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", partitionName);

    if (lseek(fd, headerlen, SEEK_SET) != headerlen)
        die("error rewinding %s", imageFile);

    int left = block_size - headerlen;
    while (left < 0) left += block_size;
    while (left > 0) {
        len = read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left);
        if (len <= 0) die("error reading %s", imageFile);
        if (mtd_write_data(out, buf, len) != len)
            die("error writing %s", partitionName);
        left -= len;
    }

    if (mtd_write_close(out)) die("error closing %s", partitionName);

	if (deleteImage)
		unlink(imageFile);

    return 0;
}
Beispiel #14
0
int write_update_for_bootloader(
        const char *update, int update_length,
        const char *log_filename) {
    const MtdPartition *part = mtd_find_partition_by_name(CACHE_NAME);
    if (part == NULL) {
        LOGE("Can't find %s\n", CACHE_NAME);
        return -1;
    }

    MtdWriteContext *write = mtd_write_partition(part);
    if (write == NULL) {
        LOGE("Can't open %s\n(%s)\n", CACHE_NAME, strerror(errno));
        return -1;
    }

    /* Write an invalid (zero) header first, to disable any previous
     * update and any other structured contents (like a filesystem),
     * and as a placeholder for the amount of space required.
     */

    struct update_header header;
    memset(&header, 0, sizeof(header));
    const ssize_t header_size = sizeof(header);
    if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
        LOGE("Can't write header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }

    /* Write each section individually block-aligned, so we can write
     * each block independently without complicated buffering.
     */

    memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE);
    header.version = UPDATE_VERSION;
    header.size = header_size;

    if (log_filename != NULL) {
        // Write 1 byte into the following block, then fill to the end
        // in order to reserve that block.  We'll use the block to
        // send a copy of the log through to the next invocation of
        // recovery.  We write the log as late as possible in order to
        // capture any messages emitted by this function.
        mtd_erase_blocks(write, 0);
        if (mtd_write_data(write, (char*) &header, 1) != 1) {
            LOGE("Can't write log block to %s\n(%s)\n",
                 CACHE_NAME, strerror(errno));
            mtd_write_close(write);
            return -1;
        }
    }

    off_t image_start_pos = mtd_erase_blocks(write, 0);
    header.image_length = update_length;
    if ((int) header.image_offset == -1 ||
        mtd_write_data(write, update, update_length) != update_length) {
        LOGE("Can't write update to %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }
    mtd_erase_blocks(write, 0);
    /* Sending image offset as it is.Apps bootloader will take care of bad blocks */
    header.image_offset = 0x80000;

    /* Write the header last, after all the blocks it refers to, so that
     * when the magic number is installed everything is valid.
     */

    if (mtd_write_close(write)) {
        LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno));
        return -1;
    }

    write = mtd_write_partition(part);
    if (write == NULL) {
        LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno));
        return -1;
    }

    if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
        LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }

    if (log_filename != NULL) {
        LOGE("writing log\n");
        size_t erase_size;
        if (mtd_partition_info(part, NULL, &erase_size, NULL) != 0) {
            LOGE("Error reading block size\n(%s)\n", strerror(errno));
            mtd_write_close(write);
            return -1;
        }
        mtd_erase_blocks(write, 0);

        if (erase_size > 0) {
            char* log = malloc(erase_size);
            FILE* f = fopen(log_filename, "rb");
            // The fseek() may fail if it tries to go before the
            // beginning of the log, but that's okay because we want
            // to be positioned at the start anyway.
            fseek(f, -(erase_size-sizeof(size_t)-LOG_MAGIC_SIZE), SEEK_END);
            memcpy(log, LOG_MAGIC, LOG_MAGIC_SIZE);
            size_t read = fread(log+sizeof(size_t)+LOG_MAGIC_SIZE,
                                1, erase_size-sizeof(size_t)-LOG_MAGIC_SIZE, f);
            LOGI("read %d bytes from log\n", (int)read);
            *(size_t *)(log + LOG_MAGIC_SIZE) = read;
            fclose(f);
            if (mtd_write_data(write, log, erase_size) != erase_size) {
                LOGE("failed to store log in cache partition\n(%s)\n",
                     strerror(errno));
                mtd_write_close(write);
            }
            free(log);
        }
    }

    if (mtd_erase_blocks(write, 0) != image_start_pos) {
        LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }

    LOGE("closing partition\n");
    if (mtd_write_close(write)) {
        LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno));
        return -1;
    }

    return 0;
}
Beispiel #15
0
int main(int argc, char **argv) {
    const MtdPartition *ptn;
    MtdWriteContext *write;
    void *data;
    unsigned sz;

	LOGI("enter\n");
    if (argc != 3) {
		LOGI("exit1\n");
        fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
        return 2;
    }

    int fd = open(argv[2], O_RDONLY);
    if (fd < 0) die("error opening %s", argv[2]);
    close(fd);

    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]);
    
    LOGI("flashing %s from %s\n", argv[1], argv[2]);

    if( 0 == write_recovery(argv[2], argv[1]) )
    {
        if( remove(argv[2]) == 0 )
            LOGI("flash success!\n");
        else
            die("error remove file: %s", argv[2]);
    }
    else
        die("error closing %s", argv[1]);

#if 0
    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]);

	LOGI("read header!\n");
	
    char header[HEADER_SIZE];
    int headerlen = read(fd, header, sizeof(header));
    if (headerlen <= 0) die("error reading %s header", argv[2]);

    MtdReadContext *in = mtd_read_partition(partition);
    if (in == NULL) {
        LOGW("error opening %s: %s\n", argv[1], strerror(errno));
        // just assume it needs re-writing
    } else {
    	LOGI("mtd_read_data\n");
        char check[HEADER_SIZE];
        int checklen = mtd_read_data(in, check, sizeof(check));
        if (checklen <= 0) {
            LOGW("error reading %s: %s\n", argv[1], strerror(errno));
            // just assume it needs re-writing
        } else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
            LOGI("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
    LOGI("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 = 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 (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 = 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]);
#endif
    return 0;
}
// Write a memory buffer to 'target' partition, a string of the form
// "MTD:<partition>[:...]" or "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(unsigned char* data, size_t len, const char* target) {
    std::string copy(target);
    std::vector<std::string> pieces = android::base::Split(copy, ":");

    if (pieces.size() < 2) {
        printf("WriteToPartition called with bad target (%s)\n", target);
        return -1;
    }

    enum PartitionType type;
    if (pieces[0] == "MTD") {
        type = MTD;
    } else if (pieces[0] == "EMMC") {
        type = EMMC;
    } else {
        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<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 = open(partition, O_RDWR | O_SYNC);
            if (fd < 0) {
                printf("failed to open %s: %s\n", partition, strerror(errno));
                return -1;
            }

            for (size_t attempt = 0; attempt < 2; ++attempt) {
                if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
                    printf("failed seek on %s: %s\n", partition, strerror(errno));
                    return -1;
                }
                while (start < len) {
                    size_t to_write = len - start;
                    if (to_write > 1<<20) to_write = 1<<20;

                    ssize_t written = TEMP_FAILURE_RETRY(write(fd, data+start, to_write));
                    if (written == -1) {
                        printf("failed write writing to %s: %s\n", partition, strerror(errno));
                        return -1;
                    }
                    start += written;
                }
                if (fsync(fd) != 0) {
                   printf("failed to sync to %s (%s)\n", partition, strerror(errno));
                   return -1;
                }
                if (close(fd) != 0) {
                   printf("failed to close %s (%s)\n", partition, strerror(errno));
                   return -1;
                }
                fd = open(partition, O_RDONLY);
                if (fd < 0) {
                   printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno));
                   return -1;
                }

                // Drop caches so our subsequent verification read
                // won't just be reading the cache.
                sync();
                int dc = open("/proc/sys/vm/drop_caches", O_WRONLY);
                if (TEMP_FAILURE_RETRY(write(dc, "3\n", 2)) == -1) {
                    printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
                } else {
                    printf("  caches dropped\n");
                }
                close(dc);
                sleep(1);

                // verify
                if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
                    printf("failed to seek back to beginning of %s: %s\n",
                           partition, strerror(errno));
                    return -1;
                }
                unsigned char buffer[4096];
                start = len;
                for (size_t p = 0; p < len; p += sizeof(buffer)) {
                    size_t to_read = len - p;
                    if (to_read > sizeof(buffer)) {
                        to_read = sizeof(buffer);
                    }

                    size_t so_far = 0;
                    while (so_far < to_read) {
                        ssize_t read_count =
                                TEMP_FAILURE_RETRY(read(fd, buffer+so_far, to_read-so_far));
                        if (read_count == -1) {
                            printf("verify read error %s at %zu: %s\n",
                                   partition, p, strerror(errno));
                            return -1;
                        }
                        if (static_cast<size_t>(read_count) < to_read) {
                            printf("short verify read %s at %zu: %zd %zu %s\n",
                                   partition, p, read_count, to_read, strerror(errno));
                        }
                        so_far += read_count;
                    }

                    if (memcmp(buffer, data+p, to_read) != 0) {
                        printf("verification failed starting at %zu\n", p);
                        start = p;
                        break;
                    }
                }

                if (start == len) {
                    printf("verification read succeeded (attempt %zu)\n", attempt+1);
                    success = true;
                    break;
                }
            }

            if (!success) {
                printf("failed to verify after all attempts\n");
                return -1;
            }

            if (close(fd) != 0) {
                printf("error closing %s (%s)\n", partition, strerror(errno));
                return -1;
            }
            sync();
            break;
        }
    }

    return 0;
}
// Write a memory buffer to 'target' partition, a string of the form
// "MTD:<partition>[:...]" or "EMMC:<partition_device>:".  Return 0 on
// success.
int WriteToPartition(unsigned char* data, size_t len,
                        const char* target) {
    char* copy = strdup(target);
    const char* magic = strtok(copy, ":");

    enum PartitionType type;

#if 0 //wschen 2012-05-24
    if (strcmp(magic, "MTD") == 0) {
        type = MTD;
    } else if (strcmp(magic, "EMMC") == 0) {
        type = EMMC;
    } else {
        printf("WriteToPartition called with bad target (%s)\n", target);
        free(copy);
        return -1;
    }
#else
    switch (phone_type()) {
        case NAND_TYPE:
            type = MTD;
            break;
        case EMMC_TYPE:
            type = EMMC;
            break;
        default:
            printf("WriteToPartition called with bad target (%s)\n", target);
            free(copy);
            return -1;
    }
#endif

    const char* partition = strtok(NULL, ":");

    if (partition == NULL) {
        printf("bad partition target name \"%s\"\n", target);
        free(copy);
        return -1;
    }

    switch (type) {
        case MTD:
            if (!mtd_partitions_scanned) {
                mtd_scan_partitions();
                mtd_partitions_scanned = 1;
            }

            const MtdPartition* mtd = mtd_find_partition_by_name(partition);
            if (mtd == NULL) {
                printf("mtd partition \"%s\" not found for writing\n",
                       partition);
                free(copy);
                return -1;
            }

            MtdWriteContext* ctx = mtd_write_partition(mtd);
            if (ctx == NULL) {
                printf("failed to init mtd partition \"%s\" for writing\n",
                       partition);
                free(copy);
                return -1;
            }

            size_t written = mtd_write_data(ctx, (char*)data, len);
            if (written != len) {
                printf("only wrote %d of %d bytes to MTD %s\n",
                       written, len, partition);
                mtd_write_close(ctx);
                free(copy);
                return -1;
            }

            if (mtd_erase_blocks(ctx, -1) < 0) {
                printf("error finishing mtd write of %s\n", partition);
                mtd_write_close(ctx);
                free(copy);
                return -1;
            }

            if (mtd_write_close(ctx)) {
                printf("error closing mtd write of %s\n", partition);
                free(copy);
                return -1;
            }
            break;

        case EMMC:
            ;
#if 0 //wschen 2011-11-29
            FILE* f = fopen(partition, "wb");
            if (fwrite(data, 1, len, f) != len) {
                printf("short write writing to %s (%s)\n",
                       partition, strerror(errno));
                free(copy);
                return -1;
            }
            if (fclose(f) != 0) {
                printf("error closing %s (%s)\n", partition, strerror(errno));
                free(copy);
                return -1;
            }
#else
            int dev;
            if (!strcmp(partition, "boot")) {
                dev = open("/dev/bootimg", O_RDWR | O_SYNC);
                if (dev == -1) {
                    printf("failed to open emmc partition \"/dev/bootimg\": %s\n", strerror(errno));
                    free(copy);
                    return -1;
                }
            } else {
                char dev_name[32];

                snprintf(dev_name, sizeof(dev_name), "/dev/%s", partition);
                dev = open(dev_name, O_RDWR | O_SYNC);
                if (dev == -1) {
                    printf("failed to open emmc partition \"%s\": %s\n", dev_name, strerror(errno));
                    free(copy);
                    return -1;
                }
            }

            if (write(dev, data, len) != len) {
                printf("short write writing to %s (%s)\n", partition, strerror(errno));
                close(dev);
                free(copy);
                return -1;
            }
            close(dev);
            sync();
#endif
            break;
    }

    free(copy);
    return 0;
}
Beispiel #18
0
int set_bootloader_message(const struct bootloader_message *in) {
//	INFO("Enter set_bootloader_message\n");
    if(in->command[0] != 0)
    {
    	LOGI("command:\n%s\n", in->command);
    	LOGI("status:\n%s\n", in->status);
    	LOGI("recovery:\n%s\n", in->recovery);
    }
    else
    	LOGI("bootloader_message is empty\n");
    	
    size_t write_size;
    const MtdPartition *part = get_root_mtd_partition(MISC_NAME);
    if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
        LOGE("Can't find %s\n", MISC_NAME);
        return -1;
    }

    MtdReadContext *read = mtd_read_partition(part);
    if (read == NULL) {
        LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
        return -1;
    }
//cmy: 以sector为单位
    ssize_t size = write_size * MISC_PAGES;
    char data[size<<9];//cmy
    ssize_t r = mtd_read_data(read, data, size);
    if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno));
    mtd_read_close(read);
    if (r != size) return -1;

    memcpy(&data[(write_size<<9) * MISC_COMMAND_PAGE], in, sizeof(*in));
	
#ifdef LOG_VERBOSE
    printf("\n--- set_bootloader_message ---\n");
    dump_data(data, size<<9);
    printf("\n");
#endif
//    INFO("\n--- set_bootloader_message ---\n");
//    dump_data(data, size);
//    INFO("\n");

// CMY:由于底层写数据时会自动执行擦除操作,因些我们可以直接写数据而不考虑擦除动作
#if 1
    MtdWriteContext *write = mtd_write_partition(part);
    if (write == NULL) {
        LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
        return -1;
    }
	LOGI("Write bootloader message\n");
    if (mtd_write_data(write, data, size) != size) {
        LOGE("Can't write %s\n(%s)\n", MISC_NAME, strerror(errno));
        mtd_write_close(write);
        return -1;
    }
    if (mtd_write_close(write)) {
        LOGE("Can't finish %s\n(%s)\n", MISC_NAME, strerror(errno));
        return -1;
    }
#endif

    LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
    return 0;
}
Beispiel #19
0
// Write a memory buffer to 'target' partition, a string of the form
// "MTD:<partition>[:...]" or "EMMC:<partition_device>:".  Return 0 on
// success.
int WriteToPartition(unsigned char* data, size_t len,
                        const char* target) {
    char* copy = strdup(target);
    const char* magic = strtok(copy, ":");

    enum PartitionType type;
    if (strcmp(magic, "MTD") == 0) {
        type = MTD;
    } else if (strcmp(magic, "EMMC") == 0) {
        type = EMMC;
    } else {
        printf("WriteToPartition called with bad target (%s)\n", target);
        return -1;
    }
    const char* partition = strtok(NULL, ":");

    if (partition == NULL) {
        printf("bad partition target name \"%s\"\n", target);
        return -1;
    }

    switch (type) {
        case MTD:
            if (!mtd_partitions_scanned) {
                mtd_scan_partitions();
                mtd_partitions_scanned = 1;
            }

            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, (char*)data, len);
            if (written != len) {
                printf("only wrote %d of %d 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:
            ;
            FILE* f = fopen(partition, "wb");
            if (fwrite(data, 1, len, f) != len) {
                printf("short write writing to %s (%s)\n",
                       partition, strerror(errno));
                return -1;
            }
            if (fclose(f) != 0) {
                printf("error closing %s (%s)\n", partition, strerror(errno));
                return -1;
            }
            break;
    }

    free(copy);
    return 0;
}
int main(int argc, char **argv) {
	const MtdPartition *ptn;
	MtdWriteContext *write;
	void *data;
	unsigned sz;
	int rc = 0;

	if (argc != 3) {
		fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
		return -EINVAL;
	}

	rc = mtd_scan_partitions();
	if (rc < 0) {
		fprintf(stderr, "error scanning partitions\n");
		return rc;
	} else if (rc == 0) {
		fprintf(stderr, "no partitions found\n");
		return -ENODEV;
	}

	const MtdPartition *partition = mtd_find_partition_by_name(argv[1]);
	if (partition == NULL) {
		fprintf(stderr, "can't find %s partition\n", argv[1]);
		return -ENODEV;
	}

	// If the first part of the file matches the partition, skip writing

	int fd = open(argv[2], O_RDONLY);
	if (fd < 0) {
		fprintf(stderr, "error opening %s\n", argv[2]);
		return fd;
	}

	char header[HEADER_SIZE];
	int headerlen = TEMP_FAILURE_RETRY(read(fd, header, sizeof(header)));
	if (headerlen <= 0) {
		fprintf(stderr, "error reading %s header\n", argv[2]);
		rc = -EIO;
		goto exit;
	}

	MtdReadContext *in = mtd_read_partition(partition);
	if (in == NULL) {
		fprintf(stderr, "error opening %s: %s\n", argv[1], strerror(errno));
		rc = -ENXIO;
		goto exit;
		// just assume it needs re-writing
	} else {
		char check[HEADER_SIZE];
		int checklen = mtd_read_data(in, check, sizeof(check));
		if (checklen <= 0) {
			fprintf(stderr, "error reading %s: %s\n", argv[1], strerror(errno));
			rc = -EIO;
			goto exit;
			// just assume it needs re-writing
		} else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
			fprintf(stderr, "header is the same, not flashing %s\n", argv[1]);
			rc = -EINVAL;
			goto exit;
		}
		mtd_read_close(in);
	}

	// Skip the header (we'll come back to it), write everything else
	printf("flashing %s from %s\n", argv[1], argv[2]);

	MtdWriteContext *out = mtd_write_partition(partition);
	if (out == NULL) {
		fprintf(stderr, "error writing %s\n", argv[1]);
		rc = -EIO;
		goto exit;
	}

	char buf[HEADER_SIZE];
	memset(buf, 0, headerlen);
	int wrote = mtd_write_data(out, buf, headerlen);
	if (wrote != headerlen) {
		fprintf(stderr, "error writing %s\n", argv[1]);
		rc = -EIO;
		goto exit;
	}

	int len;
	while ((len = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)))) > 0) {
		wrote = mtd_write_data(out, buf, len);
		if (wrote != len) {
			fprintf(stderr, "error writing %s\n", argv[1]);
			rc = -EIO;
			goto exit;
		}
	}
	if (len < 0) {
		fprintf(stderr, "error reading %s\n", argv[2]);
		rc = -EIO;
		goto exit;
	}

	rc = mtd_write_close(out);
	if (rc < 0) {
		fprintf(stderr, "error closing %s\n", argv[1]);
		goto exit;
	}

	// Now come back and write the header last

	out = mtd_write_partition(partition);
	if (out == NULL) {
		fprintf(stderr, "error re-opening %s\n", argv[1]);
		rc = -EIO;
		goto exit;
	}

	wrote = mtd_write_data(out, header, headerlen);
	if (wrote != headerlen) {
		fprintf(stderr, "error re-writing %s\n", argv[1]);
		rc = -EIO;
		goto exit;
	}

	// Need to write a complete block, so write the rest of the first block
	size_t block_size;
	rc = mtd_partition_info(partition, NULL, &block_size, NULL);
	if (rc < 0) {
		fprintf(stderr, "error getting %s block size\n", argv[1]);
		goto exit;
	}

	if (TEMP_FAILURE_RETRY(lseek(fd, headerlen, SEEK_SET)) != headerlen) {
		fprintf(stderr, "error rewinding %s\n", argv[2]);
		rc = -ESPIPE;
		goto exit;
	}

	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) {
			fprintf(stderr, "error reading %s\n", argv[2]);
			rc = -EIO;
			goto exit;
		}
		if (mtd_write_data(out, buf, len) != len) {
			fprintf(stderr, "error writing %s\n", argv[1]);
			rc = -EIO;
			goto exit;
		}
		left -= len;
	}

	rc = mtd_write_close(out);
	if (rc < 0) {
		fprintf(stderr, "error closing %s\n", argv[1]);
		goto exit;
	}

	rc = 0;

exit:
	close(fd);
	return rc;
}