4 * Tool to create an ISO image from jigdo files
6 * Copyright (c) 2004 Steve McIntyre <steve@einval.com>
19 #include <sys/types.h>
30 FILE *G_logfile = NULL;
31 FILE *G_outfile = NULL;
32 FILE *G_missing_file = NULL;
33 long long G_start_offset = 0;
34 long long G_end_offset = 0;
37 UINT64 G_out_size = 0;
38 char *G_missing_filename = NULL;
50 match_list_t *G_match_list_head = NULL;
51 match_list_t *G_match_list_tail = NULL;
53 md5_list_t *G_md5_list_head = NULL;
54 md5_list_t *G_md5_list_tail = NULL;
56 extern void file_missing(char *missing, char *filename)
60 G_missing_file = fopen(missing, "wb");
63 jd_log(0, "file_missing: Unable to open missing log %s; error %d\n", missing, errno);
67 fprintf(G_missing_file, "%s\n", filename);
70 void display_progress(int verbose_level, INT64 image_size, INT64 current_offset, char *text)
72 if ((verbose_level <= G_verbose) && (image_size > 0))
73 jd_log(1, "\r %5.2f%% %-60.60s",
74 100.0 * current_offset / image_size, text);
77 static int add_match_entry(char *match)
79 match_list_t *entry = NULL;
80 char *mirror_path = NULL;
83 /* Split "Foo=/mirror/foo" into its components */
98 jd_log(0, "Could not parse malformed match entry \"%s\"\n", match);
102 entry = calloc(1, sizeof(*entry));
106 jd_log(1, "Adding match entry %s:%s\n", match, mirror_path);
108 entry->match = match;
109 entry->mirror_path = mirror_path;
111 if (!G_match_list_head)
113 G_match_list_head = entry;
114 G_match_list_tail = entry;
118 G_match_list_tail->next = entry;
119 G_match_list_tail = entry;
125 static void usage(char *progname)
127 printf("%s [OPTIONS]\n\n", progname);
128 printf(" Options:\n");
129 printf(" -M <missing name> Rather than try to build the image, just check that\n");
130 printf(" all the needed files are available. If any are missing,\n");
131 printf(" list them in this file.\n");
132 printf(" -d <DB name> Specify an input MD5 database file, as created by jigsum\n");
133 printf(" -e <bytenum> End byte number; will end at EOF if not specified\n");
134 printf(" -f <MD5 name> Specify an input MD5 file. MD5s must be in jigdo's\n");
135 printf(" pseudo-base64 format\n");
136 printf(" -j <jigdo name> Specify the input jigdo file\n");
137 printf(" -l <logfile> Specify a logfile to append to.\n");
138 printf(" If not specified, will log to stderr\n");
139 printf(" -m <item=path> Map <item> to <path> to find the files in the mirror\n");
140 printf(" -o <outfile> Specify a file to write the ISO image to.\n");
141 printf(" If not specified, will write to stdout\n");
142 printf(" -q Quick mode. Don't check MD5sums. Dangerous!\n");
143 printf(" -s <bytenum> Start byte number; will start at 0 if not specified\n");
144 printf(" -t <template name> Specify the input template file\n");
145 printf(" -v Make the output logging more verbose\n");
146 printf(" -z Don't attempt to rebuild the image; simply print its\n");
147 printf(" size in bytes\n");
150 int main(int argc, char **argv)
152 char *template_filename = NULL;
153 char *jigdo_filename = NULL;
154 char *md5_filename = NULL;
155 char *output_name = NULL;
156 char *db_filename = NULL;
161 db_template_entry_t template;
163 INT64 current_offset = 0;
164 unsigned char data_buf[BUF_SIZE];
165 INT64 bytes_read = 0;
166 INT64 bytes_written = 0;
167 struct mk_MD5Context image_context;
168 unsigned char image_md5[16];
175 c = getopt(argc, argv, ":?M:d:e:f:h:j:l:m:o:qs:t:vz");
188 G_logfile = fopen(optarg, "ab");
191 fprintf(stderr, "Unable to open log file %s\n", optarg);
194 setlinebuf(G_logfile);
197 output_name = optarg;
198 G_outfile = fopen(output_name, "wb");
201 jd_log(0, "Unable to open output file %s\n", optarg);
208 jd_log(0, "Can only specify one jigdo file!\n");
212 jigdo_filename = optarg;
215 if (template_filename)
217 jd_log(0, "Can only specify one template file!\n");
221 template_filename = optarg;
226 jd_log(0, "Can only specify one MD5 file!\n");
230 md5_filename = optarg;
235 jd_log(0, "Can only specify one db file!\n");
239 db_filename = optarg;
242 error = add_match_entry(strdup(optarg));
247 G_missing_filename = optarg;
250 jd_log(0, "Missing argument!\n");
259 G_start_offset = strtoull(optarg, NULL, 10);
260 if (G_start_offset != 0)
264 G_end_offset = strtoull(optarg, NULL, 10);
265 if (G_end_offset != 0)
272 jd_log(0, "Unknown option!\n");
277 if ((NULL == jigdo_filename) &&
278 (NULL == md5_filename) &&
279 (NULL == db_filename) &&
282 jd_log(0, "No jigdo file, DB file or MD5 file specified!\n");
287 if (NULL == template_filename)
289 jd_log(0, "No template file specified!\n");
296 /* Build up a list of the files we've been fed */
297 error = parse_md5_file(md5_filename, &G_md5_list_head);
300 jd_log(0, "Unable to parse the MD5 file %s\n", md5_filename);
307 /* Build up a list of file mappings */
308 error = parse_jigdo_file(jigdo_filename, &G_md5_list_head, G_match_list_head, G_missing_filename);
311 jd_log(0, "Unable to parse the jigdo file %s\n", jigdo_filename);
317 output_name = "to stdout";
321 dbp = db_open(db_filename);
324 jd_log(0, "Failed to open DB file %s, error %d\n", db_filename, errno);
327 /* If we have a DB, then we should cache the template
328 * information in it too. Check and see if there is
329 * information about this template file in the database
333 /* See if we know about this template file */
334 error = db_lookup_template_by_path(dbp, template_filename, &template);
337 /* Not found. Parse it and put the details in the database */
338 error = add_new_template_file(dbp, template_filename);
341 jd_log(0, "Unable to add template file %s to database, error %d\n",
342 template_filename, error);
345 error = db_lookup_template_by_path(dbp, template_filename, &template);
348 jd_log(0, "Unable to re-read newly-added template file %s, error %d!\n",
349 template_filename, error);
354 /* Allocate enough space to cache details about 1 compressed lump,
355 * that's all we need here */
359 jd_log(0, "Unable to init JD cache interface, error %d\n", error);
363 jdp = jd_open(dbp, template_filename);
367 jd_log(0, "Unable to open JD interface for template file %s (error %d)\n",
368 template_filename, error);
373 mk_MD5Init(&image_context);
375 error = jd_size(jdp, &G_out_size);
378 jd_log(0, "Unable to read image size from the template information. Error %d\n", error);
382 if (0 == G_end_offset)
383 G_end_offset = G_out_size;
385 /* Now the main loop - iterate in read/write/md5sum */
386 current_offset = G_start_offset;
387 while (!error && (current_offset < G_end_offset))
389 error = jd_read(jdp, current_offset, sizeof(data_buf), data_buf, &bytes_read);
392 jd_log(0, "Failed to read %d bytes at offset %lld, error %d\n",
393 sizeof(data_buf), current_offset, error);
400 while (bytes_written < bytes_read)
402 size_t this_write = fwrite(data_buf, 1, bytes_read, G_outfile);
403 if (-1 == this_write)
405 jd_log(0, "Failed to write %lld bytes at offset %lld, error %d\n",
406 bytes_read, current_offset, error);
409 bytes_written += this_write;
413 mk_MD5Update(&image_context, data_buf, bytes_read);
415 current_offset += bytes_read;
419 char *last_file = NULL;
420 error = jd_last_filename(jdp, &last_file);
421 if (!error && (G_end_offset > G_start_offset))
422 jd_log(1, "\r %5.2f%% %-60.60s",
423 100.0 * (current_offset - G_start_offset) / (G_end_offset - G_start_offset), last_file);
428 jd_log(0, "Failed to create image, error %d\n", error);
437 mk_MD5Final (image_md5, &image_context);
438 char *out_md5 = hex_dump(image_md5, 16);
439 jd_log(1, "Output image MD5 is %s\n", out_md5);
442 jd_log(1, "Output image length written is %lld bytes\n", G_end_offset - G_start_offset);
446 /* Read the template file and actually build the image to <outfile> */
447 error = parse_template_file(template_filename, sizeonly, G_missing_filename,
448 G_outfile, output_name, dbp);
451 jd_log(0, "Unable to recreate image from template file %s\n", template_filename);
452 if (G_missing_filename)
453 jd_log(0, "%s contains the list of missing files\n", G_missing_filename);
462 int jd_log(int level, char *fmt, ...)
467 if (level <= G_verbose)
470 error = vfprintf(G_logfile, fmt, ap);