xref: /openbsd/gnu/usr.sbin/mkhybrid/src/mkisofs.c (revision ca3aaadb)
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 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2, or (at your option)
12    any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
22 
23 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 12/3/99 */
24 
25 #include <errno.h>
26 #include "config.h"
27 #include "mkisofs.h"
28 #include "match.h"
29 #include "apple_proto.h"
30 
31 #ifdef linux
32 #include <getopt.h>
33 #else
34 #include "getopt.h"
35 #endif
36 
37 #include "iso9660.h"
38 #include <ctype.h>
39 
40 #ifndef VMS
41 #include <time.h>
42 #else
43 #include <sys/time.h>
44 #include "vms.h"
45 #endif
46 
47 #include <stdlib.h>
48 #include <sys/stat.h>
49 
50 #ifndef VMS
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54 #endif
55 #include <fctldefs.h>
56 
57 #if defined(__NetBSD__) || defined(__OpenBSD__)
58 #include <sys/time.h>
59 #include <sys/resource.h>
60 #endif
61 
62 struct directory * root = NULL;
63 
64 #ifdef APPLE_HYB
65 static char version_string[] = "mkhybrid 1.12b5.1";
66 #else
67 static char version_string[] = "mkisofs 1.12b5";
68 #endif /* APPLE_HYB */
69 
70 char * outfile;
71 FILE * discimage;
72 unsigned int next_extent = 0;
73 unsigned int last_extent = 0;
74 unsigned int session_start = 0;
75 unsigned int path_table_size = 0;
76 unsigned int path_table[4] = {0,};
77 unsigned int path_blocks = 0;
78 
79 
80 unsigned int jpath_table_size = 0;
81 unsigned int jpath_table[4] = {0,};
82 unsigned int jpath_blocks = 0;
83 
84 struct iso_directory_record root_record;
85 struct iso_directory_record jroot_record;
86 
87 char * extension_record = NULL;
88 int extension_record_extent = 0;
89 int extension_record_size = 0;
90 
91 /* These variables are associated with command line options */
92 int use_eltorito = 0;
93 int use_RockRidge = 0;
94 int use_Joliet = 0;
95 int verbose = 0;
96 int all_files  = 0;
97 int follow_links = 0;
98 int rationalize = 0;
99 int generate_tables = 0;
100 int print_size = 0;
101 int split_output = 0;
102 char * preparer = PREPARER_DEFAULT;
103 char * publisher = PUBLISHER_DEFAULT;
104 char * appid = APPID_DEFAULT;
105 char * copyright = COPYRIGHT_DEFAULT;
106 char * biblio = BIBLIO_DEFAULT;
107 char * abstract = ABSTRACT_DEFAULT;
108 char * volset_id = VOLSET_ID_DEFAULT;
109 char * volume_id = VOLUME_ID_DEFAULT;
110 char * system_id = SYSTEM_ID_DEFAULT;
111 char * boot_catalog = BOOT_CATALOG_DEFAULT;
112 char * boot_image = BOOT_IMAGE_DEFAULT;
113 char * efi_boot_image = EFI_BOOT_IMAGE_DEFAULT;
114 int volume_set_size = 1;
115 int volume_sequence_number = 1;
116 
117 int omit_period = 0;             /* Violates iso9660, but these are a pain */
118 int transparent_compression = 0; /* So far only works with linux */
119 int omit_version_number = 0;     /* May violate iso9660, but noone uses vers*/
120 int RR_relocation_depth = 6;     /* Violates iso9660, but most systems work */
121 int full_iso9660_filenames = 0;  /* Used with Amiga.  Disc will not work with
122 				  DOS */
123 int allow_leading_dots = 0;	 /* DOS cannot read names with leading dots */
124 int split_SL_component = 1;    /* circumvent a bug in the SunOS driver */
125 int split_SL_field = 1;                /* circumvent a bug in the SunOS */
126 
127 #ifdef APPLE_HYB
128 int	apple_hyb = 0;		/* create HFS hybrid flag */
129 int	apple_ext = 0;		/* create HFS extensions flag */
130 int	apple_both = 0;		/* common flag (for above) */
131 int	hfs_extra = 0;		/* extra HFS blocks added to end of ISO vol */
132 int	mac_name = 0;		/* use Mac name for ISO/Joliet/RR flag */
133 hce_mem *hce;			/* libhfs/mkisofs extras */
134 char	*hfs_boot_file = 0;	/* name of HFS boot file */
135 int	gen_pt = 0;		/* generate HFS partition table */
136 char	*autoname = 0;		/* AutoStart filename */
137 char	*magic_file = 0;	/* name of magic file */
138 int	probe = 0;		/* search files for HFS/Unix type */
139 int	nomacfiles = 0;		/* don't look for Mac/Unix files */
140 int	hfs_select = 0;		/* Mac/Unix types to select */
141 int	create_dt = 1;		/* create the Desktp files */
142 int	bsize = 0;		/* Apple File Exchange block size */
143 int	hfs_last = MAG_LAST;	/* process magic file after map file */
144 char	*deftype = DEFTYPE;	/* default Apple TYPE */
145 char	*defcreator = DEFCREATOR; /* default Apple CREATOR */
146 char	*trans_tbl = "TRANS.TBL"; /* default name for translation table */
147 char	*hfs_volume_id = NULL;	/* HFS volume ID */
148 char	*hfs_bless = NULL;	/* name of folder to 'bless' (System Folder) */
149 
150 #endif /* APPLE_HYB */
151 
152 struct rcopts{
153   char * tag;
154   char ** variable;
155 };
156 
157 struct rcopts rcopt[] = {
158   {"PREP", &preparer},
159   {"PUBL", &publisher},
160   {"APPI", &appid},
161   {"COPY", &copyright},
162   {"BIBL", &biblio},
163   {"ABST", &abstract},
164   {"VOLS", &volset_id},
165   {"VOLI", &volume_id},
166   {"SYSI", &system_id},
167 #ifdef APPLE_HYB
168   {"TYPE", &deftype},
169   {"CREATOR", &defcreator},
170 #endif /* APPLE_HYB */
171   {NULL, NULL}
172 };
173 
174 /*
175  * In case it isn't obvious, the option handling code was ripped off from GNU-ld.
176  */
177 struct ld_option
178 {
179   /* The long option information.  */
180   struct option opt;
181   /* The short option with the same meaning ('\0' if none).  */
182   char shortopt;
183   /* The name of the argument (NULL if none).  */
184   const char *arg;
185   /* The documentation string.  If this is NULL, this is a synonym for
186      the previous option.  */
187   const char *doc;
188   enum
189     {
190       /* Use one dash before long option name.  */
191       ONE_DASH,
192       /* Use two dashes before long option name.  */
193       TWO_DASHES,
194       /* Don't mention this option in --help output.  */
195       NO_HELP
196     } control;
197 };
198 
199 /* Codes used for the long options with no short synonyms.  150 isn't
200    special; it's just an arbitrary non-ASCII char value.  */
201 #define OPTION_HELP			150
202 #define OPTION_QUIET			151
203 #define OPTION_NOSPLIT_SL_COMPONENT	152
204 #define OPTION_NOSPLIT_SL_FIELD		153
205 #define OPTION_PRINT_SIZE		154
206 #define OPTION_SPLIT_OUTPUT		155
207 #define OPTION_ABSTRACT			156
208 #define OPTION_BIBLIO			157
209 #define OPTION_COPYRIGHT		158
210 #define OPTION_SYSID			159
211 #define OPTION_VOLSET			160
212 #define OPTION_VOLSET_SIZE		161
213 #define OPTION_VOLSET_SEQ_NUM		162
214 #define OPTION_I_HIDE			163
215 #define OPTION_J_HIDE			164
216 #define OPTION_LOG_FILE			165
217 #ifdef APPLE_HYB
218 #define OPTION_CAP			200
219 #define OPTION_NETA			201
220 #define OPTION_DBL			202
221 #define OPTION_ESH			203
222 #define OPTION_FE			204
223 #define OPTION_SGI			205
224 #define OPTION_MBIN			206
225 #define OPTION_SGL			207
226 /* aliases */
227 #define OPTION_USH			208
228 #define OPTION_XIN			209
229 
230 #define OPTION_PROBE			220
231 #define OPTION_MACNAME			221
232 #define OPTION_NOMACFILES		222
233 #define OPTION_BOOT_HFS_FILE		223
234 #define OPTION_MAGIC_FILE		224
235 
236 #define OPTION_TRANS_TBL		225
237 
238 #define OPTION_GEN_PT			226
239 
240 #define OPTION_CREATE_DT		227
241 #define OPTION_HFS_HIDE			228
242 
243 #define OPTION_AUTOSTART		229
244 #define OPTION_BSIZE			230
245 #define OPTION_HFS_VOLID		231
246 
247 #define OPTION_H_LIST			240
248 #define OPTION_P_LIST			241
249 #define OPTION_I_LIST			242
250 #define OPTION_J_LIST			243
251 #define OPTION_X_LIST			244
252 
253 #define OPTION_HFS_BLESS		245
254 #endif /* APPLE_HYB */
255 
256 static const struct ld_option ld_options[] =
257 {
258   { {"all-files", no_argument, NULL, 'a'},
259       'a', NULL, "Process all files (don't skip backup files)", ONE_DASH },
260   { {"abstract", required_argument, NULL, OPTION_ABSTRACT},
261       '\0', "FILE", "Set Abstract filename" , ONE_DASH },
262   { {"appid", required_argument, NULL, 'A'},
263       'A', "ID", "Set Application ID" , ONE_DASH },
264   { {"biblio", required_argument, NULL, OPTION_BIBLIO},
265       '\0', "FILE", "Set Bibliographic filename" , ONE_DASH },
266   { {"copyright", required_argument, NULL, OPTION_COPYRIGHT},
267       '\0', "FILE", "Set Copyright filename" , ONE_DASH },
268   { {"eltorito-boot", required_argument, NULL, 'b'},
269       'b', "FILE", "Set El Torito boot image name" , ONE_DASH },
270   { {"eltorito-catalog", required_argument, NULL, 'c'},
271       'c', "FILE", "Set El Torito boot catalog name" , ONE_DASH },
272   { {"cdwrite-params", required_argument, NULL, 'C'},
273       'C', "PARAMS", "Magic paramters from cdrecord" , ONE_DASH },
274   { {"omit-period", no_argument, NULL, 'd'},
275       'd', NULL, "Omit trailing periods from filenames", ONE_DASH },
276   { {"disable-deep-relocation", no_argument, NULL, 'D'},
277       'D', NULL, "Disable deep directory relocation", ONE_DASH },
278   { {"eltorito-boot-efi", required_argument, NULL, 'e' },
279       'e', "FILE", "Set El Torito EFI boot image name" , ONE_DASH },
280   { {"follow-links", no_argument, NULL, 'f'},
281       'f', NULL, "Follow symbolic links", ONE_DASH },
282   { {"help", no_argument, NULL, OPTION_HELP},
283       '\0', NULL, "Print option help", ONE_DASH },
284   { {"hide", required_argument, NULL, OPTION_I_HIDE},
285       '\0', "GLOBFILE", "Hide ISO9660/RR file" , ONE_DASH },
286 #ifdef APPLE_HYB
287   /* NON-HFS change */
288   { {"hide-list", required_argument, NULL, OPTION_I_LIST},
289       '\0', "FILE", "list of ISO9660/RR files to hide" , ONE_DASH },
290 #endif /* APPLE_HYB */
291   { {"hide-joliet", required_argument, NULL, OPTION_J_HIDE},
292       '\0', "GLOBFILE", "Hide Joliet file" , ONE_DASH },
293 #ifdef APPLE_HYB
294   /* NON-HFS change */
295   { {"hide-joliet-list", required_argument, NULL, OPTION_J_LIST},
296       '\0', "FILE", "List of Joliet files to hide" , ONE_DASH },
297 #endif /* APPLE_HYB */
298   { {NULL, required_argument, NULL, 'i'},
299       'i', "ADD_FILES", "No longer supported" , TWO_DASHES },
300   { {"joliet", no_argument, NULL, 'J'},
301       'J', NULL, "Generate Joliet directory information", ONE_DASH },
302   { {"full-iso9660-filenames", no_argument, NULL, 'l'},
303       'l', NULL, "Allow full 32 character filenames for iso9660 names", ONE_DASH },
304   { {"allow-leading-dots", no_argument, NULL, 'L'},
305       'L', NULL, "Allow iso9660 filenames to start with '.'", ONE_DASH },
306   { {"log-file", required_argument, NULL, OPTION_LOG_FILE},
307       '\0', "LOG_FILE", "Re-direct messages to LOG_FILE", ONE_DASH },
308   { {"exclude", required_argument, NULL, 'm'},
309       'm', "GLOBFILE", "Exclude file name" , ONE_DASH },
310 #ifdef APPLE_HYB
311   { {"exclude-list", required_argument, NULL, OPTION_X_LIST},
312       'm', "FILE", "List of file names to exclude" , ONE_DASH },
313 #endif /* APPLE_HYB */
314   { {"prev-session", required_argument, NULL, 'M'},
315       'M', "FILE", "Set path to previous session to merge" , ONE_DASH },
316   { {"omit-version-number", no_argument, NULL, 'N'},
317       'N', NULL, "Omit version number from iso9660 filename", ONE_DASH },
318   { {"no-split-symlink-components", no_argument, NULL, 0},
319       0, NULL, "Inhibit splitting symlink components" , ONE_DASH },
320   { {"no-split-symlink-fields", no_argument, NULL, 0},
321       0, NULL, "Inhibit splitting symlink fields" , ONE_DASH },
322   { {"output", required_argument, NULL, 'o'},
323       'o', "FILE", "Set output file name" , ONE_DASH },
324 #ifdef APPLE_HYB
325   { {"path-list", required_argument, NULL, OPTION_P_LIST},
326       '\0', "FILE", "list of pathnames to process" , ONE_DASH },
327 #endif /* APPLE_HYB */
328   { {"preparer", required_argument, NULL, 'p'},
329       'p', "PREP", "Set Volume preparer" , ONE_DASH },
330   { {"print-size", no_argument, NULL, OPTION_PRINT_SIZE},
331       '\0', NULL, "Print estimated filesystem size and exit", ONE_DASH },
332   { {"publisher", required_argument, NULL, 'P'},
333       'P', "PUB", "Set Volume publisher" , ONE_DASH },
334   { {"quiet", no_argument, NULL, OPTION_QUIET},
335       '\0', NULL, "Run quietly", ONE_DASH },
336   { {"rational-rock", no_argument, NULL, 'r'},
337       'r', NULL, "Generate rationalized Rock Ridge directory information", ONE_DASH },
338   { {"rock", no_argument, NULL, 'R'},
339       'R', NULL, "Generate Rock Ridge directory information", ONE_DASH },
340   { {"split-output", no_argument, NULL, OPTION_SPLIT_OUTPUT},
341       '\0', NULL, "Split output into files of approx. 1GB size", ONE_DASH },
342   { {"sysid", required_argument, NULL, OPTION_SYSID},
343       '\0', "ID", "Set System ID" , ONE_DASH },
344   { {"translation-table", no_argument, NULL, 'T'},
345       'T', NULL, "Generate translation tables for systems that don't understand long filenames", ONE_DASH },
346   { {"verbose", no_argument, NULL, 'v'},
347       'v', NULL, "Verbose", ONE_DASH },
348   { {"volid", required_argument, NULL, 'V'},
349       'V', "ID", "Set Volume ID" , ONE_DASH },
350   { {"volset", required_argument, NULL, OPTION_VOLSET},
351       '\0', "ID", "Set Volume set ID" , ONE_DASH },
352   { {"volset-size", required_argument, NULL, OPTION_VOLSET_SIZE},
353       '\0', "#", "Set Volume set size" , ONE_DASH },
354   { {"volset-seqno", required_argument, NULL, OPTION_VOLSET_SEQ_NUM},
355       '\0', "#", "Set Volume set sequence number" , ONE_DASH },
356   { {"old-exclude", required_argument, NULL, 'x'},
357       'x', "FILE", "Exclude file name(depreciated)" , ONE_DASH },
358 #ifdef ERIC_neverdef
359   { {"transparent-compression", no_argument, NULL, 'z'},
360       'z', NULL, "Enable transparent compression of files", ONE_DASH },
361 #endif
362 #ifdef APPLE_HYB
363   { {"apple", no_argument, NULL, 'g'},
364       'g', NULL, "Add Apple ISO9660 extensions", ONE_DASH },
365   { {"hfs", no_argument, NULL, 'h'},
366       'h', NULL, "Create ISO9660/HFS hybrid", ONE_DASH },
367   { {"map", required_argument, NULL, 'H'},
368       'H', "MAPPING_FILE", "Map file extensions to HFS TYPE/CREATOR", ONE_DASH},
369   { {"magic", required_argument, NULL, OPTION_MAGIC_FILE},
370       '\0', "FILE", "Magic file for HFS TYPE/CREATOR", ONE_DASH},
371   { {"probe", no_argument, NULL, OPTION_PROBE},
372       '\0', NULL, "Probe all files for Unix/HFS file type", ONE_DASH },
373   { {"mac-name", no_argument, NULL, OPTION_MACNAME},
374       '\0', NULL, "Use Macintosh name for ISO9660/Joliet/RockRidge file name",
375 	ONE_DASH },
376   { {"no-mac-files", no_argument, NULL, OPTION_NOMACFILES},
377       '\0', NULL, "Do not look for Unix/Mac files", ONE_DASH },
378   { {"boot-hfs-file", required_argument, NULL, OPTION_BOOT_HFS_FILE},
379       '\0', "FILE", "Set HFS boot image name", ONE_DASH},
380   { {"part", no_argument, NULL, OPTION_GEN_PT},
381       '\0', NULL, "Generate HFS partition table", ONE_DASH },
382   { {"cluster-size", required_argument, NULL, OPTION_BSIZE},
383       '\0', "SIZE", "Cluster size for PC Exchange Macintosh files", ONE_DASH},
384   { {"auto", required_argument, NULL, OPTION_AUTOSTART},
385       '\0', "FILE", "Set HFS AutoStart file name", ONE_DASH},
386   { {"no-desktop", no_argument, NULL, OPTION_CREATE_DT},
387       '\0', NULL, "Do not create the HFS (empty) Desktop files", ONE_DASH },
388   { {"hide-hfs", required_argument, NULL, OPTION_HFS_HIDE},
389       '\0', "GLOBFILE", "Hide HFS file" , ONE_DASH },
390   { {"hide-hfs-list", required_argument, NULL, OPTION_H_LIST},
391       '\0', "GLOBFILE", "List of HFS files to hide" , ONE_DASH },
392   { {"table-name", required_argument, NULL, OPTION_TRANS_TBL},
393       '\0', "TABLE_NAME", "translation table file name", ONE_DASH },
394   { {"hfs-volid", required_argument, NULL, OPTION_HFS_VOLID},
395       '\0', "HFS_VOLID", "Volume name for the HFS partition", ONE_DASH },
396   {{"hfs-bless", required_argument, NULL, OPTION_HFS_BLESS},
397       '\0', "FOLDER_NAME", "Name of Folder to be blessed", ONE_DASH},
398   { {"cap", no_argument, NULL, OPTION_CAP},
399       '\0', NULL, "Look for AUFS CAP Macintosh files", TWO_DASHES },
400   { {"netatalk", no_argument, NULL, OPTION_NETA},
401       '\0', NULL, "Look for NETATALK Macintosh files", TWO_DASHES },
402   { {"double", no_argument, NULL, OPTION_DBL},
403       '\0', NULL, "Look for AppleDouble Macintosh files", TWO_DASHES },
404   { {"ethershare", no_argument, NULL, OPTION_ESH},
405       '\0', NULL, "Look for Helios EtherShare Macintosh files", TWO_DASHES },
406   { {"exchange", no_argument, NULL, OPTION_FE},
407       '\0', NULL, "Look for PC Exchange Macintosh files", TWO_DASHES },
408   { {"sgi", no_argument, NULL, OPTION_SGI},
409       '\0', NULL, "Look for SGI Macintosh files", TWO_DASHES },
410   { {"macbin", no_argument, NULL, OPTION_MBIN},
411       '\0', NULL, "Look for MacBinary Macintosh files", TWO_DASHES },
412   { {"single", no_argument, NULL, OPTION_SGL},
413       '\0', NULL, "Look for AppleSingle Macintosh files", TWO_DASHES },
414   { {"ushare", no_argument, NULL, OPTION_USH},
415       '\0', NULL, "Look for IPT UShare Macintosh files", TWO_DASHES },
416   { {"xinet", no_argument, NULL, OPTION_XIN},
417       '\0', NULL, "Look for XINET Macintosh files", TWO_DASHES },
418 #endif /* APPLE_HYB */
419 };
420 
421 #define OPTION_COUNT (sizeof ld_options / sizeof ld_options[0])
422 
423 #if defined(ultrix) || defined(_AUX_SOURCE)
strdup(s)424 char *strdup(s)
425 char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;}
426 #endif
427 
428 	void read_rcfile	__PR((char * appname));
429 	void usage		__PR((void));
430 static	void hide_reloc_dir	__PR((void));
431 
FDECL1(read_rcfile,char *,appname)432 void FDECL1(read_rcfile, char *, appname)
433 {
434   FILE * rcfile;
435   struct rcopts * rco;
436   char * pnt, *pnt1;
437   char linebuffer[256];
438   static char rcfn[] = ".mkisofsrc";
439   char filename[1000];
440   int linum;
441 
442   strcpy(filename, rcfn);
443   rcfile = fopen(filename, "r");
444   if (!rcfile && errno != ENOENT)
445     perror(filename);
446 
447   if (!rcfile)
448     {
449       pnt = getenv("MKISOFSRC");
450       if (pnt && strlen(pnt) <= sizeof(filename))
451 	{
452 	  strcpy(filename, pnt);
453 	  rcfile = fopen(filename, "r");
454 	  if (!rcfile && errno != ENOENT)
455 	    perror(filename);
456 	}
457     }
458 
459   if (!rcfile)
460     {
461       pnt = getenv("HOME");
462       if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename))
463 	{
464 	  strcpy(filename, pnt);
465 	  strcat(filename, "/");
466 	  strcat(filename, rcfn);
467 	  rcfile = fopen(filename, "r");
468 	  if (!rcfile && errno != ENOENT)
469 	    perror(filename);
470 	}
471     }
472   if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename))
473     {
474       strcpy(filename, appname);
475       pnt = strrchr(filename, '/');
476       if (pnt)
477 	{
478 	  strcpy(pnt + 1, rcfn);
479 	  rcfile = fopen(filename, "r");
480 	  if (!rcfile && errno != ENOENT)
481 	    perror(filename);
482 	}
483     }
484   if (!rcfile)
485     return;
486   if ( verbose > 0 )
487     {
488       fprintf(stderr, "Using \"%s\"\n", filename);
489     }
490 
491   /* OK, we got it.  Now read in the lines and parse them */
492   linum = 0;
493   while (fgets(linebuffer, sizeof(linebuffer), rcfile))
494     {
495       char *name;
496       char *name_end;
497       ++linum;
498       /* skip any leading white space */
499 	pnt = linebuffer;
500       while (*pnt == ' ' || *pnt == '\t')
501 	++pnt;
502       /* If we are looking at a # character, this line is a comment. */
503 	if (*pnt == '#')
504 	  continue;
505       /* The name should begin in the left margin.  Make sure it is in
506 	 upper case.  Stop when we see white space or a comment. */
507 	name = pnt;
508       while (*pnt && isalpha((unsigned char)*pnt))
509 	{
510 	  if(islower((unsigned char)*pnt))
511 	    *pnt = toupper((unsigned char)*pnt);
512 	  pnt++;
513 	}
514       if (name == pnt)
515 	{
516 	  fprintf(stderr, "%s:%d: name required\n", filename, linum);
517 	  continue;
518 	}
519       name_end = pnt;
520       /* Skip past white space after the name */
521       while (*pnt == ' ' || *pnt == '\t')
522 	pnt++;
523       /* silently ignore errors in the rc file. */
524       if (*pnt != '=')
525 	{
526 	  fprintf(stderr, "%s:%d: equals sign required\n", filename, linum);
527 	  continue;
528 	}
529       /* Skip pas the = sign, and any white space following it */
530       pnt++; /* Skip past '=' sign */
531       while (*pnt == ' ' || *pnt == '\t')
532 	pnt++;
533 
534       /* now it is safe to NUL terminate the name */
535 
536 	*name_end = 0;
537 
538       /* Now get rid of trailing newline */
539 
540       pnt1 = pnt;
541       while (*pnt1)
542 	{
543 	  if (*pnt1 == '\n')
544 	    {
545 	      *pnt1 = 0;
546 	      break;
547 	    }
548 	  pnt1++;
549 	};
550       /* OK, now figure out which option we have */
551       for(rco = rcopt; rco->tag; rco++) {
552 	if(strcmp(rco->tag, name) == 0)
553 	  {
554 	    *rco->variable = strdup(pnt);
555 	    break;
556 	  };
557       }
558       if (rco->tag == NULL)
559 	{
560 	  fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum,
561 		  name);
562 	}
563      }
564   if (ferror(rcfile))
565     perror(filename);
566   fclose(rcfile);
567 }
568 
569 char * path_table_l = NULL;
570 char * path_table_m = NULL;
571 
572 char * jpath_table_l = NULL;
573 char * jpath_table_m = NULL;
574 
575 int goof = 0;
576 
577 #ifndef TRUE
578 #define TRUE 1
579 #endif
580 
581 #ifndef FALSE
582 #define FALSE 0
583 #endif
584 
usage()585 void usage(){
586 #ifdef APPLE_HYB
587   const char * program_name = "mkhybrid";
588 #else
589   const char * program_name = "mkisofs";
590 #endif /* APPLE_HYB */
591 
592 #if 0
593 	fprintf(stderr,"Usage:\n");
594 	fprintf(stderr,
595 "mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \
596 [-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]"
597 "[-P publisher] [ -A app_id ] [-z] \n \
598 [-b boot_image_name] [-c boot_catalog-name] \
599 [-x path -x path ...] path\n");
600 #endif
601 
602   int i;
603 /*  const char **targets, **pp;*/
604 
605   fprintf (stderr, "Usage: %s [options] file...\n", program_name);
606 
607   fprintf (stderr, "Options:\n");
608   for (i = 0; i < OPTION_COUNT; i++)
609     {
610       if (ld_options[i].doc != NULL)
611 	{
612 	  int comma;
613 	  int len;
614 	  int j;
615 
616 	  fprintf (stderr, "  ");
617 
618 	  comma = FALSE;
619 	  len = 2;
620 
621 	  j = i;
622 	  do
623 	    {
624 	      if (ld_options[j].shortopt != '\0'
625 		  && ld_options[j].control != NO_HELP)
626 		{
627 		  fprintf (stderr, "%s-%c", comma ? ", " : "", ld_options[j].shortopt);
628 		  len += (comma ? 2 : 0) + 2;
629 		  if (ld_options[j].arg != NULL)
630 		    {
631 		      if (ld_options[j].opt.has_arg != optional_argument)
632 			{
633 			  fprintf (stderr, " ");
634 			  ++len;
635 			}
636 		      fprintf (stderr, "%s", ld_options[j].arg);
637 		      len += strlen (ld_options[j].arg);
638 		    }
639 		  comma = TRUE;
640 		}
641 	      ++j;
642 	    }
643 	  while (j < OPTION_COUNT && ld_options[j].doc == NULL);
644 
645 	  j = i;
646 	  do
647 	    {
648 	      if (ld_options[j].opt.name != NULL
649 		  && ld_options[j].control != NO_HELP)
650 		{
651 		  fprintf (stderr, "%s-%s%s",
652 			  comma ? ", " : "",
653 			  ld_options[j].control == TWO_DASHES ? "-" : "",
654 			  ld_options[j].opt.name);
655 		  len += ((comma ? 2 : 0)
656 			  + 1
657 			  + (ld_options[j].control == TWO_DASHES ? 1 : 0)
658 			  + strlen (ld_options[j].opt.name));
659 		  if (ld_options[j].arg != NULL)
660 		    {
661 		      fprintf (stderr, " %s", ld_options[j].arg);
662 		      len += 1 + strlen (ld_options[j].arg);
663 		    }
664 		  comma = TRUE;
665 		}
666 	      ++j;
667 	    }
668 	  while (j < OPTION_COUNT && ld_options[j].doc == NULL);
669 
670 	  if (len >= 30)
671 	    {
672 	      fprintf (stderr, "\n");
673 	      len = 0;
674 	    }
675 
676 	  for (; len < 30; len++)
677 	    fputc (' ', stderr);
678 
679 	  fprintf (stderr, "%s\n", ld_options[i].doc);
680 	}
681     }
682   exit(1);
683 }
684 
685 
686 /*
687  * Fill in date in the iso9660 format
688  *
689  * The standards  state that the timezone offset is in multiples of 15
690  * minutes, and is what you add to GMT to get the localtime.  The U.S.
691  * is always at a negative offset, from -5h to -8h (can vary a little
692  * with DST,  I guess).  The Linux iso9660 filesystem has had the sign
693  * of this wrong for ages (mkisofs had it wrong too for the longest time).
694  */
FDECL2(iso9660_date,char *,result,time_t,crtime)695 int FDECL2(iso9660_date,char *, result, time_t, crtime){
696   struct tm *local;
697   local = localtime(&crtime);
698   result[0] = local->tm_year;
699   result[1] = local->tm_mon + 1;
700   result[2] = local->tm_mday;
701   result[3] = local->tm_hour;
702   result[4] = local->tm_min;
703   result[5] = local->tm_sec;
704 
705   /*
706    * Must recalculate proper timezone offset each time,
707    * as some files use daylight savings time and some don't...
708    */
709   result[6] = local->tm_yday;	/* save yday 'cause gmtime zaps it */
710   local = gmtime(&crtime);
711   local->tm_year -= result[0];
712   local->tm_yday -= result[6];
713   local->tm_hour -= result[3];
714   local->tm_min -= result[4];
715   if (local->tm_year < 0)
716     {
717       local->tm_yday = -1;
718     }
719   else
720     {
721       if (local->tm_year > 0) local->tm_yday = 1;
722     }
723 
724   result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15;
725 
726   return 0;
727 }
728 
729 /* hide "./rr_moved" if all its contents are hidden */
730 static void
hide_reloc_dir()731 hide_reloc_dir()
732 {
733 	struct directory_entry * s_entry;
734 
735 	for (s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) {
736 	    if(strcmp(s_entry->name,".")==0 || strcmp(s_entry->name,"..")==0)
737 		continue;
738 
739 	    if((s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0)
740 		return;
741 	}
742 
743 	/* all entries are hidden, so hide this directory */
744 	reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
745 	reloc_dir->self->de_flags |= INHIBIT_ISO9660_ENTRY;
746 }
747 
748 /* get pathnames from the command line, and then from given file */
749 static char *
FDECL5(get_pnames,int,argc,char **,argv,int,opt,char *,pname,FILE *,fp)750 FDECL5(get_pnames, int, argc, char **, argv, int, opt, char *, pname, FILE *, fp)
751 {
752 	if (opt < argc)
753 	    return (argv[opt]);
754 
755 	if (fp == NULL)
756 	    return ((char *)0);
757 
758 	if (fscanf(fp, "%s", pname) != EOF)
759 	    return (pname);
760 
761 	return ((char *)0);
762 }
763 
764 extern char * cdwrite_data;
765 
FDECL2(main,int,argc,char **,argv)766 int FDECL2(main, int, argc, char **, argv){
767   struct directory_entry de;
768 #ifdef HAVE_SBRK
769   unsigned long mem_start;
770 #endif
771   struct stat statbuf;
772   char * scan_tree;
773   char * merge_image = NULL;
774   struct iso_directory_record * mrootp = NULL;
775   struct output_fragment * opnt;
776   int longind;
777   char shortopts[OPTION_COUNT * 3 + 2];
778   struct option longopts[OPTION_COUNT + 1];
779   int c;
780   char *log_file = 0;
781 #ifdef APPLE_HYB
782   char *afpfile = "";		/* mapping file for TYPE/CREATOR */
783   char *pathnames = 0;
784   FILE *pfp = NULL;
785   char pname[1024], *arg;
786   int no_path_names = 0;
787 #endif /* APPLE_HYB */
788 
789   if (argc < 2)
790     usage();
791 
792   /* Get the defaults from the .mkisofsrc file */
793   read_rcfile(argv[0]);
794 
795   outfile = NULL;
796 
797   /*
798    * Copy long option initialization from GNU-ld.
799    */
800   /* Starting the short option string with '-' is for programs that
801      expect options and other ARGV-elements in any order and that care about
802      the ordering of the two.  We describe each non-option ARGV-element
803      as if it were the argument of an option with character code 1.  */
804   {
805     int i, is, il;
806     shortopts[0] = '-';
807     is = 1;
808     il = 0;
809     for (i = 0; i < OPTION_COUNT; i++)
810       {
811 	if (ld_options[i].shortopt != '\0')
812 	  {
813 	    shortopts[is] = ld_options[i].shortopt;
814 	    ++is;
815 	    if (ld_options[i].opt.has_arg == required_argument
816 		|| ld_options[i].opt.has_arg == optional_argument)
817 	      {
818 		shortopts[is] = ':';
819 		++is;
820 		if (ld_options[i].opt.has_arg == optional_argument)
821 		  {
822 		    shortopts[is] = ':';
823 		    ++is;
824 		  }
825 	      }
826 	  }
827 	if (ld_options[i].opt.name != NULL)
828 	  {
829 	    longopts[il] = ld_options[i].opt;
830 	    ++il;
831 	  }
832       }
833     shortopts[is] = '\0';
834     longopts[il].name = NULL;
835   }
836 
837   while ((c = getopt_long_only (argc, argv, shortopts, longopts, &longind)) != EOF)
838     switch (c)
839       {
840       case 1:
841 	/*
842 	 * A filename that we take as input.
843 	 */
844 	optind--;
845 	goto parse_input_files;
846       case 'C':
847 	/*
848 	 * This is a temporary hack until cdwrite gets the proper hooks in
849 	 * it.
850 	 */
851 	cdwrite_data = optarg;
852 	break;
853       case 'i':
854 	fprintf(stderr, "-i option no longer supported.\n");
855 	exit(1);
856 	break;
857       case 'J':
858 	use_Joliet++;
859 	break;
860       case 'a':
861 	all_files++;
862 	break;
863       case 'b':
864 	use_eltorito++;
865 	boot_image = optarg;  /* pathname of the boot image on cd */
866 	if (boot_image == NULL) {
867 	        fprintf(stderr,"Required boot image pathname missing\n");
868 		exit(1);
869 	}
870 	break;
871       case 'e':
872 	use_eltorito++;
873 	efi_boot_image = optarg;
874 	if (efi_boot_image == NULL) {
875 		fprintf(stderr,"Required EFI boot image pathname missing\n");
876 		exit(1);
877 	}
878 	break;
879       case 'c':
880 	use_eltorito++;
881 	boot_catalog = optarg;  /* pathname of the boot image on cd */
882 	if (boot_catalog == NULL) {
883 	        fprintf(stderr,"Required boot catalog pathname missing\n");
884 		exit(1);
885 	}
886 	break;
887       case OPTION_ABSTRACT:
888 	abstract = optarg;
889 	if(strlen(abstract) > 37) {
890 		fprintf(stderr,"Abstract filename string too long\n");
891 		exit(1);
892 	};
893 	break;
894       case 'A':
895 	appid = optarg;
896 	if(strlen(appid) > 128) {
897 		fprintf(stderr,"Application-id string too long\n");
898 		exit(1);
899 	};
900 	break;
901       case OPTION_BIBLIO:
902 	biblio = optarg;
903 	if(strlen(biblio) > 37) {
904 		fprintf(stderr,"Bibliographic filename string too long\n");
905 		exit(1);
906 	};
907 	break;
908       case OPTION_COPYRIGHT:
909 	copyright = optarg;
910 	if(strlen(copyright) > 37) {
911 		fprintf(stderr,"Copyright filename string too long\n");
912 		exit(1);
913 	};
914 	break;
915       case 'd':
916 	omit_period++;
917 	break;
918       case 'D':
919 	RR_relocation_depth = 32767;
920 	break;
921       case 'f':
922 	follow_links++;
923 	break;
924       case 'l':
925 	full_iso9660_filenames++;
926 	break;
927       case 'L':
928         allow_leading_dots++;
929         break;
930      case OPTION_LOG_FILE:
931 	log_file = optarg;
932 	break;
933       case 'M':
934 	merge_image = optarg;
935 	break;
936       case 'N':
937 	omit_version_number++;
938 	break;
939       case 'o':
940 	outfile = optarg;
941 	break;
942       case 'p':
943 	preparer = optarg;
944 	if(strlen(preparer) > 128) {
945 		fprintf(stderr,"Preparer string too long\n");
946 		exit(1);
947 	};
948 	break;
949       case OPTION_PRINT_SIZE:
950 	print_size++;
951 	break;
952       case 'P':
953 	publisher = optarg;
954 	if(strlen(publisher) > 128) {
955 		fprintf(stderr,"Publisher string too long\n");
956 		exit(1);
957 	};
958 	break;
959       case OPTION_QUIET:
960 	verbose = 0;
961 	break;
962       case 'R':
963 	use_RockRidge++;
964 	break;
965       case 'r':
966 	rationalize++;
967 	use_RockRidge++;
968 	break;
969       case OPTION_SPLIT_OUTPUT:
970 	split_output++;
971 	break;
972       case OPTION_SYSID:
973 	system_id = optarg;
974 	if(strlen(system_id) > 32) {
975 		fprintf(stderr,"System ID string too long\n");
976 		exit(1);
977 	};
978 	break;
979 #ifdef APPLE_HYB
980       case OPTION_TRANS_TBL:
981 	trans_tbl = optarg;
982 	/* fall through */
983 #endif /* APPLE_HYB */
984       case 'T':
985 	generate_tables++;
986 	break;
987       case 'V':
988 	volume_id = optarg;
989 	if(strlen(volume_id) > 32) {
990 		fprintf(stderr,"Volume ID string too long\n");
991 		exit(1);
992 	};
993 	break;
994       case OPTION_VOLSET:
995 	volset_id = optarg;
996 	if(strlen(volset_id) > 128) {
997 		fprintf(stderr,"Volume set ID string too long\n");
998 		exit(1);
999 	};
1000 	break;
1001       case OPTION_VOLSET_SIZE:
1002 	volume_set_size = atoi(optarg);
1003 	break;
1004       case OPTION_VOLSET_SEQ_NUM:
1005 	volume_sequence_number = atoi(optarg);
1006 	if (volume_sequence_number > volume_set_size) {
1007 		fprintf(stderr,"Volume set sequence number too big\n");
1008 		exit(1);
1009 	}
1010 	break;
1011       case 'v':
1012 	verbose++;
1013 	break;
1014       case 'z':
1015 #ifdef VMS
1016 	fprintf(stderr,"Transparent compression not supported with VMS\n");
1017 	exit(1);
1018 #else
1019 	transparent_compression++;
1020 #endif
1021 	break;
1022       case 'x':
1023       case 'm':
1024 	/*
1025 	 * Somehow two options to do basically the same thing got added somewhere along
1026 	 * the way.  The 'match' code supports limited globbing, so this is the one
1027 	 * that got selected.  Unfortunately the 'x' switch is probably more intuitive.
1028 	 */
1029         add_match(optarg);
1030 	break;
1031       case OPTION_I_HIDE:
1032 	i_add_match(optarg);
1033 	break;
1034       case OPTION_J_HIDE:
1035 	j_add_match(optarg);
1036 	break;
1037       case OPTION_HELP:
1038 	usage ();
1039 	exit (0);
1040 	break;
1041       case OPTION_NOSPLIT_SL_COMPONENT:
1042 	split_SL_component = 0;
1043 	break;
1044       case OPTION_NOSPLIT_SL_FIELD:
1045 	split_SL_field = 0;
1046 	break;
1047 #ifdef APPLE_HYB
1048       case 'H':
1049 	afpfile = optarg;
1050 	hfs_last = MAP_LAST;
1051 	break;
1052       case 'h':
1053 	apple_hyb = 1;
1054 	break;
1055       case 'g':
1056 	apple_ext = 1;
1057 	break;
1058       case OPTION_PROBE:
1059 	probe = 1;
1060 	break;
1061       case OPTION_MACNAME:
1062 	mac_name = 1;
1063 	break;
1064       case OPTION_NOMACFILES:
1065 	nomacfiles = 1;
1066 	break;
1067       case OPTION_BOOT_HFS_FILE:
1068 	hfs_boot_file = optarg;
1069 	/* fall through */
1070       case OPTION_GEN_PT:
1071 	gen_pt = 1;
1072 	break;
1073       case OPTION_MAGIC_FILE:
1074 	magic_file = optarg;
1075 	hfs_last = MAG_LAST;
1076 	break;
1077       case OPTION_AUTOSTART:
1078 	autoname = optarg;
1079 	/* gen_pt = 1; */
1080 	break;
1081       case OPTION_BSIZE:
1082 	bsize = atoi(optarg);
1083 	break;
1084       case OPTION_HFS_VOLID:
1085 	hfs_volume_id = optarg;
1086 	break;
1087       case OPTION_HFS_BLESS:
1088 	hfs_bless = optarg;
1089 	break;
1090       /* Mac/Unix types to include */
1091       case OPTION_CAP:
1092 	hfs_select |= DO_CAP;
1093 	break;
1094       case OPTION_NETA:
1095 	hfs_select |= DO_NETA;
1096 	break;
1097       case OPTION_DBL:
1098 	hfs_select |= DO_DBL;
1099 	break;
1100       case OPTION_ESH:
1101       case OPTION_USH:
1102 	hfs_select |= DO_ESH;
1103 	break;
1104       case OPTION_FE:
1105 	hfs_select |= DO_FEU;
1106 	hfs_select |= DO_FEL;
1107 	break;
1108       case OPTION_SGI:
1109       case OPTION_XIN:
1110 	hfs_select |= DO_SGI;
1111 	break;
1112       case OPTION_MBIN:
1113 	hfs_select |= DO_MBIN;
1114 	break;
1115       case OPTION_SGL:
1116 	hfs_select |= DO_SGL;
1117 	break;
1118       case OPTION_CREATE_DT:
1119 	create_dt = 0;
1120 	break;
1121       case OPTION_HFS_HIDE:
1122         hfs_add_match(optarg);
1123 	break;
1124       case OPTION_H_LIST:
1125 	hfs_add_list(optarg);
1126 	break;
1127 /* NON-HFS change
1128    The next options will probably appear in mkisofs in the future */
1129       case OPTION_P_LIST:
1130 	pathnames = optarg;
1131 	break;
1132       case OPTION_X_LIST:
1133 	add_list(optarg);
1134 	break;
1135       case OPTION_I_LIST:
1136 	i_add_list(optarg);
1137 	break;
1138       case OPTION_J_LIST:
1139 	j_add_list(optarg);
1140 	break;
1141 #endif /* APPLE_HYB */
1142       default:
1143 	usage();
1144 	exit(1);
1145       }
1146 
1147 parse_input_files:
1148 
1149 #if defined(__NetBSD__) || defined(__OpenBSD__)
1150     {
1151     struct rlimit rlp;
1152 	if (getrlimit(RLIMIT_DATA,&rlp) == -1)
1153 		perror("Warning: getrlimit");
1154 	else {
1155 		rlp.rlim_cur=33554432;
1156 		if (setrlimit(RLIMIT_DATA,&rlp) == -1)
1157 			perror("Warning: setrlimit");
1158 		}
1159 	}
1160 #endif
1161 #ifdef HAVE_SBRK
1162   mem_start = (unsigned long) sbrk(0);
1163 #endif
1164 
1165   /* if the -hide-joliet option has been given, set the Joliet option */
1166   if (!use_Joliet && j_ishidden())
1167     use_Joliet++;
1168 
1169 #ifdef APPLE_HYB
1170   if (apple_hyb && apple_ext) {
1171     fprintf(stderr,"can't have both -apple and -hfs options");
1172     exit (1);
1173   }
1174 
1175   /* if -probe, -macname, any hfs selection and/or mapping file is given,
1176      but no HFS option, then select apple_hyb */
1177   if (!apple_hyb && !apple_ext) {
1178     if (*afpfile || probe || mac_name || nomacfiles || hfs_select || hfs_boot_file || magic_file || hfs_ishidden() || gen_pt || autoname || bsize)
1179 	apple_hyb = 1;
1180   }
1181 
1182   if (apple_ext && hfs_boot_file) {
1183     fprintf(stderr,"can't have -hfs-boot-file with -apple\n");
1184     exit (1);
1185   }
1186 
1187   if (hfs_select)
1188     /* if we have selected certain types of Mac/Unix files, then turn off
1189        probe and nomacfiles */
1190     probe = nomacfiles = 0;
1191 
1192   if (apple_hyb || apple_ext)
1193     apple_both = 1;
1194 
1195   if (apple_both) {
1196     /* set up the TYPE/CREATOR mappings */
1197     hfs_init(afpfile, 0, probe, nomacfiles, hfs_select);
1198   }
1199 
1200   if (apple_ext && !use_RockRidge) {
1201     /* use RockRidge to set the SystemUse field ... */
1202     use_RockRidge++;
1203     rationalize++;
1204   }
1205 
1206 #endif /* APPLE_HYB */
1207 
1208   if(verbose > 1) fprintf(stderr,"%s\n", version_string);
1209 
1210   if(cdwrite_data == NULL && merge_image != NULL)
1211     {
1212       fprintf(stderr,"Multisession usage bug: Must specify -C if -M is used.\n");
1213       exit(0);
1214     }
1215 
1216   if(cdwrite_data != NULL && merge_image == NULL)
1217     {
1218       fprintf(stderr,"Warning: -C specified without -M: old session data will not be merged.\n");
1219     }
1220 
1221   /*  The first step is to scan the directory tree, and take some notes */
1222 
1223   scan_tree = argv[optind];
1224 
1225 
1226   if(!scan_tree){
1227 	  usage();
1228 	  exit(1);
1229   };
1230 
1231 #ifndef VMS
1232   if(scan_tree[strlen(scan_tree)-1] != '/') {
1233     scan_tree = (char *) e_malloc(strlen(argv[optind])+2);
1234     strcpy(scan_tree, argv[optind]);
1235     strcat(scan_tree, "/");
1236   };
1237 #endif
1238 
1239   if(use_RockRidge){
1240 #if 1
1241 	extension_record = generate_rr_extension_record("RRIP_1991A",
1242 				       "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
1243 				       "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size);
1244 #else
1245 	extension_record = generate_rr_extension_record("IEEE_P1282",
1246 				       "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
1247 				       "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size);
1248 #endif
1249   }
1250 
1251   if (log_file) {
1252     FILE *lfp;
1253     int i;
1254 
1255     /* open log file - test that we can open OK */
1256     if ((lfp = fopen(log_file, "w")) == NULL) {
1257       fprintf(stderr,"can't open logfile: %s\n", log_file);
1258       exit (1);
1259     }
1260     fclose(lfp);
1261 
1262     /* redirect all stderr message to log_file */
1263     fprintf(stderr, "re-directing all messages to %s\n", log_file);
1264     fflush(stderr);
1265 
1266     /* associate stderr with the log file */
1267     if (freopen(log_file, "w", stderr) == NULL) {
1268       fprintf(stderr,"can't open logfile: %s\n", log_file);
1269       exit (1);
1270     }
1271     if(verbose > 1) {
1272       for (i=0;i<argc;i++)
1273        fprintf(stderr,"%s ", argv[i]);
1274 
1275       fprintf(stderr,"\n%s\n", version_string);
1276     }
1277   }
1278 
1279   /*
1280    * See if boot catalog file exists in root directory, if not
1281    * we will create it.
1282    */
1283   if (use_eltorito)
1284     init_boot_catalog(argv[optind]);
1285 
1286   /*
1287    * Find the device and inode number of the root directory.
1288    * Record this in the hash table so we don't scan it more than
1289    * once.
1290    */
1291   stat_filter(argv[optind], &statbuf);
1292   add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1293 
1294   memset(&de, 0, sizeof(de));
1295 
1296   de.filedir = root;  /* We need this to bootstrap */
1297 
1298   if (cdwrite_data != NULL && merge_image == NULL) {
1299     /* in case we want to add a new session, but don't want to merge old one */
1300     get_session_start(NULL);
1301   }
1302 
1303   if( merge_image != NULL )
1304     {
1305       mrootp = merge_isofs(merge_image);
1306       if( mrootp == NULL )
1307 	{
1308 	  /*
1309 	   * Complain and die.
1310 	   */
1311 	  fprintf(stderr,"Unable to open previous session image %s\n",
1312 		  merge_image);
1313 	  exit(1);
1314 	}
1315 
1316       memcpy(&de.isorec.extent, mrootp->extent, 8);
1317     }
1318 
1319   /*
1320    * Create an empty root directory. If we ever scan it for real, we will fill in the
1321    * contents.
1322    */
1323   find_or_create_directory(NULL, "", &de, TRUE);
1324 
1325 #ifdef APPLE_HYB
1326   /* NON-HFS change: see if we have a list of pathnames to process */
1327   if (pathnames) {
1328 	/* "-" means take list from the standard input */
1329 	if (strcmp(pathnames, "-")) {
1330 	    if ((pfp = fopen(pathnames, "r")) == NULL) {
1331 		fprintf(stderr, "unable to open pathname list %s\n",pathnames);
1332 		exit (1);
1333 	    }
1334 	}
1335 	else
1336 	    pfp = stdin;
1337   }
1338 #endif /* APPLE_HYB */
1339 
1340   /*
1341    * Scan the actual directory (and any we find below it)
1342    * for files to write out to the output image.  Note - we
1343    * take multiple source directories and keep merging them
1344    * onto the image.
1345    */
1346 #if APPLE_HYB
1347   /* NON-HFS change */
1348   while((arg = get_pnames(argc, argv, optind, pname, pfp)) != NULL)
1349 #else
1350   while(optind < argc)
1351 #endif /* APPLE_HYB */
1352     {
1353       char * node;
1354       struct directory * graft_dir;
1355       struct stat        st;
1356       char             * short_name;
1357       int                status;
1358       char   graft_point[1024];
1359 
1360       /*
1361        * We would like a syntax like:
1362        *
1363        * /tmp=/usr/tmp/xxx
1364        *
1365        * where the user can specify a place to graft each
1366        * component of the tree.  To do this, we may have to create
1367        * directories along the way, of course.
1368        * Secondly, I would like to allow the user to do something
1369        * like:
1370        *
1371        * /home/baz/RMAIL=/u3/users/baz/RMAIL
1372        *
1373        * so that normal files could also be injected into the tree
1374        * at an arbitrary point.
1375        *
1376        * The idea is that the last component of whatever is being
1377        * entered would take the name from the last component of
1378        * whatever the user specifies.
1379        *
1380        * The default will be that the file is injected at the
1381        * root of the image tree.
1382        */
1383 #ifdef APPLE_HYB
1384       /* NON-HFS change */
1385       node = strchr(arg, '=');
1386 #else
1387       node = strchr(argv[optind], '=');
1388 #endif /* APPLE_HYB */
1389       short_name = NULL;
1390 
1391       if( node != NULL )
1392 	{
1393 	  char * pnt;
1394 	  char * xpnt;
1395 
1396 	  *node = '\0';
1397 #ifdef APPLE_HYB
1398 	  /* NON-HFS change */
1399 	  strcpy(graft_point, arg);
1400 #else
1401 	  strcpy(graft_point, argv[optind]);
1402 #endif /* APPLE_HYB */
1403 	  *node = '=';
1404 	  node++;
1405 
1406 	  graft_dir = root;
1407 	  xpnt = graft_point;
1408 	  if( *xpnt == PATH_SEPARATOR )
1409 	    {
1410 	      xpnt++;
1411 	    }
1412 
1413 	  /*
1414 	   * Loop down deeper and deeper until we
1415 	   * find the correct insertion spot.
1416 	   */
1417 	  while(1==1)
1418 	    {
1419 	      pnt = strchr(xpnt, PATH_SEPARATOR);
1420 	      if( pnt == NULL )
1421 		{
1422 		  if( *xpnt != '\0' )
1423 		    {
1424 		      short_name = xpnt;
1425 		    }
1426 		  break;
1427 		}
1428 	      *pnt = '\0';
1429 	      graft_dir = find_or_create_directory(graft_dir,
1430 						   graft_point,
1431 						   NULL, TRUE);
1432 	      *pnt = PATH_SEPARATOR;
1433 	      xpnt = pnt + 1;
1434 	    }
1435 	}
1436       else
1437 	{
1438 	  graft_dir = root;
1439 #ifdef APPLE_HYB
1440 	  /* NON-HFS change */
1441 	  node = arg;
1442 #else
1443 	  node = argv[optind];
1444 #endif /* APPLE_HYB */
1445 	}
1446 
1447       /*
1448        * Now see whether the user wants to add a regular file,
1449        * or a directory at this point.
1450        */
1451       status = stat_filter(node, &st);
1452       if( status != 0 )
1453 	{
1454 	  /*
1455 	   * This is a fatal error - the user won't be getting what
1456 	   * they want if we were to proceed.
1457 	   */
1458 	  fprintf(stderr, "Invalid node - %s\n", node);
1459 	  exit(1);
1460 	}
1461       else
1462 	{
1463 	  if( S_ISDIR(st.st_mode) )
1464 	    {
1465 	      if (!scan_directory_tree(graft_dir, node, &de))
1466 		{
1467 		  exit(1);
1468 		}
1469 	    }
1470 	  else
1471 	    {
1472 	      if( short_name == NULL )
1473 		{
1474 		  short_name = strrchr(node, PATH_SEPARATOR);
1475 		  if( short_name == NULL || short_name < node )
1476 		    {
1477 		      short_name = node;
1478 		    }
1479 		  else
1480 		    {
1481 		      short_name++;
1482 		    }
1483 		}
1484 #ifdef APPLE_HYB
1485 	      if( !insert_file_entry(graft_dir, node, short_name, 0) )
1486 #else
1487 	      if( !insert_file_entry(graft_dir, node, short_name) )
1488 #endif /* APPLE_HYB */
1489 		{
1490 		 exit(1);
1491 		}
1492 	    }
1493 	}
1494 
1495       optind++;
1496 #ifdef APPLE_HYB
1497       /* NON-HFS change */
1498       no_path_names = 0;
1499 #endif /* APPLE_HYB */
1500     }
1501 
1502 #ifdef APPLE_HYB
1503   /* NON-HFS change */
1504   if (pfp && pfp != stdin)
1505     fclose(pfp);
1506 
1507   /* exit if we don't have any pathnames to process - not going to happen
1508      at the moment as we have to have at least one path on the command line */
1509   if(no_path_names){
1510           usage();
1511           exit(1);
1512   };
1513 #endif /* APPLE_HYB */
1514 
1515   /*
1516    * Now merge in any previous sessions.  This is driven on the source
1517    * side, since we may need to create some additional directories.
1518    */
1519   if( merge_image != NULL )
1520     {
1521       merge_previous_session(root, mrootp);
1522     }
1523 #ifdef APPLE_HYB
1524   /* free up any HFS filename mapping memory */
1525   if (apple_both)
1526     clean_hfs();
1527 #endif /* APPLE_HYB */
1528 
1529   /* hide "./rr_moved" if all its contents have been hidden */
1530   if (reloc_dir && i_ishidden())
1531     hide_reloc_dir();
1532 
1533   /*
1534    * Sort the directories in the required order (by ISO9660).  Also,
1535    * choose the names for the 8.3 filesystem if required, and do
1536    * any other post-scan work.
1537    */
1538   goof += sort_tree(root);
1539 
1540   if( use_Joliet )
1541     {
1542       goof += joliet_sort_tree(root);
1543     }
1544 
1545   if (goof)
1546     {
1547       fprintf(stderr, "Joliet tree sort failed.\n");
1548       exit(1);
1549     }
1550 
1551   /*
1552    * Fix a couple of things in the root directory so that everything
1553    * is self consistent.
1554    */
1555   root->self = root->contents;  /* Fix this up so that the path
1556 				   tables get done right */
1557 
1558   /*
1559    * OK, ready to write the file.  Open it up, and generate the thing.
1560    */
1561   if (print_size){
1562 	  discimage = fopen("/dev/null", "wb");
1563 	  if (!discimage){
1564 		  fprintf(stderr,"Unable to open /dev/null\n");
1565 		  exit(1);
1566 	  }
1567   } else if (outfile){
1568 	  discimage = fopen(outfile, "wb");
1569 	  if (!discimage){
1570 		  fprintf(stderr,"Unable to open disc image file\n");
1571 		  exit(1);
1572 
1573 	  };
1574   } else {
1575 	  discimage =  stdout;
1576 
1577 #if	defined(__CYGWIN32__)
1578 	setmode(fileno(stdout), O_BINARY);
1579 #endif
1580   }
1581 
1582   /* Now assign addresses on the disc for the path table. */
1583 
1584   path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11;
1585   if (path_blocks & 1) path_blocks++;
1586 
1587   jpath_blocks = (jpath_table_size + (SECTOR_SIZE - 1)) >> 11;
1588   if (jpath_blocks & 1) jpath_blocks++;
1589 
1590   /*
1591    * Start to set up the linked list that we use to track the
1592    * contents of the disc.
1593    */
1594   outputlist_insert(&padblock_desc);
1595 
1596   /*
1597    * PVD for disc.
1598    */
1599   outputlist_insert(&voldesc_desc);
1600 
1601   /*
1602    * SVD for El Torito. MUST be immediately after the PVD!
1603    */
1604   if( use_eltorito)
1605     {
1606       outputlist_insert(&torito_desc);
1607     }
1608 
1609   /*
1610    * SVD for Joliet.
1611    */
1612   if( use_Joliet)
1613     {
1614       outputlist_insert(&joliet_desc);
1615     }
1616 
1617   /*
1618    * Finally the last volume desctiptor.
1619    */
1620   outputlist_insert(&end_vol);
1621 
1622 
1623   outputlist_insert(&pathtable_desc);
1624   if( use_Joliet)
1625     {
1626       outputlist_insert(&jpathtable_desc);
1627     }
1628 
1629   outputlist_insert(&dirtree_desc);
1630   if( use_Joliet)
1631     {
1632       outputlist_insert(&jdirtree_desc);
1633     }
1634 
1635   outputlist_insert(&dirtree_clean);
1636 
1637   if(extension_record)
1638     {
1639       outputlist_insert(&extension_desc);
1640     }
1641 
1642   outputlist_insert(&files_desc);
1643 
1644   /*
1645    * Allow room for the various headers we will be writing.  There
1646    * will always be a primary and an end volume descriptor.
1647    */
1648   last_extent = session_start;
1649 
1650   /*
1651    * Calculate the size of all of the components of the disc, and assign
1652    * extent numbers.
1653    */
1654   for(opnt = out_list; opnt; opnt = opnt->of_next )
1655     {
1656       if( opnt->of_size != NULL )
1657 	{
1658 	  (*opnt->of_size)(last_extent);
1659 	}
1660     }
1661 
1662   /*
1663    * Generate the contents of any of the sections that we want to generate.
1664    * Not all of the fragments will do anything here - most will generate the
1665    * data on the fly when we get to the write pass.
1666    */
1667   for(opnt = out_list; opnt; opnt = opnt->of_next )
1668     {
1669       if( opnt->of_generate != NULL )
1670 	{
1671 	  (*opnt->of_generate)();
1672 	}
1673     }
1674 
1675   if( in_image != NULL )
1676     {
1677       fclose(in_image);
1678     }
1679 
1680   /*
1681    * Now go through the list of fragments and write the data that corresponds to
1682    * each one.
1683    */
1684   for(opnt = out_list; opnt; opnt = opnt->of_next )
1685     {
1686       if( opnt->of_write != NULL )
1687 	{
1688 	  (*opnt->of_write)(discimage);
1689 	}
1690     }
1691 
1692   if( verbose > 0 )
1693     {
1694 #ifdef HAVE_SBRK
1695       fprintf(stderr,"Max brk space used %x\n",
1696 	      (unsigned int)(((unsigned long)sbrk(0)) - mem_start));
1697 #endif
1698       fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9);
1699     }
1700 #ifdef APPLE_HYB
1701   last_extent += hfs_extra;
1702 #endif /* APPLE_HYB */
1703 
1704 #ifdef VMS
1705   return 1;
1706 #else
1707   return 0;
1708 #endif
1709 }
1710 
1711 void *
FDECL1(e_malloc,size_t,size)1712 FDECL1(e_malloc, size_t, size)
1713 {
1714 void* pt = 0;
1715 	if( (size > 0) && ((pt=malloc(size))==NULL) ) {
1716 		fprintf(stderr, "Not enough memory\n");
1717 		exit (1);
1718 		}
1719 return pt;
1720 }
1721