fwupgrade.c

00001 
00013 #include "common.h"
00014 #include <sys/stat.h>
00015 #include <sys/types.h>
00016 #include <fcntl.h>
00017 #include <string.h>
00018 /* To handle .exe files, this must exist */
00019 #if HAVE_ZLIB_H
00020 #include <zlib.h>
00021 #endif
00022 /* You need this 10 MB buffer for this operation... */
00023 #define BUFFERSIZE 10*1024*1024
00024 
00025 static int progress (u_int64_t sent, u_int64_t total, const char* buf, unsigned len, void *data)
00026 {
00027   int percent = (sent*100)/total;
00028 #ifdef __WIN32__
00029   printf("Progress: %I64u of %I64u (%d%%)\r", sent, total, percent);
00030 #else
00031   printf("Progress: %llu of %llu (%d%%)\r", sent, total, percent);
00032 #endif
00033   fflush(stdout);
00034   return 0;
00035 }
00036 
00037 static void usage (void)
00038 {
00039   fprintf(stderr, "usage: fwupgrade [ -D<debuglvl> ] <path>\n");
00040   exit(1);
00041 }
00042 
00046 static int read_in_fw(char *path, unsigned char *buffer) {
00047   /* File descriptor and pointer */
00048   int fd;
00049   size_t bread;
00050 
00051   /* Read in the firmware file */
00052 #ifdef __WIN32__
00053   if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
00054 #else
00055   if ( (fd = open(path, O_RDONLY)) == -1 ) {
00056 #endif
00057     printf("Could not open firmware file descriptor.\n");
00058     return -1;
00059   }
00060   bread = read(fd, buffer, BUFFERSIZE);
00061   if (bread < 0) {
00062     printf("Error while reading firmware file.\n");
00063     close(fd);
00064     return -1;
00065   }
00066   
00067   if (bread == BUFFERSIZE) {
00068     printf("Warning: this firmware file is very large.\n");
00069     printf("It probably cannot be properly decoded.\n");
00070   }
00071   close(fd);
00072   printf("Read in a firmware file of size 0x%x.\n", bread);
00073   if (bread < 1024) {
00074     printf("Ridiculously small firmware file. Aborting.\n");
00075     return -1;
00076   }
00077   return bread;
00078 }
00079 
00080 #if HAVE_ZLIB_H
00081 static void dexor_fw_image(unsigned char *buffer, size_t zimglen) {
00082   register int t = 0;
00083   register int i;
00084   register unsigned char c;
00085   char key[] = "SamBanDam";
00086 
00087   printf("\"Dexoring\" firmware zlib image...\n");
00088   for (i = 0; i < zimglen; i++) {
00089     c = key[t] | 0x80;
00090     buffer[i] = buffer[i] ^ c;
00091     t = (i+1) % 9;
00092   }
00093 }
00094 
00098 static void decompress_fw_image(unsigned char *compressed, size_t compressed_len, 
00099                          unsigned char **decompressed, size_t *rawlen) {
00100   /* Allocate another big buffer */
00101   *decompressed = (unsigned char *) malloc(BUFFERSIZE);
00102   if (*decompressed == NULL) {
00103     *rawlen = 0;
00104     return;
00105   }
00106   printf("Calling zlib uncompress()...\n");
00107   *rawlen = BUFFERSIZE;
00108   if (uncompress(*decompressed, (uLongf*) rawlen, compressed, compressed_len) != Z_OK) {
00109     printf("There was an uncompress error.\n");
00110     *rawlen = 0;
00111     return;
00112   }
00113 }
00114 
00118 static int write_fw_file(char *path, 
00119                   unsigned char *decompressed,
00120                   size_t rawlen) {
00121   int fd = -1;
00122 
00123 #ifdef __WIN32__
00124    if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0664)) == -1 ) {
00125 #else
00126    if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0664)) == -1 ) {
00127 #endif
00128      printf("Could not open uncompressed file.\n");
00129      return -1;
00130    }
00131    if (write(fd, decompressed, rawlen) == -1) {
00132      printf("Error while writing uncompressed file.\n");
00133      close(fd);
00134      unlink(path);
00135      return -1;
00136    }
00137    close(fd);
00138    return 0;
00139 }
00140 #endif
00141 
00145 static int prompt()
00146 {
00147   char buff[2];
00148   
00149   while (1) {
00150     fprintf(stdout, "> ");
00151     if ( fgets(buff, sizeof(buff), stdin) == NULL ) {
00152       if (ferror(stdin)) {
00153         fprintf(stderr, "File error on stdin\n");
00154       } else {
00155         fprintf(stderr, "EOF on stdin\n");
00156       }
00157       return 1;
00158     }
00159     if (buff[0] == 'y') {
00160       return 0;
00161     } else if (buff[0] == 'n') {
00162       return 1;
00163     }
00164   }
00165 }
00166 
00167 int main(int argc, char **argv)
00168 {
00169   njb_t njbs[NJB_MAX_DEVICES], *njb;
00170   int n, opt, debug;
00171   extern int optind;
00172   extern char *optarg;
00173   char *path;
00174   char *sendpath;
00175   char *lang;
00176   unsigned char *buffer;
00177   size_t bread;
00178   
00179   debug = 0;
00180   while ( (opt = getopt(argc, argv, "D:")) != -1 ) {
00181     switch (opt) {
00182     case 'D':
00183       debug = atoi(optarg);
00184       break;
00185     default:
00186       usage();
00187       break;
00188     }
00189   }
00190   argc -= optind;
00191   argv += optind;
00192   
00193   if ( argc != 1 ) usage();
00194   
00195   if ( debug ) NJB_Set_Debug(debug);
00196   
00197   /*
00198    * Check environment variables $LANG and $LC_CTYPE
00199    * to see if we want to support UTF-8 unicode
00200    * $LANG = "xx_XX.UTF-8" or $LC_CTYPE = "?"
00201    * trigger unicode support.
00202    */
00203   lang = getenv("LANG");
00204   if (lang != NULL) {
00205     if (strlen(lang) > 5) {
00206       if (!strcmp(&lang[strlen(lang)-5], "UTF-8")) {
00207         NJB_Set_Unicode(NJB_UC_UTF8);
00208       }
00209     }
00210   }
00211   
00212   path = argv[0];
00213   
00214   printf("Analyzing firmware file %s...\n", path);
00215 
00216   /* Allocate a buffer */
00217   buffer = (unsigned char *) malloc(BUFFERSIZE);
00218   if (buffer == NULL) {
00219     printf("Could not allocate a firmware scanning buffer.\n");
00220     return 1;
00221   }
00222 
00223   /* Read in to buffer */
00224   bread = read_in_fw(path, buffer);
00225   if (bread == -1) {
00226     return 1;
00227   }
00228 
00229   /*
00230    * See if this is a RAW (dexored) firmware image, all
00231    * firmware images starts with the string "CIFF"
00232    */
00233   if (buffer[0] == 'C' && buffer[1] == 'I' && 
00234       buffer[2] == 'F' && buffer[3] == 'F') {
00235     printf("This seems to be a raw (dexored) firmware image.\n");
00236     sendpath = path;
00237   } else {
00238 #if HAVE_ZLIB_H
00239         char uncompressed_file[] = "tempimage.bin";
00240     /* Length of the zlib compressed image */
00241     unsigned int zimglen;
00242     /* Pointer into file buffer */
00243     unsigned int offset = 0;
00244     unsigned char *decompressed;
00245     size_t rawlen;
00246         int i;
00247 
00248     printf("This seems to be a zlib compressed windows executable.\n");
00249     /* Scanning for zlib header */
00250     printf("Scanning for zlib header...\n");
00251     for (i = 0; i < bread; i++) {
00252       if (buffer[i] == 0xAB && buffer[i+1] == 0x3B && buffer[i+2] == 0x01) {
00253         offset = i-4;
00254       }
00255     }
00256     if (offset == 0) {
00257       printf("Could not locate a zlib header in this firmware file.\n");
00258       return 1;
00259     } else {
00260       printf("Found zlib header at file position 0x%x.\n", offset);
00261     }
00262     
00263     zimglen = buffer[offset+3] << 24 | buffer[offset+2] << 16 
00264       | buffer[offset+1] << 8 | buffer[offset];
00265     printf("Zlib compressed image length: 0x%x\n", zimglen);
00266     if (zimglen > bread-offset) {
00267       printf("Inconsistent length of zlib compressed image, aborting.\n");
00268       return 1;
00269     }
00270     
00271     /* "Dexor" the firmware image */
00272     dexor_fw_image(&buffer[offset+4], zimglen);
00273 
00274     /* Decompress zlib image using Zlib */
00275     decompress_fw_image(&buffer[offset+4], zimglen, &decompressed, &rawlen);
00276     if (rawlen == 0) {
00277       printf("Decompression failed. Aborting.\n");
00278       return 1;
00279     }
00280     printf("Decompressed image size: 0x%x\n", rawlen);
00281     if (decompressed[0] == 'C' && decompressed[1] == 'I' &&
00282         decompressed[2] == 'F' && decompressed[3] == 'F') {
00283       printf("The extracted image looks like a firmware file.\n");
00284     } else {
00285       printf("The extracted image does not look like a firmware file.\n");
00286       printf("Aborting.\n");
00287       return 1;
00288     }
00289 
00290     /* Write out decompressed file */
00291     printf("Writing out the extracted image to disk as \"%s\".\n", uncompressed_file);
00292     if (write_fw_file(uncompressed_file, decompressed, rawlen) == -1) {
00293       printf("Failed to write uncompressed file. Aborting.\n");
00294       return 1;
00295     }
00296     
00297     sendpath = uncompressed_file;
00298     
00299     free(decompressed);
00300 
00301 #else
00302     printf("This may be an zlib compressed .exe file firmware.\n");
00303     printf("You must compile the \"fwupgrade\" program on a system\n");
00304     printf("which has the zlib library and headers properly installed\n");
00305     printf("to enable the compression of zlib compressed firmware images.\n");
00306 #endif    
00307   }
00308   free(buffer);
00309     
00310   printf("Sending firmware file to jukebox\n");
00311   if (NJB_Discover(njbs, 0, &n) == -1) {
00312     fprintf(stderr, "could not locate any jukeboxes\n");
00313     return 1;
00314   }
00315   
00316   if ( n == 0 ) {
00317     fprintf(stderr, "no NJB devices found\n");
00318     return 0;
00319   } 
00320   
00321   njb = njbs;
00322   
00323   if ( NJB_Open(njb) == -1 ) {
00324     NJB_Error_Dump(njb,stderr);
00325     return 1;
00326   }
00327   
00328   NJB_Capture(njb);
00329 
00330   printf("I will now send the firmware to your device.\n");
00331   printf("Continue? (y/n)\n");
00332   if (prompt() == 0) {
00333     if ( NJB_Send_Firmware(njb, sendpath, progress, NULL) == -1 ) {
00334       NJB_Error_Dump(njb,stderr);
00335     } else {
00336       printf("\nFirmware upload complete.");
00337     }
00338     printf("\n");
00339   } else {
00340     printf("Aborted.\n");
00341   }
00342   
00343   NJB_Release(njb);
00344   
00345   NJB_Close(njb);
00346   
00347   return 0;
00348 }

Generated on Tue Apr 18 12:45:56 2006 for libnjb by  doxygen 1.4.6