type xstrto(_range_sfx)(const char *numstr, int base, type lower, type upper, const struct suffix_mult *suffixes) { unsigned type u = XSTR_TYPE_MAX; type r; const char *p = numstr; if (p[0] == '-') { ++p; ++u; /* two's complement */ } r = xstrtou(_range_sfx)(p, base, 0, u, suffixes); if (*numstr == '-') { r = -r; } if (r < lower || r > upper) { bb_error_msg_and_die("number %s is not in %lld..%lld range", numstr, (long long)lower, (long long)upper); } return r; }
unsigned type FAST_FUNC xatou(_range_sfx)(const char *numstr, unsigned type lower, unsigned type upper, const struct suffix_mult *suffixes) { return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes); }
type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base, type lower, type upper, const struct suffix_mult *suffixes) { unsigned type u = XSTR_TYPE_MAX; type r; const char *p = numstr; /* NB: if you'll decide to disallow '+': * at least renice applet needs to allow it */ if (p[0] == '+' || p[0] == '-') { ++p; if (p[0] == '-') ++u; /* = <type>_MIN (01111... + 1 == 10000...) */ } r = xstrtou(_range_sfx)(p, base, 0, u, suffixes); if (*numstr == '-') { r = -r; } if (r < lower || r > upper) { bb_error_msg_and_die("number %s is not in %lld..%lld range", numstr, (long long)lower, (long long)upper); } return r; }
static void parse_map_file(const char *filename) { parser_t *parser; char *tokens[6]; parser = config_open2(filename, fopen_for_read); if (parser) { while (config_read(parser, tokens, 6, 6, "# \t", PARSE_NORMAL)) { evt_tab = xrealloc_vector(evt_tab, 1, n_evt); evt_tab[n_evt].s_type = xstrdup(tokens[0]); evt_tab[n_evt].n_type = xstrtou(tokens[1], 16); evt_tab[n_evt].s_code = xstrdup(tokens[2]); evt_tab[n_evt].n_code = xatou16(tokens[3]); evt_tab[n_evt].value = xatoi_positive(tokens[4]); evt_tab[n_evt].desc = xstrdup(tokens[5]); n_evt++; } config_close(parser); } else { evt_tab = (void*)f_evt_tab; n_evt = ARRAY_SIZE(f_evt_tab); } }
unsigned type FAST_FUNC xstrtou()(const char *numstr, int base) { return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL); }
unsigned type FAST_FUNC xstrtou(_sfx)(const char *numstr, int base, const struct suffix_mult *suffixes) { return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes); }
unsigned type FAST_FUNC xstrtou(_range)(const char *numstr, int base, unsigned type lower, unsigned type upper) { return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL); }
int nandwrite_main(int argc UNUSED_PARAM, char **argv) { /* Buffer for OOB data */ unsigned char *oobbuf; unsigned opts; int fd; ssize_t cnt; unsigned mtdoffset, meminfo_writesize, blockstart, limit; unsigned end_addr = ~0; struct mtd_info_user meminfo; struct mtd_oob_buf oob; unsigned char *filebuf; const char *opt_s = "0", *opt_f = "-", *opt_l; if (IS_NANDDUMP) { opt_complementary = "=1"; opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l); } else { /* nandwrite */ opt_complementary = "-1:?2"; opts = getopt32(argv, "ps:", &opt_s); } argv += optind; if (IS_NANDWRITE && argv[1]) opt_f = argv[1]; if (!LONE_DASH(opt_f)) { int tmp_fd = xopen(opt_f, IS_NANDDUMP ? O_WRONLY | O_TRUNC | O_CREAT : O_RDONLY ); xmove_fd(tmp_fd, IS_NANDDUMP ? STDOUT_FILENO : STDIN_FILENO); } fd = xopen(argv[0], O_RDWR); xioctl(fd, MEMGETINFO, &meminfo); mtdoffset = xstrtou(opt_s, 0); if (IS_NANDDUMP && (opts & OPT_l)) { unsigned length = xstrtou(opt_l, 0); if (length < meminfo.size - mtdoffset) end_addr = mtdoffset + length; } /* Pull it into a CPU register (hopefully) - smaller code that way */ meminfo_writesize = meminfo.writesize; if (mtdoffset & (meminfo_writesize - 1)) bb_error_msg_and_die("start address is not page aligned"); filebuf = xmalloc(meminfo_writesize); oobbuf = xmalloc(meminfo.oobsize); oob.start = 0; oob.length = meminfo.oobsize; oob.ptr = oobbuf; blockstart = mtdoffset & ~(meminfo.erasesize - 1); if (blockstart != mtdoffset) { unsigned tmp; /* mtdoffset is in the middle of an erase block, verify that * this block is OK. Advance mtdoffset only if this block is * bad. */ tmp = next_good_eraseblock(fd, &meminfo, blockstart); if (tmp != blockstart) { /* bad block(s), advance mtdoffset */ if (IS_NANDDUMP & !(opts & OPT_b)) { int bad_len = MIN(tmp, end_addr) - mtdoffset; dump_bad(&meminfo, bad_len, !(opts & OPT_o)); } mtdoffset = tmp; } } cnt = -1; limit = MIN(meminfo.size, end_addr); while (mtdoffset < limit) { int input_fd = IS_NANDWRITE ? STDIN_FILENO : fd; int output_fd = IS_NANDWRITE ? fd : STDOUT_FILENO; blockstart = mtdoffset & ~(meminfo.erasesize - 1); if (blockstart == mtdoffset) { /* starting a new eraseblock */ mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart); if (IS_NANDWRITE) printf("Writing at 0x%08x\n", mtdoffset); else if (mtdoffset > blockstart) { int bad_len = MIN(mtdoffset, limit) - blockstart; dump_bad(&meminfo, bad_len, !(opts & OPT_o)); } if (mtdoffset >= limit) break; } xlseek(fd, mtdoffset, SEEK_SET); /* get some more data from input */ cnt = full_read(input_fd, filebuf, meminfo_writesize); if (cnt == 0) { /* even with -p, we do not pad past the end of input * (-p only zero-pads last incomplete page) */ break; } if (cnt < meminfo_writesize) { if (IS_NANDDUMP) bb_error_msg_and_die("short read"); if (!(opts & OPT_p)) bb_error_msg_and_die("input size is not rounded up to page size, " "use -p to zero pad"); /* zero pad to end of write block */ memset(filebuf + cnt, 0, meminfo_writesize - cnt); } xwrite(output_fd, filebuf, meminfo_writesize); if (IS_NANDDUMP && !(opts & OPT_o)) { /* Dump OOB data */ oob.start = mtdoffset; xioctl(fd, MEMREADOOB, &oob); xwrite(output_fd, oobbuf, meminfo.oobsize); } mtdoffset += meminfo_writesize; if (cnt < meminfo_writesize) break; } if (IS_NANDWRITE && cnt != 0) { /* We filled entire MTD, but did we reach EOF on input? */ if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) { /* no */ bb_error_msg_and_die("not enough space in MTD device"); } } if (ENABLE_FEATURE_CLEAN_UP) { free(filebuf); close(fd); } return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { FILE *data; bus_space_handle_t ioh; bus_space_tag_t tag; u_int32_t addr; u_int32_t value; int do_write, has_addr; int count; int width; int i, c, ret; do_write = 0; has_addr = 0; count = -1; width = 4; data = NULL; while((c = getopt(argc, argv, ARGUMENTS)) != -1) { switch (c) { case 'a': /* Set address */ if (xstrtou(optarg, (u_long *) &addr) != 0) errx(1, "not a number: %s", optarg); has_addr = 1; break; case 'b': /* Set access width */ if (xstrtou(optarg, (u_long *) &width) != 0) errx(1, "not a number: %s", optarg); switch (width) { case 1: case 2: case 4: break; default: errx(1, "bad width: %d", width); } break; case 'c': /* Set value count */ if (xstrtou(optarg, (u_long *) &count) != 0) errx(1, "not a number: %s", optarg); break; case 'f': /* File to read from/write to */ do_write = 1; if ((data = fopen(optarg, "r")) == NULL) err(1, "could not open %s", optarg); break; case 'h': /* Show help */ usage(); return 0; case 'v': /* Verbose operation */ verbose = 1; break; case 'w': /* Value to write */ if (xstrtou(optarg, (u_long *) &value) != 0) errx(1, "not a number: %s", optarg); do_write = 1; break; default: errx(1, "unknown argument -%c", optopt); } } argc -= optind; argv += optind; /* Validate user isn't insane. */ if (argc > 0) errx(1, "stray arguments"); if (! has_addr) errx(1, "address is mandatory"); /* Grab bus space. */ if ((ret = bus_space_tag(&tag)) != 0) err(1, "could not access physical memory, error %d", ret); if (count == -1) { if (data != NULL) count = PAGE_SIZE / width; else count = 1; } if ((ret = bus_space_map(tag, addr, count * width, 0, &ioh)) != 0) err(1, "could not map bus space, error %d", ret); if (do_write) { for (i = 0; i < count; i++) { if (data != NULL) { if (fscanf(data, "%x", &value) != 1) { if (feof(data)) break; else if (ferror(data)) err(1, "file read error"); else err(1, "invalid input"); } } VERBOSE(("[%03d] 0x%08x <- 0x%08x", i, addr + i * width, value)); switch (width) { case 1: bus_space_write_1(tag, ioh, i * width, value); break; case 2: bus_space_write_2(tag, ioh, i * width, value); break; case 4: bus_space_write_4(tag, ioh, i * width, value); break; } } } else { for (i = 0; i < count; i++) { switch (width) { case 1: value = bus_space_read_1(tag, ioh, i * width); printf("%02x\n", value); break; case 2: value = bus_space_read_2(tag, ioh, i * width); printf("%04x\n", value); break; case 4: value = bus_space_read_4(tag, ioh, i * width); printf("%08x\n", value); break; } } } return (0); }
unsigned type xatou(_sfx)(const char *numstr, const struct suffix_mult *suffixes) { return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes); }
unsigned type xatou(_range)(const char *numstr, unsigned type lower, unsigned type upper) { return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL); }