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