📄 netflash.c
字号:
pid = atoi(value); if (pid) kill(pid, signo); unlink(file); } fclose(f);}/****************************************************************************//* * Find the current console device. We output trace to this device * if it is the controlling tty at process start. */char *consolelist[] = { "/dev/console", "/dev/ttyS0", "/dev/cua0", "/dev/ttyS1", "/dev/cua1", "/dev/ttyAM0"};#define clistsize (sizeof(consolelist) / sizeof(char *)) char *getconsole(void){ struct stat myst, st; int i; if (fstat(0, &myst) < 0) return((char *) NULL); for (i = 0; (i < clistsize); i++) { if (!stat(consolelist[i], &st) && (myst.st_rdev == st.st_rdev)) return(consolelist[i]); } return "/dev/null";}/****************************************************************************/static const char *kill_partial[] = {#ifdef CONFIG_USER_SNORT_SNORT "snort",#endif#ifdef CONFIG_USER_SQUID_SQUID "squid",#endif#if defined(CONFIG_USER_FREESWAN) || defined(CONFIG_USER_OPENSWAN) "pluto",#endif#ifdef CONFIG_USER_CLAMAV_CLAMD "clamd",#endif NULL};/* * Kill off processes to reclaim some memory. Only kills processes * that we know are unnecessary for obtaining the image. */void kill_processes_partial(void){ const char **p; int count; notice("killing unnecessary tasks..."); sleep(1); kill(1, SIGTSTP); /* Stop init from reforking tasks */ atexit(restartinit); /* If exit prematurely, restart init */ sync(); /* Ask them nicely. */ count = 0; for (p = kill_partial; *p; p++) count += killprocname(*p, SIGTERM); if (count) sleep(5); /* give em a moment... */ /* Time for the no-nonsense approach. */ count = 0; for (p = kill_partial; *p; p++) count += killprocname(*p, SIGKILL); if (count) sleep(2); /* give em another moment... */}/* * Kill of processes now to reclaim some memory. Need this now so * we can buffer an entire firmware image... */void kill_processes(char *console){ int ttyfd; struct termios tio; DIR *dir; struct dirent *dp; char filename[128]; if (console == NULL) console = getconsole(); ttyfd = open(console, O_RDWR|O_NDELAY|O_NOCTTY); if (ttyfd >= 0) { if (tcgetattr(ttyfd, &tio) >= 0) { tio.c_cflag |= CLOCAL; tcsetattr(ttyfd, TCSANOW, &tio); } close(ttyfd); } if (!docgi) { freopen(console, "w", stdout); freopen(console, "w", stderr); } notice("killing tasks..."); fflush(stdout); sleep(1); kill(1, SIGTSTP); /* Stop init from reforking tasks */ atexit(restartinit); /* If exit prematurely, restart init */ sync(); signal(SIGTERM,SIG_IGN); /* Don't kill ourselves... */ setpgrp(); /* Don't let our parent kill us */ sleep(1); signal(SIGHUP, SIG_IGN); /* Don't die if our parent dies due to * a closed controlling terminal */ killprocpid("/var/run/ifmond.pid", SIGKILL); /*Don't take down network interfaces that use dhcpcd*/ dir = opendir(PID_DIR); if (dir) { while ((dp = readdir(dir)) != NULL) { if (strncmp(dp->d_name, DHCPCD_PID_FILE, sizeof(DHCPCD_PID_FILE)-1) != 0) continue; if (strcmp(dp->d_name + strlen(dp->d_name) - 4, ".pid") != 0) continue; snprintf(filename, sizeof(filename), "%s/%s", PID_DIR, dp->d_name); killprocpid(filename, SIGKILL); } closedir(dir); } kill(-1, SIGTERM); /* Kill everything that'll die */ sleep(5); /* give em a moment... (it may take a while for, e.g., pppd to shutdown cleanly */ kill(-1, SIGKILL); /* Really make sure that everything is dead */ sleep(2); /* give em another moment... */ if (console) freopen(console, "w", stdout);#if CONFIG_USER_NETFLASH_WATCHDOG if (watchdog) watchdog_fd = open("/dev/watchdog", O_WRONLY);#endif}/****************************************************************************/#if defined(CONFIG_USER_MOUNT_UMOUNT) || defined(CONFIG_USER_BUSYBOX_UMOUNT)void umount_all(void){ char *localargv[4]; int localargc; pid_t pid; int status; localargc = 0; localargv[localargc++] = "umount"; localargv[localargc++] = "-a"; localargv[localargc++] = "-r"; localargv[localargc++] = NULL; pid = vfork(); if (pid == -1) { error("vfork() failed %m"); exit_failed(VFORK_FAIL); } else if (pid == 0) { execvp("/bin/umount", localargv); _exit(1); } waitpid(pid, &status, 0);}#endif/****************************************************************************/static int get_segment(int rd, char *sgdata, int sgpos, int sgsize){ int sglength; int sgoffset; if (offset > sgpos) sgoffset = offset - sgpos; else sgoffset = 0; /* XXX: preserve case could be optimized to read less */ if (preserve || sgoffset) { if (lseek(rd, sgpos, SEEK_SET) != sgpos) { error("lseek(%x) failed\n", sgpos); exit_failed(BAD_SEG_SEEK); } else if (read(rd, sgdata, preserve ? sgsize : sgoffset) < 0) { error("read() failed, pos=%x, errno=%d\n", sgpos, errno); exit_failed(BAD_SEG_READ); } } sgpos -= offset - sgoffset; sgdata += sgoffset; sgsize -= sgoffset;#ifdef CONFIG_USER_NETFLASH_DECOMPRESS if (doinflate) { sglength = decompress(sgdata, sgsize); } else {#endif /* Copy the file blocks into the segment buffer */ sglength = 0; while (fileblocks && (fileblocks->pos < sgpos + sgsize)) { if (fileblocks->pos + fileblocks->length > sgpos + sgsize) sglength = sgsize; else sglength = fileblocks->pos + fileblocks->length - sgpos; if (fileblocks->pos < sgpos) { memcpy(sgdata, fileblocks->data + (sgpos - fileblocks->pos), sglength); } else { memcpy(sgdata + (fileblocks->pos - sgpos), fileblocks->data, sglength - (fileblocks->pos - sgpos)); } if (fileblocks->pos + fileblocks->length > sgpos + sgsize) { /* Need to keep fileblocks pointing to this block * for the start of the next segment. */ break; } /* Modify the global: this is an optimization to save searching * through blocks that have been programmed already. */ fileblocks = fileblocks->next; }#ifdef CONFIG_USER_NETFLASH_DECOMPRESS }#endif if (sglength !=0) { if (preserve) sglength = sgsize; sglength += sgoffset; } return sglength;}static void check_segment(int rd, char *sgdata, int sgpos, int sglength, char *check_buf){ if (lseek(rd, sgpos, SEEK_SET) != sgpos) { error("lseek(%x) failed", sgpos); exitstatus = BAD_SEG_SEEK; } else if (read(rd, check_buf, sglength) < 0) { error("read failed, pos=%x, errno=%d", sgpos, errno); exitstatus = BAD_SEG_READ; } else if (memcmp(sgdata, check_buf, sglength) != 0) { int i; error("check failed, pos=%x", sgpos); for (i = 0; i < sglength; i++) { if (sgdata[i] != check_buf[i]) printf("%x(%x,%x) ", sgpos + i, sgdata[i] & 0xff, check_buf[i] & 0xff); } printf("\n"); exitstatus = BAD_SEG_CHECK; }}#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULES)static void program_mtd_segment(int rd, char *sgdata, int sgpos, int sglength, int sgsize){ erase_info_t erase_info; int pos; /* Unlock the segment to be reprogrammed. */ if (dounlock) { erase_info.start = sgpos; erase_info.length = sgsize; /* Don't bother checking for failure */ ioctl(rd, MEMUNLOCK, &erase_info); } erase_info.start = sgpos; erase_info.length = sgsize; if (lseek(rd, sgpos, SEEK_SET) != sgpos) { error("lseek(%x) failed", sgpos); exitstatus = BAD_SEG_SEEK; } else if (ioctl(rd, MEMERASE, &erase_info) < 0) { error("ioctl(MEMERASE) failed, errno=%d", errno); exitstatus = ERASE_FAIL; } else if (sglength > 0) { if (lseek(rd, sgpos, SEEK_SET) != sgpos) { error("lseek(%x) failed", sgpos); exitstatus = BAD_SEG_SEEK; } else { /* * Always write in 512 byte chunks as MTD on * a DoC device can only handle 512 byte writes. * * NOTE: we rely on the fact the sgdata buffer is always * a multiple of 512 in real size (erase_size for MTD) * which should always be true, I think. */ for (pos = sgpos; (sglength >= 512); ) { if (write(rd, sgdata, 512) == -1) { error("write() failed, " "pos=%x, errno=%d", pos, errno); exitstatus = BAD_SEG_WRITE; } pos += 512; sgdata += 512; sglength -= 512; } /* * If there is a remainder, then still write a 512 byte * chunk, but preserve what is already there. */ if (sglength > 0) { char buf[512]; if (lseek(rd, pos, SEEK_SET) != pos) { error("lseek(%x) failed", pos); exitstatus = BAD_SEG_SEEK; } else if (read(rd, buf, 512) == -1) { error("read() failed, " "pos=%x, errno=%d", pos, errno); exitstatus = BAD_SEG_READ; } else if (lseek(rd, pos, SEEK_SET) != pos) { error("lseek(%x) failed", pos); exitstatus = BAD_SEG_SEEK; } else { memcpy(buf, sgdata, sglength); if (write(rd, buf, 512) == -1) { error("write() failed, pos=%x, errno=%d", pos, errno); exitstatus = BAD_SEG_WRITE; } } } } } else if (dojffs2) { static struct jffs2_unknown_node marker = { JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, sizeof(struct jffs2_unknown_node),#if __BYTE_ORDER == __BIG_ENDIAN 0xf060dc98#else 0xe41eb0b1#endif }; if (lseek(rd, sgpos, SEEK_SET) != sgpos) { error("lseek(%x) failed", sgpos); exitstatus = BAD_SEG_SEEK; } else if (write(rd, &marker, sizeof(marker)) < 0) { error("write() failed, pos=%x, " "errno=%d", sgpos, errno); exitstatus = BAD_SEG_WRITE; } } if (dolock) { erase_info.start = sgpos; erase_info.length = sgsize; if (ioctl(rd, MEMLOCK, &erase_info) < 0) { error("ioctl(MEMLOCK) failed, " "errno=%d", errno); exitstatus = ERASE_FAIL; } }}#elsestatic void program_blkmem_segment(int rd, char *sgdata, int sgpos, int sglength, int sgsize){ char buf[128]; struct blkmem_program_t *prog = (struct blkmem_program_t *)buf; prog->magic1 = BMPROGRAM_MAGIC_1; prog->magic2 = BMPROGRAM_MAGIC_2; prog->reset = 0; prog->blocks = 1; prog->block[0].data = sgdata; prog->block[0].pos = sgpos; prog->block[0].length = sglength; prog->block[0].magic3 = BMPROGRAM_MAGIC_3; if (ioctl(rd, BMPROGRAM, prog) != 0) { error("ioctl(BMPROGRAM) failed, errno=%d", errno); exitstatus = BAD_SEG_WRITE; }}#endif#if defined(CONFIG_NFTL_RW) || defined(CONFIG_IDE)static void program_generic_segment(int rd, char *sgdata, int sgpos, int sglength, int sgsize){ if (!stop_early && sglength < sgsize) { memset(sgdata + sglength, 0xff, sgsize - sglength); sglength = sgsize; } if (sglength > 0) { if (lseek(rd, sgpos, SEEK_SET) != sgpos) { error("lseek(%x) failed", sgpos); exitstatus = BAD_SEG_SEEK; } else if (write(rd, sgdata, sglength) < 0) { error("write() failed, pos=%x, " "errno=%d", sgpos, errno); exitstatus = BAD_SEG_WRITE; } else if (fdatasync(rd) < 0) { error("fdatasync() failed, pos=%x, " "errno=%d", sgpos, errno); exitstatus = BAD_SEG_CHECK; } }}#endifstatic void program_flash(int rd, int devsize, char *sgdata, int sgsize, char *check_buf){ int sgpos, sglength; unsigned long total;#ifdef CONFIG_LEDMAN int ledmancount = 0;#endif#ifdef CONFIG_LEDMAN ledman_cmd(LEDMAN_CMD_ALT_ON, LEDMAN_NVRAM_1); ledman_cmd(LEDMAN_CMD_ALT_ON, LEDMAN_NVRAM_2);#endif /* Round the image size up to the segment size */ if (stop_early) { total = (image_length + sgsize - 1) & ~(sgsize - 1); } else { total = devsize; } /* Write the data one segment at a time */ sgpos = offset - (offset % sgsize); for (; sgpos < devsize; sgpos += sgsize) { sglength = get_segment(rd, sgdata, sgpos, sgsize); if (stop_early && sglength <= 0) { break; } if (checkimage) { check_segment(rd, sgdata, sgpos, sglength, check_buf); } else#if defined(CONFIG_MTD_NETtel) if (!preserveconfig || sgpos < 0xe0000 || sgpos >= 0x100000) {#endif program_segment(rd, sgdata, sgpos, sglength, sgsize);#ifdef CONFIG_LEDMAN ledman_cmd(LEDMAN_CMD_OFF | LEDMAN_CMD_ALTBIT, ledmancount ? LEDMAN_NVRAM_1 : LEDMAN_NVRAM_2); ledman_cmd(LEDMAN_CMD_ON | LEDMAN_CMD_ALTBIT, ledmancount ? LEDMAN_NVRAM_2 : LEDMAN_NVRAM_1); ledmancount = (ledmancount + 1) & 1;#endif#ifdef CONFIG_USER_NETFLASH_WATCHDOG if (watchdog) write(watchdog_fd, "\0", 1); #endif#if defined(CONFIG_MTD_NETtel) } /* if (!preserveconfig || ...) */#endif printf("\r%5dK %3d%%", (sgpos + sgsize) / 1024, (sgpos + sgsize) * 100L / total); fflush(stdout); } printf("\n"); fflush(stdout);#ifdef CONFIG_LEDMAN ledman_cmd(LEDMAN_CMD_ALT_OFF, LEDMAN_NVRAM_1); ledman_cmd(LEDMAN_CMD_ALT_OFF, LEDMAN_NVRAM_2);#endif /* Put the flash back in read mode, some old boot loaders don't */ lseek(rd, 0, SEEK_SET); read(rd, sgdata, 1);}/****************************************************************************/int usage(int rc){ printf("usage: netflash [-bCfFhijklntuv"#ifdef CONFIG_USER_NETFLASH_DECOMPRESS "z"#endif "?] [-c console-device] [-d delay] "#ifdef CONFIG_USER_NETFLASH_SETSRC "[-I ip-address] "#endif#ifdef CONFIG_USER_NETFLASH_HMACMD5 "[-m hmac-md5-key] "#endif "[-o offset] [-r flash-device] " "[net-server] file-name\n\n" "\t-b\tdon't reboot hardware when done\n" "\t-C\tcheck that image was written correctly\n" "\t-f\tuse FTP as load protocol\n" "\t-F\tforce overwrite (do not preserve special regions)\n" "\t-h\tprint help\n" "\t-i\tignore any version information\n" "\t-H\tignore hardware type information\n"#ifdef CONFIG_USER_NETFLASH_SETSRC "\t-I\toriginate TFTP request from this address\n"#endif "\t-j\timage is a JFFS2 filesystem\n" "\t-k\tdon't kill other processes (or delays kill until\n" "\t\tafter downloading when root filesystem is inside flash)\n" "\t-K\tonly kill unnecessary processes (or delays kill until\n" "\t\tafter downloading when root filesystem is inside flash)\n" "\t-l\tlock flash segments when done\n" "\t-n\tfile with no checksum at end (implies no version information)\n" "\t-p\tpreserve portions of flash segments not actually written.\n" "\t-s\tstop erasing/programming at end of input data\n" "\t-S\tdo not stop erasing/programming at end of input data\n" "\t-t\tcheck the image and then throw it away \n" "\t-u\tunlock flash segments before programming\n" "\t-v\tdisplay version number\n"#if CONFIG_USER_NETFLASH_WATCHDOG "\t-w\tdon't tickle hardware watchdog\n"#endif#ifdef CONFIG_USER_NETFLASH_DECOMPRESS "\t-z\tdecompress image before writing\n"#endif ); exit(rc);}/****************************************************************************//* * when we call reboot, we don't want anything in our way, most certainly * not logd ! */#define __NR_raw_reboot __NR_rebootstatic _syscall3(int, raw_reboot, int, magic, int, magic2, int, flag);/****************************************************************************/int netflashmain(int argc, char *argv[]){ char *srvname, *filename; char *rdev, *console; char *sgdata, *check_buf = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -