static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_concat *concat = CONCAT(mtd); int i, err = 0; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; uint64_t size; if (ofs >= subdev->size) { size = 0; ofs -= subdev->size; continue; } if (ofs + len > subdev->size) size = subdev->size - ofs; else size = len; err = mtd_unlock(subdev, ofs, size); if (err) break; len -= size; if (len == 0) break; err = -EINVAL; ofs = 0; } return err; }
static ssize_t mtd_op_protect(struct cdev *cdev, size_t count, loff_t offset, int prot) { struct mtd_info *mtd = cdev->priv; if (!mtd->unlock || !mtd->lock) return -ENOSYS; if (prot) return mtd_lock(mtd, offset, count); else return mtd_unlock(mtd, offset, count); }
void format_mount_2nd_jffs2(void) { int format = 0; char s[256]; int size; int part; const char *p; if (!wait_action_idle(10)) return; if (!mtd_getinfo(SECOND_JFFS2_PARTITION, &part, &size)) return; _dprintf("Format 2nd jffs2: %d, %d\n", part, size); if(!check_in_rootfs(SECOND_JFFS2_PATH, "2nd_jffs", format)) return; if (!mtd_unlock(SECOND_JFFS2_PARTITION)) { error("unlocking"); return; } modprobe(JFFS_NAME); sprintf(s, MTD_BLKDEV(%d), part); if (mount(s, SECOND_JFFS2_PATH, JFFS_NAME, MS_NOATIME, "") != 0) { if( (get_model()==MODEL_RTAC56U || get_model()==MODEL_RTAC56S || get_model()==MODEL_RTAC3200 || get_model()==MODEL_RTAC68U || get_model()==MODEL_RPAC68U || get_model()==MODEL_DSLAC68U || get_model()==MODEL_RTAC87U || get_model()==MODEL_RTAC88U || get_model()==MODEL_RTAC3100 || get_model()==MODEL_RTAC5300 || get_model==MODEL_RTAC5300R || get_model()==MODEL_RTN18U || get_model()==MODEL_RTAC1200G || get_model()==MODEL_RTAC1200GP) ^ (mtd_erase(SECOND_JFFS2_PARTITION)) ){ error("formatting"); return; } format = 1; if (mount(s, SECOND_JFFS2_PATH, JFFS_NAME, MS_NOATIME, "") != 0) { _dprintf("*** jffs2 2-nd mount error\n"); //modprobe_r(JFFS_NAME); error("mounting"); return; } } sprintf(s, "rm -rf %s/*", SECOND_JFFS2_PATH); system(s); notice_set("2nd_jffs", format ? "Formatted" : "Loaded"); if (((p = nvram_get("jffs2_exec")) != NULL) && (*p != 0)) { chdir(SECOND_JFFS2_PATH); system(p); chdir("/"); } run_userfile(SECOND_JFFS2_PATH, ".asusrouter", SECOND_JFFS2_PATH, 3); }
static void test_mtd_unlock(void **state) { int eb = 0xBA; struct mtd_dev_info mtd; memset(&mtd, 0, sizeof(mtd)); mtd.bb_allowed = 1; mtd.eb_cnt = 1024; mtd.eb_size = 128; struct erase_info_user ei; memset(&ei, 0, sizeof(ei)); ei.start = eb * mtd.eb_size; ei.length = mtd.eb_size; expect_ioctl(MEMUNLOCK, 0, &ei); int r = mtd_unlock(&mtd, 4, eb); assert_int_equal(r, 0); (void) state; }
int main (int argc, char **argv) { int ch, i, boot, imagefd = 0, force, unlocked; char *erase[MAX_ARGS], *device = NULL; char *fis_layout = NULL; size_t offset = 0, part_offset = 0, dump_len = 0; enum { CMD_ERASE, CMD_WRITE, CMD_UNLOCK, CMD_JFFS2WRITE, CMD_FIXTRX, CMD_FIXSEAMA, CMD_VERIFY, CMD_DUMP, } cmd = -1; erase[0] = NULL; boot = 0; force = 0; buflen = 0; quiet = 0; no_erase = 0; while ((ch = getopt(argc, argv, #ifdef FIS_SUPPORT "F:" #endif "frnqe:d:s:j:p:o:l:")) != -1) switch (ch) { case 'f': force = 1; break; case 'r': boot = 1; break; case 'n': no_erase = 1; break; case 'j': jffs2file = optarg; break; case 's': errno = 0; jffs2_skip_bytes = strtoul(optarg, 0, 0); if (errno) { fprintf(stderr, "-s: illegal numeric string\n"); usage(); } break; case 'q': quiet++; break; case 'e': i = 0; while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS)) i++; erase[i++] = optarg; erase[i] = NULL; break; case 'd': jffs2dir = optarg; break; case 'p': errno = 0; part_offset = strtoul(optarg, 0, 0); if (errno) { fprintf(stderr, "-p: illegal numeric string\n"); usage(); } break; case 'l': errno = 0; dump_len = strtoul(optarg, 0, 0); if (errno) { fprintf(stderr, "-l: illegal numeric string\n"); usage(); } break; case 'o': errno = 0; offset = strtoul(optarg, 0, 0); if (errno) { fprintf(stderr, "-o: illegal numeric string\n"); usage(); } break; #ifdef FIS_SUPPORT case 'F': fis_layout = optarg; break; #endif case '?': default: usage(); } argc -= optind; argv += optind; if (argc < 2) usage(); if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) { cmd = CMD_UNLOCK; device = argv[1]; } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) { cmd = CMD_ERASE; device = argv[1]; } else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) { cmd = CMD_FIXTRX; device = argv[1]; } else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) { cmd = CMD_FIXSEAMA; device = argv[1]; } else if ((strcmp(argv[0], "verify") == 0) && (argc == 3)) { cmd = CMD_VERIFY; imagefile = argv[1]; device = argv[2]; } else if ((strcmp(argv[0], "dump") == 0) && (argc == 2)) { cmd = CMD_DUMP; device = argv[1]; } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { cmd = CMD_WRITE; device = argv[2]; if (strcmp(argv[1], "-") == 0) { imagefile = "<stdin>"; imagefd = 0; } else { imagefile = argv[1]; if ((imagefd = open(argv[1], O_RDONLY)) < 0) { fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); exit(1); } } if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); exit(1); } /* check trx file before erasing or writing anything */ if (!image_check(imagefd, device) && !force) { fprintf(stderr, "Image check failed.\n"); exit(1); } } else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) { cmd = CMD_JFFS2WRITE; device = argv[2]; imagefile = argv[1]; if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); exit(1); } } else { usage(); } sync(); i = 0; unlocked = 0; while (erase[i] != NULL) { mtd_unlock(erase[i]); mtd_erase(erase[i]); if (strcmp(erase[i], device) == 0) unlocked = 1; i++; } switch (cmd) { case CMD_UNLOCK: if (!unlocked) mtd_unlock(device); break; case CMD_VERIFY: mtd_verify(device, imagefile); break; case CMD_DUMP: mtd_dump(device, offset, dump_len); break; case CMD_ERASE: if (!unlocked) mtd_unlock(device); mtd_erase(device); break; case CMD_WRITE: if (!unlocked) mtd_unlock(device); mtd_write(imagefd, device, fis_layout, part_offset); break; case CMD_JFFS2WRITE: if (!unlocked) mtd_unlock(device); mtd_write_jffs2(device, imagefile, jffs2dir); break; case CMD_FIXTRX: if (mtd_fixtrx) { mtd_fixtrx(device, offset); } case CMD_FIXSEAMA: if (mtd_fixseama) mtd_fixseama(device, 0); break; } sync(); if (boot) do_reboot(); return 0; }
void start_jffs2(void) { if (!nvram_match("jffs2_on", "1")) { notice_set("jffs", ""); return; } int format = 0; char s[256]; int size; int part; const char *p; struct statfs sf; int model = 0; int i = 0; while(1) { if (wait_action_idle(10)) break; else i++; if(i>=10) { _dprintf("Mount jffs2 failed!"); return; } } if (!mtd_getinfo(JFFS2_PARTITION, &part, &size)) return; model = get_model(); _dprintf("start jffs2: %d, %d\n", part, size); if (nvram_match("jffs2_format", "1")) { nvram_set("jffs2_format", "0"); nvram_commit_x(); if (!mtd_erase(JFFS_NAME)) { error("formatting"); return; } format = 1; } sprintf(s, "%d", size); p = nvram_get("jffs2_size"); if ((p == NULL) || (strcmp(p, s) != 0)) { if (format) { nvram_set("jffs2_size", s); nvram_commit_x(); } else if ((p != NULL) && (*p != 0)) { error("verifying known size of"); return; } } if (statfs("/jffs", &sf) == 0) { switch(model) { case MODEL_RTAC56S: case MODEL_RTAC56U: case MODEL_RTAC3200: case MODEL_DSLAC68U: case MODEL_RPAC68U: case MODEL_RTAC68U: case MODEL_RTAC87U: case MODEL_RTN18U: case MODEL_RTN65U: case MODEL_RTN14U: // it should be better to use LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,6,36) { if (sf.f_type != 0x73717368 /* squashfs */) { // already mounted notice_set("jffs", format ? "Formatted" : "Loaded"); return; } break; } default: { if (sf.f_type != 0x71736873 /* squashfs */) { // already mounted notice_set("jffs", format ? "Formatted" : "Loaded"); return; } break; } } } if (nvram_get_int("jffs2_clean_fs")) { if (!mtd_unlock(JFFS2_PARTITION)) { error("unlocking"); return; } } modprobe(JFFS_NAME); sprintf(s, MTD_BLKDEV(%d), part); if (mount(s, "/jffs", JFFS_NAME, MS_NOATIME, "") != 0) { if (!mtd_erase(JFFS_NAME)) { error("formatting"); return; } format = 1; if (mount(s, "/jffs", JFFS_NAME, MS_NOATIME, "") != 0) { _dprintf("*** jffs2 2-nd mount error\n"); //modprobe_r(JFFS_NAME); error("mounting"); return; } } #ifdef TEST_INTEGRITY int test; if (format) { if (f_write("/jffs/.tomato_do_not_erase", &size, sizeof(size), 0, 0) != sizeof(size)) { stop_jffs2(0); error("setting integrity test for"); return; } } if ((f_read("/jffs/.tomato_do_not_erase", &test, sizeof(test)) != sizeof(test)) || (test != size)) { stop_jffs2(0); error("testing integrity of"); return; } #endif if (nvram_get_int("jffs2_clean_fs")) { _dprintf("Clean /jffs/*\n"); system("rm -fr /jffs/*"); nvram_unset("jffs2_clean_fs"); nvram_commit_x(); } notice_set("jffs", format ? "Formatted" : "Loaded"); if (((p = nvram_get("jffs2_exec")) != NULL) && (*p != 0)) { chdir("/jffs"); system(p); chdir("/"); } run_userfile("/jffs", ".asusrouter", "/jffs", 3); if (!check_if_dir_exist("/jffs/scripts/")) mkdir("/jffs/scripts/", 0755); if (!check_if_dir_exist("/jffs/configs/")) mkdir("/jffs/configs/", 0755); }
void format_mount_2nd_jffs2(void) { int format = 0; char s[256]; int size; int part; const char *p; struct statfs sf; int model = 0; if (!wait_action_idle(10)) return; if (!mtd_getinfo(SECOND_JFFS2_PARTITION, &part, &size)) return; _dprintf("Format 2nd jffs2: %d, %d\n", part, size); model = get_model(); sprintf(s, "%d", size); if (statfs(SECOND_JFFS2_PATH, &sf) == 0) { switch(model) { case MODEL_RTAC56S: case MODEL_RTAC56U: case MODEL_RTAC3200: case MODEL_DSLAC68U: case MODEL_RPAC68U: case MODEL_RTAC68U: case MODEL_RTAC87U: case MODEL_RTN18U: case MODEL_RTN65U: case MODEL_RTN14U: // it should be better to use LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,6,36) { if (sf.f_type != 0x73717368 /* squashfs */) { // already mounted notice_set("2nd_jffs", format ? "Formatted" : "Loaded"); return; } break; } default: { if (sf.f_type != 0x71736873 /* squashfs */) { // already mounted notice_set("2nd_jffs", format ? "Formatted" : "Loaded"); return; } break; } } } if (!mtd_unlock(SECOND_JFFS2_PARTITION)) { error("unlocking"); return; } modprobe(JFFS_NAME); sprintf(s, MTD_BLKDEV(%d), part); if (mount(s, SECOND_JFFS2_PATH, JFFS_NAME, MS_NOATIME, "") != 0) { if( (get_model()==MODEL_RTAC56U || get_model()==MODEL_RTAC56S || get_model()==MODEL_RTAC3200 || get_model()==MODEL_RTAC68U || get_model()==MODEL_RPAC68U || get_model()==MODEL_DSLAC68U || get_model()==MODEL_RTAC87U || get_model()==MODEL_RTN18U) ^ (!mtd_erase(JFFS_NAME)) ){ error("formatting"); return; } format = 1; if (mount(s, SECOND_JFFS2_PATH, JFFS_NAME, MS_NOATIME, "") != 0) { _dprintf("*** jffs2 2-nd mount error\n"); //modprobe_r(JFFS_NAME); error("mounting"); return; } } sprintf(s, "rm -rf %s/*", SECOND_JFFS2_PATH); system(s); notice_set("2nd_jffs", format ? "Formatted" : "Loaded"); if (((p = nvram_get("jffs2_exec")) != NULL) && (*p != 0)) { chdir(SECOND_JFFS2_PATH); system(p); chdir("/"); } run_userfile(SECOND_JFFS2_PATH, ".asusrouter", SECOND_JFFS2_PATH, 3); }
static int flash_erase(int mtdnum) { int fd; char mtd_device[LINESIZE]; struct mtd_dev_info *mtd; int noskipbad = 0; int unlock = 0; unsigned int eb, eb_start, eb_cnt; struct flash_description *flash = get_flash_info(); if (!mtd_dev_present(flash->libmtd, mtdnum)) { ERROR("MTD %d does not exist\n", mtdnum); return -ENODEV; } mtd = &flash->mtd_info[mtdnum].mtd; snprintf(mtd_device, sizeof(mtd_device), "/dev/mtd%d", mtdnum); if ((fd = open(mtd_device, O_RDWR)) < 0) { ERROR( "%s: %s: %s", __func__, mtd_device, strerror(errno)); return -ENODEV; } /* * prepare to erase all of the MTD partition, */ eb_start = 0; eb_cnt = (mtd->size / mtd->eb_size) - eb_start; for (eb = 0; eb < eb_start + eb_cnt; eb++) { /* Always skip bad sectors */ if (!noskipbad) { int ret = mtd_is_bad(mtd, fd, eb); if (ret > 0) { continue; } else if (ret < 0) { if (errno == EOPNOTSUPP) { noskipbad = 1; } else { ERROR("%s: MTD get bad block failed", mtd_device); return -EFAULT; } } } if (unlock) { if (mtd_unlock(mtd, fd, eb) != 0) { TRACE("%s: MTD unlock failure", mtd_device); continue; } } if (mtd_erase(flash->libmtd, mtd, fd, eb) != 0) { ERROR("%s: MTD Erase failure", mtd_device); return -EFAULT; } } close(fd); return 0; }
int main (int argc, char **argv) { int ch, i, boot, unlock, imagefd, unlocked, offset, len; char *erase[MAX_ARGS], *device, *imagefile, *tmp; enum { CMD_ERASE, CMD_WRITE, CMD_UNLOCK } cmd; erase[0] = NULL; boot = 0; buflen = 0; quiet = 0; verbose = 0; offset = 0; len = 0; while ((ch = getopt(argc, argv, "vwrqe:o:l:")) != -1) switch (ch) { case 'r': boot = 1; break; case 'q': quiet++; break; case 'e': i = 0; while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS)) i++; erase[i++] = optarg; erase[i] = NULL; break; case 'v': verbose++; break; case 'o': offset = atoi(optarg); break; case 'l': len = atoi(optarg); break; case 'w': write_check++; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc < 2) usage(); if(len == 0){ len = getFileSize(argv[1]); } if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) { cmd = CMD_UNLOCK; device = argv[1]; } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) { cmd = CMD_ERASE; device = argv[1]; } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { cmd = CMD_WRITE; device = argv[2]; if (strcmp(argv[1], "-") == 0) { imagefile = "<stdin>"; imagefd = 0; } else { imagefile = argv[1]; if ((imagefd = open(argv[1], O_RDONLY)) < 0) { fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); exit(1); } } if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); exit(1); } } else { usage(); } sync(); i = 0; unlocked = 0; while (erase[i] != NULL) { if (quiet < 2) fprintf(stderr, "Unlocking %s ...\n", erase[i]); mtd_unlock(erase[i]); if (quiet < 2) fprintf(stderr, "Erasing %s ...\n", erase[i]); mtd_erase(erase[i]); if (strcmp(erase[i], device) == 0) unlocked = 1; i++; } if (!unlocked) { if (quiet < 2) fprintf(stderr, "Unlocking %s ...\n", device); mtd_unlock(device); } switch (cmd) { case CMD_UNLOCK: break; case CMD_ERASE: if (quiet < 2) fprintf(stderr, "Erasing %s ...\n", device); mtd_erase(device); break; case CMD_WRITE: if (quiet < 2) fprintf(stderr, "Writing from %s to %s ... ", imagefile, device); mtd_write(imagefd, offset, len, device); #if 0 //def CONFIG_DUAL_IMAGE if (!strcmp(device, "Kernel")) { printf("Reset stable flag and try coutner.\n"); system("nvram_set uboot Image1Stable 0"); system("nvram_set uboot Image1Try 0"); } #endif if (quiet < 2) fprintf(stderr, "\n"); break; } sync(); if (boot) { fflush(stdout); syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL); } return 0; }
void start_jffs2(void) { if (!nvram_match("jffs2_on", "1")) { notice_set("jffs", ""); return; } int format = 0; char s[256]; int size; int part; const char *p; struct statfs sf; if (!wait_action_idle(10)) return; if (!mtd_getinfo("jffs2", &part, &size)) return; _dprintf("*** jffs2: %d, %d\n", part, size); if (nvram_match("jffs2_format", "1")) { nvram_set("jffs2_format", "0"); if (!mtd_erase("jffs2")) { error("formatting"); return; } format = 1; } sprintf(s, "%d", size); p = nvram_get("jffs2_size"); if ((p == NULL) || (strcmp(p, s) != 0)) { if (format) { nvram_set("jffs2_size", s); nvram_commit_x(); } else if ((p != NULL) && (*p != 0)) { error("verifying known size of"); return; } } if ((statfs("/jffs", &sf) == 0) && (sf.f_type != 0x71736873 /* squashfs */)) { // already mounted notice_set("jffs", format ? "Formatted" : "Loaded"); return; } if (!mtd_unlock("jffs2")) { error("unlocking"); return; } modprobe(JFFS_NAME); sprintf(s, MTD_BLKDEV(%d), part); if (mount(s, "/jffs", JFFS_NAME, MS_NOATIME, "") != 0) { _dprintf("*** jffs2 mount error\n"); //modprobe_r(JFFS_NAME); error("mounting"); return; } #ifdef TEST_INTEGRITY int test; if (format) { if (f_write("/jffs/.tomato_do_not_erase", &size, sizeof(size), 0, 0) != sizeof(size)) { stop_jffs2(); error("setting integrity test for"); return; } } if ((f_read("/jffs/.tomato_do_not_erase", &test, sizeof(test)) != sizeof(test)) || (test != size)) { stop_jffs2(); error("testing integrity of"); return; } #endif notice_set("jffs", format ? "Formatted" : "Loaded"); if (((p = nvram_get("jffs2_exec")) != NULL) && (*p != 0)) { chdir("/jffs"); system(p); chdir("/"); } run_userfile("/jffs", ".asusrouter", "/jffs", 3); if (!check_if_dir_exist("/jffs/scripts/")) mkdir("/jffs/scripts/", 0755); if (!check_if_dir_exist("/jffs/configs/")) mkdir("/jffs/configs/", 0755); }
int main (int argc, char **argv) { int ch, i, boot, imagefd = 0, force, unlocked; char *erase[MAX_ARGS], *device = NULL; enum { CMD_ERASE, CMD_WRITE, CMD_UNLOCK, CMD_REFRESH, CMD_JFFS2WRITE } cmd = -1; erase[0] = NULL; boot = 0; force = 0; buflen = 0; quiet = 0; while ((ch = getopt(argc, argv, "frqe:d:j:")) != -1) switch (ch) { case 'f': force = 1; break; case 'r': boot = 1; break; case 'j': jffs2file = optarg; break; case 'q': quiet++; break; case 'e': i = 0; while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS)) i++; erase[i++] = optarg; erase[i] = NULL; break; case 'd': jffs2dir = optarg; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc < 2) usage(); if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) { cmd = CMD_UNLOCK; device = argv[1]; } else if ((strcmp(argv[0], "refresh") == 0) && (argc == 2)) { cmd = CMD_REFRESH; device = argv[1]; } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) { cmd = CMD_ERASE; device = argv[1]; } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { cmd = CMD_WRITE; device = argv[2]; if (strcmp(argv[1], "-") == 0) { imagefile = "<stdin>"; imagefd = 0; } else { imagefile = argv[1]; if ((imagefd = open(argv[1], O_RDONLY)) < 0) { fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); exit(1); } } if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); exit(1); } /* check trx file before erasing or writing anything */ if (!image_check(imagefd, device) && !force) { fprintf(stderr, "Image check failed.\n"); exit(1); } } else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) { cmd = CMD_JFFS2WRITE; device = argv[2]; imagefile = argv[1]; if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); exit(1); } } else { usage(); } sync(); i = 0; unlocked = 0; while (erase[i] != NULL) { mtd_unlock(erase[i]); mtd_erase(erase[i]); if (strcmp(erase[i], device) == 0) unlocked = 1; i++; } switch (cmd) { case CMD_UNLOCK: if (!unlocked) mtd_unlock(device); break; case CMD_ERASE: if (!unlocked) mtd_unlock(device); mtd_erase(device); break; case CMD_WRITE: if (!unlocked) mtd_unlock(device); mtd_write(imagefd, device); break; case CMD_JFFS2WRITE: if (!unlocked) mtd_unlock(device); mtd_write_jffs2(device, imagefile, jffs2dir); break; case CMD_REFRESH: mtd_refresh(device); break; } sync(); if (boot) do_reboot(); return 0; }
int mtd_main(int argc, char **argv) { int ch, i, boot, unlock, imagefd, force, quiet, unlocked; char *erase[MAX_ARGS], *device, *imagefile; enum { CMD_ERASE, CMD_WRITE, CMD_UNLOCK } cmd; erase[0] = NULL; boot = 0; force = 0; buflen = 0; quiet = 0; while ((ch = getopt(argc, argv, "frqe:")) != -1) switch (ch) { case 'f': force = 1; break; case 'r': boot = 1; break; case 'q': quiet++; break; case 'e': i = 0; while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS)) i++; erase[i++] = optarg; erase[i] = NULL; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc < 2) usage(); if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) { cmd = CMD_UNLOCK; device = argv[1]; } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) { cmd = CMD_ERASE; device = argv[1]; } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { cmd = CMD_WRITE; device = argv[2]; if (strcmp(argv[1], "-") == 0) { imagefile = "<stdin>"; imagefd = 0; } else { imagefile = argv[1]; if ((imagefd = open(argv[1], O_RDONLY)) < 0) { fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); exit(1); } } /* * check trx file before erasing or writing anything */ if (!image_check(imagefd, device)) { if ((quiet < 2) || !force) fprintf(stderr, "TRX check failed!\n"); if (!force) exit(1); } else { if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); exit(1); } } } else { usage(); } sync(); i = 0; unlocked = 0; while (erase[i] != NULL) { if (quiet < 2) fprintf(stderr, "Unlocking %s ...\n", erase[i]); mtd_unlock(erase[i]); if (quiet < 2) fprintf(stderr, "Erasing %s ...\n", erase[i]); mtd_erase(erase[i]); if (strcmp(erase[i], device) == 0) unlocked = 1; i++; } if (!unlocked) { if (quiet < 2) fprintf(stderr, "Unlocking %s ...\n", device); mtd_unlock(device); } switch (cmd) { case CMD_UNLOCK: break; case CMD_ERASE: if (quiet < 2) fprintf(stderr, "Erasing %s ...\n", device); mtd_erase(device); break; case CMD_WRITE: if (quiet < 2) fprintf(stderr, "Writing from %s to %s ... ", imagefile, device); mtd_write(imagefd, device, quiet); if (quiet < 2) fprintf(stderr, "\n"); break; } sync(); if (boot) kill(1, 15); // send SIGTERM to init for reboot return 0; }
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_part *part = PART(mtd); return mtd_unlock(part->master, ofs + part->offset, len); }
void start_jffs2(void) { if (!nvram_match("jffs2_enable", "1")) { notice_set("jffs", ""); return; } int format = 0; char s[256]; int size; int part; const char *p; int model = 0; int i = 0; while(1) { if (wait_action_idle(10)) break; else i++; if(i>=10) { _dprintf("Mount jffs2 failed!"); return; } } if (!mtd_getinfo(JFFS2_PARTITION, &part, &size)) return; model = get_model(); _dprintf("start jffs2: %d, %d\n", part, size); if (nvram_match("jffs2_format", "1")) { nvram_set("jffs2_format", "0"); nvram_commit_x(); if (mtd_erase(JFFS2_MTD_NAME)) { error("formatting"); return; } format = 1; } sprintf(s, "%d", size); p = nvram_get("jffs2_size"); if ((p == NULL) || (strcmp(p, s) != 0)) { if (format) { nvram_set("jffs2_size", s); nvram_commit_x(); } else if ((p != NULL) && (*p != 0)) { error("verifying known size of"); return; } } if(!check_in_rootfs("/jffs", "jffs", format)) return; if (nvram_get_int("jffs2_clean_fs")) { if (!mtd_unlock(JFFS2_PARTITION)) { error("unlocking"); return; } } modprobe(JFFS_NAME); sprintf(s, MTD_BLKDEV(%d), part); if (mount(s, "/jffs", JFFS_NAME, MS_NOATIME, "") != 0) { if (mtd_erase(JFFS2_MTD_NAME)) { jffs2_fail = 1; error("formatting"); return; } format = 1; if (mount(s, "/jffs", JFFS_NAME, MS_NOATIME, "") != 0) { _dprintf("*** jffs2 2-nd mount error\n"); //modprobe_r(JFFS_NAME); error("mounting"); jffs2_fail = 1; return; } } if(nvram_match("force_erase_jffs2", "1")) { _dprintf("\n*** force erase jffs2 ***\n"); mtd_erase(JFFS2_MTD_NAME); nvram_set("jffs2_clean_fs", "1"); nvram_commit(); reboot(RB_AUTOBOOT); } #ifdef TEST_INTEGRITY int test; if (format) { if (f_write("/jffs/.tomato_do_not_erase", &size, sizeof(size), 0, 0) != sizeof(size)) { stop_jffs2(0); error("setting integrity test for"); return; } } if ((f_read("/jffs/.tomato_do_not_erase", &test, sizeof(test)) != sizeof(test)) || (test != size)) { stop_jffs2(0); error("testing integrity of"); return; } #endif if (nvram_get_int("jffs2_clean_fs")) { _dprintf("Clean /jffs/*\n"); system("rm -fr /jffs/*"); nvram_unset("jffs2_clean_fs"); nvram_commit_x(); } notice_set("jffs", format ? "Formatted" : "Loaded"); jffs2_fail = 0; if (((p = nvram_get("jffs2_exec")) != NULL) && (*p != 0)) { chdir("/jffs"); system(p); chdir("/"); } run_userfile("/jffs", ".asusrouter", "/jffs", 3); if (!check_if_dir_exist("/jffs/scripts/")) mkdir("/jffs/scripts/", 0755); if (!check_if_dir_exist("/jffs/configs/")) mkdir("/jffs/configs/", 0755); }
int main(int argc, char *argv[]) { libmtd_t mtd_desc; struct mtd_dev_info mtd; int fd, clmpos = 0, clmlen = 8; unsigned long long start; unsigned int eb, eb_start, eb_cnt; int isNAND; int error = 0; off_t offset = 0; /* * Process user arguments */ for (;;) { int option_index = 0; static const char *short_options = "jNqu"; static const struct option long_options[] = { {"help", no_argument, 0, 0}, {"version", no_argument, 0, 0}, {"jffs2", no_argument, 0, 'j'}, {"noskipbad", no_argument, 0, 'N'}, {"quiet", no_argument, 0, 'q'}, {"silent", no_argument, 0, 'q'}, {"unlock", no_argument, 0, 'u'}, {0, 0, 0, 0}, }; int c = getopt_long(argc, argv, short_options, long_options, &option_index); if (c == EOF) break; switch (c) { case 0: switch (option_index) { case 0: display_help(); return 0; case 1: display_version(); return 0; } break; case 'j': jffs2 = 1; break; case 'N': noskipbad = 1; break; case 'q': quiet = 1; break; case 'u': unlock = 1; break; case '?': error = 1; break; } } switch (argc - optind) { case 3: mtd_device = argv[optind]; start = simple_strtoull(argv[optind + 1], &error); eb_cnt = simple_strtoul(argv[optind + 2], &error); break; default: case 0: errmsg("no MTD device specified"); case 1: errmsg("no start erase block specified"); case 2: errmsg("no erase block count specified"); error = 1; break; } if (error) return errmsg("Try `--help' for more information"); /* * Locate MTD and prepare for erasure */ mtd_desc = libmtd_open(); if (mtd_desc == NULL) return errmsg("can't initialize libmtd"); if ((fd = open(mtd_device, O_RDWR)) < 0) return sys_errmsg("%s", mtd_device); if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0) return errmsg("mtd_get_dev_info failed"); eb_start = start / mtd.eb_size; isNAND = mtd.type == MTD_NANDFLASH ? 1 : 0; if (jffs2) { cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); if (!isNAND) cleanmarker.totlen = cpu_to_je32(sizeof(cleanmarker)); else { struct nand_oobinfo oobinfo; if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) return sys_errmsg("%s: unable to get NAND oobinfo", mtd_device); /* Check for autoplacement */ if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { /* Get the position of the free bytes */ if (!oobinfo.oobfree[0][1]) return errmsg(" Eeep. Autoplacement selected and no empty space in oob"); clmpos = oobinfo.oobfree[0][0]; clmlen = oobinfo.oobfree[0][1]; if (clmlen > 8) clmlen = 8; } else { /* Legacy mode */ switch (mtd.oob_size) { case 8: clmpos = 6; clmlen = 2; break; case 16: clmpos = 8; clmlen = 8; break; case 64: clmpos = 16; clmlen = 8; break; } } cleanmarker.totlen = cpu_to_je32(8); } cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(cleanmarker) - 4)); } /* * Now do the actual erasing of the MTD device */ if (eb_cnt == 0) eb_cnt = (mtd.size / mtd.eb_size) - eb_start; for (eb = eb_start; eb < eb_start + eb_cnt; eb++) { offset = (off_t)eb * mtd.eb_size; if (!noskipbad) { int ret = mtd_is_bad(&mtd, fd, eb); if (ret > 0) { verbose(!quiet, "Skipping bad block at %08"PRIxoff_t, offset); continue; } else if (ret < 0) { if (errno == EOPNOTSUPP) { noskipbad = 1; if (isNAND) return errmsg("%s: Bad block check not available", mtd_device); } else return sys_errmsg("%s: MTD get bad block failed", mtd_device); } } show_progress(&mtd, offset, eb, eb_start, eb_cnt); if (unlock) { if (mtd_unlock(&mtd, fd, eb) != 0) { sys_errmsg("%s: MTD unlock failure", mtd_device); continue; } } if (mtd_erase(mtd_desc, &mtd, fd, eb) != 0) { sys_errmsg("%s: MTD Erase failure", mtd_device); continue; } /* format for JFFS2 ? */ if (!jffs2) continue; /* write cleanmarker */ if (isNAND) { if (mtd_write_oob(mtd_desc, &mtd, fd, (uint64_t)offset + clmpos, clmlen, &cleanmarker) != 0) { sys_errmsg("%s: MTD writeoob failure", mtd_device); continue; } } else { if (lseek(fd, offset, SEEK_SET) < 0) { sys_errmsg("%s: MTD lseek failure", mtd_device); continue; } if (write(fd, &cleanmarker, sizeof(cleanmarker)) != sizeof(cleanmarker)) { sys_errmsg("%s: MTD write failure", mtd_device); continue; } } verbose(!quiet, " Cleanmarker written at %"PRIxoff_t, offset); } show_progress(&mtd, offset, eb, eb_start, eb_cnt); bareverbose(!quiet, "\n"); return 0; }