Re-factoring:
[jigit.git] / mkimage.c
1 /*
2  * mkimage
3  *
4  * Tool to create an ISO image from jigdo files
5  *
6  * Copyright (c) 2004 Steve McIntyre <steve@einval.com>
7  *
8  * GPL v2 - see COPYING
9  */
10
11 #define BZ2_SUPPORT
12
13 #include <errno.h>
14 #include <math.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <limits.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <sys/mman.h>
24 #include "endian.h"
25 #include "jigdb.h"
26 #include "jte.h"
27
28 FILE *G_logfile = NULL;
29 FILE *G_outfile = NULL;
30 FILE *G_missing_file = NULL;
31 long long G_start_offset = 0;
32 long long G_end_offset = 0;
33 int G_quick = 0;
34 int G_verbose = 0;
35 UINT64 G_out_size = 0;
36 char *G_missing_filename = NULL;
37
38 typedef enum state_
39 {
40     STARTING,
41     IN_DATA,
42     IN_DESC,
43     DUMP_DESC,
44     DONE,
45     ERROR
46 } e_state;
47
48 match_list_t *G_match_list_head = NULL;
49 match_list_t *G_match_list_tail = NULL;
50
51 md5_list_t *G_md5_list_head = NULL;
52 md5_list_t *G_md5_list_tail = NULL;
53
54 extern void file_missing(char *missing, char *filename)
55 {
56     if (!G_missing_file)
57     {
58         G_missing_file = fopen(missing, "wb");
59         if (!G_missing_file)
60         {
61             fprintf(G_logfile, "file_missing: Unable to open missing log %s; error %d\n", missing, errno);
62             exit(1);
63         }
64     }
65     fprintf(G_missing_file, "%s\n", filename);
66 }
67
68 extern void display_progress(FILE *file, char *text)
69 {
70     INT64 written = ftello(file);
71     if (G_out_size > 0)
72         fprintf(G_logfile, "\r %5.2f%%  %-60.60s",
73                100.0 * written / G_out_size, text);
74 }
75
76 static int add_match_entry(char *match)
77 {
78     match_list_t *entry = NULL;
79     char *mirror_path = NULL;
80     char *ptr = match;
81
82     /* Split "Foo=/mirror/foo" into its components */
83     while (*ptr)
84     {
85         if ('=' == *ptr)
86         {
87             *ptr = 0;
88             ptr++;
89             mirror_path = ptr;
90             break;
91         }
92         ptr++;
93     }
94
95     if (!mirror_path)
96     {
97         fprintf(G_logfile, "Could not parse malformed match entry \"%s\"\n", match);
98         return EINVAL;
99     }        
100     
101     entry = calloc(1, sizeof(*entry));
102     if (!entry)
103         return ENOMEM;
104
105     fprintf(G_logfile, "Adding match entry %s:%s\n", match, mirror_path);
106
107     entry->match = match;
108     entry->mirror_path = mirror_path;
109     
110     if (!G_match_list_head)
111     {
112         G_match_list_head = entry;
113         G_match_list_tail = entry;
114     }
115     else
116     {
117         G_match_list_tail->next = entry;
118         G_match_list_tail = entry;
119     }
120     
121     return 0;
122 }
123
124 static void usage(char *progname)
125 {
126     printf("%s [OPTIONS]\n\n", progname);
127     printf(" Options:\n");
128         printf(" -M <missing name>   Rather than try to build the image, just check that\n");
129         printf("                     all the needed files are available. If any are missing,\n");
130         printf("                     list them in this file.\n");
131     printf(" -d <DB name>        Specify an input MD5 database file, as created by jigsum\n");
132     printf(" -e <bytenum>        End byte number; will end at EOF if not specified\n");    
133     printf(" -f <MD5 name>       Specify an input MD5 file. MD5s must be in jigdo's\n");
134         printf("                     pseudo-base64 format\n");
135     printf(" -j <jigdo name>     Specify the input jigdo file\n");
136     printf(" -l <logfile>        Specify a logfile to append to.\n");
137     printf("                     If not specified, will log to stderr\n");
138     printf(" -m <item=path>      Map <item> to <path> to find the files in the mirror\n");
139     printf(" -o <outfile>        Specify a file to write the ISO image to.\n");
140     printf("                     If not specified, will write to stdout\n");
141     printf(" -q                  Quick mode. Don't check MD5sums. Dangerous!\n");
142     printf(" -s <bytenum>        Start byte number; will start at 0 if not specified\n");
143     printf(" -t <template name>  Specify the input template file\n");
144         printf(" -v                  Make the output logging more verbose\n");
145     printf(" -z                  Don't attempt to rebuild the image; simply print its\n");
146     printf("                     size in bytes\n");
147 }
148
149 int main(int argc, char **argv)
150 {
151     char *template_filename = NULL;
152     char *jigdo_filename = NULL;
153     char *md5_filename = NULL;
154     char *output_name = NULL;
155     char *db_filename = NULL;
156     int c = -1;
157     int error = 0;
158     int sizeonly = 0;
159     JIGDB *dbp = NULL;
160     db_template_entry_t *template;
161
162     G_logfile = stderr;
163     G_outfile = stdout;
164
165     while(1)
166     {
167         c = getopt(argc, argv, ":?M:d:e:f:h:j:l:m:o:qs:t:vz");
168         if (-1 == c)
169             break;
170         
171         switch(c)
172         {
173             case 'v':
174                 G_verbose++;
175                 break;
176             case 'q':
177                 G_quick = 1;
178                 break;
179             case 'l':
180                 G_logfile = fopen(optarg, "ab");
181                 if (!G_logfile)
182                 {
183                     fprintf(stderr, "Unable to open log file %s\n", optarg);
184                     return errno;
185                 }
186                 setlinebuf(G_logfile);
187                 break;
188             case 'o':
189                 output_name = optarg;
190                 G_outfile = fopen(output_name, "wb");
191                 if (!G_outfile)
192                 {
193                     fprintf(stderr, "Unable to open output file %s\n", optarg);
194                     return errno;
195                 }
196                 break;
197             case 'j':
198                 if (jigdo_filename)
199                 {
200                     fprintf(G_logfile, "Can only specify one jigdo file!\n");
201                     return EINVAL;
202                 }
203                 /* else */
204                 jigdo_filename = optarg;
205                 break;
206             case 't':
207                 if (template_filename)
208                 {
209                     fprintf(G_logfile, "Can only specify one template file!\n");
210                     return EINVAL;
211                 }
212                 /* else */
213                 template_filename = optarg;
214                 break;
215             case 'f':
216                 if (md5_filename)
217                 {
218                     fprintf(G_logfile, "Can only specify one MD5 file!\n");
219                     return EINVAL;
220                 }
221                 /* else */
222                 md5_filename = optarg;
223                 break;                
224             case 'd':
225                 if (db_filename)
226                 {
227                     fprintf(G_logfile, "Can only specify one db file!\n");
228                     return EINVAL;
229                 }
230                 /* else */
231                 db_filename = optarg;
232                 break;                
233             case 'm':
234                 error = add_match_entry(strdup(optarg));
235                 if (error)
236                     return error;
237                 break;
238             case 'M':
239                 G_missing_filename = optarg;
240                 break;
241             case ':':
242                 fprintf(G_logfile, "Missing argument!\n");
243                 return EINVAL;
244                 break;
245             case 'h':
246             case '?':
247                 usage(argv[0]);
248                 return 0;
249                 break;
250             case 's':
251                 G_start_offset = strtoull(optarg, NULL, 10);
252                 if (G_start_offset != 0)
253                     G_quick = 1;
254                 break;
255             case 'e':
256                 G_end_offset = strtoull(optarg, NULL, 10);
257                 if (G_end_offset != 0)
258                     G_quick = 1;
259                 break;
260             case 'z':
261                 sizeonly = 1;
262                 break;
263             default:
264                 fprintf(G_logfile, "Unknown option!\n");
265                 return EINVAL;
266         }
267     }
268
269     if (0 == G_end_offset)
270         G_end_offset = LLONG_MAX;
271
272     if ((NULL == jigdo_filename) &&
273         (NULL == md5_filename) && 
274         (NULL == db_filename) && 
275         !sizeonly)
276     {
277         fprintf(G_logfile, "No jigdo file, DB file or MD5 file specified!\n");
278         usage(argv[0]);
279         return EINVAL;
280     }
281     
282     if (NULL == template_filename)
283     {
284         fprintf(G_logfile, "No template file specified!\n");
285         usage(argv[0]);
286         return EINVAL;
287     }    
288
289     if (md5_filename)
290     {
291         /* Build up a list of the files we've been fed */
292         error = parse_md5_file(md5_filename);
293         if (error)
294         {
295             fprintf(G_logfile, "Unable to parse the MD5 file %s\n", md5_filename);
296             return error;
297         }
298     }
299
300     if (jigdo_filename)
301     {
302         /* Build up a list of file mappings */
303         error = parse_jigdo_file(jigdo_filename);
304         if (error)
305         {
306             fprintf(G_logfile, "Unable to parse the jigdo file %s\n", jigdo_filename);
307             return error;
308         }
309     }
310
311     if (!output_name)
312         output_name = "to stdout";
313
314     if (db_filename)
315     {
316         dbp = db_open(db_filename);
317         if (!dbp)
318         {
319             fprintf(G_logfile, "Failed to open DB file %s, error %d\n", db_filename, errno);
320             return errno;
321         }
322         /* If we have a DB, then we should cache the template
323          * information in it too. Check and see if there is
324          * information about this template file in the database
325          * already. */
326     }
327
328     /* See if we know about this template file */
329     error = db_lookup_template_by_path(dbp, template_filename, &template);
330     if (error)
331     {
332         /* Not found. Parse it and put the details in the database */
333         
334     }
335
336     /* Read the template file and actually build the image to <outfile> */
337     error = parse_template_file(template_filename, sizeonly, G_missing_filename,
338                                 G_outfile, output_name, dbp);
339     if (error)
340     {
341         fprintf(G_logfile, "Unable to recreate image from template file %s\n", template_filename);
342         if (G_missing_filename)
343             fprintf(G_logfile, "%s contains the list of missing files\n", G_missing_filename);
344         return error;
345     }        
346
347     fclose(G_logfile);
348     return 0;
349 }
350