Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Examples

fwupgrade.c

#include "common.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
/* To handle .exe files, this must exist */
#if HAVE_ZLIB_H
#include <zlib.h>
#endif
/* You need this 10 MB buffer for this operation... */
#define BUFFERSIZE 10*1024*1024

static int progress (u_int64_t sent, u_int64_t total, const char* buf, unsigned len, void *data)
{
  int percent = (sent*100)/total;
#ifdef __WIN32__
  printf("Progress: %I64u of %I64u (%d%%)\r", sent, total, percent);
#else
  printf("Progress: %llu of %llu (%d%%)\r", sent, total, percent);
#endif
  fflush(stdout);
  return 0;
}

static void usage (void)
{
  fprintf(stderr, "usage: fwupgrade [ -D<debuglvl> ] <path>\n");
  exit(1);
}

static int read_in_fw(char *path, unsigned char *buffer) {
  /* File descriptor and pointer */
  int fd;
  size_t bread;

  /* Read in the firmware file */
#ifdef __WIN32__
  if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
#else
  if ( (fd = open(path, O_RDONLY)) == -1 ) {
#endif
    printf("Could not open firmware file descriptor.\n");
    return -1;
  }
  bread = read(fd, buffer, BUFFERSIZE);
  if (bread < 0) {
    printf("Error while reading firmware file.\n");
    close(fd);
    return -1;
  }
  
  if (bread == BUFFERSIZE) {
    printf("Warning: this firmware file is very large.\n");
    printf("It probably cannot be properly decoded.\n");
  }
  close(fd);
  printf("Read in a firmware file of size 0x%x.\n", bread);
  if (bread < 1024) {
    printf("Ridiculously small firmware file. Aborting.\n");
    return -1;
  }
  return bread;
}

#if HAVE_ZLIB_H
static void dexor_fw_image(unsigned char *buffer, size_t zimglen) {
  register int t = 0;
  register int i;
  register unsigned char c;
  char key[] = "SamBanDam";

  printf("\"Dexoring\" firmware zlib image...\n");
  for (i = 0; i < zimglen; i++) {
    c = key[t] | 0x80;
    buffer[i] = buffer[i] ^ c;
    t = (i+1) % 9;
  }
}

static void decompress_fw_image(unsigned char *compressed, size_t compressed_len, 
                         unsigned char **decompressed, size_t *rawlen) {
  /* Allocate another big buffer */
  *decompressed = (unsigned char *) malloc(BUFFERSIZE);
  if (*decompressed == NULL) {
    *rawlen = 0;
    return;
  }
  printf("Calling zlib uncompress()...\n");
  *rawlen = BUFFERSIZE;
  if (uncompress(*decompressed, (uLongf*) rawlen, compressed, compressed_len) != Z_OK) {
    printf("There was an uncompress error.\n");
    *rawlen = 0;
    return;
  }
}

static int write_fw_file(char *path, 
                  unsigned char *decompressed,
                  size_t rawlen) {
  int fd = -1;

#ifdef __WIN32__
   if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0664)) == -1 ) {
#else
   if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0664)) == -1 ) {
#endif
     printf("Could not open uncompressed file.\n");
     return -1;
   }
   if (write(fd, decompressed, rawlen) == -1) {
     printf("Error while writing uncompressed file.\n");
     close(fd);
     unlink(path);
     return -1;
   }
   close(fd);
   return 0;
}
#endif

static int prompt()
{
  char buff[2];
  
  while (1) {
    fprintf(stdout, "> ");
    if ( fgets(buff, sizeof(buff), stdin) == NULL ) {
      if (ferror(stdin)) {
        fprintf(stderr, "File error on stdin\n");
      } else {
        fprintf(stderr, "EOF on stdin\n");
      }
      return 1;
    }
    if (buff[0] == 'y') {
      return 0;
    } else if (buff[0] == 'n') {
      return 1;
    }
  }
}

int main(int argc, char **argv)
{
  njb_t njbs[NJB_MAX_DEVICES], *njb;
  int n, opt, debug;
  extern int optind;
  extern char *optarg;
  char *path;
  char *sendpath;
  char *lang;
  unsigned char *buffer;
  size_t bread;
  
  debug = 0;
  while ( (opt = getopt(argc, argv, "D:")) != -1 ) {
    switch (opt) {
    case 'D':
      debug = atoi(optarg);
      break;
    default:
      usage();
      break;
    }
  }
  argc -= optind;
  argv += optind;
  
  if ( argc != 1 ) usage();
  
  if ( debug ) NJB_Set_Debug(debug);
  
  /*
   * Check environment variables $LANG and $LC_CTYPE
   * to see if we want to support UTF-8 unicode
   * $LANG = "xx_XX.UTF-8" or $LC_CTYPE = "?"
   * trigger unicode support.
   */
  lang = getenv("LANG");
  if (lang != NULL) {
    if (strlen(lang) > 5) {
      if (!strcmp(&lang[strlen(lang)-5], "UTF-8")) {
        NJB_Set_Unicode(NJB_UC_UTF8);
      }
    }
  }
  
  path = argv[0];
  
  printf("Analyzing firmware file %s...\n", path);

  /* Allocate a buffer */
  buffer = (unsigned char *) malloc(BUFFERSIZE);
  if (buffer == NULL) {
    printf("Could not allocate a firmware scanning buffer.\n");
    return 1;
  }

  /* Read in to buffer */
  bread = read_in_fw(path, buffer);
  if (bread == -1) {
    return 1;
  }

  /*
   * See if this is a RAW (dexored) firmware image, all
   * firmware images starts with the string "CIFF"
   */
  if (buffer[0] == 'C' && buffer[1] == 'I' && 
      buffer[2] == 'F' && buffer[3] == 'F') {
    printf("This seems to be a raw (dexored) firmware image.\n");
    sendpath = path;
  } else {
#if HAVE_ZLIB_H
        char uncompressed_file[] = "tempimage.bin";
    /* Length of the zlib compressed image */
    unsigned int zimglen;
    /* Pointer into file buffer */
    unsigned int offset = 0;
    unsigned char *decompressed;
    size_t rawlen;
        int i;

    printf("This seems to be a zlib compressed windows executable.\n");
    /* Scanning for zlib header */
    printf("Scanning for zlib header...\n");
    for (i = 0; i < bread; i++) {
      if (buffer[i] == 0xAB && buffer[i+1] == 0x3B && buffer[i+2] == 0x01) {
        offset = i-4;
      }
    }
    if (offset == 0) {
      printf("Could not locate a zlib header in this firmware file.\n");
      return 1;
    } else {
      printf("Found zlib header at file position 0x%x.\n", offset);
    }
    
    zimglen = buffer[offset+3] << 24 | buffer[offset+2] << 16 
      | buffer[offset+1] << 8 | buffer[offset];
    printf("Zlib compressed image length: 0x%x\n", zimglen);
    if (zimglen > bread-offset) {
      printf("Inconsistent length of zlib compressed image, aborting.\n");
      return 1;
    }
    
    /* "Dexor" the firmware image */
    dexor_fw_image(&buffer[offset+4], zimglen);

    /* Decompress zlib image using Zlib */
    decompress_fw_image(&buffer[offset+4], zimglen, &decompressed, &rawlen);
    if (rawlen == 0) {
      printf("Decompression failed. Aborting.\n");
      return 1;
    }
    printf("Decompressed image size: 0x%x\n", rawlen);
    if (decompressed[0] == 'C' && decompressed[1] == 'I' &&
        decompressed[2] == 'F' && decompressed[3] == 'F') {
      printf("The extracted image looks like a firmware file.\n");
    } else {
      printf("The extracted image does not look like a firmware file.\n");
      printf("Aborting.\n");
      return 1;
    }

    /* Write out decompressed file */
    printf("Writing out the extracted image to disk as \"%s\".\n", uncompressed_file);
    if (write_fw_file(uncompressed_file, decompressed, rawlen) == -1) {
      printf("Failed to write uncompressed file. Aborting.\n");
      return 1;
    }
    
    sendpath = uncompressed_file;
    
    free(decompressed);

#else
    printf("This may be an zlib compressed .exe file firmware.\n");
    printf("You must compile the \"fwupgrade\" program on a system\n");
    printf("which has the zlib library and headers properly installed\n");
    printf("to enable the compression of zlib compressed firmware images.\n");
#endif    
  }
  free(buffer);
    
  printf("Sending firmware file to jukebox\n");
  if (NJB_Discover(njbs, 0, &n) == -1) {
    fprintf(stderr, "could not locate any jukeboxes\n");
    return 1;
  }
  
  if ( n == 0 ) {
    fprintf(stderr, "no NJB devices found\n");
    return 0;
  } 
  
  njb = njbs;
  
  if ( NJB_Open(njb) == -1 ) {
    NJB_Error_Dump(njb,stderr);
    return 1;
  }
  
  NJB_Capture(njb);

  printf("I will now send the firmware to your device.\n");
  printf("Continue? (y/n)\n");
  if (prompt() == 0) {
    if ( NJB_Send_Firmware(njb, sendpath, progress, NULL) == -1 ) {
      NJB_Error_Dump(njb,stderr);
    } else {
      printf("\nFirmware upload complete.");
    }
    printf("\n");
  } else {
    printf("Aborted.\n");
  }
  
  NJB_Release(njb);
  
  NJB_Close(njb);
  
  return 0;
}

Generated on Thu Oct 20 20:35:56 2005 for libnjb by  doxygen 1.4.4