📄 netflash.c
字号:
int rd, rc, tmpfd; int delay; int dochecksum, dokill, dokillpartial, doreboot, doftp; int dopreserve, doversion, doremoveversion, dohardwareversion; int devsize = 0, sgsize = 0; struct fileblock_t *fb;#ifdef CONFIG_USER_NETFLASH_HMACMD5 char *hmacmd5key = NULL;#endif#if defined(CONFIG_USER_NETFLASH_WITH_CGI) && !defined(RECOVER_PROGRAM) char options[64]; char *new_argv[10];#endif rdev = "/dev/flash/image"; srvname = NULL; filename = NULL; console = NULL; dochecksum = 1; dokill = 1; dokillpartial = 0; doreboot = 1; dolock = 0; dounlock = 0; delay = 0; doftp = 0; dothrow = 0; dopreserve = 1; preserveconfig = 0; checkimage = 0; dojffs2 = 0; doremoveversion = 1;#ifdef CONFIG_USER_NETFLASH_VERSION doversion = 1; dohardwareversion = 1;#else doversion = 0; dohardwareversion = 0;#endif /*CONFIG_USER_NETFLASH_VERSION*/#ifdef CONFIG_USER_NETFLASH_DECOMPRESS doinflate = 0;#endif#if defined(CONFIG_USER_NETFLASH_WITH_CGI) && !defined(RECOVER_PROGRAM) if (argc == 2 && strncmp(argv[1], "cgi://", 6) == 0) { char *pt; char *sep; int new_argc = 0; docgi = 1; dokillpartial = 1; /* Our "command line" options come from stdin for cgi * Format of the command line is: cgi://dataname,optionsname */ pt = argv[1] + 6; sep = strchr(pt, ','); if (sep) { int len = sep - pt; if (len >= sizeof(cgi_data)) { len = sizeof(cgi_data) - 1; } strncpy(cgi_data, pt, len); cgi_data[len] = 0; strncpy(cgi_options, sep + 1, sizeof(cgi_options)); cgi_options[sizeof(cgi_options) - 1] = 0; } else { exit_failed(BAD_CGI_FORMAT); } if ((file_length = cgi_load(cgi_data, cgi_options, options)) <= 0) { exit_failed(BAD_CGI_DATA); } new_argv[new_argc++] = argv[0]; /* Parse the options */ pt = strtok(options, " \t"); while (pt) { assert(new_argc < 10); new_argv[new_argc++] = pt; pt = strtok(0, " \t"); } argc = new_argc; argv = new_argv; }#endif while ((rc = getopt(argc, argv, CMD_LINE_OPTIONS)) > 0) { switch (rc) { case 'p': preserve = 1; stop_early = 1; break; case 's': stop_early = 1; break; case 'S': nostop_early = 1; break; case 'b': doreboot = 0; break; case 'c': console = optarg; break; case 'C': checkimage = 1; break; case 'd': delay = (atoi(optarg)); break; case 'f': doftp = 1; break; case 'F': dopreserve = 0; break; case 'i': doversion = 0; break; case 'H': dohardwareversion = 0; break; case 'j': dojffs2 = 1; nostop_early = 1; break; case 'k': dokill = 0; break; case 'K': dokill = 1; dokillpartial = 1; break; case 'l': dolock++; break;#ifdef CONFIG_USER_NETFLASH_HMACMD5 case 'm': hmacmd5key = optarg; break;#endif case 'n': /* No checksum implies no version */ dochecksum = doversion = dohardwareversion = doremoveversion = 0; break; case 'o': offset = strtol(optarg, NULL, 0); break; case 'r': rdev = optarg; break; case 't': dothrow = 1; break; case 'u': dounlock++; break; case 'v': notice("version %s", version); exit(0);#ifdef CONFIG_USER_NETFLASH_DECOMPRESS case 'z': doinflate = 1; break;#endif#ifdef CONFIG_USER_NETFLASH_SETSRC case 'I': srcaddr = optarg; break;#endif#ifdef CONFIG_USER_NETFLASH_WATCHDOG case 'w': watchdog = 0; break;#endif case 'h': case '?': usage(0); break; } } /* * for /dev/flash/image we want to stop early unless the user * has told us not to (-S). This allows us to preserve logd info * * So we override the default of not stopping early for /dev/flash/image */ if (strcmp(rdev, "/dev/flash/image") == 0) { if (nostop_early == 0) stop_early = 1; } if ((nfd = fopen("/dev/null", "rw")) == NULL) { error("open(/dev/null) failed: %s", strerror(errno)); exit_failed(NO_DEV_NULL); } if (!docgi) { if (optind == (argc - 1)) { srvname = NULL; filename = argv[optind]; } else if (optind == (argc - 2)) { srvname = argv[optind++]; filename = argv[optind]; } else { usage(1); } } if (delay > 0) { /* sleep the required time */ notice("waiting %d seconds before updating flash...",delay); sleep(delay); } /* * Need to do any real FTP setup early, before killing processes * (and this losing association with the controlling tty). */ if (doftp) { if (ftpconnect(srvname)) { error("ftpconnect failed"); exit_failed(FTP_CONNECT_FAIL); } } if (dokill) { if (dokillpartial) kill_processes_partial(); else kill_processes(console); } /* * Open the flash device and allocate a segment sized block. * This is the largest block we need to allocate, so we do * it first to try to avoid fragmentation effects. */ if (dopreserve && (strcmp(rdev, "/dev/flash/image") == 0)) preserveconfig = 1; rd = open(rdev, O_RDWR); if (rd < 0) { error("open(%s) failed: %s", rdev, strerror(errno)); exit_failed(BAD_OPEN_FLASH); } if (stat(rdev, &stat_rdev) != 0) { error("stat(%s) failed: %s", rdev, strerror(errno)); exit_failed(BAD_OPEN_FLASH); } else if (S_ISBLK(stat_rdev.st_mode)) {#ifdef CONFIG_NFTL_RW if (major(stat_rdev.st_rdev) == NFTL_MAJOR) { unsigned long l; program_segment = program_generic_segment; preserveconfig = dolock = dounlock = 0; if (ioctl(rd, BLKGETSIZE, &l) < 0) { error("ioctl(BLKGETSIZE) failed, errno=%d", errno); exit_failed(BAD_OPEN_FLASH); } devsize = l*512; /* Sectors are always 512 bytes */ /* Use a larger sgsize for efficiency, but it * must divide evenly into devsize. */ for (sgsize = 512; sgsize < 64 * 1024; sgsize <<= 1) if (devsize & sgsize) break; }#endif#ifdef CONFIG_IDE if ((major(stat_rdev.st_rdev) == IDE0_MAJOR) || (major(stat_rdev.st_rdev) == IDE1_MAJOR) || (major(stat_rdev.st_rdev) == IDE2_MAJOR) || (major(stat_rdev.st_rdev) == IDE3_MAJOR)) { struct hd_geometry geo; program_segment = program_generic_segment; preserveconfig = dolock = dounlock = 0; if (ioctl(rd, HDIO_GETGEO, &geo) < 0) { error("ioctl(HDIO_GETGEO) failed, errno=%d", errno); exit_failed(BAD_OPEN_FLASH); } devsize = geo.heads*geo.cylinders*geo.sectors*512; /* Use a larger sgsize for efficiency, but it * must divide evenly into devsize. */ for (sgsize = 512; sgsize < 64 * 1024; sgsize <<= 1) if (devsize & sgsize) break; }#endif } if (!program_segment) {#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULES) mtd_info_t mtd_info, rootfs_info; program_segment = program_mtd_segment; if (ioctl(rd, MEMGETINFO, &mtd_info) < 0) { error("ioctl(MEMGETINFO) failed, errno=%d", errno); exit_failed(BAD_OPEN_FLASH); } devsize = mtd_info.size; sgsize = mtd_info.erasesize; /* * NETtel/x86 boards that boot direct from INTEL FLASH also have a * boot sector at the top of the FLASH. When programming complete * images we need to not overwrite this. */ if (preserveconfig) { if ((tmpfd = open("/dev/flash/rootfs", O_RDONLY)) > 0) { if (ioctl(tmpfd, MEMGETINFO, &rootfs_info) >= 0) { if (rootfs_info.size & 0x000fffff) { devsize = devsize - (0x00100000 - (rootfs_info.size & 0x000fffff)); } } close(tmpfd); } }#else program_segment = program_blkmem_segment; if (ioctl(rd, BMGETSIZEB, &devsize) != 0) { error("ioctl(BMGETSIZEB) failed, errno=%d", errno); exit_failed(BAD_OPEN_FLASH); } if (ioctl(rd, BMSGSIZE, &sgsize) != 0) { error("ioctl(BMSGSIZE) failed, errno=%d", errno); exit_failed(BAD_OPEN_FLASH); }#endif } if (offset < 0) { error("offset is less than zero"); exit_failed(BAD_OFFSET); } if (offset >= devsize) { error("offset is greater than device size (%d)", devsize); exit_failed(BAD_OFFSET); } sgdata = malloc(sgsize); if (!sgdata) { error("Insufficient memory for image!"); exit_failed(NO_MEMORY); } if (checkimage) { check_buf = malloc(sgsize); if (!check_buf) { error("Insufficient memory for image!"); exit_failed(NO_MEMORY); } } /* * Fetch file into memory buffers. Exactly how depends on the exact * load method. Support for tftp, http and local file currently. */ if (!docgi) { fileblocks = NULL; file_offset = 0; file_length = 0; if (srvname) { if (doftp) ftpfetch(srvname, filename); else tftpfetch(srvname, filename); } else if (filefetch(filename) < 0) { error("failed to find %s", filename); exit_failed(NO_IMAGE); } } /* * Do some checks on the data received * - starts at offset 0 * - length > 0 * - no holes * - checksum */ if (fileblocks == NULL) { error("failed to load new image"); exit_failed(NO_IMAGE); }#ifndef CONFIG_USER_NETFLASH_CRYPTO if (!dothrow)#endif if (fileblocks->pos != 0) { error("failed to load new image"); exit_failed(NO_IMAGE); } if (file_length == 0) { error("failed to load new image"); exit_failed(NO_IMAGE); } for (fb = fileblocks; fb->next != NULL; fb = fb->next) if (fb->pos + fb->length != fb->next->pos) { error("failed to load new image"); exit_failed(NO_IMAGE); } if (!docgi) { notice("got \"%s\", length=%ld", filename, file_length); }#ifdef CONFIG_USER_NETFLASH_CRYPTO check_crypto_signature();#endif#ifdef CONFIG_USER_NETFLASH_HMACMD5 if (hmacmd5key) check_hmac_md5(hmacmd5key); else#endif if (dochecksum) chksum(); /* * Check the version information. * Side effect: this also checks whether version information is present, * and if so, removes it, since it doesn't need to get written to flash. */ if (doversion || doremoveversion) rc = check_vendor();#ifdef CONFIG_USER_NETFLASH_VERSION if (doversion || dohardwareversion) { switch (rc){ case 5: error("VERSION - you are trying to load an " "image that does not\n " "contain valid version information."); exit_failed(NO_VERSION); default: break; } } if (doversion) { switch (rc){#ifndef CONFIG_USER_NETFLASH_VERSION_ALLOW_CURRENT case 3: error("VERSION - you are trying to upgrade " "with the same firmware\n" " version that you already have."); exit_failed(ALREADY_CURRENT);#endif /* !CONFIG_USER_NETFLASH_VERSION_ALLOW_CURRENT */#ifndef CONFIG_USER_NETFLASH_VERSION_ALLOW_OLDER case 4: error("VERSION - you are trying to upgrade " "with an older version of\n" " the firmware."); exit_failed(VERSION_OLDER);#endif /* !CONFIG_USER_NETFLASH_VERSION_ALLOW_OLDER */ case 6: error("VERSION - you are trying to load an " "image for a different language."); exit_failed(BAD_LANGUAGE); case 0: default: break; } } if (dohardwareversion) { switch (rc){ case 1: error("VERSION - product name incorrect."); exit_failed(WRONG_PRODUCT); case 2: error("VERSION - vendor name incorrect."); exit_failed(WRONG_VENDOR); case 0: default: break; } }#endif /*CONFIG_USER_NETFLASH_VERSION*/#ifdef CONFIG_USER_NETFLASH_DECOMPRESS doinflate = check_decompression(doinflate);#else image_length = file_length;#endif /* Check image that we fetched will actually fit in the FLASH device. */ if (image_length > devsize - offset) { error("image too large for FLASH device (size=%d)", devsize - offset); exit_failed(IMAGE_TOO_BIG); } if (dothrow) { notice("the image is good."); exit(IMAGE_GOOD); }#if defined(CONFIG_USER_NETFLASH_WITH_CGI) && !defined(RECOVER_PROGRAM) if (docgi) { // let's let our parent know it's ok. kill(getppid(),SIGUSR1); }#endif if (flashing_rootfs(rdev)) { /* * Our filesystem is live, so we MUST kill processes if we haven't * done it already. */ notice("flashing root filesystem, kill is forced"); if (!dokill || dokillpartial) { kill_processes(console); } /* We must reboot on this platform */ doreboot = 1; }#ifdef CONFIG_PROP_LOGD_LOGD log_upgrade();#endif#if defined(CONFIG_USER_MOUNT_UMOUNT) || defined(CONFIG_USER_BUSYBOX_UMOUNT) if (doreboot) {#if defined(CONFIG_USER_FLATFSD_USE_FLASH_FS) && defined(CONFIG_PROP_LOGD_LOGD) /* Log the reboot to /etc/config before it's umounted */ char tmp[50]; sprintf(tmp, "/bin/logd reboot %d: %s", getpid(), basename(argv[0])); system(tmp);#endif umount_all(); }#endif#ifdef CONFIG_JFFS_FS /* Stop the JFFS garbage collector */ killprocname("jffs_gcd", SIGSTOP);#endif#ifdef CONFIG_JFFS2_FS /* Stop the JFFS2 garbage collector */ killprocname("jffs2_gcd_mtd1", SIGSTOP);#endif /* * Program the FLASH device. */ fflush(stdout); sleep(1); notice("programming FLASH device %s", rdev);#ifndef TEST_NO_DEVICE program_flash(rd, devsize, sgdata, sgsize, check_buf);#endif /* TEST_NO_DEVICE */ if (doreboot) { /* Wait half a second */ usleep(500000); raw_reboot(0xfee1dead, 672274793, 0x01234567); } return exitstatus;}static void exit_failed(int rc){#ifdef CONFIG_USER_NETFLASH_WATCHDOG close(watchdog_fd);#endif exit(rc);}/****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -