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