firmware-utils: honor env SOURCE_DATE_EPOCH
[oweals/openwrt.git] / tools / firmware-utils / src / hcsmakeimage.c
1 #include <stdlib.h>
2 #include <sys/types.h>
3 #include <stdio.h>
4 #include <inttypes.h>
5 #include <string.h>
6 #include <getopt.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <time.h>
10 #include <sys/stat.h>
11 #include <libgen.h>
12 #include "bcmalgo.h"
13
14
15 int flag_print_version;
16 int flag_print_help;
17 int flag_compress;
18
19 uint16_t sa2100_magic  = 0x2100;
20 uint16_t sa3349_magic  = 0x3349;
21 uint32_t default_date = 0x00000000; //A long time ago in a galaxy far far away....
22 uint32_t default_load_address = 0x80010000; //The default load_address for the firmware image
23
24 static void print_help ( const char* ename )
25 {
26         printf ( "Firmware image packer and calculator for broadcom-based modems.\n" );
27         printf ( "Part of bcm-utils package.\n" );
28         printf ( "(c) 2009 Necromant (http://necromant.ath.cx). Thanks to Luke-jr for his initial work.\n" );
29         printf ( "usage: %s [options]\n", ename );
30         printf ( "Valid options are:\n" );
31         printf ( "--magic_bytes=value \t- specify magic bytes at the beginning of the image. default - 3349\n" );
32         printf ( "\t\t\t these can be sa2100 (for DPC2100 modem),\n\t\t\t sa3349 (haxorware guys use this one for some reason),\n\t\t\t or a custom hex value e.g. 0xFFFF\n" );
33         printf ( "--compress \t\t - Make use of LZMA (weird!) compression (Doesn't work yet).\n" );
34         printf ( "--rev_maj=value\t\t - major revision number. default 0\n" );
35         printf ( "--rev_min=value\t\t - minor revision number default 0\n" );
36         printf ( "--filename=value\t - use this filename in header instead of default (input filename)\n" );
37         printf ( "--ldaddress=value\t - hex value of the target load address. defaults to 0x80010000\n" );
38         printf ( "--input_file=value\t - What file are we packing?\n" );
39         printf ( "--output_file=value\t - What file shall we write? (default: image.bin)\n" );
40 #ifdef _HAX0RSTYLE
41         printf ( "--credz\t - Give some credz!\n" );
42 #endif
43         printf ( "\n" );
44 }
45
46 static time_t source_date_epoch = -1;
47 static void set_source_date_epoch() {
48         char *env = getenv("SOURCE_DATE_EPOCH");
49         char *endptr = env;
50         errno = 0;
51         if (env && *env) {
52                 source_date_epoch = strtoull(env, &endptr, 10);
53                 if (errno || (endptr && *endptr != '\0')) {
54                         fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
55                         exit(1);
56                 }
57         }
58 }
59
60 int main ( int argc, char** argv )
61 {
62         if ( argc<2 )
63         {
64                 print_help ( argv[0] );
65         }
66
67         static struct option long_options[] =
68         {
69                 {"magic_bytes",          required_argument,   0,        'm'},
70                 {"rev_maj",        required_argument,   0,      'j'},
71                 {"rev_min",       required_argument,   0,     'n'},
72                 {"ldaddress",       required_argument,   0,     'l'},
73                 {"filename",       required_argument,   0,     'f'},
74                 {"input_file",       required_argument,   0,     'i'},
75                 {"output_file",       required_argument,   0,     'o'},
76                 {"compress",     no_argument,       &flag_compress,    'c'},
77                 {"version",     no_argument,       &flag_print_version,    'v'},
78                 {"help",        no_argument,       &flag_print_help,    'h'},
79                 {0, 0, 0, 0}
80         };
81         int option_index = 0;
82         int opt_result=0;
83         char* filename=NULL;
84         char* input=NULL;
85         char* magic=NULL;
86         char* major=NULL;
87         char* minor=NULL;
88         char* ldaddr=NULL;
89         char* output=NULL;
90
91         while ( opt_result>=0 )
92         {
93                 opt_result = getopt_long ( argc, argv, "m:j:n:f:i:o:vh", long_options, &option_index );
94                 switch ( opt_result )
95                 {
96                         case 0:
97                                 printf ( "o!\n" );
98                                 break;
99                         case 'h':
100                                 print_help ( argv[0] );
101                                 break;
102                         case 'l':
103                                 ldaddr=optarg;
104                                 break;
105                         case 'f':
106                                 filename=optarg;
107                                 break;
108                         case 'i':
109                                 input=optarg;
110                                 break;
111                         case 'o':
112                                 output=optarg;
113                                 break;
114                         case 'm':
115                                 magic=optarg;
116                                 break;
117                         case 'j':
118                                 major=optarg;
119                                 break;
120                         case 'n':
121                                 minor=optarg;
122                                 break;
123                 }
124         }
125         if ( input==NULL )
126         {
127                 printf ( "Telepaths are still on holidays. I guess you should tell me what file should I process.\n\n" );
128                 exit ( 1 );
129         }
130         if ( access ( input,R_OK ) !=0 )
131         {
132                 printf ( "I cannot access the file %s. Is it there? Am I allowed?\n\n", input );
133                 exit ( 1 );
134         }
135         uint32_t magicnum=sa2100_magic;
136
137         if ( magic )
138         {
139                 if ( strcmp ( magic,"sa2100" ) ==0 ) magicnum=sa2100_magic; else
140                                 if ( strcmp ( magic,"sa3349" ) ==0 ) magicnum=sa3349_magic; else
141                         {
142                                 sscanf ( magic, "0x%04X", &magicnum );
143                         }
144         }
145         unsigned int majrev=0;
146         if ( major )
147         {
148                 sscanf ( major, "%d", &majrev );
149         }
150         unsigned int minrev=0;
151         if ( minor )
152         {
153                 sscanf ( minor, "%d", &minrev );
154         }
155         uint32_t ldaddress = default_load_address;
156         if ( ldaddr )
157         {
158                 sscanf ( ldaddr, "0x%08X", &ldaddress );
159         }
160         char* dupe = strdup(input);
161         char* fname = basename ( dupe );
162         if ( filename )
163         {
164                 fname = filename;
165         }
166
167         time_t t = -1;
168         set_source_date_epoch();
169         if (source_date_epoch != -1) {
170                 t = source_date_epoch;
171         } else if ((time(&t) == (time_t)(-1))) {
172                 fprintf(stderr, "time call failed\n");
173                 return EXIT_FAILURE;
174         }
175
176         struct stat buf;
177         stat ( input,&buf );
178         ldr_header_t* head = construct_header ( magicnum, (uint16_t) majrev, (uint16_t) minrev, ( uint32_t ) t, ( uint32_t ) buf.st_size, ldaddress, fname, get_file_crc ( input ) );
179         free(dupe);
180         //uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc
181         //FILE* fd = fopen ("/tftpboot/haxorware11rev32.bin","r");
182         //fread(head,sizeof(ldr_header_t),1,fd);
183         char* filebuffer = malloc ( buf.st_size+10 );
184         FILE* fd = fopen ( input,"r" );
185         fread ( filebuffer, 1, buf.st_size,fd );
186         if (!output)
187                 {
188                 output = malloc(strlen(input+5));
189                 strcpy(output,input);
190                 strcat(output,".bin");
191                 }
192         dump_header ( head );
193         FILE* fd_out = fopen ( output,"w+" );
194         if (!fd_out)
195                 {
196                 fprintf(stderr, "Failed to open output file: %s\n", output);
197                 exit(1);
198                 }
199         fwrite ( head,1,sizeof ( ldr_header_t ),fd_out );
200         fwrite ( filebuffer,1,buf.st_size,fd_out );
201         printf("Firmware image %s is ready\n", output);
202         return 0;
203 }