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