1 /* @(#)mkisofs.c	1.289 17/01/05 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)mkisofs.c	1.289 17/01/05 joerg";
6 #endif
7 /*
8  * Program mkisofs.c - generate iso9660 filesystem  based upon directory
9  * tree on hard disk.
10  *
11  * Written by Eric Youngdale (1993).
12  *
13  * Copyright 1993 Yggdrasil Computing, Incorporated
14  * Copyright (c) 1997-2017 J. Schilling
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2, or (at your option)
19  * any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  */
30 
31 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 22/2/2000 */
32 /* MAC UDF images by HELIOS Software GmbH support@helios.de */
33 /* HFS+ by HELIOS Software GmbH support@helios.de */
34 
35 /* DUPLICATES_ONCE Alex Kopylov cdrtools@bootcd.ru 19.06.2004 */
36 
37 #ifdef	USE_FIND
38 #include <schily/walk.h>
39 #include <schily/find.h>
40 #endif
41 #include "mkisofs.h"
42 #include "rock.h"
43 #include <schily/errno.h>
44 #include <schily/time.h>
45 #include <schily/fcntl.h>
46 #include <schily/ctype.h>
47 #include "match.h"
48 #include <schily/schily.h>
49 #include <schily/nlsdefs.h>
50 #include <schily/checkerr.h>
51 #ifdef UDF
52 #include "udf.h"
53 #endif
54 
55 #include <schily/io.h>				/* for setmode() prototype */
56 #include <schily/getargs.h>
57 
58 #ifdef VMS
59 #include "vms.h"
60 #endif
61 
62 #ifdef	no_more_needed
63 #include <schily/resource.h>
64 #endif	/* no_more_needed */
65 
66 #include "../cdrecord/version.h"
67 
68 struct directory *root = NULL;
69 int		path_ind;
70 
71 char	version_string[] = VERSION;
72 
73 char		*outfile;
74 FILE		*discimage;
75 UInt32_t	next_extent	= 0;
76 UInt32_t	last_extent	= 0;
77 UInt32_t	session_start	= 0;
78 unsigned int	path_table_size	= 0;
79 unsigned int	path_table[4]	= {0, };
80 unsigned int	path_blocks	= 0;
81 
82 
83 unsigned int	jpath_table_size = 0;
84 unsigned int	jpath_table[4]	= {0, };
85 unsigned int	jpath_blocks	= 0;
86 
87 struct iso_directory_record root_record;
88 struct iso_directory_record jroot_record;
89 
90 char	*extension_record = NULL;
91 UInt32_t extension_record_extent = 0;
92 int	extension_record_size = 0;
93 BOOL	archive_isreg;
94 dev_t	archive_dev;
95 ino_t	archive_ino;
96 
97 /* These variables are associated with command line options */
98 int	check_oldnames = 0;
99 int	check_session = 0;
100 int	use_eltorito = 0;
101 int	hard_disk_boot = 0;
102 int	not_bootable = 0;
103 int	no_emul_boot = 0;
104 int	load_addr = 0;
105 int	load_size = 0;
106 int	boot_info_table = 0;
107 int	use_sparcboot = 0;
108 int	use_sunx86boot = 0;
109 int	use_genboot = 0;
110 int	use_RockRidge = 0;
111 int	use_XA = 0;
112 int	osecsize = 0;	/* Output-sector size, 0 means default secsize 2048 */
113 int	use_Joliet = 0;
114 int	jlen = JMAX;	/* maximum Joliet file name length */
115 /*
116  *	Verbose levels currently used:
117  *
118  *	1+	Boot information
119  *	1+	Rcfile information
120  *	1+	Name mapping information
121  *	1+	Progress information
122  *	2+	Version informaton
123  *	2+	Output Extent (of_write) information
124  *	2+	PReP boot information
125  *	3+	HFS warnings
126  *	3+	Dump dirtree
127  */
128 int	verbose = 1;
129 int	debug = 0;
130 int	gui = 0;
131 BOOL	legacy = FALSE;		/* Implement legacy support for historic CLI */
132 int	all_files = 1;		/* New default is to include all files */
133 BOOL	Hflag = FALSE;		/* Follow links on cmdline (-H)	*/
134 BOOL	follow_links = FALSE;	/* Follow all links (-L)	*/
135 #if	defined(__MINGW32__) || defined(_MSC_VER)
136 /*
137  * Never cache inodes on DOS or Win-DOS.
138  */
139 int	cache_inodes = 0;
140 #else
141 int	cache_inodes = -1;	/* Cache inodes if OS has unique inodes */
142 #endif
143 int	rationalize = 0;	/* Need to call stat_fix()	*/
144 int	rationalize_uid = 0;
145 int	rationalize_gid = 0;
146 int	rationalize_filemode = 0;
147 int	rationalize_dirmode = 0;
148 uid_t	uid_to_use = 0;		/* when rationalizing uid */
149 gid_t	gid_to_use = 0;		/* when rationalizing gid */
150 int	filemode_to_use = 0;	/* if non-zero, when rationalizing file mode */
151 int	dirmode_to_use = 0;	/* if non-zero, when rationalizing dir mode */
152 int	new_dir_mode = 0555;	/* neither -new-dir-mode nor -dir-mode used */
153 int	generate_tables = 0;
154 int	dopad = 1;	/* Now default to do padding */
155 int	print_size = 0;
156 int	split_output = 0;
157 char	*icharset = NULL;	/* input charset to convert to UNICODE */
158 char	*ocharset = NULL;	/* output charset to convert from UNICODE */
159 char	*preparer = PREPARER_DEFAULT;
160 char	*publisher = PUBLISHER_DEFAULT;
161 char	*appid = APPID_DEFAULT;
162 char	*copyright = COPYRIGHT_DEFAULT;
163 char	*biblio = BIBLIO_DEFAULT;
164 char	*abstract = ABSTRACT_DEFAULT;
165 char	*volset_id = VOLSET_ID_DEFAULT;
166 char	*volume_id = VOLUME_ID_DEFAULT;
167 char	*system_id = SYSTEM_ID_DEFAULT;
168 char	*boot_catalog;
169 char	*boot_image = BOOT_IMAGE_DEFAULT;
170 char	*genboot_image = BOOT_IMAGE_DEFAULT;
171 int	ucs_level = 3;		/* We now have Unicode tables so use level 3 */
172 int	volume_set_size = 1;
173 int	volume_sequence_number = 1;
174 /* -------------------------------------------------------------------------- */
175 char	*merge_image;		/* CLI Parameter for -M option		    */
176 char	*check_image;		/* CLI Parameter for -check-session option  */
177 char	*reloc_root = NULL;	/* CLI Parameter for -root option	    */
178 char	*reloc_old_root = NULL;	/* CLI Parameter for -oldroot option	    */
179 extern char	*cdrecord_data;	/* CLI Parameter for -C option		    */
180 int	disable_deep_reloc;	/* CLI Parameter for -D option		    */
181 char	*dirmode_str;		/* CLI Parameter for -dir-mode option	    */
182 char	*filemode_str;		/* CLI Parameter for -file-mode option	    */
183 char	*gid_str;		/* CLI Parameter for -gid option	    */
184 int	help;			/* CLI Parameter for -help option	    */
185 int	joliet_long;		/* CLI Parameter for -joliet-long option    */
186 char	*jcharset;		/* CLI Parameter for -jcharset option	    */
187 int	max_filenames;		/* CLI Parameter for -max-iso9660-filenames option */
188 char	*log_file;		/* CLI Parameter for -log-file option	    */
189 char	*new_dirmode_str;	/* CLI Parameter for -new-dir-mode option   */
190 char	*pathnames;		/* CLI Parameter for -help option	    */
191 int	rationalize_rr;		/* CLI Parameter for -path-list option	    */
192 char	*sectype;		/* CLI Parameter for -s option		    */
193 char	*uid_str;		/* CLI Parameter for -uid option	    */
194 int	untranslated_filenames;	/* CLI Parameter for -U option		    */
195 int	pversion;		/* CLI Parameter for -version option	    */
196 int	rationalize_xa;		/* CLI Parameter for -xa option		    */
197 ldate	modification_date;	/* CLI Parameter for -modification-date	    */
198 #ifdef	APPLE_HYB
199 char	*afpfile = "";		/* CLI Parameter for -map option	    */
200 char	*root_info;		/* CLI Parameter for -root-info option	    */
201 #endif
202 BOOL	nodesc = FALSE;		/* Whether not to descend directories	    */
203 #ifdef	USE_FIND
204 BOOL	dofind	  = FALSE;	/* -find option found		*/
205 int	find_ac	  = 0;		/* ac past -find option		*/
206 char	*const *find_av = NULL;	/* av past -find option		*/
207 int	find_pac  = 0;		/* ac for first find primary	*/
208 char	*const *find_pav = NULL; /* av for first find primary	*/
209 findn_t	*find_node;		/* syntaxtree from find_parse()	*/
210 void	*plusp;			/* residual for -exec ...{} +	*/
211 int	find_patlen;		/* len for -find pattern state	*/
212 
213 LOCAL 	int		walkflags = WALK_CHDIR | WALK_PHYS | WALK_NOEXIT;
214 LOCAL	int		maxdepth = -1;
215 LOCAL	int		mindepth = -1;
216 EXPORT	struct WALK	walkstate;
217 #else
218 LOCAL 	int		walkflags = 0;
219 #endif
220 
221 extern	time_t		begun;
222 extern	struct timeval	tv_begun;
223 
224 LOCAL	BOOL		data_change_warn;
225 
226 struct eltorito_boot_entry_info *first_boot_entry = NULL;
227 struct eltorito_boot_entry_info *last_boot_entry = NULL;
228 struct eltorito_boot_entry_info *current_boot_entry = NULL;
229 
230 int	use_graft_ptrs;		/* Use graft points */
231 int	match_igncase;		/* Ignore case with -exclude-list and -hide* */
232 int	jhide_trans_tbl;	/* Hide TRANS.TBL from Joliet tree */
233 int	hide_rr_moved;		/* Name RR_MOVED .rr_moved in Rock Ridge tree */
234 int	omit_period = 0;	/* Violates iso9660, but these are a pain */
235 int	transparent_compression = 0; /* So far only works with linux */
236 int	omit_version_number = 0; /* May violate iso9660, but noone uses vers */
237 int	no_rr = 0;		/* Do not use RR attributes from old session */
238 int	force_rr = 0;		/* Force to use RR attributes from old session */
239 Uint	RR_relocation_depth = 6; /* Violates iso9660, but most systems work */
240 int	do_largefiles = 0;	/* Whether to allow multi-extent files */
241 off_t	maxnonlarge = (off_t)0xFFFFFFFF;
242 int	iso9660_level = 1;
243 int	iso9660_namelen = LEN_ISONAME; /* 31 characters, may be set to 37 */
244 int	full_iso9660_filenames = 0; /* Full 31 character iso9660 filenames */
245 int	nolimitpathtables = 0;	/* Don't limit size of pathtable. Violates iso9660 */
246 int	relaxed_filenames = 0;	/* For Amiga.  Disc will not work with DOS */
247 int	allow_lowercase = 0;	/* Allow lower case letters */
248 int	no_allow_lowercase = 0;	/* Do not allow lower case letters */
249 int	allow_multidot = 0;	/* Allow more than on dot in filename */
250 int	iso_translate = 1;	/* 1 == enables '#', '-' and '~' removal */
251 int	allow_leading_dots = 0;	/* DOS cannot read names with leading dots */
252 #ifdef	VMS
253 int	use_fileversion = 1;	/* Use file version # from filesystem */
254 #else
255 int	use_fileversion = 0;	/* Use file version # from filesystem */
256 #endif
257 int	split_SL_component = 1;	/* circumvent a bug in the SunOS driver */
258 int	split_SL_field = 1;	/* circumvent a bug in the SunOS */
259 char	*trans_tbl;		/* default name for translation table */
260 int	stream_media_size = 0;	/* # of blocks on the media */
261 char	*stream_filename;	/* Default stream file name */
262 
263 #ifdef APPLE_HYB
264 int	donotwrite_macpart = 0;	/* Do not write "hfs" hybrid with UDF */
265 int	apple_hyb = 0;		/* -hfs HFS hybrid flag */
266 int	no_apple_hyb = 0;	/* -no-hfs HFS hybrid flag */
267 int	apple_ext = 0;		/* create HFS extensions flag */
268 int	apple_both = 0;		/* common flag (for above) */
269 int	hfs_extra = 0;		/* extra HFS blocks added to end of ISO vol */
270 int	use_mac_name = 0;	/* use Mac name for ISO/Joliet/RR flag */
271 hce_mem	*hce;			/* libhfs/mkisofs extras */
272 char	*hfs_boot_file = 0;	/* name of HFS boot file */
273 int	gen_pt = 0;		/* generate HFS partition table */
274 char	*autoname = 0;		/* AutoStart filename */
275 char	*magic_file = 0;	/* name of magic file */
276 int	probe = 0;		/* search files for HFS/Unix type */
277 int	nomacfiles = 0;		/* don't look for Mac/Unix files */
278 int	hfs_select = 0;		/* Mac/Unix types to select */
279 int	create_dt = 1;		/* create the Desktp files */
280 int	afe_size = 0;		/* Apple File Exchange block size */
281 int	hfs_last = MAG_LAST;	/* process magic file after map file */
282 char	*deftype;		/* default Apple TYPE */
283 char	*defcreator;		/* default Apple CREATOR */
284 char	*hfs_volume_id = NULL;	/* HFS volume ID */
285 int	icon_pos = 0;		/* Keep icon position */
286 char	*hfs_icharset = NULL;	/* input HFS charset name */
287 char    *hfs_ocharset = NULL;	/* output HFS charset name */
288 int	hfs_lock = 1;		/* lock HFS volume (read-only) */
289 char	*hfs_bless = NULL;	/* name of folder to 'bless' (System Folder) */
290 char	*hfs_parms = NULL;	/* low level HFS parameters */
291 
292 #ifdef PREP_BOOT
293 char	*prep_boot_image[4];
294 int	use_prep_boot = 0;
295 int	use_chrp_boot = 0;
296 #endif	/* PREP_BOOT */
297 #else	/* APPLE_HYB */
298 int	donotwrite_macpart = 1;	/* Do not write "hfs" hybrid with UDF */
299 #endif	/* APPLE_HYB */
300 
301 #ifdef UDF
302 int	rationalize_udf = 0;	/* -udf (rationalized UDF)	*/
303 int	use_udf = 0;		/* -udf or -UDF			*/
304 int	create_udfsymlinks = 1;	/* include symlinks in UDF	*/
305 #endif
306 
307 #ifdef DVD_AUD_VID
308 int	dvd_audio = 0;
309 int	dvd_hybrid = 0;
310 int	dvd_video = 0;
311 int	dvd_aud_vid_flag = DVD_SPEC_NONE;
312 #endif
313 
314 #ifdef SORTING
315 int	do_sort = 0;		/* sort file data */
316 #endif /* SORTING */
317 
318 /*
319  * inode numbers for zero sized files start from this number and count
320  * backwards. This is done to allow unique inode numbers even on multi-session
321  * disks.
322  */
323 UInt32_t null_inodes = NULL_INO_MAX;
324 BOOL	correct_inodes = TRUE;	/* TRUE: add a "correct inodes" fingerprint */
325 BOOL	rrip112 = TRUE;		/* TRUE: create Rock Ridge V 1.12	    */
326 BOOL	long_rr_time = FALSE;	/* TRUE: use long (17 Byte) time format	    */
327 
328 #ifdef	DUPLICATES_ONCE
329 int	duplicates_once = 0;	/* encode duplicate files once */
330 #endif
331 
332 siconvt_t	*in_nls = NULL;  /* input UNICODE conversion table */
333 siconvt_t	*out_nls = NULL; /* output UNICODE conversion table */
334 #ifdef APPLE_HYB
335 siconvt_t	*hfs_inls = NULL; /* input HFS UNICODE conversion table */
336 siconvt_t	*hfs_onls = NULL; /* output HFS UNICODE conversion table */
337 #endif /* APPLE_HYB */
338 
339 struct rcopts {
340 	char		*tag;
341 	char		**variable;
342 };
343 
344 struct rcopts rcopt[] = {
345 	{"PREP", &preparer},
346 	{"PUBL", &publisher},
347 	{"APPI", &appid},
348 	{"COPY", &copyright},
349 	{"BIBL", &biblio},
350 	{"ABST", &abstract},
351 	{"VOLS", &volset_id},
352 	{"VOLI", &volume_id},
353 	{"SYSI", &system_id},
354 #ifdef APPLE_HYB
355 	{"HFS_TYPE", &deftype},
356 	{"HFS_CREATOR", &defcreator},
357 #endif	/* APPLE_HYB */
358 	{NULL, NULL}
359 };
360 
361 #ifdef	USE_FIND
362 LOCAL	int	getfind		__PR((char *arg, long *valp,
363 					int *pac, char *const **pav));
364 #endif
365 
366 LOCAL	int	getH		__PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
367 LOCAL	int	getL		__PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
368 LOCAL	int	getP		__PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
369 LOCAL	int	dolegacy	__PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
370 
371 LOCAL	int	get_boot_image	__PR((char *opt_arg));
372 LOCAL	int	get_hd_boot	__PR((char *opt_arg));
373 LOCAL	int	get_ne_boot	__PR((char *opt_arg));
374 LOCAL	int	get_no_boot	__PR((char *opt_arg));
375 LOCAL	int	get_boot_addr	__PR((char *opt_arg));
376 LOCAL	int	get_boot_size	__PR((char *opt_arg));
377 LOCAL	int	get_boot_platid	__PR((char *opt_arg));
378 LOCAL	int	get_boot_table	__PR((char *opt_arg));
379 #ifdef	APPLE_HYB
380 #ifdef PREP_BOOT
381 LOCAL	int	get_prep_boot	__PR((char *opt_arg));
382 LOCAL	int	get_chrp_boot	__PR((char *opt_arg));
383 #endif
384 LOCAL	int	get_bsize	__PR((char *opt_arg));
385 
386 LOCAL	int	hfs_cap		__PR((void));
387 LOCAL	int	hfs_neta	__PR((void));
388 LOCAL	int	hfs_dbl		__PR((void));
389 LOCAL	int	hfs_esh		__PR((void));
390 LOCAL	int	hfs_fe		__PR((void));
391 LOCAL	int	hfs_sgi		__PR((void));
392 LOCAL	int	hfs_mbin	__PR((void));
393 LOCAL	int	hfs_sgl		__PR((void));
394 LOCAL	int	hfs_dave	__PR((void));
395 LOCAL	int	hfs_sfm		__PR((void));
396 LOCAL	int	hfs_xdbl	__PR((void));
397 LOCAL	int	hfs_xhfs	__PR((void));
398 LOCAL	int	hfs_nohfs	__PR((void));
399 #endif	/* APPLE_HYB */
400 
401 LOCAL	void	ldate_error	__PR((char *arg));
402 LOCAL	char	*strntoi	__PR((char *p, int n, int *ip));
403 LOCAL	int	mosize		__PR((int y, int m));
404 LOCAL	char	*parse_date	__PR((char *arg, struct tm *tp));
405 LOCAL	int	get_ldate	__PR((char *opt_arg, void *valp));
406 
407 LOCAL int
get_boot_image(opt_arg)408 get_boot_image(opt_arg)
409 	char	*opt_arg;
410 {
411 	do_sort++;		/* We sort bootcat/botimage */
412 	use_eltorito++;
413 	boot_image = opt_arg;	/* pathname of the boot image */
414 					/* on disk */
415 	if (boot_image == NULL || *boot_image == '\0') {
416 		comerrno(EX_BAD,
417 		_("Required Eltorito boot image pathname missing\n"));
418 	}
419 	get_boot_entry();
420 	current_boot_entry->boot_image = boot_image;
421 	return (1);
422 }
423 
424 LOCAL int
get_hd_boot(opt_arg)425 get_hd_boot(opt_arg)
426 	char	*opt_arg;
427 {
428 	use_eltorito++;
429 	hard_disk_boot++;
430 	get_boot_entry();
431 	current_boot_entry->hard_disk_boot = 1;
432 	return (1);
433 }
434 
435 LOCAL int
get_ne_boot(opt_arg)436 get_ne_boot(opt_arg)
437 	char	*opt_arg;
438 {
439 	use_eltorito++;
440 	no_emul_boot++;
441 	get_boot_entry();
442 	current_boot_entry->no_emul_boot = 1;
443 	return (1);
444 }
445 
446 LOCAL int
get_no_boot(opt_arg)447 get_no_boot(opt_arg)
448 	char	*opt_arg;
449 {
450 	use_eltorito++;
451 	not_bootable++;
452 	get_boot_entry();
453 	current_boot_entry->not_bootable = 1;
454 	return (1);
455 }
456 
457 LOCAL int
get_boot_addr(opt_arg)458 get_boot_addr(opt_arg)
459 	char	*opt_arg;
460 {
461 	long	val;
462 	char	*ptr;
463 
464 	use_eltorito++;
465 	val = strtol(opt_arg, &ptr, 0);
466 	if (*ptr || val < 0 || val >= 0x10000) {
467 		comerrno(EX_BAD, _("Boot image load address invalid.\n"));
468 	}
469 	load_addr = val;
470 	get_boot_entry();
471 	current_boot_entry->load_addr = load_addr;
472 	return (1);
473 }
474 
475 LOCAL int
get_boot_size(opt_arg)476 get_boot_size(opt_arg)
477 	char	*opt_arg;
478 {
479 	long	val;
480 	char	*ptr;
481 
482 	use_eltorito++;
483 	val = strtol(opt_arg, &ptr, 0);
484 	if (*ptr || val < 0 || val >= 0x10000) {
485 		comerrno(EX_BAD,
486 		_("Boot image load size invalid.\n"));
487 	}
488 	load_size = val;
489 	get_boot_entry();
490 	current_boot_entry->load_size = load_size;
491 	return (1);
492 }
493 
494 LOCAL int
get_boot_platid(opt_arg)495 get_boot_platid(opt_arg)
496 	char	*opt_arg;
497 {
498 	long	val;
499 	char	*ptr;
500 
501 	use_eltorito++;
502 	if (streql(opt_arg, "x86")) {
503 		val = EL_TORITO_ARCH_x86;
504 	} else if (streql(opt_arg, "PPC")) {
505 		val = EL_TORITO_ARCH_PPC;
506 	} else if (streql(opt_arg, "Mac")) {
507 		val = EL_TORITO_ARCH_MAC;
508 	} else if (streql(opt_arg, "efi")) {
509 		val = EL_TORITO_ARCH_EFI;
510 	} else {
511 		val = strtol(opt_arg, &ptr, 0);
512 		if (*ptr || val < 0 || val >= 0x100) {
513 			comerrno(EX_BAD, _("Bad boot system ID.\n"));
514 		}
515 	}
516 
517 	/*
518 	 * If there is already a boot entry and the boot file name has been set
519 	 * for this boot entry and the new platform id differs from the
520 	 * previous value, we start a new boot section.
521 	 */
522 	if (current_boot_entry &&
523 	    current_boot_entry->boot_image != NULL &&
524 	    current_boot_entry->boot_platform != val) {
525 		new_boot_entry();
526 	}
527 	get_boot_entry();
528 	current_boot_entry->type |= ELTORITO_BOOT_ID;
529 	current_boot_entry->boot_platform = val;
530 	return (1);
531 }
532 
533 LOCAL int
get_boot_table(opt_arg)534 get_boot_table(opt_arg)
535 	char	*opt_arg;
536 {
537 	use_eltorito++;
538 	boot_info_table++;
539 	get_boot_entry();
540 	current_boot_entry->boot_info_table = 1;
541 	return (1);
542 }
543 
544 #ifdef	APPLE_HYB
545 #ifdef PREP_BOOT
546 LOCAL int
get_prep_boot(opt_arg)547 get_prep_boot(opt_arg)
548 	char	*opt_arg;
549 {
550 	use_prep_boot++;
551 	if (use_prep_boot > 4 - use_chrp_boot) {
552 		comerrno(EX_BAD,
553 		_("Maximum of 4 PRep+CHRP partition entries are allowed\n"));
554 	}
555 	/* pathname of the boot image on cd */
556 	prep_boot_image[use_prep_boot - 1] = opt_arg;
557 	if (prep_boot_image[use_prep_boot - 1] == NULL) {
558 		comerrno(EX_BAD,
559 		_("Required PReP boot image pathname missing\n"));
560 	}
561 	return (1);
562 }
563 
564 LOCAL int
get_chrp_boot(opt_arg)565 get_chrp_boot(opt_arg)
566 	char	*opt_arg;
567 {
568 	if (use_chrp_boot)
569 		return (1);		/* silently allow duplicates */
570 	use_chrp_boot = 1;
571 	if (use_prep_boot > 3) {
572 		comerrno(EX_BAD,
573 		_("Maximum of 4 PRep+CHRP partition entries are allowed\n"));
574 	}
575 	return (1);
576 }
577 #endif	/* PREP_BOOT */
578 
579 
580 LOCAL int
get_bsize(opt_arg)581 get_bsize(opt_arg)
582 	char	*opt_arg;
583 {
584 	afe_size = atoi(opt_arg);
585 	hfs_select |= DO_FEU;
586 	hfs_select |= DO_FEL;
587 	return (1);
588 }
589 
590 LOCAL int
hfs_cap()591 hfs_cap()
592 {
593 	hfs_select |= DO_CAP;
594 	return (1);
595 }
596 
597 LOCAL int
hfs_neta()598 hfs_neta()
599 {
600 	hfs_select |= DO_NETA;
601 	return (1);
602 }
603 
604 LOCAL int
hfs_dbl()605 hfs_dbl()
606 {
607 	hfs_select |= DO_DBL;
608 	return (1);
609 }
610 
611 LOCAL int
hfs_esh()612 hfs_esh()
613 {
614 	hfs_select |= DO_ESH;
615 	return (1);
616 }
617 
618 LOCAL int
hfs_fe()619 hfs_fe()
620 {
621 	hfs_select |= DO_FEU;
622 	hfs_select |= DO_FEL;
623 	return (1);
624 }
625 
626 LOCAL int
hfs_sgi()627 hfs_sgi()
628 {
629 	hfs_select |= DO_SGI;
630 	return (1);
631 }
632 
633 LOCAL int
hfs_mbin()634 hfs_mbin()
635 {
636 	hfs_select |= DO_MBIN;
637 	return (1);
638 }
639 
640 LOCAL int
hfs_sgl()641 hfs_sgl()
642 {
643 	hfs_select |= DO_SGL;
644 	return (1);
645 }
646 
647 LOCAL int
hfs_dave()648 hfs_dave()
649 {
650 	hfs_select |= DO_DAVE;
651 	return (1);
652 }
653 
654 
655 LOCAL int
hfs_sfm()656 hfs_sfm()
657 {
658 	hfs_select |= DO_SFM;
659 	return (1);
660 }
661 
662 LOCAL int
hfs_xdbl()663 hfs_xdbl()
664 {
665 	hfs_select |= DO_XDBL;
666 	return (1);
667 }
668 
669 LOCAL int
hfs_xhfs()670 hfs_xhfs()
671 {
672 #ifdef	IS_MACOS_X
673 	hfs_select |= DO_XHFS;
674 #else
675 	errmsgno(EX_BAD,
676 	_("Warning: --osx-hfs only works on MacOS X ... ignoring\n"));
677 #endif
678 	return (1);
679 }
680 
681 LOCAL int
hfs_nohfs()682 hfs_nohfs()
683 {
684 	no_apple_hyb = 1;
685 	return (1);
686 }
687 
688 #endif	/* APPLE_HYB */
689 
690 LOCAL void
ldate_error(arg)691 ldate_error(arg)
692 	char	*arg;
693 {
694 	comerrno(EX_BAD, _("Ilegal date specification '%s'.\n"), arg);
695 }
696 
697 LOCAL char *
strntoi(p,n,ip)698 strntoi(p, n, ip)
699 	char	*p;
700 	int	n;
701 	int	*ip;
702 {
703 	int	i = 0;
704 	int	digits = 0;
705 	int	c;
706 
707 	while (*p) {
708 		if (digits >= n)
709 			break;
710 		c = *p;
711 		if (c < '0' || c > '9')
712 			break;
713 		p++;
714 		digits++;
715 		i *= 10;
716 		i += c - '0';
717 	}
718 	*ip = i;
719 
720 	return (p);
721 }
722 
723 #define	dysize(A) (((A)%4)? 365 : (((A)%100) == 0 && ((A)%400)) ? 365 : 366)
724 
725 static int dmsize[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
726 
727 LOCAL int
mosize(y,m)728 mosize(y, m)
729 	int	y;
730 	int	m;
731 {
732 
733 	if (m == 1 && dysize(y) == 366)
734 		return (29);
735 	return (dmsize[m]);
736 }
737 
738 LOCAL char *
parse_date(arg,tp)739 parse_date(arg, tp)
740 	char	*arg;
741 	struct tm *tp;
742 {
743 	char	*oarg = arg;
744 	char	*p;
745 
746 	tp->tm_mon = tp->tm_hour = tp->tm_min = tp->tm_sec = 0;
747 	tp->tm_mday = 1;
748 	tp->tm_isdst = -1;
749 
750 	p = strchr(arg, '/');
751 	if (p == NULL)
752 		p = strchr(arg, '-');
753 	if (p) {
754 		if ((p - arg) != 2 && (p - arg) != 4)
755 			ldate_error(oarg);
756 		p = strntoi(arg, 4, &tp->tm_year);
757 		if ((p - arg) != 2 && (p - arg) != 4)
758 			ldate_error(oarg);
759 		if ((p - arg) == 2) {
760 			if (tp->tm_year < 69)
761 				tp->tm_year += 100;
762 		} else {
763 			tp->tm_year -= 1900;
764 		}
765 		if (*p == '/' || *p == '-')
766 			p++;
767 	} else if (strlen(arg) < 4) {
768 		ldate_error(oarg);
769 	} else {
770 		p = strntoi(arg, 4, &tp->tm_year);
771 		if ((p - arg) != 4)
772 			ldate_error(oarg);
773 		tp->tm_year -= 1900;
774 	}
775 	if (*p == '\0' || strchr(".+-", *p))
776 		return (p);
777 	arg = p;
778 	p = strntoi(arg, 2, &tp->tm_mon);
779 	if ((p - arg) != 2)
780 		ldate_error(oarg);
781 	tp->tm_mon -= 1;
782 	if (tp->tm_mon < 0 || tp->tm_mon >= 12)
783 		ldate_error(oarg);
784 	if (*p == '/' || *p == '-')
785 		p++;
786 	if (*p == '\0' || strchr(".+-", *p))
787 		return (p);
788 	arg = p;
789 	p = strntoi(arg, 2, &tp->tm_mday);
790 	if ((p - arg) != 2)
791 		ldate_error(oarg);
792 	if (tp->tm_mday < 1 || tp->tm_mday > mosize(tp->tm_year+1900, tp->tm_mon))
793 		ldate_error(oarg);
794 	if (*p == ' ')
795 		p++;
796 	if (*p == '\0' || strchr(".+-", *p))
797 		return (p);
798 	arg = p;
799 	p = strntoi(arg, 2, &tp->tm_hour);
800 	if ((p - arg) != 2)
801 		ldate_error(oarg);
802 	if (tp->tm_hour > 23)
803 		ldate_error(oarg);
804 	if (*p == ':')
805 		p++;
806 	if (*p == '\0' || strchr(".+-", *p))
807 		return (p);
808 	arg = p;
809 	p = strntoi(arg, 2, &tp->tm_min);
810 	if ((p - arg) != 2)
811 		ldate_error(oarg);
812 	if (tp->tm_min > 59)
813 		ldate_error(oarg);
814 	if (*p == ':')
815 		p++;
816 	if (*p == '\0' || strchr(".+-", *p))
817 		return (p);
818 	arg = p;
819 	p = strntoi(arg, 2, &tp->tm_sec);
820 	if ((p - arg) != 2)
821 		ldate_error(oarg);
822 	if (tp->tm_sec > 61)
823 		ldate_error(oarg);
824 	return (p);
825 }
826 
827 /*
828  * Parse a date spec similar to:
829  * YYYY[MM[DD[HH[MM[SS]]]]][.hh][+-GHGM]
830  */
831 LOCAL int
get_ldate(opt_arg,valp)832 get_ldate(opt_arg, valp)
833 	char	*opt_arg;
834 	void	*valp;
835 {
836 	time_t	t;
837 	int	usec = 0;
838 	int	gmtoff = -100;
839 	struct tm tm;
840 	char	*p;
841 	char	*arg;
842 
843 	p = parse_date(opt_arg, &tm);
844 	if (*p == '.') {
845 		p++;
846 		arg = p;
847 		p = strntoi(arg, 2, &usec);
848 		if ((p - arg) != 2)
849 			ldate_error(opt_arg);
850 		if (usec > 99)
851 			ldate_error(opt_arg);
852 		usec *= 10000;
853 	}
854 	if (*p == ' ')
855 		p++;
856 	if (*p == '+' || *p == '-') {
857 		int	i;
858 		char	*s = p++;
859 
860 		arg = p;
861 		p = strntoi(arg, 2, &gmtoff);
862 		if ((p - arg) != 2)
863 			ldate_error(opt_arg);
864 		arg = p;
865 		p = strntoi(arg, 2, &i);
866 		if ((p - arg) != 2)
867 			ldate_error(opt_arg);
868 		if (i > 59)
869 			ldate_error(opt_arg);
870 		gmtoff *= 60;
871 		gmtoff += i;
872 		if (gmtoff % 15)
873 			ldate_error(opt_arg);
874 		if (*s == '-')
875 			gmtoff *= -1;
876 		gmtoff /= 15;
877 		if (gmtoff < -48 || gmtoff > 52)
878 			ldate_error(opt_arg);
879 	}
880 	if (*p != '\0')
881 		ldate_error(opt_arg);
882 
883 	seterrno(0);
884 	t = mktime(&tm);
885 	if (t == -1 && geterrno() != 0)
886 		comerr(_("Date '%s' is out of range.\n"), opt_arg);
887 
888 	((ldate *)valp)->l_sec = t;
889 	((ldate *)valp)->l_usec = usec;
890 	((ldate *)valp)->l_gmtoff = gmtoff;
891 
892 	return (1);
893 }
894 
895 #ifdef	USE_FIND
896 /* ARGSUSED */
897 LOCAL int
getfind(arg,valp,pac,pav)898 getfind(arg, valp, pac, pav)
899 	char	*arg;
900 	long	*valp;	/* Not used until we introduce a ptr to opt struct */
901 	int	*pac;
902 	char	*const	**pav;
903 {
904 	dofind = TRUE;
905 	find_ac = *pac;
906 	find_av = *pav;
907 	find_ac--, find_av++;
908 	return (NOARGS);
909 }
910 #endif
911 
912 /* ARGSUSED */
913 LOCAL int
getH(arg,valp,pac,pav,opt)914 getH(arg, valp, pac, pav, opt)	/* Follow symlinks encountered on cmdline */
915 	const char	*arg;
916 	void		*valp;
917 	int		*pac;
918 	char	*const	**pav;
919 	const char	*opt;
920 {
921 /*error("getH\n");*/
922 	if (opt[0] == '-' && opt[1] == 'H' && opt[2] == '\0') {
923 #ifdef	APPLE_HYB
924 		if (legacy) {
925 			errmsgno(EX_BAD, _("The option '-H' is deprecated since 2002.\n"));
926 			errmsgno(EX_BAD, _("The option '-H' was disabled in 2006.\n"));
927 			errmsgno(EX_BAD, _("Use '-map' instead of '-H' as documented instead of using the legacy mode.\n"));
928 			afpfile = (char *)arg;
929 			return (1);
930 		}
931 #endif
932 		return (BADFLAG);	/* POSIX -H is not yet active */
933 	}
934 	follow_links = FALSE;
935 	Hflag = TRUE;
936 #ifdef	USE_FIND
937 	*(int *)valp |= WALK_ARGFOLLOW;
938 #endif
939 	return (1);
940 }
941 
942 /* ARGSUSED */
943 LOCAL int
getL(arg,valp,pac,pav,opt)944 getL(arg, valp, pac, pav, opt)	/* Follow all symlinks */
945 	const char	*arg;
946 	void		*valp;
947 	int		*pac;
948 	char	*const	**pav;
949 	const char	*opt;
950 {
951 /*error("getL\n");*/
952 	if (opt[0] == '-' && opt[1] == 'L' && opt[2] == '\0') {
953 		if (legacy) {
954 			errmsgno(EX_BAD, _("The option '-L' is deprecated since 2002.\n"));
955 			errmsgno(EX_BAD, _("The option '-L' was disabled in 2006.\n"));
956 			errmsgno(EX_BAD,
957 				_("Use '-allow-leading-dots' instead of '-L' as documented instead of using the legacy mode.\n"));
958 			allow_leading_dots = TRUE;
959 			return (1);
960 		}
961 		return (BADFLAG);	/* POSIX -L is not yet active */
962 	}
963 	follow_links = TRUE;
964 	Hflag = FALSE;
965 #ifdef	USE_FIND
966 	*(int *)valp |= WALK_ALLFOLLOW;
967 #endif
968 	return (1);
969 }
970 
971 /* ARGSUSED */
972 LOCAL int
getP(arg,valp,pac,pav,opt)973 getP(arg, valp, pac, pav, opt)	/* Do not follow symlinks */
974 	const char	*arg;
975 	void		*valp;
976 	int		*pac;
977 	char	*const	**pav;
978 	const char	*opt;
979 {
980 /*error("getP\n");*/
981 	if (opt[0] == '-' && opt[1] == 'P' && opt[2] == '\0') {
982 		if (legacy) {
983 			errmsgno(EX_BAD, _("The option '-P' is deprecated since 2002.\n"));
984 			errmsgno(EX_BAD, _("The option '-P' was disabled in 2006.\n"));
985 			errmsgno(EX_BAD, _("Use '-publisher' instead of '-P' as documented instead of using the legacy mode.\n"));
986 			publisher = (char *)arg;
987 			return (1);
988 		}
989 		return (BADFLAG);	/* POSIX -P is not yet active */
990 	}
991 	follow_links = FALSE;
992 	Hflag = FALSE;
993 #ifdef	USE_FIND
994 	*(int *)valp &= ~(WALK_ARGFOLLOW | WALK_ALLFOLLOW);
995 #endif
996 	return (1);
997 }
998 
999 LOCAL struct ga_flags *gl_flags;
1000 /* ARGSUSED */
1001 LOCAL int
dolegacy(arg,valp,pac,pav,opt)1002 dolegacy(arg, valp, pac, pav, opt)	/* Follow symlinks encountered on cmdline */
1003 	const char	*arg;
1004 	void		*valp;
1005 	int		*pac;
1006 	char	*const	**pav;
1007 	const char	*opt;
1008 {
1009 	legacy = TRUE;
1010 #ifdef	APPLE_HYB
1011 	gl_flags[2].ga_format = "H&";	/* Apple Hybrid "-map" */
1012 #endif
1013 #ifdef	OPT_L_HAS_ARG			/* never ;-) */
1014 	gl_flags[4].ga_format = "L&";	/* -allow-leading-dots */
1015 #endif
1016 	gl_flags[6].ga_format = "P&";	/* -publisher */
1017 	return (1);
1018 }
1019 
1020 struct mki_option {
1021 	/*
1022 	 * The long option information.
1023 	 */
1024 	struct ga_flags	opt;
1025 	/*
1026 	 * The documentation string.  If this is NULL or empty, this is a
1027 	 * synonym for the previous option.
1028 	 *
1029 	 * If the string starts with a '-', the (long) option is a
1030 	 * double dash option.
1031 	 *
1032 	 * If the next character in the string is a ^A (\1), then the following
1033 	 * characters are the argument name for the option. The arg string ends
1034 	 * before a \1 or a \2 is seen. A \1 is skipped.
1035 	 *
1036 	 * The rest of the string is the real documentation string. If it
1037 	 * starts with \2, then the option is hidden from the online help.
1038 	 */
1039 	const char	*doc;
1040 };
1041 
1042 
1043 LOCAL int	save_pname = 0;
1044 
1045 LOCAL const struct mki_option mki_options[] =
1046 {
1047 #ifdef	USE_FIND
1048 	{{"find~", NULL, (getpargfun)getfind },
1049 	__("\1file... [find expr.]\1Option separator: Use find command line to the right")},
1050 #endif
1051 	/*
1052 	 * The options -H/-L/-P did have different meaning in old releases of
1053 	 * mkisofs. In October 2002, mkisofs introduced a warning that the
1054 	 * short options -H/-L/-P should not be used with the old meaning
1055 	 * anymore. The long options should be used instead. The options
1056 	 * -H/-L/-P previously have been associated with the following long
1057 	 * options:
1058 	 *
1059 	 *	-H	-map				2000..2002
1060 	 *	-L	-allow-leading-dots		1995..2002
1061 	 *	-P	-publisher			1993..2002
1062 	 *
1063 	 * Since December 2006, the short options -H/-L/-P have been disabled
1064 	 * for their old meaning.
1065 	 *
1066 	 * Warning: for the -legacy mode, the entries for -H/-L/-P need to stay
1067 	 * at their current index in mki_options[] or dolegacy() needs to be
1068 	 * changed to fit the modification.
1069 	 */
1070 	{{"posix-H~", &walkflags, getH },
1071 	__("Follow symbolic links encountered on command line")},
1072 	{{"H~", &walkflags, getH },
1073 #ifdef	LATER
1074 	NULL},
1075 #else
1076 	__("\2")},
1077 #endif
1078 	{{"posix-L~", &walkflags, getL },
1079 	__("Follow all symbolic links")},
1080 	{{"L~", &walkflags, getL },
1081 #ifdef	LATER
1082 	NULL},
1083 #else
1084 	__("\2")},
1085 #endif
1086 	{{"posix-P~", &walkflags, getP },
1087 	__("Do not follow symbolic links (default)")},
1088 	{{"P~", &walkflags, getP },
1089 #ifdef	LATER
1090 	NULL},
1091 #else
1092 	__("\2")},
1093 #endif
1094 
1095 	{{"abstract*", &abstract },
1096 	__("\1FILE\1Set Abstract filename")},
1097 	{{"A*,appid*", &appid },
1098 	__("\1ID\1Set Application ID")},
1099 	{{"biblio*", &biblio },
1100 	__("\1FILE\1Set Bibliographic filename")},
1101 	/*
1102 	 * If this includes UWIN, we need to modify the condition.
1103 	 */
1104 #if !defined(__MINGW32__) && !defined(_MSC_VER)
1105 	{{"cache-inodes", &cache_inodes },
1106 	__("Cache inodes (needed to detect hard links)")},
1107 #endif
1108 	{{"no-cache-inodes%0", &cache_inodes },
1109 	__("Do not cache inodes (if filesystem has no unique inodes)")},
1110 	{{"rrip110%0", &rrip112 },
1111 	__("Create old Rock Ridge V 1.10")},
1112 	{{"rrip112", &rrip112 },
1113 	__("Create new Rock Ridge V 1.12 (default)")},
1114 #ifdef	DUPLICATES_ONCE
1115 	{{"duplicates-once", &duplicates_once},
1116 	__("Optimize storage by encoding duplicate files once")},
1117 #endif
1118 	{{"check-oldnames", &check_oldnames },
1119 	__("Check all imported ISO9660 names from old session")},
1120 	{{"check-session*", &check_image },
1121 	__("\1FILE\1Check all ISO9660 names from previous session")},
1122 	{{"copyright*", &copyright },
1123 	__("\1FILE\1Set Copyright filename")},
1124 	{{"debug+", &debug },
1125 	__("Set debug flag")},
1126 	{{"ignore-error", &ignerr },
1127 	__("Ignore errors")},
1128 	{{"b& ,eltorito-boot&", NULL, (getpargfun)get_boot_image },
1129 	__("\1FILE\1Set El Torito boot image name")},
1130 	{{"eltorito-alt-boot~", NULL, (getpargfun)new_boot_entry },
1131 	__("Start specifying alternative El Torito boot parameters")},
1132 	{{"eltorito-platform&", NULL, (getpargfun)get_boot_platid },
1133 	__("\1ID\1Set El Torito platform id for the next boot entry")},
1134 	{{"B&,sparc-boot&", NULL, (getpargfun)scan_sparc_boot },
1135 	__("\1FILES\1Set sparc boot image names")},
1136 	{{"sunx86-boot&", NULL, (getpargfun)scan_sunx86_boot },
1137 	__("\1FILES\1Set sunx86 boot image names")},
1138 	{{"G*,generic-boot*", &genboot_image },
1139 	__("\1FILE\1Set generic boot image name")},
1140 	{{"sparc-label&", NULL, (getpargfun)sparc_boot_label },
1141 	__("\1label text\1Set sparc boot disk label")},
1142 	{{"sunx86-label&", NULL, (getpargfun)sunx86_boot_label },
1143 	__("\1label text\1Set sunx86 boot disk label")},
1144 	{{"c* ,eltorito-catalog*", &boot_catalog },
1145 	__("\1FILE\1Set El Torito boot catalog name")},
1146 	{{"C*,cdrecord-params*", &cdrecord_data },
1147 	__("\1PARAMS\1Magic paramters from cdrecord")},
1148 	{{"d,omit-period", &omit_period },
1149 	__("Omit trailing periods from filenames (violates ISO9660)")},
1150 	{{"data-change-warn", &data_change_warn },
1151 	__("Treat data/size changes as warning only")},
1152 	{{"dir-mode*", &dirmode_str },
1153 	__("\1mode\1Make the mode of all directories this mode.")},
1154 	{{"D,disable-deep-relocation", &disable_deep_reloc },
1155 	__("Disable deep directory relocation (violates ISO9660)")},
1156 	{{"file-mode*", &filemode_str },
1157 	__("\1mode\1Make the mode of all plain files this mode.")},
1158 	{{"errctl&", NULL, (getpargfun)errconfig },
1159 	__("\1name\1Read error control defs from file or inline.")},
1160 	{{"f,follow-links", &follow_links },
1161 	__("Follow symbolic links")},
1162 	{{"gid*", &gid_str },
1163 	__("\1gid\1Make the group owner of all files this gid.")},
1164 	{{"graft-points", &use_graft_ptrs },
1165 	__("Allow to use graft points for filenames")},
1166 	{{"root*", &reloc_root },
1167 	__("\1DIR\1Set root directory for all new files and directories")},
1168 	{{"old-root*", &reloc_old_root },
1169 	__("\1DIR\1Set root directory in previous session that is searched for files")},
1170 	{{"help", &help },
1171 	__("Print option help")},
1172 	{{"hide& ", NULL, (getpargfun)i_add_match },
1173 	__("\1GLOBFILE\1Hide ISO9660/RR file")},
1174 	{{"hide-list&", NULL, (getpargfun)i_add_list },
1175 	__("\1FILE\1File with list of ISO9660/RR files to hide")},
1176 	{{"hidden& ", NULL, (getpargfun)h_add_match },
1177 	__("\1GLOBFILE\1Set hidden attribute on ISO9660 file")},
1178 	{{"hidden-list&", NULL, (getpargfun)h_add_list },
1179 	__("\1FILE\1File with list of ISO9660 files with hidden attribute")},
1180 	{{"hide-joliet& ", NULL, (getpargfun)j_add_match },
1181 	__("\1GLOBFILE\1Hide Joliet file")},
1182 	{{"hide-joliet-list&", NULL, (getpargfun)j_add_list },
1183 	__("\1FILE\1File with list of Joliet files to hide")},
1184 #ifdef UDF
1185 	{{"hide-udf& ", NULL, (getpargfun)u_add_match },
1186 	__("\1GLOBFILE\1Hide UDF file")},
1187 	{{"hide-udf-list&", NULL, (getpargfun)u_add_list },
1188 	__("\1FILE\1File with list of UDF files to hide")},
1189 #endif
1190 	{{"hide-joliet-trans-tbl", &jhide_trans_tbl},
1191 	__("Hide TRANS.TBL from Joliet tree")},
1192 	{{"hide-rr-moved", &hide_rr_moved },
1193 	__("Rename RR_MOVED to .rr_moved in Rock Ridge tree")},
1194 	{{"gui", &gui},
1195 	__("Switch behaviour for GUI")},
1196 	{{"input-charset*", &icharset },
1197 	__("\1CHARSET\1Local input charset for file name conversion")},
1198 	{{"output-charset*", &ocharset },
1199 	__("\1CHARSET\1Output charset for file name conversion")},
1200 	{{"iso-level#", &iso9660_level },
1201 	__("\1LEVEL\1Set ISO9660 conformance level (1..3) or 4 for ISO9660 version 2")},
1202 	{{"J,joliet", &use_Joliet },
1203 	__("Generate Joliet directory information")},
1204 	{{"joliet-long", &joliet_long },
1205 	__("Allow Joliet file names to be 103 Unicode characters")},
1206 	{{"jcharset*", &jcharset },
1207 	__("\1CHARSET\1Local charset for Joliet directory information")},
1208 	{{"l,full-iso9660-filenames", &full_iso9660_filenames },
1209 	__("Allow full 31 character filenames for ISO9660 names")},
1210 	{{"max-iso9660-filenames", &max_filenames },
1211 	__("Allow 37 character filenames for ISO9660 names (violates ISO9660)")},
1212 
1213 	{{"allow-leading-dots", &allow_leading_dots },
1214 	__("Allow ISO9660 filenames to start with '.' (violates ISO9660)")},
1215 	{{"ldots", &allow_leading_dots },
1216 	__("Allow ISO9660 filenames to start with '.' (violates ISO9660)")},
1217 
1218 	{{"log-file*", &log_file },
1219 	__("\1LOG_FILE\1Re-direct messages to LOG_FILE")},
1220 	{{"long-rr-time%1", &long_rr_time },
1221 	__("Use long Rock Ridge time format")},
1222 	{{"m& ,exclude& ", NULL, (getpargfun)add_match },
1223 	__("\1GLOBFILE\1Exclude file name")},
1224 	{{"exclude-list&", NULL, (getpargfun)add_list},
1225 	__("\1FILE\1File with list of file names to exclude")},
1226 
1227 	{{"hide-ignorecase", &match_igncase },
1228 	__("Ignore case with -exclude-list and -hide* options")},
1229 	{{"exclude-ignorecase", &match_igncase },
1230 	NULL},
1231 
1232 	{{"modification-date&", &modification_date, (getpargfun)get_ldate },
1233 	__("\1DATE\1Set the modification date field of the PVD")},
1234 	{{"nobak%0", &all_files },
1235 	__("Do not include backup files")},
1236 	{{"no-bak%0", &all_files},
1237 	__("Do not include backup files")},
1238 	{{"pad", &dopad },
1239 	__("Pad output to a multiple of 32k (default)")},
1240 	{{"no-pad%0", &dopad },
1241 	__("Do not pad output to a multiple of 32k")},
1242 	{{"no-limit-pathtables", &nolimitpathtables },
1243 	__("Allow more than 65535 parent directories (violates ISO9660)")},
1244 	{{"no-long-rr-time%0", &long_rr_time },
1245 	__("Use short Rock Ridge time format")},
1246 	{{"M*,prev-session*", &merge_image },
1247 	__("\1FILE\1Set path to previous session to merge")},
1248 	{{"dev*", &merge_image },
1249 	__("\1SCSIdev\1Set path to previous session to merge")},
1250 	{{"N,omit-version-number", &omit_version_number },
1251 	__("Omit version number from ISO9660 filename (violates ISO9660)")},
1252 	{{"new-dir-mode*", &new_dirmode_str },
1253 	__("\1mode\1Mode used when creating new directories.")},
1254 	{{"force-rr", &force_rr },
1255 	__("Inhibit automatic Rock Ridge detection for previous session")},
1256 	{{"no-rr", &no_rr },
1257 	__("Inhibit reading of Rock Ridge attributes from previous session")},
1258 	{{"no-split-symlink-components%0", &split_SL_component },
1259 	__("Inhibit splitting symlink components")},
1260 	{{"no-split-symlink-fields%0", &split_SL_field },
1261 	__("Inhibit splitting symlink fields")},
1262 	{{"o* ,output* ", &outfile },
1263 	__("\1FILE\1Set output file name")},
1264 	{{"path-list*", &pathnames },
1265 	__("\1FILE\1File with list of pathnames to process")},
1266 	{{"p* ,preparer*", &preparer },
1267 	__("\1PREP\1Set Volume preparer")},
1268 	{{"print-size", &print_size },
1269 	__("Print estimated filesystem size and exit")},
1270 	{{"publisher*", &publisher },
1271 	__("\1PUB\1Set Volume publisher")},
1272 	{{"quiet%0", &verbose },
1273 	__("Run quietly")},
1274 	{{"r,rational-rock", &rationalize_rr },
1275 	__("Generate rationalized Rock Ridge directory information")},
1276 	{{"R,rock", &use_RockRidge },
1277 	__("Generate Rock Ridge directory information")},
1278 	{{"s* ,sectype*", &sectype },
1279 	__("\1TYPE\1Set output sector type to e.g. data/xa1/raw")},
1280 	{{"short-rr-time%0", &long_rr_time },
1281 	__("Use short Rock Ridge time format")},
1282 
1283 #ifdef SORTING
1284 	{ {"sort&", NULL, add_sort_list },
1285 	__("\1FILE\1Sort file content locations according to rules in FILE")},
1286 	{ {"isort&", NULL, add_sort_list },
1287 	__("\1FILE\1Sort file content locations according to rules in FILE (ignore case)")},
1288 #endif /* SORTING */
1289 
1290 	{{"split-output", &split_output },
1291 	__("Split output into files of approx. 1GB size")},
1292 	{{"stream-file-name*", &stream_filename },
1293 	__("\1FILE_NAME\1Set the stream file ISO9660 name (incl. version)")},
1294 	{{"stream-media-size#", &stream_media_size },
1295 	__("\1#\1Set the size of your CD media in sectors")},
1296 	{{"sysid*", &system_id },
1297 	__("\1ID\1Set System ID")},
1298 	{{"T,translation-table", &generate_tables },
1299 	__("Generate translation tables for systems that don't understand long filenames")},
1300 	{{"table-name*", &trans_tbl },
1301 	__("\1TABLE_NAME\1Translation table file name")},
1302 	{{"ucs-level#", &ucs_level },
1303 	__("\1LEVEL\1Set Joliet UCS level (1..3)")},
1304 
1305 #ifdef UDF
1306 	{{"udf", &rationalize_udf },
1307 	__("Generate rationalized UDF file system")},
1308 	{{"UDF", &use_udf },
1309 	__("Generate UDF file system")},
1310 	{{"udf-symlinks", &create_udfsymlinks },
1311 	__("Create symbolic links on UDF image (default)")},
1312 	{{"no-udf-symlinks%0", &create_udfsymlinks },
1313 	__("Do not reate symbolic links on UDF image")},
1314 #endif
1315 
1316 #ifdef DVD_AUD_VID
1317 	{{"dvd-audio", &dvd_audio },
1318 	"Generate DVD-Audio compliant UDF file system"},
1319 	{{"dvd-hybrid", &dvd_hybrid },
1320 	"Generate a hybrid (DVD-Audio and DVD-Video) compliant UDF file system"},
1321 	{{"dvd-video", &dvd_video },
1322 	__("Generate DVD-Video compliant UDF file system")},
1323 #endif
1324 
1325 	{{"uid*", &uid_str },
1326 	__("\1uid\1Make the owner of all files this uid.")},
1327 	{{"U,untranslated-filenames", &untranslated_filenames },
1328 	/* CSTYLED */
1329 	__("Allow Untranslated filenames (for HPUX & AIX - violates ISO9660). Forces -l, -d, -N, -allow-leading-dots, -relaxed-filenames, -allow-lowercase, -allow-multidot")},
1330 	{{"relaxed-filenames", &relaxed_filenames },
1331 	__("Allow 7 bit ASCII except lower case characters (violates ISO9660)")},
1332 	{{"no-iso-translate%0", &iso_translate },
1333 	__("Do not translate illegal ISO characters '~', '-' and '#' (violates ISO9660)")},
1334 	{{"allow-lowercase", &allow_lowercase },
1335 	__("Allow lower case characters in addition to the current character set (violates ISO9660)")},
1336 	{{"no-allow-lowercase", &no_allow_lowercase },
1337 	__("Do not allow lower case characters in addition to the current character set.")},
1338 	{{"+allow-lowercase", &no_allow_lowercase },
1339 	NULL},
1340 	{{"allow-multidot", &allow_multidot },
1341 	__("Allow more than one dot in filenames (e.g. .tar.gz) (violates ISO9660)")},
1342 	{{"use-fileversion", &use_fileversion },
1343 	__("\1LEVEL\1Use file version # from filesystem")},
1344 	{{"v+,verbose+", &verbose },
1345 	__("Verbose")},
1346 	{{"version", &pversion },
1347 	__("Print the current version")},
1348 	{{"V*,volid*", &volume_id },
1349 	__("\1ID\1Set Volume ID")},
1350 	{{"volset* ", &volset_id },
1351 	__("\1ID\1Set Volume set ID")},
1352 	{{"volset-size#", &volume_set_size },
1353 	__("\1#\1Set Volume set size")},
1354 	{{"volset-seqno#", &volume_sequence_number },
1355 	__("\1#\1Set Volume set sequence number")},
1356 	{{"x& ,old-exclude&", NULL, (getpargfun)add_match },
1357 	__("\1FILE\1Exclude file name(depreciated)")},
1358 	{{"hard-disk-boot~", NULL, (getpargfun)get_hd_boot },
1359 	__("Boot image is a hard disk image")},
1360 	{{"no-emul-boot~", NULL, (getpargfun)get_ne_boot },
1361 	__("Boot image is 'no emulation' image")},
1362 	{{"no-boot~", NULL, (getpargfun)get_no_boot },
1363 	__("Boot image is not bootable")},
1364 	{{"boot-load-seg&", NULL, (getpargfun)get_boot_addr },
1365 	__("\1#\1Set load segment for boot image")},
1366 	{{"boot-load-size&", NULL, (getpargfun)get_boot_size },
1367 	__("\1#\1Set numbers of load sectors")},
1368 	{{"boot-info-table~", NULL, (getpargfun)get_boot_table },
1369 	__("Patch boot image with info table")},
1370 	{{"XA", &use_XA },
1371 	__("Generate XA directory attributes")},
1372 	{{"xa", &rationalize_xa },
1373 	__("Generate rationalized XA directory attributes")},
1374 	{{"z,transparent-compression", &transparent_compression },
1375 	__("Enable transparent compression of files")},
1376 
1377 #ifdef APPLE_HYB
1378 	{{"hfs-type*", &deftype },
1379 	__("\1TYPE\1Set HFS default TYPE")},
1380 	{{"hfs-creator", &defcreator },
1381 	__("\1CREATOR\1Set HFS default CREATOR")},
1382 	{{"g,apple", &apple_ext },
1383 	__("Add Apple ISO9660 extensions")},
1384 	{{"h,hfs", &apple_hyb },
1385 	__("Create ISO9660/HFS hybrid")},
1386 	{{"map*", &afpfile },
1387 	__("\1MAPPING_FILE\1Map file extensions to HFS TYPE/CREATOR")},
1388 	{{"magic*", &magic_file },
1389 	__("\1FILE\1Magic file for HFS TYPE/CREATOR")},
1390 	{{"probe", &probe },
1391 	__("Probe all files for Apple/Unix file types")},
1392 	{{"mac-name", &use_mac_name },
1393 	__("Use Macintosh name for ISO9660/Joliet/RockRidge file name")},
1394 	{{"no-mac-files", &nomacfiles },
1395 	__("Do not look for Unix/Mac files (depreciated)")},
1396 	{{"boot-hfs-file*", &hfs_boot_file },
1397 	__("\1FILE\1Set HFS boot image name")},
1398 	{{"part", &gen_pt },
1399 	__("Generate HFS partition table")},
1400 	{{"cluster-size&", NULL, (getpargfun)get_bsize },
1401 	__("\1SIZE\1Cluster size for PC Exchange Macintosh files")},
1402 	{{"auto*", &autoname },
1403 	__("\1FILE\1Set HFS AutoStart file name")},
1404 	{{"no-desktop%0", &create_dt },
1405 	__("Do not create the HFS (empty) Desktop files")},
1406 	{{"hide-hfs& ", NULL, (getpargfun)hfs_add_match },
1407 	__("\1GLOBFILE\1Hide HFS file")},
1408 	{{"hide-hfs-list&", NULL, (getpargfun)hfs_add_list },
1409 	__("\1FILE\1List of HFS files to hide")},
1410 	{{"hfs-volid*", &hfs_volume_id },
1411 	__("\1HFS_VOLID\1Volume name for the HFS partition")},
1412 	{{"icon-position", &icon_pos },
1413 	__("Keep HFS icon position")},
1414 	{{"root-info*", &root_info },
1415 	__("\1FILE\1finderinfo for root folder")},
1416 	{{"input-hfs-charset*", &hfs_icharset },
1417 	__("\1CHARSET\1Local input charset for HFS file name conversion")},
1418 	{{"output-hfs-charset*", &hfs_ocharset },
1419 	__("\1CHARSET\1Output charset for HFS file name conversion")},
1420 	{{"hfs-unlock%0", &hfs_lock },
1421 	__("Leave HFS Volume unlocked")},
1422 	{{"hfs-bless*", &hfs_bless },
1423 	__("\1FOLDER_NAME\1Name of Folder to be blessed")},
1424 	{{"hfs-parms*", &hfs_parms },
1425 	__("\1PARAMETERS\1Comma separated list of HFS parameters")},
1426 #ifdef PREP_BOOT
1427 	{{"prep-boot&", NULL, (getpargfun)get_prep_boot },
1428 	__("\1FILE\1PReP boot image file -- up to 4 are allowed")},
1429 	{{"chrp-boot&", NULL, (getpargfun)get_chrp_boot },
1430 	__("Add CHRP boot header")},
1431 #endif	/* PREP_BOOT */
1432 	{{"cap~", NULL, (getpargfun)hfs_cap },
1433 	__("-Look for AUFS CAP Macintosh files")},
1434 	{{"netatalk~", NULL, (getpargfun)hfs_neta},
1435 	__("-Look for NETATALK Macintosh files")},
1436 	{{"double~", NULL, (getpargfun)hfs_dbl },
1437 	__("-Look for AppleDouble Macintosh files")},
1438 	{{"ethershare~", NULL, (getpargfun)hfs_esh },
1439 	__("-Look for Helios EtherShare Macintosh files")},
1440 	{{"exchange~", NULL, (getpargfun)hfs_fe },
1441 	__("-Look for PC Exchange Macintosh files")},
1442 	{{"sgi~", NULL, (getpargfun)hfs_sgi },
1443 	__("-Look for SGI Macintosh files")},
1444 	{{"macbin~", NULL, (getpargfun)hfs_mbin },
1445 	__("-Look for MacBinary Macintosh files")},
1446 	{{"single~", NULL, (getpargfun)hfs_sgl },
1447 	__("-Look for AppleSingle Macintosh files")},
1448 	{{"ushare~", NULL, (getpargfun)hfs_esh },
1449 	__("-Look for IPT UShare Macintosh files")},
1450 	{{"xinet~", NULL, (getpargfun)hfs_sgi },
1451 	__("-Look for XINET Macintosh files")},
1452 	{{"dave~", NULL, (getpargfun)hfs_dave },
1453 	__("-Look for DAVE Macintosh files")},
1454 	{{"sfm~", NULL, (getpargfun)hfs_sfm },
1455 	__("-Look for SFM Macintosh files")},
1456 	{{"osx-double~", NULL, (getpargfun)hfs_xdbl },
1457 	__("-Look for MacOS X AppleDouble Macintosh files")},
1458 	{{"osx-hfs~", NULL, (getpargfun)hfs_xhfs },
1459 	__("-Look for MacOS X HFS Macintosh files")},
1460 	{{"no-hfs~", NULL, (getpargfun)hfs_nohfs },
1461 	__("Do not create ISO9660/HFS hybrid")},
1462 #endif	/* APPLE_HYB */
1463 	{{"legacy~", NULL, dolegacy },
1464 	__("\2")},
1465 };
1466 
1467 #define	OPTION_COUNT (sizeof mki_options / sizeof (mki_options[0]))
1468 
1469 LOCAL	void	read_rcfile	__PR((char *appname));
1470 LOCAL	void	susage		__PR((int excode));
1471 LOCAL	void	usage		__PR((int excode));
1472 EXPORT	int	iso9660_date	__PR((char *result, time_t crtime));
1473 LOCAL	void	hide_reloc_dir	__PR((void));
1474 LOCAL	char	*get_pnames	__PR((int argc, char *const *argv, int opt,
1475 					char *pname, int pnsize, FILE *fp));
1476 EXPORT	int	main		__PR((int argc, char *argv[]));
1477 LOCAL	void	list_locales	__PR((void));
1478 EXPORT	char	*findgequal	__PR((char *s));
1479 LOCAL	char	*escstrcpy	__PR((char *to, size_t tolen, char *from));
1480 struct directory *get_graft	__PR((char *arg, char *graft_point, size_t glen,
1481 						char *nodename, size_t nlen,
1482 						char **short_namep, BOOL do_insert));
1483 EXPORT	void	*e_malloc	__PR((size_t size));
1484 EXPORT	char	*e_strdup	__PR((const char *s));
1485 LOCAL	void	ovstrcpy	__PR((char *p2, char *p1));
1486 LOCAL	void	checkarch	__PR((char *name));
1487 
1488 LOCAL void
read_rcfile(appname)1489 read_rcfile(appname)
1490 	char		*appname;
1491 {
1492 	FILE		*rcfile = (FILE *)NULL;
1493 	struct rcopts	*rco;
1494 	char		*pnt,
1495 			*pnt1;
1496 	char		linebuffer[256];
1497 	static char	rcfn[] = ".mkisofsrc";
1498 	char		filename[1000];
1499 	int		linum;
1500 
1501 	strlcpy(filename, rcfn, sizeof (filename));
1502 	if (access(filename, R_OK) == 0)
1503 		rcfile = fopen(filename, "r");
1504 	if (!rcfile && errno != ENOENT)
1505 		errmsg(_("Cannot open '%s'.\n"), filename);
1506 
1507 	if (!rcfile) {
1508 		pnt = getenv("MKISOFSRC");
1509 		if (pnt && strlen(pnt) <= sizeof (filename)) {
1510 			strlcpy(filename, pnt, sizeof (filename));
1511 			if (access(filename, R_OK) == 0)
1512 				rcfile = fopen(filename, "r");
1513 			if (!rcfile && errno != ENOENT)
1514 				errmsg(_("Cannot open '%s'.\n"), filename);
1515 		}
1516 	}
1517 	if (!rcfile) {
1518 		pnt = getenv("HOME");
1519 		if (pnt && strlen(pnt) + strlen(rcfn) + 2 <=
1520 							sizeof (filename)) {
1521 			strlcpy(filename, pnt, sizeof (filename));
1522 			if (strlen(rcfn) + 2 <=
1523 			    (sizeof (filename) - strlen(filename))) {
1524 				strcat(filename, "/");
1525 				strcat(filename, rcfn);
1526 			}
1527 			if (access(filename, R_OK) == 0)
1528 				rcfile = fopen(filename, "r");
1529 			if (!rcfile && errno != ENOENT)
1530 				errmsg(_("Cannot open '%s'.\n"), filename);
1531 		}
1532 	}
1533 	if (!rcfile && strlen(appname) + sizeof (rcfn) + 2 <=
1534 							sizeof (filename)) {
1535 		strlcpy(filename, appname, sizeof (filename));
1536 		pnt = strrchr(filename, '/');
1537 		if (pnt) {
1538 			strlcpy(pnt + 1, rcfn,
1539 				sizeof (filename) - (pnt + 1 - filename));
1540 			if (access(filename, R_OK) == 0)
1541 				rcfile = fopen(filename, "r");
1542 			if (!rcfile && errno != ENOENT)
1543 				errmsg(_("Cannot open '%s'.\n"), filename);
1544 		}
1545 	}
1546 	if (!rcfile)
1547 		return;
1548 	if (verbose > 0) {
1549 		fprintf(stderr, _("Using \"%s\"\n"), filename);
1550 	}
1551 	/* OK, we got it.  Now read in the lines and parse them */
1552 	linum = 0;
1553 	while (fgets(linebuffer, sizeof (linebuffer), rcfile)) {
1554 		char	*name;
1555 		char	*name_end;
1556 
1557 		++linum;
1558 		/* skip any leading white space */
1559 		pnt = linebuffer;
1560 		while (*pnt == ' ' || *pnt == '\t')
1561 			++pnt;
1562 		/*
1563 		 * If we are looking at a # character, this line is a comment.
1564 		 */
1565 		if (*pnt == '#')
1566 			continue;
1567 		/*
1568 		 * The name should begin in the left margin.  Make sure it is
1569 		 * in upper case.  Stop when we see white space or a comment.
1570 		 */
1571 		name = pnt;
1572 		while (*pnt && (isalpha((unsigned char) *pnt) || *pnt == '_')) {
1573 			if (islower((unsigned char) *pnt))
1574 				*pnt = toupper((unsigned char) *pnt);
1575 			pnt++;
1576 		}
1577 		if (name == pnt) {
1578 			fprintf(stderr, _("%s:%d: name required\n"), filename,
1579 					linum);
1580 			continue;
1581 		}
1582 		name_end = pnt;
1583 		/* Skip past white space after the name */
1584 		while (*pnt == ' ' || *pnt == '\t')
1585 			pnt++;
1586 		/* silently ignore errors in the rc file. */
1587 		if (*pnt != '=') {
1588 			fprintf(stderr, _("%s:%d: equals sign required after '%.*s'\n"),
1589 						filename, linum,
1590 						/* XXX Should not be > int */
1591 						(int)(name_end-name), name);
1592 			continue;
1593 		}
1594 		/* Skip pas the = sign, and any white space following it */
1595 		pnt++;	/* Skip past '=' sign */
1596 		while (*pnt == ' ' || *pnt == '\t')
1597 			pnt++;
1598 
1599 		/* now it is safe to NUL terminate the name */
1600 
1601 		*name_end = 0;
1602 
1603 		/* Now get rid of trailing newline */
1604 
1605 		pnt1 = pnt;
1606 		while (*pnt1) {
1607 			if (*pnt1 == '\n') {
1608 				*pnt1 = 0;
1609 				break;
1610 			}
1611 			pnt1++;
1612 		}
1613 		/* OK, now figure out which option we have */
1614 		for (rco = rcopt; rco->tag; rco++) {
1615 			if (strcmp(rco->tag, name) == 0) {
1616 				*rco->variable = e_strdup(pnt);
1617 				break;
1618 			}
1619 		}
1620 		if (rco->tag == NULL) {
1621 			fprintf(stderr, _("%s:%d: field name \"%s\" unknown\n"),
1622 				filename, linum,
1623 				name);
1624 		}
1625 	}
1626 	if (ferror(rcfile))
1627 		errmsg(_("Read error on '%s'.\n"), filename);
1628 	fclose(rcfile);
1629 }
1630 
1631 char	*path_table_l = NULL;
1632 char	*path_table_m = NULL;
1633 
1634 char	*jpath_table_l = NULL;
1635 char	*jpath_table_m = NULL;
1636 
1637 int	goof = 0;
1638 
1639 #ifndef TRUE
1640 #define	TRUE 1
1641 #endif
1642 
1643 #ifndef FALSE
1644 #define	FALSE 0
1645 #endif
1646 
1647 LOCAL void
susage(excode)1648 susage(excode)
1649 	int		excode;
1650 {
1651 	const char	*program_name = "mkisofs";
1652 
1653 #ifdef	USE_FIND
1654 	fprintf(stderr, _("Usage: %s [options] [-find] file... [find expression]\n"), program_name);
1655 #else
1656 	fprintf(stderr, _("Usage: %s [options] file...\n"), program_name);
1657 #endif
1658 	fprintf(stderr, _("\nUse %s -help\n"), program_name);
1659 	fprintf(stderr, _("to get a list all of valid options.\n"));
1660 #ifdef	USE_FIND
1661 	fprintf(stderr, _("\nUse %s -find -help\n"), program_name);
1662 	fprintf(stderr, _("to get a list of all valid -find options.\n"));
1663 #endif
1664 	error(_("\nMost important Options:\n"));
1665 	error(_("	-posix-H		Follow sylinks encountered on command line\n"));
1666 	error(_("	-posix-L		Follow all symlinks\n"));
1667 	error(_("	-posix-P		Do not follow symlinks (default)\n"));
1668 	error(_("	-o FILE, -output FILE	Set output file name\n"));
1669 	error(_("	-R, -rock		Generate Rock Ridge directory information\n"));
1670 	error(_("	-r, -rational-rock	Generate rationalized Rock Ridge directory info\n"));
1671 	error(_("	-J, -joliet		Generate Joliet directory information\n"));
1672 	error(_("	-print-size		Print estimated filesystem size and exit\n"));
1673 #ifdef	UDF
1674 	error(_("	-UDF			Generate UDF file system\n"));
1675 #endif
1676 #ifdef	DVD_AUD_VID
1677 	error(_("	-dvd-audio		Generate DVD-Audio compliant UDF file system\n"));
1678 	error(_("	-dvd-video		Generate DVD-Video compliant UDF file system\n"));
1679 	error(_("	-dvd-hybrid		Generate a hybrid (DVD-Audio/DVD-Video) compliant UDF file system\n"));
1680 #endif
1681 	error(_("	-iso-level LEVEL	Set ISO9660 level (1..3) or 4 for ISO9660 v 2\n"));
1682 	error(_("	-V ID, -volid ID	Set Volume ID\n"));
1683 	error(_("	-graft-points		Allow to use graft points for filenames\n"));
1684 	error(_("	-M FILE, -prev-session FILE	Set path to previous session to merge\n"));
1685 
1686 	exit(excode);
1687 }
1688 
1689 const char *optend	__PR((const char *fmt));
1690 const char *
optend(fmt)1691 optend(fmt)
1692 	const char	*fmt;
1693 {
1694 	int		c;
1695 	const char	*ofmt = fmt;
1696 
1697 	for (; *fmt != '\0'; fmt++) {
1698 		c = *fmt;
1699 		if (c == '\\') {
1700 			if (*++fmt == '\0')
1701 				break;
1702 			continue;
1703 		}
1704 		if (c == ',' || c == '%' || c == '*' || c == '?' ||
1705 		    c == '#' || c == '&' || c == '~')
1706 			break;
1707 		if (fmt > ofmt && c == '+')
1708 			break;
1709 
1710 	}
1711 	return (fmt);
1712 }
1713 
1714 int	printopts	__PR((FILE *f, const char *fmt, const char *arg, int twod));
1715 int
printopts(f,fmt,arg,twod)1716 printopts(f, fmt, arg, twod)
1717 	FILE		*f;
1718 	const char	*fmt;
1719 	const char	*arg;
1720 	int		twod;
1721 {
1722 	const char	*p;
1723 	int		len = 0;
1724 	int		optlen;
1725 	int		arglen = 0;
1726 
1727 	if (arg) {
1728 		if (*arg == '-' || *arg == '\\')
1729 			arg++;
1730 
1731 		if (*arg == '\1') {
1732 			p = ++arg;
1733 			while (*p != '\0' && *p != '\1' && *p != '\2')
1734 				p++;
1735 			arglen = p - arg;
1736 			if (arglen == 0)
1737 				arg = NULL;
1738 		} else {
1739 			arg = NULL;
1740 		}
1741 	}
1742 	for (p = optend(fmt); p > fmt; p = optend(fmt)) {
1743 		optlen = p - fmt;
1744 		len += fprintf(f, "%s%.*s%s%.*s",
1745 				*fmt == '+' ? "" :
1746 					(optlen > 1 && twod) ? "--" : "-",
1747 				(int)(p - fmt), fmt,
1748 				arg != NULL ? " " : "",
1749 				arglen, arg != NULL ? arg : "");
1750 		fmt = p;
1751 		while (*fmt != '\0' && *fmt != ',')
1752 			fmt++;
1753 		if (*fmt == ',') {
1754 			fmt++;
1755 			len += fprintf(f, ", ");
1756 		}
1757 	}
1758 	return (len);
1759 }
1760 
1761 const char	*docstr	__PR((const char *str, int *no_help));
1762 const char *
docstr(str,no_help)1763 docstr(str, no_help)
1764 	const char	*str;
1765 	int		*no_help;
1766 {
1767 	if (no_help)
1768 		*no_help = 0;
1769 	if (str == NULL)
1770 		return (str);
1771 
1772 	if (*str == '-' || *str == '\\')
1773 		str++;
1774 
1775 	if (*str == '\1') {
1776 		str++;
1777 		while (*str != '\0' && *str != '\1' && *str != '\2')
1778 			str++;
1779 	}
1780 	if (*str == '\1') {
1781 		str++;
1782 	} else if (*str == '\2') {
1783 		str++;
1784 		if (no_help)
1785 			*no_help = 1;
1786 	}
1787 
1788 	if (*str == '\0')
1789 		return (NULL);
1790 	return (str);
1791 }
1792 
1793 LOCAL void
usage(excode)1794 usage(excode)
1795 	int		excode;
1796 {
1797 	const char	*program_name = "mkisofs";
1798 
1799 	int	i;
1800 
1801 #ifdef	USE_FIND
1802 	fprintf(stderr, _("Usage: %s [options] [-find] file... [find expression]\n"), program_name);
1803 #else
1804 	fprintf(stderr, _("Usage: %s [options] file...\n"), program_name);
1805 #endif
1806 
1807 	fprintf(stderr, _("Options:\n"));
1808 	for (i = 0; i < (int)OPTION_COUNT; i++) {
1809 		if (docstr(mki_options[i].doc, NULL) != NULL) {
1810 			int	len;
1811 			int	j;
1812 
1813 			fprintf(stderr, "  ");
1814 			len = 2;
1815 			j = i;
1816 			do {
1817 				int		twodash;
1818 				int		no_help;
1819 				const char 	*doc;
1820 
1821 				doc = mki_options[j].doc;
1822 				twodash = (doc != NULL && *doc == '-');
1823 				doc = docstr(doc, &no_help);
1824 
1825 				if (!no_help) {
1826 					/*
1827 					 * If more options for one doc, then
1828 					 * print a comma as separator.
1829 					 */
1830 					if (j > i)
1831 						len += fprintf(stderr, ", ");
1832 					len += printopts(stderr,
1833 						mki_options[j].opt.ga_format,
1834 						mki_options[j].doc,
1835 						twodash);
1836 				}
1837 				++j;
1838 			}
1839 			while (j < (int)OPTION_COUNT &&
1840 				docstr(mki_options[j].doc, NULL) == NULL);
1841 
1842 			if (len >= 30) {
1843 				fprintf(stderr, "\n");
1844 				len = 0;
1845 			}
1846 			for (; len < 30; len++)
1847 				fputc(' ', stderr);
1848 
1849 			fprintf(stderr, "%s\n",
1850 					docstr(mki_options[i].doc, NULL));
1851 		}
1852 	}
1853 	exit(excode);
1854 }
1855 
1856 
1857 /*
1858  * Fill in date in the iso9660 format
1859  * This takes 7 bytes and supports year 1900 .. 2155 with 1 second granularity
1860  *
1861  * The standards  state that the timezone offset is in multiples of 15
1862  * minutes, and is what you add to GMT to get the localtime.  The U.S.
1863  * is always at a negative offset, from -5h to -8h (can vary a little
1864  * with DST,  I guess).  The Linux iso9660 filesystem has had the sign
1865  * of this wrong for ages (mkisofs had it wrong too until February 1997).
1866  */
1867 EXPORT int
iso9660_date(result,crtime)1868 iso9660_date(result, crtime)
1869 	char	*result;
1870 	time_t	crtime;
1871 {
1872 	struct tm	local;
1873 	struct tm	gmt;
1874 
1875 	local = *localtime(&crtime);
1876 	gmt   = *gmtime(&crtime);
1877 
1878 	result[0] = local.tm_year;
1879 	result[1] = local.tm_mon + 1;
1880 	result[2] = local.tm_mday;
1881 	result[3] = local.tm_hour;
1882 	result[4] = local.tm_min;
1883 	result[5] = local.tm_sec;
1884 
1885 	local.tm_min  -= gmt.tm_min;
1886 	local.tm_hour -= gmt.tm_hour;
1887 	local.tm_yday -= gmt.tm_yday;
1888 	local.tm_year -= gmt.tm_year;
1889 	if (local.tm_year)		/* Hit new-year limit	*/
1890 		local.tm_yday = local.tm_year;	/* yday = +-1	*/
1891 
1892 	result[6] = (local.tm_min + 60 *
1893 			(local.tm_hour + 24 * local.tm_yday)) / 15;
1894 
1895 	return (0);
1896 }
1897 
1898 /*
1899  * Fill in date in the iso9660 long format
1900  * This takes 17 bytes and supports year 0 .. 9999 with 10ms granularity
1901  * If iso9660_ldate() is called with gmtoff set to -100, the gmtoffset for
1902  * the related time is computed via localtime(). For the modification
1903  * date in the PVD, the date and the GMT offset may be defined via the
1904  * -modification-date command line option.
1905  */
1906 EXPORT int
iso9660_ldate(result,crtime,nsec,gmtoff)1907 iso9660_ldate(result, crtime, nsec, gmtoff)
1908 	char	*result;
1909 	time_t	crtime;
1910 	int	nsec;
1911 	int	gmtoff;
1912 {
1913 	struct tm	local;
1914 	struct tm	gmt;
1915 
1916 	local = *localtime(&crtime);
1917 	gmt   = *gmtime(&crtime);
1918 
1919 	/*
1920 	 * There was a comment here about breaking in the year 2000.
1921 	 * That's not true, in 2000 tm_year == 100, so 1900+tm_year == 2000.
1922 	 */
1923 	sprintf(result, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d%2.2d",
1924 		1900 + local.tm_year,
1925 		local.tm_mon + 1, local.tm_mday,
1926 		local.tm_hour, local.tm_min, local.tm_sec,
1927 		nsec / 10000000);
1928 
1929 	if (gmtoff == -100) {
1930 		local.tm_min  -= gmt.tm_min;
1931 		local.tm_hour -= gmt.tm_hour;
1932 		local.tm_yday -= gmt.tm_yday;
1933 		local.tm_year -= gmt.tm_year;
1934 		if (local.tm_year)		/* Hit new-year limit	*/
1935 			local.tm_yday = local.tm_year;	/* yday = +-1	*/
1936 
1937 		result[16] = (local.tm_min + 60 *
1938 				(local.tm_hour + 24 * local.tm_yday)) / 15;
1939 	} else {
1940 		result[16] = gmtoff;
1941 	}
1942 	return (0);
1943 }
1944 
1945 /* hide "./rr_moved" if all its contents are hidden */
1946 LOCAL void
hide_reloc_dir()1947 hide_reloc_dir()
1948 {
1949 	struct directory_entry *s_entry;
1950 
1951 	for (s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) {
1952 		if (strcmp(s_entry->name, ".") == 0 ||
1953 				strcmp(s_entry->name, "..") == 0)
1954 			continue;
1955 
1956 		if ((s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0)
1957 			return;
1958 	}
1959 
1960 	/* all entries are hidden, so hide this directory */
1961 	reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
1962 	reloc_dir->self->de_flags |= INHIBIT_ISO9660_ENTRY;
1963 }
1964 
1965 /*
1966  * get pathnames from the command line, and then from given file
1967  */
1968 LOCAL char *
get_pnames(argc,argv,opt,pname,pnsize,fp)1969 get_pnames(argc, argv, opt, pname, pnsize, fp)
1970 	int	argc;
1971 	char	* const *argv;
1972 	int	opt;
1973 	char	*pname;
1974 	int	pnsize;
1975 	FILE	*fp;
1976 {
1977 	int	len;
1978 
1979 	/* we may of already read the first line from the pathnames file */
1980 	if (save_pname) {
1981 		save_pname = 0;
1982 		return (pname);
1983 	}
1984 
1985 #ifdef	USE_FIND
1986 	if (dofind && opt < (find_pav - argv))
1987 		return (argv[opt]);
1988 	else if (!dofind && opt < argc)
1989 		return (argv[opt]);
1990 #else
1991 	if (opt < argc)
1992 		return (argv[opt]);
1993 #endif
1994 
1995 	if (fp == NULL)
1996 		return ((char *)0);
1997 
1998 	if (fgets(pname, pnsize, fp)) {
1999 		/* Discard newline */
2000 		len = strlen(pname);
2001 		if (pname[len - 1] == '\n') {
2002 			pname[len - 1] = '\0';
2003 		}
2004 		return (pname);
2005 	}
2006 	return ((char *)0);
2007 }
2008 
2009 EXPORT int
main(argc,argv)2010 main(argc, argv)
2011 	int		argc;
2012 	char		*argv[];
2013 {
2014 	int	cac = argc;
2015 	char	* const *cav = argv;
2016 
2017 	struct directory_entry de;
2018 
2019 #ifdef HAVE_SBRK
2020 	unsigned long	mem_start;
2021 #endif
2022 	struct stat	statbuf;
2023 	struct iso_directory_record *mrootp = NULL;
2024 	struct output_fragment *opnt;
2025 	struct ga_flags	flags[OPTION_COUNT + 1];
2026 	int		c;
2027 	int		n;
2028 	char		*node = NULL;
2029 	FILE		*pfp = NULL;
2030 	char		pname[2*PATH_MAX + 1 + 1];	/* may be too short */
2031 	char		*arg;				/* if '\\' present  */
2032 	char		nodename[PATH_MAX + 1];
2033 	int		no_path_names = 1;
2034 	int		warn_violate = 0;
2035 	int		have_cmd_line_pathspec = 0;
2036 	int		rationalize_all = 0;
2037 	int		argind = 0;
2038 #ifdef APPLE_HYB
2039 	int		hfs_ct = 0;
2040 #endif	/* APPLE_HYB */
2041 
2042 
2043 #ifdef __EMX__
2044 	/* This gives wildcard expansion with Non-Posix shells with EMX */
2045 	_wildcard(&argc, &argv);
2046 #endif
2047 	save_args(argc, argv);
2048 
2049 #if	defined(USE_NLS)
2050 	setlocale(LC_ALL, "");
2051 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
2052 #define	TEXT_DOMAIN "mkisofs"	/* Use this only if it weren't */
2053 #endif
2054 	arg = searchfileinpath("share/locale", F_OK,
2055 					SIP_ANY_FILE|SIP_NO_PATH, NULL);
2056 	if (arg)
2057 		(void) bindtextdomain(TEXT_DOMAIN, arg);
2058 	else
2059 #ifdef	PROTOTYPES
2060 	(void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
2061 #else
2062 	(void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
2063 #endif
2064 	(void) textdomain(TEXT_DOMAIN);
2065 #endif
2066 
2067 
2068 	if (argc < 2) {
2069 		errmsgno(EX_BAD, _("Missing pathspec.\n"));
2070 		susage(1);
2071 	}
2072 	/* Get the defaults from the .mkisofsrc file */
2073 	read_rcfile(argv[0]);
2074 
2075 	{
2076 		int		i;
2077 
2078 		for (i = 0; i < (int)OPTION_COUNT; i++) {
2079 			flags[i] = mki_options[i].opt;
2080 		}
2081 		flags[i].ga_format = NULL;
2082 		gl_flags = flags;
2083 	}
2084 	time(&begun);
2085 	gettimeofday(&tv_begun, NULL);
2086 	modification_date.l_sec  = tv_begun.tv_sec;
2087 	modification_date.l_usec = tv_begun.tv_usec;
2088 	modification_date.l_gmtoff = -100;
2089 
2090 	cac--;
2091 	cav++;
2092 	c = getvargs(&cac, &cav, GA_NO_PROPS, flags);
2093 	if (c < 0) {
2094 		if (c == BADFLAG && strchr(cav[0], '=')) {
2095 			argind = argc - cac;
2096 			goto args_ok;
2097 		}
2098 		error(_("Bad Option '%s' (error %d %s).\n"),
2099 					cav[0], c, getargerror(c));
2100 		susage(EX_BAD);
2101 	}
2102 args_ok:
2103 	if (argind == 0)
2104 		argind = argc - cac;
2105 	path_ind = argind;
2106 	if (cac > 0)
2107 		have_cmd_line_pathspec = 1;
2108 	if (help)
2109 		usage(0);
2110 	if (pversion) {
2111 		printf(_("mkisofs %s (%s-%s-%s)\n\n\
2112 Copyright (C) 1993-1997 %s\n\
2113 Copyright (C) 1997-2017 %s\n"),
2114 			version_string,
2115 			HOST_CPU, HOST_VENDOR, HOST_OS,
2116 			_("Eric Youngdale"),
2117 			_("Joerg Schilling"));
2118 #ifdef	APPLE_HYB
2119 		printf(_("Copyright (C) 1997-2001 James Pearson\n"));
2120 #endif
2121 #ifdef	UDF
2122 		printf(_("Copyright (C) 2006      HELIOS Software GmbH\n"));
2123 #endif
2124 #ifdef	OPTION_SILO_BOOT
2125 		printf(_("Warning: this is unofficial (modified) version of mkisofs that incorporates\n"));
2126 		printf(_("	support for a non Sparc compliant boot method called SILO.\n"));
2127 		printf(_("	The official method to create Sparc boot CDs is to use -sparc-boot\n"));
2128 		printf(_("	In case of problems first test with an official version of mkisofs.\n"));
2129 #endif
2130 		exit(0);
2131 	}
2132 #ifdef	USE_FIND
2133 	if (dofind) {
2134 		finda_t	fa;
2135 
2136 		cac = find_ac;
2137 		cav = find_av;
2138 		find_firstprim(&cac, &cav);
2139 		find_pac = cac;
2140 		find_pav = cav;
2141 		argind = argc - find_ac;
2142 
2143 		if (cac > 0) {
2144 			find_argsinit(&fa);
2145 			fa.walkflags = walkflags;
2146 			fa.Argc = cac;
2147 			fa.Argv = (char **)cav;
2148 			find_node = find_parse(&fa);
2149 			if (fa.primtype == FIND_ERRARG)
2150 				comexit(fa.error);
2151 			if (fa.primtype != FIND_ENDARGS)
2152 				comerrno(EX_BAD, _("Incomplete expression.\n"));
2153 			plusp = fa.plusp;
2154 			find_patlen = fa.patlen;
2155 			walkflags = fa.walkflags;
2156 			maxdepth = fa.maxdepth;
2157 			mindepth = fa.mindepth;
2158 
2159 			if (find_node &&
2160 			    !(check_image || print_size) &&
2161 			    (outfile == NULL ||
2162 			    (outfile[0] == '-' && outfile[1] == '\0'))) {
2163 				if (find_pname(find_node, "-exec") ||
2164 				    find_pname(find_node, "-exec+") ||
2165 				    find_pname(find_node, "-ok"))
2166 					comerrno(EX_BAD,
2167 					_("Cannot -exec with '-o -'.\n"));
2168 			}
2169 		}
2170 
2171 		if (find_ac <= 0 || find_ac == find_pac) {
2172 			errmsgno(EX_BAD, _("Missing pathspec for -find.\n"));
2173 			susage(EX_BAD);
2174 		}
2175 	}
2176 #endif
2177 #ifdef DVD_AUD_VID
2178 
2179 	dvd_aud_vid_flag = (dvd_audio ? DVD_SPEC_AUDIO : 0)
2180 			| (dvd_hybrid ? DVD_SPEC_HYBRD : 0)
2181 			| (dvd_video ? DVD_SPEC_VIDEO : 0);
2182 
2183 #endif
2184 
2185 	if (abstract) {
2186 		if (strlen(abstract) > 37) {
2187 			comerrno(EX_BAD,
2188 			_("Abstract filename string too long (cur. %lld max. 37 chars).\n"),
2189 			(Llong)strlen(abstract));
2190 		}
2191 	}
2192 	if (appid) {
2193 		if (strlen(appid) > 128) {
2194 			comerrno(EX_BAD,
2195 			_("Application-id string too long (cur. %lld max. 128 chars).\n"),
2196 			(Llong)strlen(appid));
2197 		}
2198 	}
2199 	if (biblio) {
2200 		if (strlen(biblio) > 37) {
2201 			comerrno(EX_BAD,
2202 			_("Bibliographic filename string too long (cur. %lld max. 37 chars).\n"),
2203 			(Llong)strlen(biblio));
2204 		}
2205 	}
2206 #ifdef	DUPLICATES_ONCE
2207 	/*
2208 	 * If -duplicates-once was specified, do not implicitly enable
2209 	 * -cache-inodes.
2210 	 */
2211 	if (cache_inodes < 0 && duplicates_once)
2212 		cache_inodes = 0;
2213 #endif
2214 #if	defined(IS_CYGWIN)
2215 	/*
2216 	 * If we have 64 bit inode numbers, Cygwin should be able to work
2217 	 * correctly on NTFS, otherwise disable caching unless it has
2218 	 * been enforced via -cache-inodes.
2219 	 */
2220 	if (cache_inodes < 0 && sizeof (ino_t) < 8)
2221 		cache_inodes = 0;
2222 #endif
2223 	if (cache_inodes < 0)
2224 		cache_inodes = 1;
2225 #ifdef	DUPLICATES_ONCE
2226 	if (!cache_inodes && !duplicates_once) {
2227 #else
2228 	if (!cache_inodes) {
2229 #endif
2230 		correct_inodes = FALSE;
2231 		if (use_RockRidge) {
2232 			errmsgno(EX_BAD,
2233 			_("Warning: Cannot write inode/link information with -no-cache-inodes.\n"));
2234 		} else {
2235 			errmsgno(EX_BAD,
2236 			_("Warning: Cannot add inode hints with -no-cache-inodes.\n"));
2237 		}
2238 	}
2239 #if	defined(__MINGW32__)
2240 	if (cache_inodes) {
2241 		cache_inodes = 0;
2242 		correct_inodes = FALSE;
2243 		errmsgno(EX_BAD,
2244 		_("Warning: cannot -cache-inodes on this platform - ignoring.\n"));
2245 	}
2246 #endif
2247 	if (!correct_inodes)
2248 		rrip112 = FALSE;
2249 	if (check_image) {
2250 		check_session++;
2251 		check_oldnames++;
2252 		merge_image = check_image;
2253 		outfile = DEV_NULL;
2254 		/*
2255 		 * cdrecord_data is handled specially in multi.c
2256 		 * as we cannot write to all strings.
2257 		 * If mkisofs is called with -C xx,yy
2258 		 * our default is overwritten.
2259 		 */
2260 /*		cdrecord_data = "0,0";*/
2261 	}
2262 	if (copyright) {
2263 		if (strlen(copyright) > 37) {
2264 			comerrno(EX_BAD,
2265 			_("Copyright filename string too long (cur. %lld max. 37 chars).\n"),
2266 			(Llong)strlen(copyright));
2267 		}
2268 	}
2269 	if (genboot_image)
2270 		use_genboot++;
2271 	if (boot_catalog)
2272 		use_eltorito++;
2273 	else
2274 		boot_catalog = BOOT_CATALOG_DEFAULT;
2275 	if (omit_period && iso9660_level < 4)
2276 		warn_violate++;
2277 	if (data_change_warn)
2278 		errconfig("WARN|GROW|SHRINK *");
2279 	if (dirmode_str) {
2280 		char	*end = 0;
2281 
2282 		rationalize++;
2283 		use_RockRidge++;
2284 		rationalize_dirmode++;
2285 
2286 		/*
2287 		 * If -new-dir-mode was specified, new_dir_mode is set
2288 		 * up later with a value that matches the -new-dir-mode arg.
2289 		 */
2290 		new_dir_mode = dirmode_to_use = strtol(dirmode_str, &end, 8);
2291 		if (!end || *end != 0 ||
2292 		    dirmode_to_use < 0 || dirmode_to_use > 07777) {
2293 			comerrno(EX_BAD, _("Bad mode for -dir-mode\n"));
2294 		}
2295 	}
2296 	if (disable_deep_reloc)
2297 		RR_relocation_depth = 0xFFFFFFFF;
2298 	if (filemode_str) {
2299 		char	*end = 0;
2300 
2301 		rationalize++;
2302 		use_RockRidge++;
2303 		rationalize_filemode++;
2304 
2305 		filemode_to_use = strtol(filemode_str, &end, 8);
2306 		if (!end || *end != 0 ||
2307 		    filemode_to_use < 0 || filemode_to_use > 07777) {
2308 			comerrno(EX_BAD, _("Bad mode for -file-mode\n"));
2309 		}
2310 	}
2311 #ifdef	__warn_follow__
2312 	if (follow_links) {
2313 			errmsgno(EX_BAD,
2314 			_("Warning: -follow-links does not always work correctly; be careful.\n"));
2315 	}
2316 #endif
2317 	if (gid_str) {
2318 		char	*end = 0;
2319 
2320 		rationalize++;
2321 		use_RockRidge++;
2322 		rationalize_gid++;
2323 
2324 		gid_to_use = strtol(gid_str, &end, 0);
2325 		if (!end || *end != 0) {
2326 			comerrno(EX_BAD, _("Bad value for -gid\n"));
2327 		}
2328 	}
2329 	switch (iso9660_level) {
2330 
2331 	case 1:
2332 		/*
2333 		 * Only on file section
2334 		 * 8.3 d or d1 characters for files
2335 		 * 8   d or d1 characters for directories
2336 		 */
2337 		break;
2338 	case 2:
2339 		/*
2340 		 * Only on file section
2341 		 */
2342 		break;
2343 	case 3:
2344 		/*
2345 		 * No restrictions
2346 		 */
2347 		do_largefiles++;
2348 		break;
2349 	case 4:
2350 		/*
2351 		 * This is ISO-9660:1988 (ISO-9660 version 2)
2352 		 */
2353 		do_largefiles++;
2354 		iso9660_namelen = MAX_ISONAME_V2; /* allow 207 chars */
2355 		full_iso9660_filenames++;	/* 31+ chars	*/
2356 		omit_version_number++;
2357 		RR_relocation_depth = 0xFFFFFFFF;
2358 
2359 		/*
2360 		 * From -U ...
2361 		 */
2362 		omit_period++;			/* trailing dot */
2363 		allow_leading_dots++;
2364 		relaxed_filenames++;		/* all chars	*/
2365 		allow_lowercase++;		/* even lowcase	*/
2366 		allow_multidot++;		/* > 1 dots	*/
2367 		break;
2368 
2369 	default:
2370 		comerrno(EX_BAD, _("Illegal iso9660 Level %d, use 1..3 or 4.\n"),
2371 					iso9660_level);
2372 	}
2373 
2374 	if (joliet_long) {
2375 		use_Joliet++;
2376 		jlen = JLONGMAX;
2377 	}
2378 	if (jcharset) {
2379 		use_Joliet++;
2380 		icharset = jcharset;
2381 	}
2382 	if (max_filenames && iso9660_level < 4) {
2383 		iso9660_namelen = MAX_ISONAME_V1; /* allow 37 chars */
2384 		full_iso9660_filenames++;
2385 		omit_version_number++;
2386 		warn_violate++;
2387 	}
2388 	if (allow_leading_dots && iso9660_level < 4)
2389 		warn_violate++;
2390 	if (omit_version_number && iso9660_level < 4)
2391 		warn_violate++;
2392 	if (new_dirmode_str) {
2393 		char	*end = 0;
2394 
2395 		rationalize++;
2396 
2397 		new_dir_mode = strtol(new_dirmode_str, &end, 8);
2398 		if (!end || *end != 0 ||
2399 		    new_dir_mode < 0 || new_dir_mode > 07777) {
2400 			comerrno(EX_BAD, _("Bad mode for -new-dir-mode\n"));
2401 		}
2402 	}
2403 	if (sectype) {
2404 		if (strcmp(sectype, "data") == 0)
2405 			osecsize = 2048;
2406 		else if (strcmp(sectype, "xa1") == 0)
2407 			osecsize = 2056;
2408 		else if (strcmp(sectype, "raw") == 0) {
2409 			osecsize = 2352;
2410 			comerrno(EX_BAD,
2411 				_("Unsupported sector type '%s'.\n"),
2412 				sectype);
2413 		}
2414 	}
2415 	if (preparer) {
2416 		if (strlen(preparer) > 128) {
2417 			comerrno(EX_BAD, _("Preparer string too long (cur. %lld max. 128 chars).\n"),
2418 			(Llong)strlen(preparer));
2419 		}
2420 	}
2421 	if (publisher) {
2422 		if (strlen(publisher) > 128) {
2423 			comerrno(EX_BAD,
2424 				_("Publisher string too long (cur. %lld max. 128 chars).\n"),
2425 				(Llong)strlen(publisher));
2426 		}
2427 	}
2428 	if (rationalize_rr) {
2429 		rationalize_all++;
2430 		use_RockRidge++;
2431 	}
2432 	if (stream_filename) {
2433 		if (strlen(stream_filename) > MAX_ISONAME)
2434 			comerrno(EX_BAD,
2435 				_("stream-file-name too long (%llu), max is %d.\n"),
2436 				(Ullong)strlen(stream_filename), MAX_ISONAME);
2437 		if (strchr(stream_filename, '/'))
2438 			comerrno(EX_BAD, _("Illegal character '/' in stream-file-name.\n"));
2439 		iso9660_level = 4;
2440 	} else {
2441 		stream_filename = omit_version_number ? "STREAM.IMG" : "STREAM.IMG;1";
2442 	}
2443 	if (system_id) {
2444 		if (strlen(system_id) > 32) {
2445 			comerrno(EX_BAD,
2446 					_("System ID string too long\n"));
2447 		}
2448 	}
2449 	if (trans_tbl)
2450 		generate_tables++;
2451 	else
2452 		trans_tbl = "TRANS.TBL";
2453 	if (ucs_level < 1 || ucs_level > 3)
2454 		comerrno(EX_BAD, _("Illegal UCS Level %d, use 1..3.\n"),
2455 						ucs_level);
2456 #ifdef	DVD_AUD_VID
2457 	if (dvd_aud_vid_flag) {
2458 		if (!use_udf)
2459 			rationalize_udf++;
2460 	}
2461 #endif
2462 #ifdef	UDF
2463 	if (rationalize_udf) {
2464 		rationalize_all++;
2465 		use_udf++;
2466 	}
2467 #endif
2468 	if (uid_str) {
2469 		char	*end = 0;
2470 
2471 		rationalize++;
2472 		use_RockRidge++;
2473 		rationalize_uid++;
2474 
2475 		uid_to_use = strtol(uid_str, &end, 0);
2476 		if (!end || *end != 0) {
2477 			comerrno(EX_BAD, _("Bad value for -uid\n"));
2478 		}
2479 	}
2480 	if (untranslated_filenames && iso9660_level < 4) {
2481 		/*
2482 		 * Minimal (only truncation of 31+ characters)
2483 		 * translation of filenames.
2484 		 *
2485 		 * Forces -l, -d, -N, -allow-leading-dots,
2486 		 * -relaxed-filenames,
2487 		 * -allow-lowercase, -allow-multidot
2488 		 *
2489 		 * This is for HP-UX, which does not recognize ANY
2490 		 * extentions (Rock Ridge, Joliet), causing pain when
2491 		 * loading software. pfs_mount can be used to read the
2492 		 * extensions, but the untranslated filenames can be
2493 		 * read by the "native" cdfs mounter. Completely
2494 		 * violates iso9660.
2495 		 */
2496 		full_iso9660_filenames++;	/* 31 chars	*/
2497 		omit_period++;			/* trailing dot */
2498 		allow_leading_dots++;
2499 		omit_version_number++;
2500 		relaxed_filenames++;		/* all chars	*/
2501 		allow_lowercase++;		/* even lowcase	*/
2502 		allow_multidot++;		/* > 1 dots	*/
2503 		warn_violate++;
2504 	}
2505 	if (no_allow_lowercase)
2506 		allow_lowercase = 0;
2507 	if (relaxed_filenames && iso9660_level < 4)
2508 		warn_violate++;
2509 	if (iso_translate == 0 && iso9660_level < 4)
2510 		warn_violate++;
2511 	if (allow_lowercase && iso9660_level < 4)
2512 		warn_violate++;
2513 	if (allow_multidot && iso9660_level < 4)
2514 		warn_violate++;
2515 	if (volume_id) {
2516 		if (strlen(volume_id) > 32) {
2517 			comerrno(EX_BAD,
2518 				_("Volume ID string too long (cur. %lld max. 32 chars).\n"),
2519 				(Llong)strlen(volume_id));
2520 		}
2521 	}
2522 	if (volset_id) {
2523 		if (strlen(volset_id) > 128) {
2524 			comerrno(EX_BAD,
2525 			_("Volume set ID string too long (cur. %lld max. 128 chars).\n"),
2526 			(Llong)strlen(volset_id));
2527 		}
2528 	}
2529 	if (volume_set_size) {
2530 		if (volume_set_size <= 0) {
2531 			comerrno(EX_BAD,
2532 			_("Illegal Volume Set Size %d\n"), volume_set_size);
2533 		}
2534 		if (volume_set_size > 1) {
2535 			comerrno(EX_BAD,
2536 			_("Volume Set Size > 1 not yet supported\n"));
2537 		}
2538 	}
2539 	if (volume_sequence_number) {
2540 		if (volume_sequence_number > volume_set_size) {
2541 			comerrno(EX_BAD,
2542 			_("Volume set sequence number too big\n"));
2543 		}
2544 	}
2545 	if (rationalize_xa) {
2546 		rationalize_all++;
2547 		use_XA++;
2548 	}
2549 	if (transparent_compression) {
2550 #ifdef VMS
2551 		comerrno(EX_BAD,
2552 		_("Transparent compression not supported with VMS\n"));
2553 #endif
2554 	}
2555 #ifdef APPLE_HYB
2556 	if (deftype) {
2557 		hfs_ct++;
2558 		if (strlen(deftype) != 4) {
2559 			comerrno(EX_BAD,
2560 			_("HFS default TYPE string has illegal length.\n"));
2561 		}
2562 	} else {
2563 		deftype = APPLE_TYPE_DEFAULT;
2564 	}
2565 	if (defcreator) {
2566 		hfs_ct++;
2567 		if (strlen(defcreator) != 4) {
2568 			comerrno(EX_BAD,
2569 			_("HFS default CREATOR string has illegal length.\n"));
2570 		}
2571 	} else {
2572 		defcreator = APPLE_CREATOR_DEFAULT;
2573 	}
2574 	if (afpfile && *afpfile != '\0')
2575 		hfs_last = MAP_LAST;
2576 	if (magic_file)
2577 		hfs_last = MAG_LAST;
2578 	if (nomacfiles) {
2579 		errmsgno(EX_BAD,
2580 		_("Warning: -no-mac-files no longer used ... ignoring\n"));
2581 	}
2582 	if (hfs_boot_file)
2583 		gen_pt = 1;
2584 	if (root_info)
2585 		icon_pos = 1;
2586 	if (hfs_icharset)
2587 		use_mac_name = 1;
2588 	if (hfs_parms)
2589 		hfs_parms = e_strdup(hfs_parms);
2590 
2591 	if (apple_hyb && apple_ext) {
2592 		comerrno(EX_BAD, _("Can't have both -apple and -hfs options\n"));
2593 	}
2594 	/*
2595 	 * if -probe, -macname, any hfs selection and/or mapping file is given,
2596 	 * but no HFS option, then select apple_hyb
2597 	 */
2598 	if (!apple_hyb && !apple_ext) {
2599 		if (*afpfile || probe || use_mac_name || hfs_select ||
2600 				hfs_boot_file || magic_file ||
2601 				hfs_ishidden() || gen_pt || autoname ||
2602 				afe_size || icon_pos || hfs_ct ||
2603 				hfs_icharset || hfs_ocharset) {
2604 			apple_hyb = 1;
2605 #ifdef UDF
2606 			if ((DO_XHFS & hfs_select) && use_udf) {
2607 				donotwrite_macpart = 1;
2608 				if (!no_apple_hyb) {
2609 					error(
2610 					_("Warning: no HFS hybrid will be created with -udf and --osx-hfs\n"));
2611 				}
2612 			}
2613 #endif
2614 		}
2615 	}
2616 #ifdef UDF
2617 	if (!use_udf && create_udfsymlinks)
2618 		create_udfsymlinks = 0;
2619 #if 0
2620 	if (use_RockRidge && use_udf && create_udfsymlinks) {
2621 		error(_("Warning: cannot create UDF symlinks with activated Rock Ridge\n"));
2622 		create_udfsymlinks = 0;
2623 	}
2624 #endif
2625 #endif
2626 	if (no_apple_hyb) {
2627 		donotwrite_macpart = 1;
2628 	}
2629 	if (apple_hyb && !donotwrite_macpart && do_largefiles > 0) {
2630 		do_largefiles = 0;
2631 		maxnonlarge = (off_t)0x7FFFFFFF;
2632 		error(_("Warning: cannot support large files with -hfs\n"));
2633 	}
2634 #ifdef UDF
2635 	if (apple_hyb && use_udf && !donotwrite_macpart) {
2636 		comerrno(EX_BAD, _("Can't have -hfs with -udf\n"));
2637 	}
2638 #endif
2639 	if (apple_ext && hfs_boot_file) {
2640 		comerrno(EX_BAD, _("Can't have -hfs-boot-file with -apple\n"));
2641 	}
2642 	if (apple_ext && autoname) {
2643 		comerrno(EX_BAD, _("Can't have -auto with -apple\n"));
2644 	}
2645 	if (apple_hyb && (use_sparcboot || use_sunx86boot)) {
2646 		comerrno(EX_BAD, _("Can't have -hfs with -sparc-boot/-sunx86-boot\n"));
2647 	}
2648 	if (apple_hyb && use_genboot) {
2649 		comerrno(EX_BAD, _("Can't have -hfs with -generic-boot\n"));
2650 	}
2651 #ifdef PREP_BOOT
2652 	if (apple_ext && use_prep_boot) {
2653 		comerrno(EX_BAD, _("Can't have -prep-boot with -apple\n"));
2654 	}
2655 #endif	/* PREP_BOOT */
2656 
2657 	if (apple_hyb || apple_ext)
2658 		apple_both = 1;
2659 
2660 	if (probe)
2661 		/* we need to search for all types of Apple/Unix files */
2662 		hfs_select = ~0;
2663 
2664 	if (apple_both && verbose && !(hfs_select || *afpfile || magic_file)) {
2665 		errmsgno(EX_BAD,
2666 		_("Warning: no Apple/Unix files will be decoded/mapped\n"));
2667 	}
2668 	if (apple_both && verbose && !afe_size &&
2669 					(hfs_select & (DO_FEU | DO_FEL))) {
2670 		errmsgno(EX_BAD,
2671 		_("Warning: assuming PC Exchange cluster size of 512 bytes\n"));
2672 		afe_size = 512;
2673 	}
2674 	if (apple_both) {
2675 		/* set up the TYPE/CREATOR mappings */
2676 		hfs_init(afpfile, 0, hfs_select);
2677 	}
2678 	if (apple_ext && !use_RockRidge) {
2679 #ifdef	nonono
2680 		/* use RockRidge to set the SystemUse field ... */
2681 		use_RockRidge++;
2682 		rationalize_all++;
2683 #else
2684 		/* EMPTY */
2685 #endif
2686 	}
2687 	if (apple_ext && !(use_XA || use_RockRidge)) {
2688 		comerrno(EX_BAD, _("Need either -XA/-xa or -R/-r for -apple to become active.\n"));
2689 	}
2690 #endif	/* APPLE_HYB */
2691 
2692 	/*
2693 	 * if the -hide-joliet option has been given, set the Joliet option
2694 	 */
2695 	if (!use_Joliet && j_ishidden())
2696 		use_Joliet++;
2697 #ifdef	UDF
2698 	/*
2699 	 * if the -hide-udf option has been given, set the UDF option
2700 	 */
2701 	if (!use_udf && u_ishidden())
2702 		use_udf++;
2703 #endif
2704 
2705 	if (rationalize_all) {
2706 		rationalize++;
2707 		rationalize_uid++;
2708 		rationalize_gid++;
2709 		rationalize_filemode++;
2710 		rationalize_dirmode++;
2711 	}
2712 
2713 	/*
2714 	 * XXX This is a hack until we have a decent separate name handling
2715 	 * XXX for UDF filenames.
2716 	 */
2717 #ifdef DVD_AUD_VID
2718 	if (dvd_aud_vid_flag && use_Joliet) {
2719 		use_Joliet = 0;
2720 		error(_("Warning: Disabling Joliet support for DVD-Video/DVD-Audio.\n"));
2721 	}
2722 #endif
2723 #ifdef	UDF
2724 	if (use_udf && !use_Joliet)
2725 		jlen = 255;
2726 #endif
2727 
2728 	if (use_RockRidge && (iso9660_namelen > MAX_ISONAME_V2_RR))
2729 		iso9660_namelen = MAX_ISONAME_V2_RR;
2730 
2731 	if (warn_violate)
2732 		error(_("Warning: creating filesystem that does not conform to ISO-9660.\n"));
2733 	if (iso9660_level > 3)
2734 		error(_("Warning: Creating ISO-9660:1999 (version 2) filesystem.\n"));
2735 	if (iso9660_namelen > LEN_ISONAME)
2736 		error(_("Warning: ISO-9660 filenames longer than %d may cause buffer overflows in the OS.\n"),
2737 			LEN_ISONAME);
2738 	if (use_Joliet && !use_RockRidge) {
2739 		error(_("Warning: creating filesystem with (nonstandard) Joliet extensions\n"));
2740 		error(_("         but without (standard) Rock Ridge extensions.\n"));
2741 		error(_("         It is highly recommended to add Rock Ridge\n"));
2742 	}
2743 	if (transparent_compression) {
2744 		error(_("Warning: using transparent compression. This is a nonstandard Rock Ridge\n"));
2745 		error(_("         extension. The resulting filesystem can only be transparently\n"));
2746 		error(_("         read on Linux. On other operating systems you need to call\n"));
2747 		error(_("         mkzftree by hand to decompress the files.\n"));
2748 	}
2749 	if (transparent_compression && !use_RockRidge) {
2750 		error(_("Warning: transparent decompression is a Linux Rock Ridge extension, but\n"));
2751 		error(_("         creating filesystem without Rock Ridge attributes; files\n"));
2752 		error(_("         will not be transparently decompressed.\n"));
2753 	}
2754 
2755 #if	defined(USE_NLS) && defined(HAVE_NL_LANGINFO) && defined(CODESET)
2756 	/*
2757 	 * If the locale has not been set up, nl_langinfo() returns the
2758 	 * name of the default codeset. This should be either "646",
2759 	 * "ISO-646", "ASCII", or something similar. Unfortunately, the
2760 	 * POSIX standard does not include a list of valid locale names,
2761 	 * so ne need to find all values in use.
2762 	 *
2763 	 * Observed:
2764 	 * Solaris 	"646"
2765 	 * Linux	"ANSI_X3.4-1968"	strange value from Linux...
2766 	 */
2767 	if (icharset == NULL) {
2768 		char	*codeset = nl_langinfo(CODESET);
2769 		Uchar	*p;
2770 
2771 		if (codeset != NULL)
2772 			codeset = e_strdup(codeset);
2773 		if (codeset == NULL)			/* Should not happen */
2774 			goto setcharset;
2775 		if (*codeset == '\0')			/* Invalid locale    */
2776 			goto setcharset;
2777 
2778 		for (p = (Uchar *)codeset; *p != '\0'; p++) {
2779 			if (islower(*p))
2780 				*p = toupper(*p);
2781 		}
2782 		p = (Uchar *)strstr(codeset, "ISO");
2783 		if (p != NULL) {
2784 			if (*p == '_' || *p == '-')
2785 				p++;
2786 			codeset = (char *)p;
2787 		}
2788 		if (strcmp("646", codeset) != 0 &&
2789 		    strcmp("ASCII", codeset) != 0 &&
2790 		    strcmp("US-ASCII", codeset) != 0 &&
2791 		    strcmp("US_ASCII", codeset) != 0 &&
2792 		    strcmp("USASCII", codeset) != 0 &&
2793 		    strcmp("ANSI_X3.4-1968", codeset) != 0)
2794 			icharset = nl_langinfo(CODESET);
2795 
2796 		if (codeset != NULL)
2797 			free(codeset);
2798 
2799 		if (verbose > 0 && icharset != NULL) {
2800 			error(_("Setting input-charset to '%s' from locale.\n"),
2801 				icharset);
2802 		}
2803 	}
2804 setcharset:
2805 	/*
2806 	 * Allow to switch off locale with -input-charset "".
2807 	 */
2808 	if (icharset != NULL && *icharset == '\0')
2809 		icharset = NULL;
2810 #endif
2811 	if (icharset == NULL) {
2812 #if	(defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__DJGPP__)) && !defined(IS_CYGWIN_1)
2813 		icharset = "cp437";
2814 #else
2815 		icharset = "default";
2816 #endif
2817 	}
2818 	in_nls = sic_open(icharset);
2819 
2820 	/*
2821 	 * set the output charset to the same as the input or the given output
2822 	 * charset
2823 	 */
2824 	if (ocharset == NULL) {
2825 		ocharset = in_nls ? in_nls->sic_name : NULL;
2826 	}
2827 	out_nls = sic_open(ocharset);
2828 
2829 	if (in_nls == NULL || out_nls == NULL) { /* Unknown charset specified */
2830 		fprintf(stderr, _("Unknown charset '%s'.\nKnown charsets are:\n"),
2831 		in_nls == NULL ? icharset : (ocharset ? ocharset : "NULL"));
2832 		list_locales();
2833 		exit(EX_BAD);
2834 	}
2835 #ifdef	USE_ICONV
2836 	/*
2837 	 * XXX If we ever allow this, we neeed to fix the call to conv_charset()
2838 	 * XXX in name.c::iso9660_file_length().
2839 	 */
2840 	if ((in_nls->sic_cd2uni != NULL || out_nls->sic_cd2uni != NULL) &&
2841 	    (in_nls->sic_name != out_nls->sic_name)) {
2842 		errmsgno(EX_BAD,
2843 		_("Iconv based locales may change file name length.\n"));
2844 		comerrno(EX_BAD,
2845 		_("Cannot yet have different -input-charset/-output-charset.\n"));
2846 	}
2847 #endif
2848 
2849 #ifdef APPLE_HYB
2850 	if (hfs_icharset == NULL || strcmp(hfs_icharset, "mac-roman") == 0) {
2851 		hfs_icharset = "cp10000";
2852 	}
2853 	hfs_inls = sic_open(hfs_icharset);
2854 
2855 	if (hfs_ocharset == NULL) {
2856 		hfs_ocharset = hfs_inls ? hfs_inls->sic_name : NULL;
2857 	}
2858 	if (hfs_ocharset == NULL || strcmp(hfs_ocharset, "mac-roman") == 0) {
2859 		hfs_ocharset = "cp10000";
2860 	}
2861 	hfs_onls = sic_open(hfs_ocharset);
2862 
2863 	if (use_mac_name)
2864 		apple_hyb = 1;
2865 	if (apple_hyb && (hfs_inls == NULL || hfs_onls == NULL)) {
2866 		fprintf(stderr, _("Unknown HFS charset '%s'.\nKnown charsets are:\n"),
2867 		hfs_inls == NULL ? hfs_icharset : (hfs_ocharset ? hfs_ocharset : "NULL"));
2868 		list_locales();
2869 		exit(EX_BAD);
2870 	}
2871 #ifdef	USE_ICONV
2872 	if (apple_hyb &&
2873 	    ((hfs_inls->sic_cd2uni != NULL || hfs_onls->sic_cd2uni != NULL) &&
2874 	    (hfs_inls->sic_name != hfs_onls->sic_name))) {
2875 		errmsgno(EX_BAD,
2876 		_("Iconv based locales may change file name length.\n"));
2877 		comerrno(EX_BAD,
2878 		_("Cannot yet have different -input-hfs-charset/-output-hfs-charset.\n"));
2879 	}
2880 #endif
2881 #endif /* APPLE_HYB */
2882 
2883 	if (merge_image != NULL) {
2884 		if (open_merge_image(merge_image) < 0) {
2885 			/* Complain and die. */
2886 			comerr(_("Unable to open previous session image '%s'.\n"),
2887 				merge_image);
2888 		}
2889 	}
2890 	/* We don't need root privilleges anymore. */
2891 #ifdef	HAVE_SETREUID
2892 	if (setreuid(-1, getuid()) < 0)
2893 #else
2894 #ifdef	HAVE_SETEUID
2895 	if (seteuid(getuid()) < 0)
2896 #else
2897 	if (setuid(getuid()) < 0)
2898 #endif
2899 #endif
2900 		comerr(_("Panic cannot set back effective uid.\n"));
2901 
2902 
2903 #ifdef	no_more_needed
2904 #ifdef __NetBSD__
2905 	{
2906 		int		resource;
2907 		struct rlimit	rlp;
2908 
2909 		if (getrlimit(RLIMIT_DATA, &rlp) == -1)
2910 			errmsg(_("Warning: Cannot get rlimit.\n"));
2911 		else {
2912 			rlp.rlim_cur = 33554432;
2913 			if (setrlimit(RLIMIT_DATA, &rlp) == -1)
2914 				errmsg(_("Warning: Cannot set rlimit.\n"));
2915 		}
2916 	}
2917 #endif
2918 #endif	/* no_more_needed */
2919 #ifdef HAVE_SBRK
2920 	mem_start = (unsigned long) sbrk(0);
2921 #endif
2922 
2923 	if (verbose > 1) {
2924 		fprintf(stderr, "%s (%s-%s-%s)\n",
2925 				version_string,
2926 				HOST_CPU, HOST_VENDOR, HOST_OS);
2927 	}
2928 	if (cdrecord_data == NULL && !check_session && merge_image != NULL) {
2929 		comerrno(EX_BAD,
2930 		_("Multisession usage bug: Must specify -C if -M is used.\n"));
2931 	}
2932 	if (cdrecord_data != NULL && merge_image == NULL) {
2933 		errmsgno(EX_BAD,
2934 		_("Warning: -C specified without -M: old session data will not be merged.\n"));
2935 	}
2936 #ifdef APPLE_HYB
2937 	if (merge_image != NULL && apple_hyb) {
2938 		errmsgno(EX_BAD,
2939 		_("Warning: files from previous sessions will not be included in the HFS volume.\n"));
2940 	}
2941 #endif	/* APPLE_HYB */
2942 
2943 	/*
2944 	 * see if we have a list of pathnames to process
2945 	 */
2946 	if (pathnames) {
2947 		/* "-" means take list from the standard input */
2948 		if (strcmp(pathnames, "-") != 0) {
2949 			if ((pfp = fopen(pathnames, "r")) == NULL) {
2950 				comerr(_("Unable to open pathname list %s.\n"),
2951 								pathnames);
2952 			}
2953 		} else
2954 			pfp = stdin;
2955 	}
2956 
2957 	/* The first step is to scan the directory tree, and take some notes */
2958 
2959 	if ((arg = get_pnames(argc, argv, argind, pname,
2960 					sizeof (pname), pfp)) == NULL) {
2961 		if (check_session == 0 && !stream_media_size) {
2962 			errmsgno(EX_BAD, _("Missing pathspec.\n"));
2963 			susage(1);
2964 		}
2965 	}
2966 
2967 	/*
2968 	 * if we don't have a pathspec, then save the pathspec found
2969 	 * in the pathnames file (stored in pname) - we don't want
2970 	 * to skip this pathspec when we read the pathnames file again
2971 	 */
2972 	if (!have_cmd_line_pathspec && !stream_media_size) {
2973 		save_pname = 1;
2974 	}
2975 	if (stream_media_size) {
2976 #ifdef	UDF
2977 		if (use_XA || use_RockRidge || use_udf || use_Joliet)
2978 #else
2979 		if (use_XA || use_RockRidge || use_Joliet)
2980 #endif
2981 			comerrno(EX_BAD,
2982 			_("Cannot use XA, Rock Ridge, UDF or Joliet with -stream-media-size\n"));
2983 		if (merge_image)
2984 			comerrno(EX_BAD,
2985 			_("Cannot use multi session with -stream-media-size\n"));
2986 		if (use_eltorito || use_sparcboot || use_sunx86boot ||
2987 #ifdef APPLE_HYB
2988 		    use_genboot || use_prep_boot || hfs_boot_file)
2989 #else
2990 		    use_genboot)
2991 #endif
2992 			comerrno(EX_BAD,
2993 			_("Cannot use boot options with -stream-media-size\n"));
2994 #ifdef APPLE_HYB
2995 		if (apple_hyb)
2996 			comerrno(EX_BAD,
2997 			_("Cannot use Apple hybrid options with -stream-media-size\n"));
2998 #endif
2999 	}
3000 
3001 	if (use_RockRidge) {
3002 		/* BEGIN CSTYLED */
3003 #if 1
3004 		extension_record = generate_rr_extension_record("RRIP_1991A",
3005 			"THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
3006 			"PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.",
3007 			&extension_record_size);
3008 #else
3009 		extension_record = generate_rr_extension_record("IEEE_P1282",
3010 			"THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
3011 			"PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.",
3012 			&extension_record_size);
3013 #endif
3014 		/* END CSTYLED */
3015 	}
3016 	checkarch(outfile);
3017 	if (log_file) {
3018 		FILE		*lfp;
3019 		int		i;
3020 
3021 		/* open log file - test that we can open OK */
3022 		if ((lfp = fopen(log_file, "w")) == NULL) {
3023 			comerr(_("Can't open logfile: '%s'.\n"), log_file);
3024 		}
3025 		fclose(lfp);
3026 
3027 		/* redirect all stderr message to log_file */
3028 		fprintf(stderr, _("re-directing all messages to %s\n"), log_file);
3029 		fflush(stderr);
3030 
3031 		/* associate stderr with the log file */
3032 		if (freopen(log_file, "w", stderr) == NULL) {
3033 			comerr(_("Can't open logfile: '%s'.\n"), log_file);
3034 		}
3035 		if (verbose > 1) {
3036 			for (i = 0; i < argc; i++)
3037 				fprintf(stderr, "%s ", argv[i]);
3038 
3039 			fprintf(stderr, "\n%s (%s-%s-%s)\n",
3040 				version_string,
3041 				HOST_CPU, HOST_VENDOR, HOST_OS);
3042 		}
3043 	}
3044 	/* Find name of root directory. */
3045 	if (arg != NULL)
3046 		node = findgequal(arg);
3047 	if (!use_graft_ptrs)
3048 		node = NULL;
3049 	if (node == NULL) {
3050 		if (use_graft_ptrs && arg != NULL)
3051 			node = escstrcpy(nodename, sizeof (nodename), arg);
3052 		else
3053 			node = arg;
3054 	} else {
3055 		/*
3056 		 * Remove '\\' escape chars which are located
3057 		 * before '\\' and '=' chars
3058 		 */
3059 		node = escstrcpy(nodename, sizeof (nodename), ++node);
3060 	}
3061 
3062 	/*
3063 	 * See if boot catalog file exists in root directory, if not we will
3064 	 * create it.
3065 	 */
3066 	if (use_eltorito)
3067 		init_boot_catalog(node);
3068 
3069 	/*
3070 	 * Find the device and inode number of the root directory. Record this
3071 	 * in the hash table so we don't scan it more than once.
3072 	 */
3073 	stat_filter(node, &statbuf);
3074 	add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
3075 
3076 	memset(&de, 0, sizeof (de));
3077 
3078 	/*
3079 	 * PO:
3080 	 * Isn't root NULL at this time anyway?
3081 	 * I think it is created by the first call to
3082 	 * find_or_create_directory() below.
3083 	 */
3084 	de.filedir = root;	/* We need this to bootstrap */
3085 
3086 	if (cdrecord_data != NULL && merge_image == NULL) {
3087 		/*
3088 		 * in case we want to add a new session, but don't want to
3089 		 * merge old one
3090 		 */
3091 		get_session_start(NULL);
3092 	}
3093 	if (merge_image != NULL) {
3094 		char	sector[SECTOR_SIZE];
3095 		UInt32_t extent;
3096 
3097 		errno = 0;
3098 		mrootp = merge_isofs(merge_image);
3099 		if (mrootp == NULL) {
3100 			/* Complain and die. */
3101 			if (errno == 0)
3102 				errno = -1;
3103 			comerr(_("Unable to find previous session PVD '%s'.\n"),
3104 				merge_image);
3105 		}
3106 		memcpy(de.isorec.extent, mrootp->extent, 8);
3107 
3108 		/*
3109 		 * Look for RR Attributes in '.' entry of root dir.
3110 		 * This is the first ISO directory entry in the root dir.
3111 		 */
3112 		extent = get_733(mrootp->extent);
3113 		readsecs(extent, sector, 1);
3114 		c = rr_flags((struct iso_directory_record *)sector);
3115 		if (c & RR_FLAG_XA)
3116 			fprintf(stderr, _("XA signatures found\n"));
3117 		if (c & RR_FLAG_AA)
3118 			fprintf(stderr, _("AA signatures found\n"));
3119 		if (c & ~(RR_FLAG_XA|RR_FLAG_AA)) {
3120 			extern	int	su_version;
3121 			extern	int	rr_version;
3122 			extern	char	er_id[];
3123 
3124 			if (c & RR_FLAG_SP) {
3125 				fprintf(stderr, _("SUSP signatures version %d found\n"), su_version);
3126 				if (c & RR_FLAG_ER) {
3127 					if (rr_version < 1) {
3128 						fprintf(stderr,
3129 							_("No valid Rock Ridge signature found\n"));
3130 						if (!force_rr)
3131 							no_rr++;
3132 					} else {
3133 						fprintf(stderr,
3134 							_("Rock Ridge signatures version %d found\n"),
3135 						rr_version);
3136 						fprintf(stderr,
3137 							_("Rock Ridge id '%s'\n"), er_id);
3138 					}
3139 				}
3140 			} else {
3141 				fprintf(stderr, _("Bad Rock Ridge signatures found (SU record missing)\n"));
3142 				if (!force_rr)
3143 					no_rr++;
3144 			}
3145 		} else {
3146 			fprintf(stderr, _("No SUSP/Rock Ridge present\n"));
3147 			if ((c & (RR_FLAG_XA|RR_FLAG_AA)) == 0) {
3148 				if (!force_rr)
3149 					no_rr++;
3150 			}
3151 		}
3152 		if (no_rr)
3153 			fprintf(stderr, _("Disabling Rock Ridge / XA / AA\n"));
3154 	}
3155 	/*
3156 	 * Create an empty root directory. If we ever scan it for real,
3157 	 * we will fill in the contents.
3158 	 */
3159 	find_or_create_directory(NULL, "", &de, TRUE);
3160 
3161 #ifdef APPLE_HYB
3162 	/* may need to set window layout of the volume */
3163 	if (root_info)
3164 		set_root_info(root_info);
3165 #endif /* APPLE_HYB */
3166 
3167 	/*
3168 	 * Scan the actual directory (and any we find below it) for files to
3169 	 * write out to the output image.  Note - we take multiple source
3170 	 * directories and keep merging them onto the image.
3171 	 */
3172 	if (check_session)
3173 		goto path_done;
3174 
3175 #ifdef	USE_FIND
3176 	if (dofind) {
3177 extern		int	walkfunc	__PR((char *nm, struct stat *fs, int type, struct WALK *state));
3178 
3179 		walkinitstate(&walkstate);
3180 		if (find_patlen > 0) {
3181 			walkstate.patstate = ___malloc(sizeof (int) * find_patlen,
3182 						_("space for pattern state"));
3183 		}
3184 
3185 		find_timeinit(time(0));
3186 		walkstate.walkflags	= walkflags;
3187 		walkstate.maxdepth	= maxdepth;
3188 		walkstate.mindepth	= mindepth;
3189 		walkstate.lname		= NULL;
3190 		walkstate.tree		= find_node;
3191 		walkstate.err		= 0;
3192 		walkstate.pflags	= 0;
3193 
3194 		nodesc = TRUE;
3195 		for (;
3196 		    (arg = get_pnames(argc, argv, argind, pname, sizeof (pname),
3197 							pfp)) != NULL;
3198 								argind++) {
3199 			/*
3200 			 * Make silly GCC happy and double initialize graft_dir.
3201 			 */
3202 			struct directory *graft_dir = NULL;
3203 			char		graft_point[PATH_MAX + 1];
3204 			struct wargs	wa;
3205 			char		*snp;
3206 
3207 			graft_point[0] = '\0';
3208 			snp = NULL;
3209 			if (use_graft_ptrs)
3210 				graft_dir = get_graft(arg,
3211 						    graft_point, sizeof (graft_point),
3212 						    nodename, sizeof (nodename),
3213 						    &snp, FALSE);
3214 			if (graft_point[0] != '\0') {
3215 				arg = nodename;
3216 				wa.dir = graft_dir;
3217 			} else {
3218 				wa.dir = root;
3219 			}
3220 			wa.name = snp;
3221 			walkstate.auxp = &wa;
3222 			walkstate.auxi = strlen(arg);
3223 			treewalk(arg, walkfunc, &walkstate);
3224 			no_path_names = 0;
3225 		}
3226 		find_plusflush(plusp, &walkstate);
3227 	} else
3228 #endif
3229 
3230 	while ((arg = get_pnames(argc, argv, argind, pname,
3231 					sizeof (pname), pfp)) != NULL) {
3232 		char		graft_point[PATH_MAX + 1];
3233 
3234 		get_graft(arg, graft_point, sizeof (graft_point),
3235 				nodename, sizeof (nodename), NULL, TRUE);
3236 		argind++;
3237 		no_path_names = 0;
3238 	}
3239 
3240 path_done:
3241 	if (pfp && pfp != stdin)
3242 		fclose(pfp);
3243 
3244 	/*
3245 	 * exit if we don't have any pathnames to process
3246 	 * - not going to happen at the moment as we have to have at least one
3247 	 * path on the command line
3248 	 */
3249 	if (no_path_names && !check_session && !stream_media_size) {
3250 		errmsgno(EX_BAD, _("No pathnames found.\n"));
3251 		susage(1);
3252 	}
3253 	/*
3254 	 * Now merge in any previous sessions.  This is driven on the source
3255 	 * side, since we may need to create some additional directories.
3256 	 */
3257 	if (merge_image != NULL) {
3258 		if (merge_previous_session(root, mrootp,
3259 					reloc_root, reloc_old_root) < 0) {
3260 			comerrno(EX_BAD, _("Cannot merge previous session.\n"));
3261 		}
3262 		close_merge_image();
3263 
3264 		/*
3265 		 * set up parent_dir and filedir in relocated entries which
3266 		 * were read from previous session so that
3267 		 * finish_cl_pl_entries can do its job
3268 		 */
3269 		match_cl_re_entries();
3270 		free(mrootp);
3271 	}
3272 #ifdef APPLE_HYB
3273 	/* free up any HFS filename mapping memory */
3274 	if (apple_both)
3275 		clean_hfs();
3276 #endif	/* APPLE_HYB */
3277 
3278 	/* hide "./rr_moved" if all its contents have been hidden */
3279 	if (reloc_dir && i_ishidden())
3280 		hide_reloc_dir();
3281 
3282 	/* insert the boot catalog if required */
3283 	if (use_eltorito)
3284 		insert_boot_cat();
3285 
3286 	/*
3287 	 * Free up any matching memory
3288 	 */
3289 	for (n = 0; n < MAX_MAT; n++)
3290 		gen_del_match(n);
3291 
3292 #ifdef SORTING
3293 	del_sort();
3294 #endif /* SORTING */
3295 
3296 	/*
3297 	 * Sort the directories in the required order (by ISO9660).  Also,
3298 	 * choose the names for the 8.3 filesystem if required, and do any
3299 	 * other post-scan work.
3300 	 */
3301 	goof += sort_tree(root);
3302 
3303 	if (goof) {
3304 		comerrno(EX_BAD, _("ISO9660/Rock Ridge tree sort failed.\n"));
3305 	}
3306 #ifdef UDF
3307 	if (use_Joliet || use_udf) {
3308 #else
3309 	if (use_Joliet) {
3310 #endif
3311 		goof += joliet_sort_tree(root);
3312 	}
3313 	if (goof) {
3314 		comerrno(EX_BAD, _("Joliet tree sort failed.\n"));
3315 	}
3316 	/*
3317 	 * Fix a couple of things in the root directory so that everything is
3318 	 * self consistent. Fix this up so that the path tables get done right.
3319 	 */
3320 	root->self = root->contents;
3321 
3322 	/* OK, ready to write the file.  Open it up, and generate the thing. */
3323 	if (print_size) {
3324 		discimage = fopen(DEV_NULL, "wb");
3325 		if (!discimage) {
3326 			comerr(_("Unable to open /dev/null\n"));
3327 		}
3328 	} else if (outfile != NULL &&
3329 			!(outfile[0] == '-' && outfile[1] == '\0')) {
3330 		discimage = fopen(outfile, "wb");
3331 		if (!discimage) {
3332 			comerr(_("Unable to open disc image file '%s'.\n"), outfile);
3333 		}
3334 	} else {
3335 		discimage = stdout;
3336 		setmode(fileno(stdout), O_BINARY);
3337 	}
3338 #ifdef	HAVE_SETVBUF
3339 	setvbuf(discimage, NULL, _IOFBF, 64*1024);
3340 #endif
3341 
3342 	/* Now assign addresses on the disc for the path table. */
3343 
3344 	path_blocks = ISO_BLOCKS(path_table_size);
3345 	if (path_blocks & 1)
3346 		path_blocks++;
3347 
3348 	jpath_blocks = ISO_BLOCKS(jpath_table_size);
3349 	if (jpath_blocks & 1)
3350 		jpath_blocks++;
3351 
3352 	/*
3353 	 * Start to set up the linked list that we use to track the contents
3354 	 * of the disc.
3355 	 */
3356 #ifdef APPLE_HYB
3357 #ifdef PREP_BOOT
3358 	if ((apple_hyb && !donotwrite_macpart) || use_prep_boot || use_chrp_boot)
3359 #else	/* PREP_BOOT */
3360 	if (apple_hyb && !donotwrite_macpart)
3361 #endif	/* PREP_BOOT */
3362 		outputlist_insert(&hfs_desc);
3363 #endif	/* APPLE_HYB */
3364 	if (use_sparcboot || use_sunx86boot)
3365 		outputlist_insert(&sunlabel_desc);
3366 	if (use_genboot)
3367 		outputlist_insert(&genboot_desc);
3368 	outputlist_insert(&startpad_desc);
3369 
3370 	/* PVD for disc. */
3371 	outputlist_insert(&voldesc_desc);
3372 
3373 	/* SVD for El Torito. MUST be immediately after the PVD! */
3374 	if (use_eltorito) {
3375 		outputlist_insert(&torito_desc);
3376 	}
3377 	/* Enhanced PVD for disc. neded if we write ISO-9660:1999 */
3378 	if (iso9660_level > 3)
3379 		outputlist_insert(&xvoldesc_desc);
3380 
3381 	/* SVD for Joliet. */
3382 	if (use_Joliet) {
3383 		outputlist_insert(&joliet_desc);
3384 	}
3385 	/* Finally the last volume descriptor. */
3386 	outputlist_insert(&end_vol);
3387 
3388 #ifdef UDF
3389 	if (use_udf) {
3390 		outputlist_insert(&udf_vol_recognition_area_frag);
3391 	}
3392 #endif
3393 
3394 	/* Insert the version descriptor. */
3395 	outputlist_insert(&version_desc);
3396 
3397 #ifdef UDF
3398 	if (use_udf) {
3399 		/*
3400 		 * Most of the space before sector 256 is wasted when
3401 		 * UDF is turned on. The waste could be reduced by
3402 		 * putting the ISO9660/Joliet structures before the
3403 		 * pad_to_sector_256; the problem is that they might
3404 		 * overshoot sector 256, so there would have to be some
3405 		 * ugly logic to detect this case and rearrange things
3406 		 * appropriately. I don't know if it's worth it.
3407 		 */
3408 		outputlist_insert(&udf_pad_to_sector_32_frag);
3409 		outputlist_insert(&udf_main_seq_frag);
3410 		outputlist_insert(&udf_main_seq_copy_frag);
3411 		outputlist_insert(&udf_integ_seq_frag);
3412 		outputlist_insert(&udf_pad_to_sector_256_frag);
3413 		outputlist_insert(&udf_anchor_vol_desc_frag);
3414 		outputlist_insert(&udf_file_set_desc_frag);
3415 		outputlist_insert(&udf_dirtree_frag);
3416 		outputlist_insert(&udf_file_entries_frag);
3417 	}
3418 #endif
3419 
3420 	/* Now start with path tables and directory tree info. */
3421 	if (!stream_media_size)
3422 		outputlist_insert(&pathtable_desc);
3423 	else
3424 		outputlist_insert(&strpath_desc);
3425 
3426 	if (use_Joliet) {
3427 		outputlist_insert(&jpathtable_desc);
3428 	}
3429 
3430 	if (!stream_media_size)
3431 		outputlist_insert(&dirtree_desc);
3432 
3433 	if (use_Joliet) {
3434 		outputlist_insert(&jdirtree_desc);
3435 	}
3436 	outputlist_insert(&dirtree_clean);
3437 
3438 	if (extension_record) {
3439 		outputlist_insert(&extension_desc);
3440 	}
3441 
3442 	if (!stream_media_size) {
3443 		outputlist_insert(&files_desc);
3444 	} else {
3445 		outputlist_insert(&strfile_desc);
3446 		outputlist_insert(&strdir_desc);
3447 	}
3448 
3449 	/*
3450 	 * Allow room for the various headers we will be writing.
3451 	 * There will always be a primary and an end volume descriptor.
3452 	 */
3453 	last_extent = session_start;
3454 
3455 	/*
3456 	 * Calculate the size of all of the components of the disc, and assign
3457 	 * extent numbers.
3458 	 */
3459 	for (opnt = out_list; opnt; opnt = opnt->of_next) {
3460 		opnt->of_start_extent = last_extent;
3461 		if (opnt->of_size != NULL) {
3462 			if (verbose > 2)
3463 				fprintf(stderr, _("Computing size: %-40sStart Block %u\n"),
3464 					opnt->of_name, last_extent);
3465 			(*opnt->of_size) (last_extent);
3466 		}
3467 	}
3468 
3469 	/*
3470 	 * Generate the contents of any of the sections that we want to
3471 	 * generate. Not all of the fragments will do anything here
3472 	 * - most will generate the data on the fly when we get to the write
3473 	 * pass.
3474 	 */
3475 	for (opnt = out_list; opnt; opnt = opnt->of_next) {
3476 		if (opnt->of_generate != NULL) {
3477 			if (verbose > 2)
3478 				fprintf(stderr, _("Generating content: %-40s\n"),
3479 					opnt->of_name);
3480 			(*opnt->of_generate) ();
3481 		}
3482 	}
3483 
3484 	/*
3485 	 * Padding just after the ISO-9660 filesystem.
3486 	 *
3487 	 * files_desc does not have an of_size function. For this
3488 	 * reason, we must insert us after the files content has been
3489 	 * generated.
3490 	 */
3491 #ifdef UDF
3492 	if (use_udf) {
3493 		/* Single anchor volume descriptor pointer at end */
3494 		outputlist_insert(&udf_end_anchor_vol_desc_frag);
3495 		if (udf_end_anchor_vol_desc_frag.of_size != NULL) {
3496 			(*udf_end_anchor_vol_desc_frag.of_size) (last_extent);
3497 		}
3498 		if (dopad) {
3499 			/*
3500 			 * Pad with anchor volume descriptor pointer
3501 			 * blocks instead of zeroes.
3502 			 */
3503 			outputlist_insert(&udf_padend_avdp_frag);
3504 			if (udf_padend_avdp_frag.of_size != NULL) {
3505 				(*udf_padend_avdp_frag.of_size) (last_extent);
3506 			}
3507 		}
3508 	} else
3509 #endif
3510 	if (dopad && !(use_sparcboot || use_sunx86boot)) {
3511 		outputlist_insert(&endpad_desc);
3512 		if (endpad_desc.of_size != NULL) {
3513 			(*endpad_desc.of_size) (last_extent);
3514 		}
3515 	}
3516 	c = 0;
3517 	if (use_sparcboot) {
3518 		if (dopad) {
3519 			/* Padding before the boot partitions. */
3520 			outputlist_insert(&interpad_desc);
3521 			if (interpad_desc.of_size != NULL) {
3522 				(*interpad_desc.of_size) (last_extent);
3523 			}
3524 		}
3525 		c = make_sun_label();
3526 		last_extent += c;
3527 		outputlist_insert(&sunboot_desc);
3528 		if (dopad) {
3529 			outputlist_insert(&endpad_desc);
3530 			if (endpad_desc.of_size != NULL) {
3531 				(*endpad_desc.of_size) (last_extent);
3532 			}
3533 		}
3534 	} else if (use_sunx86boot) {
3535 		if (dopad) {
3536 			/* Padding before the boot partitions. */
3537 			outputlist_insert(&interpad_desc);
3538 			if (interpad_desc.of_size != NULL) {
3539 				(*interpad_desc.of_size) (last_extent);
3540 			}
3541 		}
3542 		c = make_sunx86_label();
3543 		last_extent += c;
3544 		outputlist_insert(&sunboot_desc);
3545 		if (dopad) {
3546 			outputlist_insert(&endpad_desc);
3547 			if (endpad_desc.of_size != NULL) {
3548 				(*endpad_desc.of_size) (last_extent);
3549 			}
3550 		}
3551 	}
3552 	if (print_size > 0) {
3553 		if (verbose > 0)
3554 			fprintf(stderr,
3555 			_("Total extents scheduled to be written = %u\n"),
3556 			(last_extent - session_start));
3557 		printf("%u\n", (last_extent - session_start));
3558 		exit(0);
3559 	}
3560 	/*
3561 	 * Now go through the list of fragments and write the data that
3562 	 * corresponds to each one.
3563 	 */
3564 	for (opnt = out_list; opnt; opnt = opnt->of_next) {
3565 		Uint	oext;
3566 
3567 		oext = last_extent_written;
3568 		if (opnt->of_start_extent != 0 &&
3569 		    opnt->of_start_extent != last_extent_written) {
3570 			/*
3571 			 * Consistency check.
3572 			 * XXX Should make sure that all entries have
3573 			 * XXXX of_start_extent set up correctly.
3574 			 */
3575 			comerrno(EX_BAD,
3576 			_("Implementation botch: %s should start at %u but starts at %u.\n"),
3577 			opnt->of_name, opnt->of_start_extent, last_extent_written);
3578 		}
3579 		if (opnt->of_write != NULL) {
3580 			if (verbose > 1)
3581 				fprintf(stderr, _("Writing:   %-40sStart Block %u\n"),
3582 					opnt->of_name, last_extent_written);
3583 			(*opnt->of_write) (discimage);
3584 			if (verbose > 1)
3585 				fprintf(stderr, _("Done with: %-40sBlock(s)    %u\n"),
3586 					opnt->of_name, last_extent_written-oext);
3587 		}
3588 	}
3589 	if (last_extent != last_extent_written) {
3590 		comerrno(EX_BAD,
3591 		_("Implementation botch: FS should end at %u but ends at %u.\n"),
3592 				last_extent, last_extent_written);
3593 	}
3594 
3595 	if (verbose > 0) {
3596 #ifdef HAVE_SBRK
3597 		fprintf(stderr, _("Max brk space used %x\n"),
3598 			(unsigned int)(((unsigned long) sbrk(0)) - mem_start));
3599 #endif
3600 		fprintf(stderr, _("%u extents written (%u MB)\n"),
3601 			(last_extent-session_start),
3602 			(last_extent-session_start) >> 9);
3603 	}
3604 #ifdef VMS
3605 	return (1);
3606 #else
3607 	return (0);
3608 #endif
3609 }
3610 
3611 LOCAL void
list_locales()3612 list_locales()
3613 {
3614 	int	n;
3615 
3616 	n = sic_list(stdout);
3617 	if (n <= 0) {
3618 		const char	*ins_base = sic_base();
3619 
3620 		if (ins_base == NULL)
3621 			ins_base = "$INS_BASE/lib/siconv/";
3622 		errmsgno(EX_BAD, _("Installation problem: '%s' %s.\n"),
3623 			ins_base, n < 0 ? _("missing"):_("incomplete"));
3624 		if (n == 0) {
3625 			errmsgno(EX_BAD,
3626 			_("Check '%s' for missing translation tables.\n"),
3627 			ins_base);
3628 		}
3629 	}
3630 #ifdef	USE_ICONV
3631 	if (n > 0) {
3632 		errmsgno(EX_BAD,
3633 		_("'iconv -l' lists more available names.\n"));
3634 	}
3635 #endif
3636 }
3637 
3638 /*
3639  * Find unescaped equal sign in graft pointer string.
3640  */
3641 EXPORT char *
findgequal(s)3642 findgequal(s)
3643 	char	*s;
3644 {
3645 	char	*p = s;
3646 
3647 	while ((p = strchr(p, '=')) != NULL) {
3648 		if (p > s && p[-1] != '\\')
3649 			return (p);
3650 		p++;
3651 	}
3652 	return (NULL);
3653 }
3654 
3655 /*
3656  * Find unescaped equal sign in string.
3657  */
3658 LOCAL char *
escstrcpy(to,tolen,from)3659 escstrcpy(to, tolen, from)
3660 	char	*to;
3661 	size_t	tolen;
3662 	char	*from;
3663 {
3664 	char	*p = to;
3665 
3666 	if (debug)
3667 		error("FROM: '%s'\n", from);
3668 
3669 	to[0] = '\0';
3670 	if (tolen > 0) {
3671 		to[--tolen] = '\0';	/* Fill in last nul char   */
3672 	}
3673 	while ((*p = *from++) != '\0' && tolen-- > 0) {
3674 		if (*p == '\\') {
3675 			if ((*p = *from++) == '\0')
3676 				break;
3677 			if (*p != '\\' && *p != '=') {
3678 				p[1] = p[0];
3679 				*p++ = '\\';
3680 			}
3681 		}
3682 		p++;
3683 	}
3684 	if (debug)
3685 		error("ESC:  '%s'\n", to);
3686 	return (to);
3687 }
3688 
3689 struct directory *
get_graft(arg,graft_point,glen,nodename,nlen,short_namep,do_insert)3690 get_graft(arg, graft_point, glen, nodename, nlen, short_namep, do_insert)
3691 	char		*arg;
3692 	char		*graft_point;
3693 	size_t		glen;
3694 	char		*nodename;
3695 	size_t		nlen;
3696 	char		**short_namep;
3697 	BOOL		do_insert;
3698 {
3699 	char		*node = NULL;
3700 	struct directory_entry de;
3701 	struct directory *graft_dir = root;
3702 	struct stat	st;
3703 	char		*short_name;
3704 	int		status;
3705 
3706 	fillbytes(&de, sizeof (de), '\0');
3707 	/*
3708 	 * We would like a syntax like:
3709 	 *
3710 	 *	/tmp=/usr/tmp/xxx
3711 	 *
3712 	 * where the user can specify a place to graft each component
3713 	 * of the tree.  To do this, we may have to create directories
3714 	 * along the way, of course. Secondly, I would like to allow
3715 	 * the user to do something like:
3716 	 *
3717 	 *	/home/baz/RMAIL=/u3/users/baz/RMAIL
3718 	 *
3719 	 * so that normal files could also be injected into the tree
3720 	 * at an arbitrary point.
3721 	 *
3722 	 * The idea is that the last component of whatever is being
3723 	 * entered would take the name from the last component of
3724 	 * whatever the user specifies.
3725 	 *
3726 	 * The default will be that the file is injected at the root of
3727 	 * the image tree.
3728 	 */
3729 	node = findgequal(arg);
3730 	if (!use_graft_ptrs)
3731 		node = NULL;
3732 	/*
3733 	 * Remove '\\' escape chars which are located
3734 	 * before '\\' and '=' chars ---> below in escstrcpy()
3735 	 */
3736 
3737 	short_name = NULL;
3738 
3739 	if (node != NULL || reloc_root) {
3740 		char		*pnt;
3741 		char		*xpnt;
3742 		size_t		len;
3743 
3744 		/* insert -root prefix */
3745 		if (reloc_root != NULL) {
3746 			strlcpy(graft_point, reloc_root, glen);
3747 			len = strlen(graft_point);
3748 
3749 			if ((len < (glen -1)) &&
3750 			    (len == 0 || graft_point[len-1] != '/')) {
3751 				graft_point[len++] = '/';
3752 				graft_point[len] = '\0';
3753 			}
3754 		} else {
3755 			len = 0;
3756 		}
3757 
3758 		if (node) {
3759 			*node = '\0';
3760 			escstrcpy(&graft_point[len], glen - len, arg);
3761 			*node = '=';
3762 		}
3763 
3764 		/*
3765 		 * Remove unwanted "./" & "/" sequences from start...
3766 		 */
3767 		do {
3768 			xpnt = graft_point;
3769 			while (xpnt[0] == '.' && xpnt[1] == '/')
3770 				xpnt += 2;
3771 			while (*xpnt == PATH_SEPARATOR) {
3772 				xpnt++;
3773 			}
3774 			/*
3775 			 * The string becomes shorter, there is no need to check
3776 			 * the length. Make sure to support overlapping strings.
3777 			 */
3778 			ovstrcpy(graft_point, xpnt);
3779 		} while (xpnt > graft_point);
3780 
3781 		if (node) {
3782 			node = escstrcpy(nodename, nlen, ++node);
3783 		} else {
3784 			node = arg;
3785 		}
3786 
3787 		graft_dir = root;
3788 		xpnt = graft_point;
3789 
3790 		/*
3791 		 * If "node" points to a directory, then graft_point
3792 		 * needs to point to a directory too.
3793 		 */
3794 		if (follow_links)
3795 			status = stat_filter(node, &st);
3796 		else
3797 			status = lstat_filter(node, &st);
3798 		if (status == 0 && S_ISDIR(st.st_mode)) {
3799 			len = strlen(graft_point);
3800 
3801 			if ((len < (glen -1)) &&
3802 			    (len == 0 || graft_point[len-1] != '/')) {
3803 				graft_point[len++] = '/';
3804 				graft_point[len] = '\0';
3805 			}
3806 		}
3807 		if (debug)
3808 			error("GRAFT:'%s'\n", xpnt);
3809 		/*
3810 		 * Loop down deeper and deeper until we find the
3811 		 * correct insertion spot.
3812 		 * Canonicalize the filename while parsing it.
3813 		 */
3814 		for (;;) {
3815 			do {
3816 				while (xpnt[0] == '.' && xpnt[1] == '/')
3817 					xpnt += 2;
3818 				while (xpnt[0] == '/')
3819 					xpnt += 1;
3820 				if (xpnt[0] == '.' && xpnt[1] == '.' && xpnt[2] == '/') {
3821 					if (graft_dir && graft_dir != root) {
3822 						graft_dir = graft_dir->parent;
3823 						xpnt += 2;
3824 					}
3825 				}
3826 			} while ((xpnt[0] == '/') || (xpnt[0] == '.' && xpnt[1] == '/'));
3827 			pnt = strchr(xpnt, PATH_SEPARATOR);
3828 			if (pnt == NULL) {
3829 				if (*xpnt != '\0') {
3830 					short_name = xpnt;
3831 					if (short_namep)
3832 						*short_namep = xpnt;
3833 				}
3834 				break;
3835 			}
3836 			*pnt = '\0';
3837 			if (debug) {
3838 				error("GRAFT Point:'%s' in '%s : %s' (%s)\n",
3839 					xpnt,
3840 					graft_dir->whole_name,
3841 					graft_dir->de_name,
3842 					graft_point);
3843 			}
3844 			graft_dir = find_or_create_directory(graft_dir,
3845 				graft_point,
3846 				NULL, TRUE);
3847 			*pnt = PATH_SEPARATOR;
3848 			xpnt = pnt + 1;
3849 		}
3850 	} else {
3851 		graft_dir = root;
3852 		if (use_graft_ptrs)
3853 			node = escstrcpy(nodename, nlen, arg);
3854 		else
3855 			node = arg;
3856 	}
3857 
3858 	/*
3859 	 * Now see whether the user wants to add a regular file, or a
3860 	 * directory at this point.
3861 	 */
3862 	if (follow_links || Hflag)
3863 		status = stat_filter(node, &st);
3864 	else
3865 		status = lstat_filter(node, &st);
3866 	if (status != 0) {
3867 		/*
3868 		 * This is a fatal error - the user won't be getting
3869 		 * what they want if we were to proceed.
3870 		 */
3871 		comerr(_("Invalid node - '%s'.\n"), node);
3872 	} else {
3873 		if (S_ISDIR(st.st_mode)) {
3874 			if (debug) {
3875 				error(_("graft_dir: '%s : %s', node: '%s', (scan)\n"),
3876 					graft_dir->whole_name,
3877 					graft_dir->de_name, node);
3878 			}
3879 			if (!do_insert)
3880 				return (graft_dir);
3881 			if (!scan_directory_tree(graft_dir,
3882 							node, &de)) {
3883 				exit(1);
3884 			}
3885 			if (debug) {
3886 				error(_("scan done\n"));
3887 			}
3888 		} else {
3889 			if (short_name == NULL) {
3890 				short_name = strrchr(node,
3891 						PATH_SEPARATOR);
3892 				if (short_name == NULL ||
3893 						short_name < node) {
3894 					short_name = node;
3895 				} else {
3896 					short_name++;
3897 				}
3898 			}
3899 			if (debug) {
3900 				error(_("graft_dir: '%s : %s', node: '%s', short_name: '%s'\n"),
3901 					graft_dir->whole_name,
3902 					graft_dir->de_name, node,
3903 					short_name);
3904 			}
3905 			if (!do_insert)
3906 				return (graft_dir);
3907 			if (!insert_file_entry(graft_dir, node,
3908 							short_name, NULL, 0)) {
3909 				/*
3910 				 * Should we ignore this?
3911 				 */
3912 /*				exit(1);*/
3913 				/* EMPTY */
3914 			}
3915 		}
3916 	}
3917 	return (graft_dir);
3918 }
3919 
3920 EXPORT void *
e_malloc(size)3921 e_malloc(size)
3922 	size_t		size;
3923 {
3924 	void		*pt = 0;
3925 
3926 	if (size == 0)
3927 		size = 1;
3928 	if ((pt = malloc(size)) == NULL) {
3929 		comerr(_("Not enough memory\n"));
3930 	}
3931 	/*
3932 	 * Not all code is clean yet.
3933 	 * Filling all allocated data with zeroes will help
3934 	 * to avoid core dumps.
3935 	 */
3936 	memset(pt, 0, size);
3937 	return (pt);
3938 }
3939 
3940 EXPORT char *
e_strdup(s)3941 e_strdup(s)
3942 	const	char	*s;
3943 {
3944 	char	*ret = strdup(s);
3945 
3946 	if (s == NULL)
3947 		comerr(_("Not enough memory for strdup(%s)\n"), s);
3948 	return (ret);
3949 }
3950 
3951 /*
3952  * A strcpy() that works with overlapping buffers
3953  */
3954 LOCAL void
ovstrcpy(p2,p1)3955 ovstrcpy(p2, p1)
3956 	register char	*p2;
3957 	register char	*p1;
3958 {
3959 	while ((*p2++ = *p1++) != '\0')
3960 		;
3961 }
3962 
3963 LOCAL void
checkarch(name)3964 checkarch(name)
3965 	char	*name;
3966 {
3967 	struct stat	stbuf;
3968 
3969 	archive_isreg = FALSE;
3970 	archive_dev = (dev_t)0;
3971 	archive_ino = (ino_t)0;
3972 
3973 	if (name == NULL)
3974 		return;
3975 	if (stat(name, &stbuf) < 0)
3976 		return;
3977 
3978 	if (S_ISREG(stbuf.st_mode)) {
3979 		archive_dev = stbuf.st_dev;
3980 		archive_ino = stbuf.st_ino;
3981 		archive_isreg = TRUE;
3982 	} else if (((stbuf.st_mode & S_IFMT) == 0) ||
3983 			S_ISFIFO(stbuf.st_mode) ||
3984 			S_ISSOCK(stbuf.st_mode)) {
3985 		/*
3986 		 * This is a pipe or similar on different UNIX implementations.
3987 		 * (stbuf.st_mode & S_IFMT) == 0 may happen in stange cases.
3988 		 */
3989 		archive_dev = NODEV;
3990 		archive_ino = (ino_t)-1;
3991 	}
3992 }
3993