]> git.proxmox.com Git - grub2.git/blame - util/mkisofs/mkisofs.c
2009-11-11 Robert Millan <rmh.grub@aybabtu.com>
[grub2.git] / util / mkisofs / mkisofs.c
CommitLineData
4b4c4f64
RM
1/*
2 * Program mkisofs.c - generate iso9660 filesystem based upon directory
3 * tree on hard disk.
4
5 Written by Eric Youngdale (1993).
6
7 Copyright 1993 Yggdrasil Computing, Incorporated
8
fa8b1c51
RM
9 Copyright (C) 2009 Free Software Foundation, Inc.
10
4b4c4f64
RM
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
fa8b1c51 13 the Free Software Foundation; either version 3, or (at your option)
4b4c4f64
RM
14 any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
fa8b1c51 22 along with this program; if not, see <http://www.gnu.org/licenses/>.
4b4c4f64
RM
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
24
11e9a115 25static char rcsid[] ="$Id: mkisofs.c,v 1.32 1999/03/07 21:48:49 eric Exp $";
4b4c4f64
RM
26
27#include <errno.h>
4b4c4f64 28#include "config.h"
63eb2d63 29#include "mkisofs.h"
11e9a115 30#include "match.h"
4b4c4f64
RM
31
32#ifdef linux
33#include <getopt.h>
63eb2d63
RM
34#else
35#include "getopt.h"
4b4c4f64
RM
36#endif
37
38#include "iso9660.h"
39#include <ctype.h>
40
41#ifndef VMS
42#include <time.h>
43#else
44#include <sys/time.h>
45#include "vms.h"
46#endif
47
48#include <stdlib.h>
49#include <sys/stat.h>
50
51#ifndef VMS
52#ifdef HAVE_UNISTD_H
53#include <unistd.h>
54#endif
55#endif
11e9a115 56#include <fctldefs.h>
4b4c4f64
RM
57
58#include "exclude.h"
59
60#ifdef __NetBSD__
61#include <sys/time.h>
62#include <sys/resource.h>
63#endif
64
65struct directory * root = NULL;
66
11e9a115 67static char version_string[] = "mkisofs 1.12b5";
4b4c4f64 68
11e9a115 69char * outfile;
4b4c4f64 70FILE * discimage;
2c55dbc0
RM
71uint64_t next_extent = 0;
72uint64_t last_extent = 0;
73uint64_t session_start = 0;
4b4c4f64
RM
74unsigned int path_table_size = 0;
75unsigned int path_table[4] = {0,};
76unsigned int path_blocks = 0;
63eb2d63
RM
77
78
79unsigned int jpath_table_size = 0;
80unsigned int jpath_table[4] = {0,};
81unsigned int jpath_blocks = 0;
82
4b4c4f64 83struct iso_directory_record root_record;
63eb2d63
RM
84struct iso_directory_record jroot_record;
85
4b4c4f64
RM
86char * extension_record = NULL;
87int extension_record_extent = 0;
63eb2d63 88int extension_record_size = 0;
4b4c4f64
RM
89
90/* These variables are associated with command line options */
91int use_eltorito = 0;
e1f240ff
RM
92int use_eltorito_emul_floppy = 0;
93int use_boot_info_table = 0;
4b4c4f64 94int use_RockRidge = 0;
63eb2d63
RM
95int use_Joliet = 0;
96int verbose = 1;
4b4c4f64
RM
97int all_files = 0;
98int follow_links = 0;
99int rationalize = 0;
100int generate_tables = 0;
63eb2d63
RM
101int print_size = 0;
102int split_output = 0;
4b4c4f64
RM
103char * preparer = PREPARER_DEFAULT;
104char * publisher = PUBLISHER_DEFAULT;
105char * appid = APPID_DEFAULT;
106char * copyright = COPYRIGHT_DEFAULT;
107char * biblio = BIBLIO_DEFAULT;
108char * abstract = ABSTRACT_DEFAULT;
109char * volset_id = VOLSET_ID_DEFAULT;
110char * volume_id = VOLUME_ID_DEFAULT;
111char * system_id = SYSTEM_ID_DEFAULT;
112char * boot_catalog = BOOT_CATALOG_DEFAULT;
113char * boot_image = BOOT_IMAGE_DEFAULT;
11e9a115
RM
114int volume_set_size = 1;
115int volume_sequence_number = 1;
4b4c4f64
RM
116
117int omit_period = 0; /* Violates iso9660, but these are a pain */
118int transparent_compression = 0; /* So far only works with linux */
119int omit_version_number = 0; /* May violate iso9660, but noone uses vers*/
dc83dd64 120unsigned int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */
4b4c4f64
RM
121int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with
122 DOS */
123int allow_leading_dots = 0; /* DOS cannot read names with leading dots */
63eb2d63
RM
124int split_SL_component = 1; /* circumvent a bug in the SunOS driver */
125int split_SL_field = 1; /* circumvent a bug in the SunOS */
4b4c4f64
RM
126
127struct rcopts{
128 char * tag;
129 char ** variable;
130};
131
132struct rcopts rcopt[] = {
133 {"PREP", &preparer},
134 {"PUBL", &publisher},
135 {"APPI", &appid},
136 {"COPY", &copyright},
137 {"BIBL", &biblio},
138 {"ABST", &abstract},
139 {"VOLS", &volset_id},
140 {"VOLI", &volume_id},
141 {"SYSI", &system_id},
142 {NULL, NULL}
143};
144
63eb2d63
RM
145/*
146 * In case it isn't obvious, the option handling code was ripped off from GNU-ld.
147 */
148struct ld_option
149{
150 /* The long option information. */
151 struct option opt;
152 /* The short option with the same meaning ('\0' if none). */
153 char shortopt;
154 /* The name of the argument (NULL if none). */
155 const char *arg;
156 /* The documentation string. If this is NULL, this is a synonym for
157 the previous option. */
158 const char *doc;
159 enum
160 {
161 /* Use one dash before long option name. */
162 ONE_DASH,
163 /* Use two dashes before long option name. */
164 TWO_DASHES,
165 /* Don't mention this option in --help output. */
166 NO_HELP
167 } control;
168};
169
170/* Codes used for the long options with no short synonyms. 150 isn't
171 special; it's just an arbitrary non-ASCII char value. */
172#define OPTION_HELP 150
173#define OPTION_QUIET 151
174#define OPTION_NOSPLIT_SL_COMPONENT 152
175#define OPTION_NOSPLIT_SL_FIELD 153
176#define OPTION_PRINT_SIZE 154
177#define OPTION_SPLIT_OUTPUT 155
11e9a115
RM
178#define OPTION_ABSTRACT 156
179#define OPTION_BIBLIO 157
180#define OPTION_COPYRIGHT 158
181#define OPTION_SYSID 159
182#define OPTION_VOLSET 160
183#define OPTION_VOLSET_SIZE 161
184#define OPTION_VOLSET_SEQ_NUM 162
185#define OPTION_I_HIDE 163
186#define OPTION_J_HIDE 164
187#define OPTION_LOG_FILE 165
63eb2d63 188
fa8b1c51
RM
189#define OPTION_CREAT_DATE 166
190#define OPTION_MODIF_DATE 167
191#define OPTION_EXPIR_DATE 168
192#define OPTION_EFFEC_DATE 169
193
e1f240ff
RM
194#define OPTION_BOOT_INFO_TABLE 170
195#define OPTION_NO_EMUL_BOOT 171
196#define OPTION_ELTORITO_EMUL_FLOPPY 172
197
63eb2d63
RM
198static const struct ld_option ld_options[] =
199{
200 { {"all-files", no_argument, NULL, 'a'},
201 'a', NULL, "Process all files (don't skip backup files)", ONE_DASH },
11e9a115
RM
202 { {"abstract", required_argument, NULL, OPTION_ABSTRACT},
203 '\0', "FILE", "Set Abstract filename" , ONE_DASH },
63eb2d63
RM
204 { {"appid", required_argument, NULL, 'A'},
205 'A', "ID", "Set Application ID" , ONE_DASH },
11e9a115
RM
206 { {"biblio", required_argument, NULL, OPTION_BIBLIO},
207 '\0', "FILE", "Set Bibliographic filename" , ONE_DASH },
208 { {"copyright", required_argument, NULL, OPTION_COPYRIGHT},
209 '\0', "FILE", "Set Copyright filename" , ONE_DASH },
63eb2d63
RM
210 { {"eltorito-boot", required_argument, NULL, 'b'},
211 'b', "FILE", "Set El Torito boot image name" , ONE_DASH },
212 { {"eltorito-catalog", required_argument, NULL, 'c'},
213 'c', "FILE", "Set El Torito boot catalog name" , ONE_DASH },
e1f240ff
RM
214 { {"boot-info-table", no_argument, NULL, OPTION_BOOT_INFO_TABLE },
215 '\0', NULL, "Patch Boot Info Table in El Torito boot image" , ONE_DASH },
216 { {"no-emul-boot", no_argument, NULL, OPTION_NO_EMUL_BOOT },
217 '\0', NULL, "Dummy option for backward compatibility" , ONE_DASH },
218 { {"eltorito-emul-floppy", no_argument, NULL, OPTION_ELTORITO_EMUL_FLOPPY },
219 '\0', NULL, "Enable floppy drive emulation for El Torito" , TWO_DASHES },
63eb2d63 220 { {"cdwrite-params", required_argument, NULL, 'C'},
6a9cead5 221 'C', "PARAMS", "Magic parameters from cdrecord" , ONE_DASH },
63eb2d63
RM
222 { {"omit-period", no_argument, NULL, 'd'},
223 'd', NULL, "Omit trailing periods from filenames", ONE_DASH },
224 { {"disable-deep-relocation", no_argument, NULL, 'D'},
225 'D', NULL, "Disable deep directory relocation", ONE_DASH },
226 { {"follow-links", no_argument, NULL, 'f'},
227 'f', NULL, "Follow symbolic links", ONE_DASH },
228 { {"help", no_argument, NULL, OPTION_HELP},
229 '\0', NULL, "Print option help", ONE_DASH },
11e9a115
RM
230 { {"hide", required_argument, NULL, OPTION_I_HIDE},
231 '\0', "GLOBFILE", "Hide ISO9660/RR file" , ONE_DASH },
232 { {"hide-joliet", required_argument, NULL, OPTION_J_HIDE},
233 '\0', "GLOBFILE", "Hide Joliet file" , ONE_DASH },
63eb2d63
RM
234 { {NULL, required_argument, NULL, 'i'},
235 'i', "ADD_FILES", "No longer supported" , TWO_DASHES },
236 { {"joliet", no_argument, NULL, 'J'},
237 'J', NULL, "Generate Joliet directory information", ONE_DASH },
238 { {"full-iso9660-filenames", no_argument, NULL, 'l'},
239 'l', NULL, "Allow full 32 character filenames for iso9660 names", ONE_DASH },
240 { {"allow-leading-dots", no_argument, NULL, 'L'},
241 'L', NULL, "Allow iso9660 filenames to start with '.'", ONE_DASH },
11e9a115
RM
242 { {"log-file", required_argument, NULL, OPTION_LOG_FILE},
243 '\0', "LOG_FILE", "Re-direct messages to LOG_FILE", ONE_DASH },
63eb2d63
RM
244 { {"exclude", required_argument, NULL, 'm'},
245 'm', "GLOBFILE", "Exclude file name" , ONE_DASH },
246 { {"prev-session", required_argument, NULL, 'M'},
247 'M', "FILE", "Set path to previous session to merge" , ONE_DASH },
248 { {"omit-version-number", no_argument, NULL, 'N'},
249 'N', NULL, "Omit version number from iso9660 filename", ONE_DASH },
250 { {"no-split-symlink-components", no_argument, NULL, 0},
251 0, NULL, "Inhibit splitting symlink components" , ONE_DASH },
252 { {"no-split-symlink-fields", no_argument, NULL, 0},
253 0, NULL, "Inhibit splitting symlink fields" , ONE_DASH },
254 { {"output", required_argument, NULL, 'o'},
255 'o', "FILE", "Set output file name" , ONE_DASH },
256 { {"preparer", required_argument, NULL, 'p'},
257 'p', "PREP", "Set Volume preparer" , ONE_DASH },
258 { {"print-size", no_argument, NULL, OPTION_PRINT_SIZE},
259 '\0', NULL, "Print estimated filesystem size and exit", ONE_DASH },
260 { {"publisher", required_argument, NULL, 'P'},
261 'P', "PUB", "Set Volume publisher" , ONE_DASH },
262 { {"quiet", no_argument, NULL, OPTION_QUIET},
263 '\0', NULL, "Run quietly", ONE_DASH },
264 { {"rational-rock", no_argument, NULL, 'r'},
265 'r', NULL, "Generate rationalized Rock Ridge directory information", ONE_DASH },
266 { {"rock", no_argument, NULL, 'R'},
267 'R', NULL, "Generate Rock Ridge directory information", ONE_DASH },
268 { {"split-output", no_argument, NULL, OPTION_SPLIT_OUTPUT},
269 '\0', NULL, "Split output into files of approx. 1GB size", ONE_DASH },
11e9a115
RM
270 { {"sysid", required_argument, NULL, OPTION_SYSID},
271 '\0', "ID", "Set System ID" , ONE_DASH },
63eb2d63
RM
272 { {"translation-table", no_argument, NULL, 'T'},
273 'T', NULL, "Generate translation tables for systems that don't understand long filenames", ONE_DASH },
274 { {"verbose", no_argument, NULL, 'v'},
275 'v', NULL, "Verbose", ONE_DASH },
276 { {"volid", required_argument, NULL, 'V'},
277 'V', "ID", "Set Volume ID" , ONE_DASH },
11e9a115
RM
278 { {"volset", required_argument, NULL, OPTION_VOLSET},
279 '\0', "ID", "Set Volume set ID" , ONE_DASH },
280 { {"volset-size", required_argument, NULL, OPTION_VOLSET_SIZE},
281 '\0', "#", "Set Volume set size" , ONE_DASH },
282 { {"volset-seqno", required_argument, NULL, OPTION_VOLSET_SEQ_NUM},
283 '\0', "#", "Set Volume set sequence number" , ONE_DASH },
63eb2d63 284 { {"old-exclude", required_argument, NULL, 'x'},
fa8b1c51 285 'x', "FILE", "Exclude file name(depreciated)" , ONE_DASH },
63eb2d63
RM
286#ifdef ERIC_neverdef
287 { {"transparent-compression", no_argument, NULL, 'z'},
288 'z', NULL, "Enable transparent compression of files", ONE_DASH },
289#endif
fa8b1c51
RM
290 { {"creation-date", required_argument, NULL, OPTION_CREAT_DATE },
291 '\0', NULL, "Override creation date", TWO_DASHES },
292 { {"modification-date", required_argument, NULL, OPTION_MODIF_DATE },
293 '\0', NULL, "Override modification date", TWO_DASHES },
294 { {"expiration-date", required_argument, NULL, OPTION_EXPIR_DATE },
295 '\0', NULL, "Override expiration date", TWO_DASHES },
296 { {"effective-date", required_argument, NULL, OPTION_EFFEC_DATE },
297 '\0', NULL, "Override effective date", TWO_DASHES },
63eb2d63
RM
298};
299
300#define OPTION_COUNT (sizeof ld_options / sizeof ld_options[0])
301
4b4c4f64
RM
302#if defined(ultrix) || defined(_AUX_SOURCE)
303char *strdup(s)
304char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;}
305#endif
306
11e9a115
RM
307 void read_rcfile __PR((char * appname));
308 void usage __PR((void));
309static void hide_reloc_dir __PR((void));
310
4b4c4f64
RM
311void FDECL1(read_rcfile, char *, appname)
312{
313 FILE * rcfile;
314 struct rcopts * rco;
315 char * pnt, *pnt1;
316 char linebuffer[256];
317 static char rcfn[] = ".mkisofsrc";
318 char filename[1000];
319 int linum;
320
321 strcpy(filename, rcfn);
322 rcfile = fopen(filename, "r");
323 if (!rcfile && errno != ENOENT)
324 perror(filename);
325
326 if (!rcfile)
327 {
328 pnt = getenv("MKISOFSRC");
329 if (pnt && strlen(pnt) <= sizeof(filename))
330 {
331 strcpy(filename, pnt);
332 rcfile = fopen(filename, "r");
333 if (!rcfile && errno != ENOENT)
334 perror(filename);
335 }
336 }
337
338 if (!rcfile)
339 {
340 pnt = getenv("HOME");
341 if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename))
342 {
343 strcpy(filename, pnt);
344 strcat(filename, "/");
345 strcat(filename, rcfn);
346 rcfile = fopen(filename, "r");
347 if (!rcfile && errno != ENOENT)
348 perror(filename);
349 }
350 }
351 if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename))
352 {
353 strcpy(filename, appname);
354 pnt = strrchr(filename, '/');
355 if (pnt)
356 {
357 strcpy(pnt + 1, rcfn);
358 rcfile = fopen(filename, "r");
359 if (!rcfile && errno != ENOENT)
360 perror(filename);
361 }
362 }
363 if (!rcfile)
364 return;
63eb2d63
RM
365 if ( verbose > 0 )
366 {
367 fprintf(stderr, "Using \"%s\"\n", filename);
368 }
369
4b4c4f64
RM
370 /* OK, we got it. Now read in the lines and parse them */
371 linum = 0;
372 while (fgets(linebuffer, sizeof(linebuffer), rcfile))
373 {
374 char *name;
375 char *name_end;
376 ++linum;
377 /* skip any leading white space */
378 pnt = linebuffer;
379 while (*pnt == ' ' || *pnt == '\t')
380 ++pnt;
381 /* If we are looking at a # character, this line is a comment. */
382 if (*pnt == '#')
383 continue;
384 /* The name should begin in the left margin. Make sure it is in
385 upper case. Stop when we see white space or a comment. */
386 name = pnt;
11e9a115 387 while (*pnt && isalpha((unsigned char)*pnt))
4b4c4f64 388 {
11e9a115
RM
389 if(islower((unsigned char)*pnt))
390 *pnt = toupper((unsigned char)*pnt);
4b4c4f64
RM
391 pnt++;
392 }
393 if (name == pnt)
394 {
395 fprintf(stderr, "%s:%d: name required\n", filename, linum);
396 continue;
397 }
398 name_end = pnt;
399 /* Skip past white space after the name */
400 while (*pnt == ' ' || *pnt == '\t')
401 pnt++;
402 /* silently ignore errors in the rc file. */
403 if (*pnt != '=')
404 {
405 fprintf(stderr, "%s:%d: equals sign required\n", filename, linum);
406 continue;
407 }
408 /* Skip pas the = sign, and any white space following it */
409 pnt++; /* Skip past '=' sign */
410 while (*pnt == ' ' || *pnt == '\t')
411 pnt++;
412
413 /* now it is safe to NUL terminate the name */
414
415 *name_end = 0;
416
417 /* Now get rid of trailing newline */
418
419 pnt1 = pnt;
420 while (*pnt1)
421 {
422 if (*pnt1 == '\n')
423 {
424 *pnt1 = 0;
425 break;
426 }
427 pnt1++;
428 };
429 /* OK, now figure out which option we have */
430 for(rco = rcopt; rco->tag; rco++) {
431 if(strcmp(rco->tag, name) == 0)
432 {
433 *rco->variable = strdup(pnt);
434 break;
435 };
436 }
437 if (rco->tag == NULL)
438 {
439 fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum,
440 name);
441 }
442 }
443 if (ferror(rcfile))
444 perror(filename);
445 fclose(rcfile);
446}
447
448char * path_table_l = NULL;
449char * path_table_m = NULL;
63eb2d63
RM
450
451char * jpath_table_l = NULL;
452char * jpath_table_m = NULL;
453
4b4c4f64
RM
454int goof = 0;
455
63eb2d63
RM
456#ifndef TRUE
457#define TRUE 1
458#endif
459
460#ifndef FALSE
461#define FALSE 0
462#endif
463
4b4c4f64 464void usage(){
63eb2d63
RM
465 const char * program_name = "mkisofs";
466#if 0
4b4c4f64
RM
467 fprintf(stderr,"Usage:\n");
468 fprintf(stderr,
469"mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \
470[-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]"
4b4c4f64
RM
471"[-P publisher] [ -A app_id ] [-z] \n \
472[-b boot_image_name] [-c boot_catalog-name] \
473[-x path -x path ...] path\n");
63eb2d63
RM
474#endif
475
dc83dd64 476 unsigned int i;
11e9a115 477/* const char **targets, **pp;*/
63eb2d63
RM
478
479 fprintf (stderr, "Usage: %s [options] file...\n", program_name);
480
481 fprintf (stderr, "Options:\n");
482 for (i = 0; i < OPTION_COUNT; i++)
483 {
484 if (ld_options[i].doc != NULL)
485 {
486 int comma;
487 int len;
dc83dd64 488 unsigned int j;
63eb2d63
RM
489
490 fprintf (stderr, " ");
491
492 comma = FALSE;
493 len = 2;
494
495 j = i;
496 do
497 {
498 if (ld_options[j].shortopt != '\0'
499 && ld_options[j].control != NO_HELP)
500 {
501 fprintf (stderr, "%s-%c", comma ? ", " : "", ld_options[j].shortopt);
502 len += (comma ? 2 : 0) + 2;
503 if (ld_options[j].arg != NULL)
504 {
505 if (ld_options[j].opt.has_arg != optional_argument)
506 {
507 fprintf (stderr, " ");
508 ++len;
509 }
510 fprintf (stderr, "%s", ld_options[j].arg);
511 len += strlen (ld_options[j].arg);
512 }
513 comma = TRUE;
514 }
515 ++j;
516 }
517 while (j < OPTION_COUNT && ld_options[j].doc == NULL);
518
519 j = i;
520 do
521 {
522 if (ld_options[j].opt.name != NULL
523 && ld_options[j].control != NO_HELP)
524 {
525 fprintf (stderr, "%s-%s%s",
526 comma ? ", " : "",
527 ld_options[j].control == TWO_DASHES ? "-" : "",
528 ld_options[j].opt.name);
529 len += ((comma ? 2 : 0)
530 + 1
531 + (ld_options[j].control == TWO_DASHES ? 1 : 0)
532 + strlen (ld_options[j].opt.name));
533 if (ld_options[j].arg != NULL)
534 {
535 fprintf (stderr, " %s", ld_options[j].arg);
536 len += 1 + strlen (ld_options[j].arg);
537 }
538 comma = TRUE;
539 }
540 ++j;
541 }
542 while (j < OPTION_COUNT && ld_options[j].doc == NULL);
543
544 if (len >= 30)
545 {
546 fprintf (stderr, "\n");
547 len = 0;
548 }
549
550 for (; len < 30; len++)
551 fputc (' ', stderr);
552
553 fprintf (stderr, "%s\n", ld_options[i].doc);
554 }
555 }
556 exit(1);
4b4c4f64
RM
557}
558
559
560/*
561 * Fill in date in the iso9660 format
562 *
563 * The standards state that the timezone offset is in multiples of 15
564 * minutes, and is what you add to GMT to get the localtime. The U.S.
565 * is always at a negative offset, from -5h to -8h (can vary a little
566 * with DST, I guess). The Linux iso9660 filesystem has had the sign
567 * of this wrong for ages (mkisofs had it wrong too for the longest time).
568 */
11e9a115 569int FDECL2(iso9660_date,char *, result, time_t, crtime){
4b4c4f64 570 struct tm *local;
11e9a115 571 local = localtime(&crtime);
4b4c4f64
RM
572 result[0] = local->tm_year;
573 result[1] = local->tm_mon + 1;
574 result[2] = local->tm_mday;
575 result[3] = local->tm_hour;
576 result[4] = local->tm_min;
577 result[5] = local->tm_sec;
578
579 /*
580 * Must recalculate proper timezone offset each time,
581 * as some files use daylight savings time and some don't...
582 */
583 result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */
11e9a115 584 local = gmtime(&crtime);
4b4c4f64
RM
585 local->tm_year -= result[0];
586 local->tm_yday -= result[6];
587 local->tm_hour -= result[3];
588 local->tm_min -= result[4];
589 if (local->tm_year < 0)
590 {
591 local->tm_yday = -1;
592 }
593 else
594 {
595 if (local->tm_year > 0) local->tm_yday = 1;
596 }
597
598 result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15;
599
600 return 0;
601}
602
11e9a115
RM
603/* hide "./rr_moved" if all its contents are hidden */
604static void
605hide_reloc_dir()
606{
607 struct directory_entry * s_entry;
608
609 for (s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) {
610 if(strcmp(s_entry->name,".")==0 || strcmp(s_entry->name,"..")==0)
611 continue;
612
613 if((s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0)
614 return;
615 }
616
617 /* all entries are hidden, so hide this directory */
618 reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
619 reloc_dir->self->de_flags |= INHIBIT_ISO9660_ENTRY;
620}
4b4c4f64
RM
621
622extern char * cdwrite_data;
623
624int FDECL2(main, int, argc, char **, argv){
4b4c4f64 625 struct directory_entry de;
63eb2d63 626#ifdef HAVE_SBRK
4b4c4f64 627 unsigned long mem_start;
63eb2d63 628#endif
4b4c4f64
RM
629 struct stat statbuf;
630 char * scan_tree;
631 char * merge_image = NULL;
632 struct iso_directory_record * mrootp = NULL;
63eb2d63
RM
633 struct output_fragment * opnt;
634 int longind;
635 char shortopts[OPTION_COUNT * 3 + 2];
636 struct option longopts[OPTION_COUNT + 1];
4b4c4f64 637 int c;
11e9a115 638 char *log_file = 0;
4b4c4f64
RM
639
640 if (argc < 2)
641 usage();
642
643 /* Get the defaults from the .mkisofsrc file */
644 read_rcfile(argv[0]);
645
646 outfile = NULL;
63eb2d63
RM
647
648 /*
649 * Copy long option initialization from GNU-ld.
650 */
651 /* Starting the short option string with '-' is for programs that
652 expect options and other ARGV-elements in any order and that care about
653 the ordering of the two. We describe each non-option ARGV-element
654 as if it were the argument of an option with character code 1. */
655 {
dc83dd64
RM
656 unsigned int i;
657 int is, il;
63eb2d63
RM
658 shortopts[0] = '-';
659 is = 1;
660 il = 0;
661 for (i = 0; i < OPTION_COUNT; i++)
662 {
663 if (ld_options[i].shortopt != '\0')
664 {
665 shortopts[is] = ld_options[i].shortopt;
666 ++is;
667 if (ld_options[i].opt.has_arg == required_argument
668 || ld_options[i].opt.has_arg == optional_argument)
669 {
670 shortopts[is] = ':';
671 ++is;
672 if (ld_options[i].opt.has_arg == optional_argument)
673 {
674 shortopts[is] = ':';
675 ++is;
676 }
677 }
678 }
679 if (ld_options[i].opt.name != NULL)
680 {
681 longopts[il] = ld_options[i].opt;
682 ++il;
683 }
684 }
685 shortopts[is] = '\0';
686 longopts[il].name = NULL;
687 }
688
689 while ((c = getopt_long_only (argc, argv, shortopts, longopts, &longind)) != EOF)
4b4c4f64
RM
690 switch (c)
691 {
63eb2d63
RM
692 case 1:
693 /*
694 * A filename that we take as input.
695 */
696 optind--;
697 goto parse_input_files;
4b4c4f64
RM
698 case 'C':
699 /*
700 * This is a temporary hack until cdwrite gets the proper hooks in
701 * it.
702 */
703 cdwrite_data = optarg;
704 break;
63eb2d63
RM
705 case 'i':
706 fprintf(stderr, "-i option no longer supported.\n");
707 exit(1);
708 break;
709 case 'J':
710 use_Joliet++;
711 break;
4b4c4f64
RM
712 case 'a':
713 all_files++;
714 break;
715 case 'b':
716 use_eltorito++;
717 boot_image = optarg; /* pathname of the boot image on cd */
718 if (boot_image == NULL) {
719 fprintf(stderr,"Required boot image pathname missing\n");
720 exit(1);
721 }
722 break;
723 case 'c':
724 use_eltorito++;
725 boot_catalog = optarg; /* pathname of the boot image on cd */
726 if (boot_catalog == NULL) {
727 fprintf(stderr,"Required boot catalog pathname missing\n");
728 exit(1);
729 }
730 break;
e1f240ff
RM
731 case OPTION_BOOT_INFO_TABLE:
732 use_boot_info_table = 1;
733 break;
734 case OPTION_NO_EMUL_BOOT:
735 fprintf (stderr, "Ignoring -no-emul-boot (no-emulation is the default behaviour)\n");
736 break;
737 case OPTION_ELTORITO_EMUL_FLOPPY:
738 use_eltorito_emul_floppy = 1;
739 break;
11e9a115
RM
740 case OPTION_ABSTRACT:
741 abstract = optarg;
742 if(strlen(abstract) > 37) {
743 fprintf(stderr,"Abstract filename string too long\n");
744 exit(1);
745 };
746 break;
4b4c4f64
RM
747 case 'A':
748 appid = optarg;
749 if(strlen(appid) > 128) {
750 fprintf(stderr,"Application-id string too long\n");
751 exit(1);
752 };
753 break;
11e9a115
RM
754 case OPTION_BIBLIO:
755 biblio = optarg;
756 if(strlen(biblio) > 37) {
757 fprintf(stderr,"Bibliographic filename string too long\n");
758 exit(1);
759 };
760 break;
761 case OPTION_COPYRIGHT:
762 copyright = optarg;
763 if(strlen(copyright) > 37) {
764 fprintf(stderr,"Copyright filename string too long\n");
765 exit(1);
766 };
767 break;
4b4c4f64
RM
768 case 'd':
769 omit_period++;
770 break;
771 case 'D':
772 RR_relocation_depth = 32767;
773 break;
774 case 'f':
775 follow_links++;
776 break;
4b4c4f64
RM
777 case 'l':
778 full_iso9660_filenames++;
779 break;
780 case 'L':
781 allow_leading_dots++;
782 break;
11e9a115
RM
783 case OPTION_LOG_FILE:
784 log_file = optarg;
785 break;
4b4c4f64
RM
786 case 'M':
787 merge_image = optarg;
788 break;
789 case 'N':
790 omit_version_number++;
791 break;
792 case 'o':
793 outfile = optarg;
794 break;
795 case 'p':
796 preparer = optarg;
797 if(strlen(preparer) > 128) {
798 fprintf(stderr,"Preparer string too long\n");
799 exit(1);
800 };
801 break;
63eb2d63
RM
802 case OPTION_PRINT_SIZE:
803 print_size++;
804 break;
4b4c4f64
RM
805 case 'P':
806 publisher = optarg;
807 if(strlen(publisher) > 128) {
808 fprintf(stderr,"Publisher string too long\n");
809 exit(1);
810 };
811 break;
63eb2d63
RM
812 case OPTION_QUIET:
813 verbose = 0;
814 break;
4b4c4f64
RM
815 case 'R':
816 use_RockRidge++;
817 break;
818 case 'r':
819 rationalize++;
820 use_RockRidge++;
821 break;
63eb2d63
RM
822 case OPTION_SPLIT_OUTPUT:
823 split_output++;
824 break;
11e9a115
RM
825 case OPTION_SYSID:
826 system_id = optarg;
827 if(strlen(system_id) > 32) {
828 fprintf(stderr,"System ID string too long\n");
829 exit(1);
830 };
831 break;
4b4c4f64
RM
832 case 'T':
833 generate_tables++;
834 break;
835 case 'V':
836 volume_id = optarg;
11e9a115
RM
837 if(strlen(volume_id) > 32) {
838 fprintf(stderr,"Volume ID string too long\n");
839 exit(1);
840 };
841 break;
842 case OPTION_VOLSET:
843 volset_id = optarg;
844 if(strlen(volset_id) > 128) {
845 fprintf(stderr,"Volume set ID string too long\n");
846 exit(1);
847 };
848 break;
849 case OPTION_VOLSET_SIZE:
850 volume_set_size = atoi(optarg);
851 break;
852 case OPTION_VOLSET_SEQ_NUM:
853 volume_sequence_number = atoi(optarg);
854 if (volume_sequence_number > volume_set_size) {
855 fprintf(stderr,"Volume set sequence number too big\n");
856 exit(1);
857 }
4b4c4f64
RM
858 break;
859 case 'v':
860 verbose++;
861 break;
862 case 'z':
863#ifdef VMS
864 fprintf(stderr,"Transparent compression not supported with VMS\n");
865 exit(1);
866#else
867 transparent_compression++;
868#endif
869 break;
63eb2d63 870 case 'x':
4b4c4f64 871 case 'm':
63eb2d63
RM
872 /*
873 * Somehow two options to do basically the same thing got added somewhere along
874 * the way. The 'match' code supports limited globbing, so this is the one
875 * that got selected. Unfortunately the 'x' switch is probably more intuitive.
876 */
4b4c4f64
RM
877 add_match(optarg);
878 break;
11e9a115
RM
879 case OPTION_I_HIDE:
880 i_add_match(optarg);
881 break;
882 case OPTION_J_HIDE:
883 j_add_match(optarg);
884 break;
63eb2d63
RM
885 case OPTION_HELP:
886 usage ();
887 exit (0);
888 break;
889 case OPTION_NOSPLIT_SL_COMPONENT:
890 split_SL_component = 0;
891 break;
892 case OPTION_NOSPLIT_SL_FIELD:
893 split_SL_field = 0;
4b4c4f64 894 break;
fa8b1c51 895 case OPTION_CREAT_DATE:
d70d3907
RM
896 if (strlen (optarg) != 16) {
897 fprintf (stderr, "date string must be 16 characters.\n");
898 exit (1);
899 }
fa8b1c51
RM
900 if (creation_date)
901 free(creation_date);
902 creation_date = strdup(optarg);
903 break;
904 case OPTION_MODIF_DATE:
d70d3907
RM
905 if (strlen (optarg) != 16) {
906 fprintf (stderr, "date string must be 16 characters.\n");
907 exit (1);
908 }
fa8b1c51
RM
909 if (modification_date)
910 free(modification_date);
911 modification_date = strdup(optarg);
912 break;
913 case OPTION_EXPIR_DATE:
d70d3907
RM
914 if (strlen (optarg) != 16) {
915 fprintf (stderr, "date string must be 16 characters.\n");
916 exit (1);
917 }
fa8b1c51
RM
918 if (expiration_date)
919 free(expiration_date);
920 expiration_date = strdup(optarg);
921 break;
922 case OPTION_EFFEC_DATE:
d70d3907
RM
923 if (strlen (optarg) != 16) {
924 fprintf (stderr, "date string must be 16 characters.\n");
925 exit (1);
926 }
fa8b1c51
RM
927 if (effective_date)
928 free(effective_date);
929 effective_date = strdup(optarg);
930 break;
4b4c4f64
RM
931 default:
932 usage();
933 exit(1);
934 }
63eb2d63
RM
935
936parse_input_files:
937
4b4c4f64
RM
938#ifdef __NetBSD__
939 {
940 int resource;
941 struct rlimit rlp;
942 if (getrlimit(RLIMIT_DATA,&rlp) == -1)
943 perror("Warning: getrlimit");
944 else {
945 rlp.rlim_cur=33554432;
946 if (setrlimit(RLIMIT_DATA,&rlp) == -1)
947 perror("Warning: setrlimit");
948 }
949 }
950#endif
951#ifdef HAVE_SBRK
952 mem_start = (unsigned long) sbrk(0);
953#endif
954
11e9a115
RM
955 /* if the -hide-joliet option has been given, set the Joliet option */
956 if (!use_Joliet && j_ishidden())
957 use_Joliet++;
958
63eb2d63 959 if(verbose > 1) fprintf(stderr,"%s\n", version_string);
4b4c4f64 960
11e9a115 961 if(cdwrite_data == NULL && merge_image != NULL)
4b4c4f64 962 {
11e9a115 963 fprintf(stderr,"Multisession usage bug: Must specify -C if -M is used.\n");
4b4c4f64
RM
964 exit(0);
965 }
966
11e9a115
RM
967 if(cdwrite_data != NULL && merge_image == NULL)
968 {
969 fprintf(stderr,"Warning: -C specified without -M: old session data will not be merged.\n");
970 }
971
4b4c4f64
RM
972 /* The first step is to scan the directory tree, and take some notes */
973
974 scan_tree = argv[optind];
975
4b4c4f64
RM
976
977 if(!scan_tree){
978 usage();
979 exit(1);
980 };
981
982#ifndef VMS
983 if(scan_tree[strlen(scan_tree)-1] != '/') {
984 scan_tree = (char *) e_malloc(strlen(argv[optind])+2);
985 strcpy(scan_tree, argv[optind]);
986 strcat(scan_tree, "/");
987 };
988#endif
989
990 if(use_RockRidge){
991#if 1
992 extension_record = generate_rr_extension_record("RRIP_1991A",
993 "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
994 "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size);
995#else
996 extension_record = generate_rr_extension_record("IEEE_P1282",
997 "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
998 "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size);
999#endif
1000 }
1001
11e9a115
RM
1002 if (log_file) {
1003 FILE *lfp;
1004 int i;
1005
1006 /* open log file - test that we can open OK */
1007 if ((lfp = fopen(log_file, "w")) == NULL) {
1008 fprintf(stderr,"can't open logfile: %s\n", log_file);
1009 exit (1);
1010 }
1011 fclose(lfp);
1012
1013 /* redirect all stderr message to log_file */
1014 fprintf(stderr, "re-directing all messages to %s\n", log_file);
1015 fflush(stderr);
1016
1017 /* associate stderr with the log file */
1018 if (freopen(log_file, "w", stderr) == NULL) {
1019 fprintf(stderr,"can't open logfile: %s\n", log_file);
1020 exit (1);
1021 }
1022 if(verbose > 1) {
1023 for (i=0;i<argc;i++)
1024 fprintf(stderr,"%s ", argv[i]);
1025
1026 fprintf(stderr,"\n%s\n", version_string);
1027 }
1028 }
1029
4b4c4f64
RM
1030 /*
1031 * See if boot catalog file exists in root directory, if not
1032 * we will create it.
1033 */
1034 if (use_eltorito)
1035 init_boot_catalog(argv[optind]);
1036
1037 /*
1038 * Find the device and inode number of the root directory.
1039 * Record this in the hash table so we don't scan it more than
1040 * once.
1041 */
1042 stat_filter(argv[optind], &statbuf);
1043 add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1044
1045 memset(&de, 0, sizeof(de));
1046
1047 de.filedir = root; /* We need this to bootstrap */
1048
11e9a115
RM
1049 if (cdwrite_data != NULL && merge_image == NULL) {
1050 /* in case we want to add a new session, but don't want to merge old one */
1051 get_session_start(NULL);
1052 }
1053
4b4c4f64
RM
1054 if( merge_image != NULL )
1055 {
1056 mrootp = merge_isofs(merge_image);
1057 if( mrootp == NULL )
1058 {
1059 /*
1060 * Complain and die.
1061 */
1062 fprintf(stderr,"Unable to open previous session image %s\n",
1063 merge_image);
1064 exit(1);
1065 }
1066
1067 memcpy(&de.isorec.extent, mrootp->extent, 8);
1068 }
1069
63eb2d63
RM
1070 /*
1071 * Create an empty root directory. If we ever scan it for real, we will fill in the
1072 * contents.
1073 */
1074 find_or_create_directory(NULL, "", &de, TRUE);
1075
4b4c4f64
RM
1076 /*
1077 * Scan the actual directory (and any we find below it)
63eb2d63
RM
1078 * for files to write out to the output image. Note - we
1079 * take multiple source directories and keep merging them
1080 * onto the image.
1081 */
1082 while(optind < argc)
1083 {
1084 char * node;
1085 struct directory * graft_dir;
1086 struct stat st;
1087 char * short_name;
1088 int status;
1089 char graft_point[1024];
1090
1091 /*
1092 * We would like a syntax like:
1093 *
1094 * /tmp=/usr/tmp/xxx
1095 *
1096 * where the user can specify a place to graft each
1097 * component of the tree. To do this, we may have to create
1098 * directories along the way, of course.
1099 * Secondly, I would like to allow the user to do something
1100 * like:
1101 *
1102 * /home/baz/RMAIL=/u3/users/baz/RMAIL
1103 *
1104 * so that normal files could also be injected into the tree
1105 * at an arbitrary point.
1106 *
1107 * The idea is that the last component of whatever is being
1108 * entered would take the name from the last component of
1109 * whatever the user specifies.
1110 *
1111 * The default will be that the file is injected at the
1112 * root of the image tree.
1113 */
1114 node = strchr(argv[optind], '=');
1115 short_name = NULL;
1116
1117 if( node != NULL )
1118 {
1119 char * pnt;
1120 char * xpnt;
1121
1122 *node = '\0';
1123 strcpy(graft_point, argv[optind]);
1124 *node = '=';
1125 node++;
1126
1127 graft_dir = root;
1128 xpnt = graft_point;
1129 if( *xpnt == PATH_SEPARATOR )
1130 {
1131 xpnt++;
1132 }
1133
1134 /*
1135 * Loop down deeper and deeper until we
1136 * find the correct insertion spot.
1137 */
1138 while(1==1)
1139 {
1140 pnt = strchr(xpnt, PATH_SEPARATOR);
1141 if( pnt == NULL )
1142 {
1143 if( *xpnt != '\0' )
1144 {
1145 short_name = xpnt;
1146 }
1147 break;
1148 }
1149 *pnt = '\0';
1150 graft_dir = find_or_create_directory(graft_dir,
1151 graft_point,
1152 NULL, TRUE);
1153 *pnt = PATH_SEPARATOR;
1154 xpnt = pnt + 1;
1155 }
1156 }
1157 else
1158 {
1159 graft_dir = root;
1160 node = argv[optind];
1161 }
1162
1163 /*
1164 * Now see whether the user wants to add a regular file,
1165 * or a directory at this point.
1166 */
1167 status = stat_filter(node, &st);
1168 if( status != 0 )
1169 {
1170 /*
1171 * This is a fatal error - the user won't be getting what
1172 * they want if we were to proceed.
1173 */
1174 fprintf(stderr, "Invalid node - %s\n", node);
1175 exit(1);
1176 }
1177 else
1178 {
1179 if( S_ISDIR(st.st_mode) )
1180 {
1181 if (!scan_directory_tree(graft_dir, node, &de))
1182 {
1183 exit(1);
1184 }
1185 }
1186 else
1187 {
1188 if( short_name == NULL )
1189 {
1190 short_name = strrchr(node, PATH_SEPARATOR);
1191 if( short_name == NULL || short_name < node )
1192 {
1193 short_name = node;
1194 }
1195 else
1196 {
1197 short_name++;
1198 }
1199 }
1200 if( !insert_file_entry(graft_dir, node, short_name) )
1201 {
1202 exit(1);
1203 }
1204 }
1205 }
1206
1207 optind++;
1208 }
1209
1210
1211 /*
1212 * Now merge in any previous sessions. This is driven on the source
1213 * side, since we may need to create some additional directories.
4b4c4f64 1214 */
63eb2d63 1215 if( merge_image != NULL )
4b4c4f64 1216 {
63eb2d63 1217 merge_previous_session(root, mrootp);
4b4c4f64
RM
1218 }
1219
11e9a115
RM
1220 /* hide "./rr_moved" if all its contents have been hidden */
1221 if (reloc_dir && i_ishidden())
1222 hide_reloc_dir();
1223
4b4c4f64 1224 /*
63eb2d63
RM
1225 * Sort the directories in the required order (by ISO9660). Also,
1226 * choose the names for the 8.3 filesystem if required, and do
1227 * any other post-scan work.
4b4c4f64 1228 */
63eb2d63 1229 goof += sort_tree(root);
4b4c4f64 1230
63eb2d63
RM
1231 if( use_Joliet )
1232 {
1233 goof += joliet_sort_tree(root);
1234 }
4b4c4f64 1235
11e9a115
RM
1236 if (goof)
1237 {
1238 fprintf(stderr, "Joliet tree sort failed.\n");
1239 exit(1);
1240 }
4b4c4f64 1241
63eb2d63
RM
1242 /*
1243 * Fix a couple of things in the root directory so that everything
1244 * is self consistent.
1245 */
1246 root->self = root->contents; /* Fix this up so that the path
1247 tables get done right */
1248
4b4c4f64
RM
1249 /*
1250 * OK, ready to write the file. Open it up, and generate the thing.
1251 */
63eb2d63 1252 if (print_size){
11e9a115 1253 discimage = fopen("/dev/null", "wb");
63eb2d63
RM
1254 if (!discimage){
1255 fprintf(stderr,"Unable to open /dev/null\n");
1256 exit(1);
1257 }
1258 } else if (outfile){
11e9a115 1259 discimage = fopen(outfile, "wb");
4b4c4f64
RM
1260 if (!discimage){
1261 fprintf(stderr,"Unable to open disc image file\n");
1262 exit(1);
1263
1264 };
11e9a115 1265 } else {
4b4c4f64
RM
1266 discimage = stdout;
1267
11e9a115
RM
1268#if defined(__CYGWIN32__)
1269 setmode(fileno(stdout), O_BINARY);
1270#endif
1271 }
1272
4b4c4f64
RM
1273 /* Now assign addresses on the disc for the path table. */
1274
1275 path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11;
1276 if (path_blocks & 1) path_blocks++;
1277
63eb2d63
RM
1278 jpath_blocks = (jpath_table_size + (SECTOR_SIZE - 1)) >> 11;
1279 if (jpath_blocks & 1) jpath_blocks++;
1280
1281 /*
1282 * Start to set up the linked list that we use to track the
1283 * contents of the disc.
1284 */
1285 outputlist_insert(&padblock_desc);
1286
1287 /*
1288 * PVD for disc.
1289 */
1290 outputlist_insert(&voldesc_desc);
1291
1292 /*
1293 * SVD for El Torito. MUST be immediately after the PVD!
1294 */
1295 if( use_eltorito)
1296 {
1297 outputlist_insert(&torito_desc);
1298 }
1299
1300 /*
1301 * SVD for Joliet.
1302 */
1303 if( use_Joliet)
1304 {
1305 outputlist_insert(&joliet_desc);
1306 }
1307
1308 /*
1309 * Finally the last volume desctiptor.
1310 */
1311 outputlist_insert(&end_vol);
4b4c4f64 1312
4b4c4f64 1313
63eb2d63
RM
1314 outputlist_insert(&pathtable_desc);
1315 if( use_Joliet)
1316 {
1317 outputlist_insert(&jpathtable_desc);
1318 }
4b4c4f64 1319
63eb2d63
RM
1320 outputlist_insert(&dirtree_desc);
1321 if( use_Joliet)
1322 {
1323 outputlist_insert(&jdirtree_desc);
1324 }
4b4c4f64 1325
63eb2d63 1326 outputlist_insert(&dirtree_clean);
4b4c4f64 1327
63eb2d63
RM
1328 if(extension_record)
1329 {
1330 outputlist_insert(&extension_desc);
1331 }
4b4c4f64 1332
63eb2d63 1333 outputlist_insert(&files_desc);
4b4c4f64 1334
63eb2d63
RM
1335 /*
1336 * Allow room for the various headers we will be writing. There
1337 * will always be a primary and an end volume descriptor.
1338 */
1339 last_extent = session_start;
1340
1341 /*
1342 * Calculate the size of all of the components of the disc, and assign
1343 * extent numbers.
1344 */
1345 for(opnt = out_list; opnt; opnt = opnt->of_next )
1346 {
1347 if( opnt->of_size != NULL )
1348 {
1349 (*opnt->of_size)(last_extent);
1350 }
1351 }
4b4c4f64 1352
63eb2d63
RM
1353 /*
1354 * Generate the contents of any of the sections that we want to generate.
1355 * Not all of the fragments will do anything here - most will generate the
1356 * data on the fly when we get to the write pass.
1357 */
1358 for(opnt = out_list; opnt; opnt = opnt->of_next )
1359 {
1360 if( opnt->of_generate != NULL )
1361 {
1362 (*opnt->of_generate)();
1363 }
1364 }
4b4c4f64
RM
1365
1366 if( in_image != NULL )
1367 {
1368 fclose(in_image);
1369 }
1370
63eb2d63
RM
1371 /*
1372 * Now go through the list of fragments and write the data that corresponds to
1373 * each one.
1374 */
1375 for(opnt = out_list; opnt; opnt = opnt->of_next )
1376 {
1377 if( opnt->of_write != NULL )
1378 {
1379 (*opnt->of_write)(discimage);
1380 }
1381 }
4b4c4f64 1382
63eb2d63
RM
1383 if( verbose > 0 )
1384 {
4b4c4f64 1385#ifdef HAVE_SBRK
63eb2d63
RM
1386 fprintf(stderr,"Max brk space used %x\n",
1387 (unsigned int)(((unsigned long)sbrk(0)) - mem_start));
4b4c4f64 1388#endif
2c55dbc0 1389 fprintf (stderr, "%llu extents written (%llu MiB)\n", last_extent, last_extent >> 9);
63eb2d63
RM
1390 }
1391
4b4c4f64
RM
1392#ifdef VMS
1393 return 1;
1394#else
1395 return 0;
1396#endif
1397}
1398
1399void *
1400FDECL1(e_malloc, size_t, size)
1401{
1402void* pt = 0;
1403 if( (size > 0) && ((pt=malloc(size))==NULL) ) {
1404 fprintf(stderr, "Not enough memory\n");
1405 exit (1);
1406 }
1407return pt;
1408}