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