/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ /* * * Patched version with stuff from the Debian's cdrtools. * Replaced various warnings/disclaimers with more simple ones. * * Eduard Bloch */ /* @(#)mkisofs.c 1.167 06/01/30 joerg */ /* Parts from @(#)mkisofs.c 1.206 07/02/26 joerg */ /* * Program genisoimage.c - generate iso9660 filesystem based upon directory * tree on hard disk. * * Written by Eric Youngdale (1993). * * Copyright 1993 Yggdrasil Computing, Incorporated * Copyright (c) 1999,2000-2004 J. Schilling * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 22/2/2000 */ #include #include "genisoimage.h" #include #include #include #include #include "match.h" #include "exclude.h" #include /* For UNICODE translation */ #include #ifdef UDF #include "udf.h" #endif #ifdef NEED_O_BINARY #include /* for setmode() prototype */ #endif #ifdef HAVE_GETOPT_H #include #else #include "getopt.h" extern int optind; extern char *optarg; #endif #ifdef VMS #include "vms.h" #endif #ifdef no_more_needed #ifdef __NetBSD__ #include #endif #endif /* no_more_needed */ #ifdef USE_ICONV #include #include #endif struct directory *root = NULL; int path_ind; char version_string[] = "genisoimage " CDRKIT_VERSION; char *outfile; FILE *discimage; unsigned int next_extent = 0; unsigned int last_extent = 0; unsigned int session_start = 0; unsigned int path_table_size = 0; unsigned int path_table[4] = {0, }; unsigned int path_blocks = 0; unsigned int jpath_table_size = 0; unsigned int jpath_table[4] = {0, }; unsigned int jpath_blocks = 0; struct iso_directory_record root_record; struct iso_directory_record jroot_record; char *extension_record = NULL; int extension_record_extent = 0; int extension_record_size = 0; /* These variables are associated with command line options */ int check_oldnames = 0; int check_session = 0; int use_eltorito = 0; int hard_disk_boot = 0; int not_bootable = 0; int no_emul_boot = 0; int load_addr = 0; int load_size = 0; int boot_info_table = 0; int use_alphaboot = 0; int use_sparcboot = 0; int use_hppaboot = 0; int use_mipsboot = 0; int use_mipselboot = 0; int use_sunx86boot = 0; int use_genboot = 0; int use_RockRidge = 0; int use_XA = 0; int osecsize = 0; /* Output-sector size, 0 means default secsize 2048 */ int use_Joliet = 0; int jlen = JMAX; /* maximum Joliet file name length */ int verbose = 1; int debug = 0; int gui = 0; int all_files = 1; /* New default is to include all files */ int follow_links = 0; #ifdef IS_CYGWIN int cache_inodes = 0; /* Do not cache inodes on Cygwin by default */ #else int cache_inodes = 1; /* Cache inodes if OS has unique inodes */ #endif int rationalize = 0; int rationalize_uid = 0; int rationalize_gid = 0; int rationalize_filemode = 0; int rationalize_dirmode = 0; uid_t uid_to_use = 0; /* when rationalizing uid */ gid_t gid_to_use = 0; /* when rationalizing gid */ int filemode_to_use = 0; /* if non-zero, when rationalizing file mode */ int dirmode_to_use = 0; /* if non-zero, when rationalizing dir mode */ int new_dir_mode = 0555; int generate_tables = 0; int dopad = 1; /* Now default to do padding */ int print_size = 0; int split_output = 0; char *icharset = NULL; /* input charset to convert to UNICODE */ char *ocharset = NULL; /* output charset to convert from UNICODE */ char *preparer = PREPARER_DEFAULT; char *publisher = PUBLISHER_DEFAULT; char *appid = APPID_DEFAULT; char *copyright = COPYRIGHT_DEFAULT; char *biblio = BIBLIO_DEFAULT; char *abstract = ABSTRACT_DEFAULT; char *volset_id = VOLSET_ID_DEFAULT; char *volume_id = VOLUME_ID_DEFAULT; char *system_id = SYSTEM_ID_DEFAULT; char *boot_catalog = BOOT_CATALOG_DEFAULT; char *boot_image = BOOT_IMAGE_DEFAULT; char *genboot_image = BOOT_IMAGE_DEFAULT; int ucs_level = 3; /* We now have Unicode tables so use level 3 */ int volume_set_size = 1; int volume_sequence_number = 1; struct eltorito_boot_entry_info *first_boot_entry = NULL; struct eltorito_boot_entry_info *last_boot_entry = NULL; struct eltorito_boot_entry_info *current_boot_entry = NULL; int use_graft_ptrs; /* Use graft points */ int jhide_trans_tbl; /* Hide TRANS.TBL from Joliet tree */ int hide_rr_moved; /* Name RR_MOVED .rr_moved in Rock Ridge tree */ int omit_period = 0; /* Violates iso9660, but these are a pain */ int transparent_compression = 0; /* So far only works with linux */ int omit_version_number = 0; /* May violate iso9660, but noone uses vers */ int no_rr = 0; /* Do not use RR attributes from old session */ int force_rr = 0; /* Force to use RR attributes from old session */ Uint RR_relocation_depth = 6; /* Violates iso9660, but most systems work */ int iso9660_level = 1; int iso9660_namelen = LEN_ISONAME; /* 31 characters, may be set to 37 */ int full_iso9660_filenames = 0; /* Full 31 character iso9660 filenames */ int relaxed_filenames = 0; /* For Amiga. Disc will not work with DOS */ int allow_lowercase = 0; /* Allow lower case letters */ int allow_multidot = 0; /* Allow more than on dot in filename */ int iso_translate = 1; /* 1 == enables '#', '-' and '~' removal */ int allow_leading_dots = 0; /* DOS cannot read names with leading dots */ int allow_limited_size = 0; /* Let the user to allow the trick explicitely */ #ifdef VMS int use_fileversion = 1; /* Use file version # from filesystem */ #else int use_fileversion = 0; /* Use file version # from filesystem */ #endif int split_SL_component = 1; /* circumvent a bug in the SunOS driver */ int split_SL_field = 1; /* circumvent a bug in the SunOS */ char *trans_tbl = "TRANS.TBL"; /* default name for translation table */ int stream_media_size = 0; /* # of blocks on the media */ char *stream_filename = NULL; /* Stream file, 0 to use default STREAM.IMG */ #ifdef APPLE_HYB int apple_hyb = 0; /* create HFS hybrid flag */ int apple_ext = 0; /* create HFS extensions flag */ int apple_both = 0; /* common flag (for above) */ int hfs_extra = 0; /* extra HFS blocks added to end of ISO vol */ int use_mac_name = 0; /* use Mac name for ISO/Joliet/RR flag */ hce_mem *hce; /* libhfs/genisoimage extras */ char *hfs_boot_file = 0; /* name of HFS boot file */ int gen_pt = 0; /* generate HFS partition table */ char *autoname = 0; /* AutoStart filename */ char *magic_filename = 0; /* name of magic file */ int probe = 0; /* search files for HFS/Unix type */ int nomacfiles = 0; /* don't look for Mac/Unix files */ int hfs_select = 0; /* Mac/Unix types to select */ int create_dt = 1; /* create the Desktp files */ int afe_size = 0; /* Apple File Exchange block size */ int hfs_last = MAG_LAST; /* process magic file after map file */ char *deftype = APPLE_TYPE_DEFAULT; /* default Apple TYPE */ char *defcreator = APPLE_CREATOR_DEFAULT; /* default Apple CREATOR */ char *hfs_volume_id = NULL; /* HFS volume ID */ int icon_pos = 0; /* Keep icon position */ char *hfs_icharset = NULL; /* input HFS charset name */ char *hfs_ocharset = NULL; /* output HFS charset name */ int hfs_lock = 1; /* lock HFS volume (read-only) */ char *hfs_bless = NULL; /* name of folder to 'bless' (System Folder) */ char *hfs_parms = NULL; /* low level HFS parameters */ #ifdef PREP_BOOT char *prep_boot_image[4]; int use_prep_boot = 0; int use_chrp_boot = 0; #endif /* PREP_BOOT */ #endif /* APPLE_HYB */ #ifdef UDF int use_udf = 0; #endif #ifdef DVD_VIDEO int dvd_video = 0; #endif #ifdef SORTING int do_sort = 0; /* sort file data */ #endif /* SORTING */ #ifdef USE_ICONV int iconv_possible; #endif struct unls_table *in_nls = NULL; /* input UNICODE conversion table */ struct unls_table *out_nls = NULL; /* output UNICODE conversion table */ #ifdef APPLE_HYB struct unls_table *hfs_inls = NULL; /* input HFS UNICODE conversion table */ struct unls_table *hfs_onls = NULL; /* output HFS UNICODE conversion table */ #endif /* APPLE_HYB */ struct rcopts { char *tag; char **variable; }; struct rcopts rcopt[] = { {"PREP", &preparer}, {"PUBL", &publisher}, {"APPI", &appid}, {"COPY", ©right}, {"BIBL", &biblio}, {"ABST", &abstract}, {"VOLS", &volset_id}, {"VOLI", &volume_id}, {"SYSI", &system_id}, #ifdef APPLE_HYB {"HFS_TYPE", &deftype}, {"HFS_CREATOR", &defcreator}, #endif /* APPLE_HYB */ {NULL, NULL} }; char *merge_warn_msg=0; /* use as pointer and boolean */ /* * In case it isn't obvious, the option handling code was ripped off * from GNU-ld. */ struct ld_option { /* The long option information. */ struct option opt; /* The short option with the same meaning ('\0' if none). */ char shortopt; /* The name of the argument (NULL if none). */ const char *arg; /* * The documentation string. If this is NULL, this is a synonym for * the previous option. */ const char *doc; enum { /* Use one dash before long option name. */ ONE_DASH, /* Use two dashes before long option name. */ TWO_DASHES, /* Don't mention this option in --help output. */ NO_HELP } control; }; /* * Codes used for the long options with no short synonyms. Note that all these * values must not be ASCII or EBCDIC. */ #define OPTION_HELP 1000 #define OPTION_QUIET 1001 #define OPTION_NOSPLIT_SL_COMPONENT 1002 #define OPTION_NOSPLIT_SL_FIELD 1003 #define OPTION_PRINT_SIZE 1004 #define OPTION_SPLIT_OUTPUT 1005 #define OPTION_ABSTRACT 1006 #define OPTION_BIBLIO 1007 #define OPTION_COPYRIGHT 1008 #define OPTION_SYSID 1009 #define OPTION_VOLSET 1010 #define OPTION_VOLSET_SIZE 1011 #define OPTION_VOLSET_SEQ_NUM 1012 #define OPTION_I_HIDE 1013 #define OPTION_J_HIDE 1014 #define OPTION_LOG_FILE 1015 #define OPTION_PVERSION 1016 #define OPTION_NOBAK 1017 #define OPTION_SPARCLABEL 1018 #define OPTION_HARD_DISK_BOOT 1019 #define OPTION_NO_EMUL_BOOT 1020 #define OPTION_NO_BOOT 1021 #define OPTION_BOOT_LOAD_ADDR 1022 #define OPTION_BOOT_LOAD_SIZE 1023 #define OPTION_BOOT_INFO_TABLE 1024 #define OPTION_HIDE_TRANS_TBL 1025 #define OPTION_HIDE_RR_MOVED 1026 #define OPTION_GUI 1027 #define OPTION_TRANS_TBL 1028 #define OPTION_P_LIST 1029 #define OPTION_I_LIST 1030 #define OPTION_J_LIST 1031 #define OPTION_X_LIST 1032 #define OPTION_NO_RR 1033 #define OPTION_JCHARSET 1034 #define OPTION_PAD 1035 #define OPTION_H_HIDE 1036 #define OPTION_H_LIST 1037 #define OPTION_CHECK_OLDNAMES 1038 #ifdef SORTING #define OPTION_SORT 1039 #endif /* SORTING */ #define OPTION_UCS_LEVEL 1040 #define OPTION_ISO_TRANSLATE 1041 #define OPTION_ISO_LEVEL 1042 #define OPTION_RELAXED_FILENAMES 1043 #define OPTION_ALLOW_LOWERCASE 1044 #define OPTION_ALLOW_MULTIDOT 1045 #define OPTION_USE_FILEVERSION 1046 #define OPTION_MAX_FILENAMES 1047 #define OPTION_ALT_BOOT 1048 #define OPTION_USE_GRAFT 1049 #define OPTION_INPUT_CHARSET 1050 #define OPTION_OUTPUT_CHARSET 1051 #define OPTION_NOPAD 1052 #define OPTION_UID 1053 #define OPTION_GID 1054 #define OPTION_FILEMODE 1055 #define OPTION_DIRMODE 1056 #define OPTION_NEW_DIR_MODE 1057 #define OPTION_CACHE_INODES 1058 #define OPTION_NOCACHE_INODES 1059 #define OPTION_CHECK_SESSION 1060 #define OPTION_FORCE_RR 1061 #define OPTION_DEBUG 1062 #define OPTION_JLONG 1063 #define OPTION_STREAM_FILE_NAME 1064 #define OPTION_STREAM_CD_SIZE 1065 #define OPTION_XA 1066 #define OPTION_XA_RATIONALIZED 1067 #define OPTION_SUNX86BOOT 1068 #define OPTION_SUNX86LABEL 1069 #define OPTION_ALLOW_LEADING_DOTS 1070 #define OPTION_PUBLISHER 1071 #ifdef JIGDO_TEMPLATE #define OPTION_JTT_OUTPUT 1101 #define OPTION_JTJ_OUTPUT 1102 #define OPTION_JT_MIN_SIZE 1103 #define OPTION_JT_PATH_MAP 1104 #define OPTION_JT_MD5_LIST 1105 #define OPTION_JT_INCLUDE 1106 #define OPTION_JT_EXCLUDE 1107 #define OPTION_JT_COMPRESS_ALGO 1108 #define OPTION_JT_CHECKSUM_ALGO_ISO 1120 #define OPTION_JT_CHECKSUM_ALGO_TMPL 1121 #endif #define OPTION_BOOTALPHA 1200 #define OPTION_HPPA_CMDLINE 1210 #define OPTION_HPPA_KERNEL_32 1211 #define OPTION_HPPA_KERNEL_64 1212 #define OPTION_HPPA_BOOTLOADER 1213 #define OPTION_HPPA_RAMDISK 1214 #define OPTION_BOOTMIPS 1220 #define OPTION_BOOTMIPSEL 1230 #ifdef UDF #define OPTION_UDF 1500 #endif #ifdef DVD_VIDEO #define OPTION_DVD 1501 #endif #ifdef APPLE_HYB #define OPTION_CAP 2000 #define OPTION_NETA 2001 #define OPTION_DBL 2002 #define OPTION_ESH 2003 #define OPTION_FE 2004 #define OPTION_SGI 2005 #define OPTION_MBIN 2006 #define OPTION_SGL 2007 /* aliases */ #define OPTION_USH 2008 #define OPTION_XIN 2009 #define OPTION_DAVE 2010 #define OPTION_SFM 2011 #define OPTION_XDBL 2012 #define OPTION_XHFS 2013 #define OPTION_PROBE 2020 #define OPTION_MACNAME 2021 #define OPTION_NOMACFILES 2022 #define OPTION_BOOT_HFS_FILE 2023 #define OPTION_MAGIC_FILE 2024 #define OPTION_HFS_LIST 2025 #define OPTION_GEN_PT 2026 #define OPTION_CREATE_DT 2027 #define OPTION_HFS_HIDE 2028 #define OPTION_AUTOSTART 2029 #define OPTION_BSIZE 2030 #define OPTION_HFS_VOLID 2031 #define OPTION_PREP_BOOT 2032 #define OPTION_ICON_POS 2033 #define OPTION_HFS_TYPE 2034 #define OPTION_HFS_CREATOR 2035 #define OPTION_ROOT_INFO 2036 #define OPTION_HFS_INPUT_CHARSET 2037 #define OPTION_HFS_OUTPUT_CHARSET 2038 #define OPTION_HFS_UNLOCK 2039 #define OPTION_HFS_BLESS 2040 #define OPTION_HFS_PARMS 2041 #define OPTION_CHRP_BOOT 2042 #define OPTION_RELOC_ROOT 2043 #define OPTION_RELOC_OLD_ROOT 2044 #define OPTION_MAP_FILE 2045 #define OPTION_ALLOW_LIMITED_SIZE 2046 #endif /* APPLE_HYB */ static int save_pname = 0; static const struct ld_option ld_options[] = { {{"nobak", no_argument, NULL, OPTION_NOBAK}, '\0', NULL, "Do not include backup files", ONE_DASH}, {{"no-bak", no_argument, NULL, OPTION_NOBAK}, '\0', NULL, "Do not include backup files", ONE_DASH}, {{"abstract", required_argument, NULL, OPTION_ABSTRACT}, '\0', "FILE", "Set Abstract filename", ONE_DASH}, {{"appid", required_argument, NULL, 'A'}, 'A', "ID", "Set Application ID", ONE_DASH}, {{"biblio", required_argument, NULL, OPTION_BIBLIO}, '\0', "FILE", "Set Bibliographic filename", ONE_DASH}, {{"cache-inodes", no_argument, NULL, OPTION_CACHE_INODES}, '\0', NULL, "Cache inodes (needed to detect hard links)", ONE_DASH}, {{"no-cache-inodes", no_argument, NULL, OPTION_NOCACHE_INODES}, '\0', NULL, "Do not cache inodes (if filesystem has no unique unides)", ONE_DASH}, {{"check-oldnames", no_argument, NULL, OPTION_CHECK_OLDNAMES}, '\0', NULL, "Check all imported ISO9660 names from old session", ONE_DASH}, {{"check-session", required_argument, NULL, OPTION_CHECK_SESSION}, '\0', "FILE", "Check all ISO9660 names from previous session", ONE_DASH}, {{"copyright", required_argument, NULL, OPTION_COPYRIGHT}, '\0', "FILE", "Set Copyright filename", ONE_DASH}, {{"debug", no_argument, NULL, OPTION_DEBUG}, '\0', NULL, "Set debug flag", ONE_DASH}, {{"eltorito-boot", required_argument, NULL, 'b'}, 'b', "FILE", "Set El Torito boot image name", ONE_DASH}, {{"eltorito-alt-boot", no_argument, NULL, OPTION_ALT_BOOT}, '\0', NULL, "Start specifying alternative El Torito boot parameters", ONE_DASH}, {{"sparc-boot", required_argument, NULL, 'B'}, 'B', "FILES", "Set sparc boot image names", ONE_DASH}, {{"sunx86-boot", required_argument, NULL, OPTION_SUNX86BOOT}, '\0', "FILES", "Set sunx86 boot image names", ONE_DASH}, {{"generic-boot", required_argument, NULL, 'G'}, 'G', "FILE", "Set generic boot image name", ONE_DASH}, {{"sparc-label", required_argument, NULL, OPTION_SPARCLABEL}, '\0', "label text", "Set sparc boot disk label", ONE_DASH}, {{"sunx86-label", required_argument, NULL, OPTION_SUNX86LABEL}, '\0', "label text", "Set sunx86 boot disk label", ONE_DASH}, {{"eltorito-catalog", required_argument, NULL, 'c'}, 'c', "FILE", "Set El Torito boot catalog name", ONE_DASH}, {{"cdrecord-params", required_argument, NULL, 'C'}, 'C', "PARAMS", "Magic paramters from cdrecord", ONE_DASH}, {{"omit-period", no_argument, NULL, 'd'}, 'd', NULL, "Omit trailing periods from filenames (violates ISO9660)", ONE_DASH}, {{"dir-mode", required_argument, NULL, OPTION_DIRMODE}, '\0', "mode", "Make the mode of all directories this mode.", ONE_DASH}, {{"disable-deep-relocation", no_argument, NULL, 'D'}, 'D', NULL, "Disable deep directory relocation (violates ISO9660)", ONE_DASH}, {{"file-mode", required_argument, NULL, OPTION_FILEMODE}, '\0', "mode", "Make the mode of all plain files this mode.", ONE_DASH}, {{"follow-links", no_argument, NULL, 'f'}, 'f', NULL, "Follow symbolic links", ONE_DASH}, {{"gid", required_argument, NULL, OPTION_GID}, '\0', "gid", "Make the group owner of all files this gid.", ONE_DASH}, {{"graft-points", no_argument, NULL, OPTION_USE_GRAFT}, '\0', NULL, "Allow to use graft points for filenames", ONE_DASH}, {{"root", required_argument, NULL, OPTION_RELOC_ROOT}, '\0', "DIR", "Set root directory for all new files and directories", ONE_DASH}, {{"old-root", required_argument, NULL, OPTION_RELOC_OLD_ROOT}, '\0', "DIR", "Set root directory in previous session that is searched for files", ONE_DASH}, {{"help", no_argument, NULL, OPTION_HELP}, '\0', NULL, "Print option help", ONE_DASH}, {{"hide", required_argument, NULL, OPTION_I_HIDE}, '\0', "GLOBFILE", "Hide ISO9660/RR file", ONE_DASH}, {{"hide-list", required_argument, NULL, OPTION_I_LIST}, '\0', "FILE", "File with list of ISO9660/RR files to hide", ONE_DASH}, {{"hidden", required_argument, NULL, OPTION_H_HIDE}, '\0', "GLOBFILE", "Set hidden attribute on ISO9660 file", ONE_DASH}, {{"hidden-list", required_argument, NULL, OPTION_H_LIST}, '\0', "FILE", "File with list of ISO9660 files with hidden attribute", ONE_DASH}, {{"hide-joliet", required_argument, NULL, OPTION_J_HIDE}, '\0', "GLOBFILE", "Hide Joliet file", ONE_DASH}, {{"hide-joliet-list", required_argument, NULL, OPTION_J_LIST}, '\0', "FILE", "File with list of Joliet files to hide", ONE_DASH}, {{"hide-joliet-trans-tbl", no_argument, NULL, OPTION_HIDE_TRANS_TBL}, '\0', NULL, "Hide TRANS.TBL from Joliet tree", ONE_DASH}, {{"hide-rr-moved", no_argument, NULL, OPTION_HIDE_RR_MOVED}, '\0', NULL, "Rename RR_MOVED to .rr_moved in Rock Ridge tree", ONE_DASH}, {{"gui", no_argument, NULL, OPTION_GUI}, '\0', NULL, "Switch behaviour for GUI", ONE_DASH}, {{NULL, required_argument, NULL, 'i'}, 'i', "ADD_FILES", "No longer supported", TWO_DASHES}, {{"input-charset", required_argument, NULL, OPTION_INPUT_CHARSET}, '\0', "CHARSET", "Local input charset for file name conversion", ONE_DASH}, {{"output-charset", required_argument, NULL, OPTION_OUTPUT_CHARSET}, '\0', "CHARSET", "Output charset for file name conversion", ONE_DASH}, {{"iso-level", required_argument, NULL, OPTION_ISO_LEVEL}, '\0', "LEVEL", "Set ISO9660 conformance level (1..3) or 4 for ISO9660 version 2", ONE_DASH}, {{"joliet", no_argument, NULL, 'J'}, 'J', NULL, "Generate Joliet directory information", ONE_DASH}, {{"joliet-long", no_argument, NULL, OPTION_JLONG}, '\0', NULL, "Allow Joliet file names to be 103 Unicode characters", ONE_DASH}, {{"jcharset", required_argument, NULL, OPTION_JCHARSET}, '\0', "CHARSET", "Local charset for Joliet directory information", ONE_DASH}, {{"full-iso9660-filenames", no_argument, NULL, 'l'}, 'l', NULL, "Allow full 31 character filenames for ISO9660 names", ONE_DASH}, {{"max-iso9660-filenames", no_argument, NULL, OPTION_MAX_FILENAMES}, '\0', NULL, "Allow 37 character filenames for ISO9660 names (violates ISO9660)", ONE_DASH}, {{"allow-limited-size", no_argument, NULL, OPTION_ALLOW_LIMITED_SIZE}, '\0', NULL, "Allow different file sizes in ISO9660/UDF on large files", ONE_DASH}, {{"allow-leading-dots", no_argument, NULL, OPTION_ALLOW_LEADING_DOTS}, '\0', NULL, "Allow ISO9660 filenames to start with '.' (violates ISO9660)", ONE_DASH}, {{"ldots", no_argument, NULL, OPTION_ALLOW_LEADING_DOTS}, '\0', NULL, "Allow ISO9660 filenames to start with '.' (violates ISO9660)", ONE_DASH}, {{"allow-leading-dots", no_argument, NULL, 'L'}, 'L', NULL, "Allow ISO9660 filenames to start with '.' (violates ISO9660)", ONE_DASH}, {{"log-file", required_argument, NULL, OPTION_LOG_FILE}, '\0', "LOG_FILE", "Re-direct messages to LOG_FILE", ONE_DASH}, {{"exclude", required_argument, NULL, 'm'}, 'm', "GLOBFILE", "Exclude file name", ONE_DASH}, {{"exclude-list", required_argument, NULL, OPTION_X_LIST}, '\0', "FILE", "File with list of file names to exclude", ONE_DASH}, {{"pad", no_argument, NULL, OPTION_PAD}, 0, NULL, "Pad output to a multiple of 32k (default)", ONE_DASH}, {{"no-pad", no_argument, NULL, OPTION_NOPAD}, 0, NULL, "Do not pad output to a multiple of 32k", ONE_DASH}, {{"prev-session", required_argument, NULL, 'M'}, 'M', "FILE", "Set path to previous session to merge", ONE_DASH}, {{"dev", required_argument, NULL, 'M'}, '\0', "SCSIdev", "Set path to previous session to merge", ONE_DASH}, {{"omit-version-number", no_argument, NULL, 'N'}, 'N', NULL, "Omit version number from ISO9660 filename (violates ISO9660)", ONE_DASH}, {{"new-dir-mode", required_argument, NULL, OPTION_NEW_DIR_MODE}, '\0', "mode", "Mode used when creating new directories.", ONE_DASH}, {{"force-rr", no_argument, NULL, OPTION_FORCE_RR}, 0, NULL, "Inhibit automatic Rock Ridge detection for previous session", ONE_DASH}, {{"no-rr", no_argument, NULL, OPTION_NO_RR}, 0, NULL, "Inhibit reading of Rock Ridge attributes from previous session", ONE_DASH}, {{"no-split-symlink-components", no_argument, NULL, OPTION_NOSPLIT_SL_COMPONENT}, 0, NULL, "Inhibit splitting symlink components", ONE_DASH}, {{"no-split-symlink-fields", no_argument, NULL, OPTION_NOSPLIT_SL_FIELD}, 0, NULL, "Inhibit splitting symlink fields", ONE_DASH}, {{"output", required_argument, NULL, 'o'}, 'o', "FILE", "Set output file name", ONE_DASH}, {{"path-list", required_argument, NULL, OPTION_P_LIST}, '\0', "FILE", "File with list of pathnames to process", ONE_DASH}, {{"preparer", required_argument, NULL, 'p'}, 'p', "PREP", "Set Volume preparer", ONE_DASH}, {{"print-size", no_argument, NULL, OPTION_PRINT_SIZE}, '\0', NULL, "Print estimated filesystem size and exit", ONE_DASH}, {{"publisher", required_argument, NULL, OPTION_PUBLISHER}, '\0', "PUB", "Set Volume publisher", ONE_DASH}, {{"publisher", required_argument, NULL, 'P'}, 'P', "PUB", "Set Volume publisher", ONE_DASH}, {{"quiet", no_argument, NULL, OPTION_QUIET}, '\0', NULL, "Run quietly", ONE_DASH}, {{"rational-rock", no_argument, NULL, 'r'}, 'r', NULL, "Generate rationalized Rock Ridge directory information", ONE_DASH}, {{"rock", no_argument, NULL, 'R'}, 'R', NULL, "Generate Rock Ridge directory information", ONE_DASH}, {{"sectype", required_argument, NULL, 's'}, 's', "TYPE", "Set output sector type to e.g. data/xa1/raw", ONE_DASH}, {{"alpha-boot", required_argument, NULL, OPTION_BOOTALPHA}, '\0', "FILE", "Set alpha boot image name (relative to image root)", ONE_DASH}, {{"hppa-cmdline", required_argument, NULL, OPTION_HPPA_CMDLINE}, '\0', "CMDLINE", "Set hppa boot command line (relative to image root)", ONE_DASH}, {{"hppa-kernel-32", required_argument, NULL, OPTION_HPPA_KERNEL_32}, '\0', "FILE", "Set hppa 32-bit image name (relative to image root)", ONE_DASH}, {{"hppa-kernel-64", required_argument, NULL, OPTION_HPPA_KERNEL_64}, '\0', "FILE", "Set hppa 64-bit image name (relative to image root)", ONE_DASH}, {{"hppa-bootloader", required_argument, NULL, OPTION_HPPA_BOOTLOADER}, '\0', "FILE", "Set hppa boot loader file name (relative to image root)", ONE_DASH}, {{"hppa-ramdisk", required_argument, NULL, OPTION_HPPA_RAMDISK}, '\0', "FILE", "Set hppa ramdisk file name (relative to image root)", ONE_DASH}, {{"mips-boot", required_argument, NULL, OPTION_BOOTMIPS}, '\0', "FILE", "Set mips boot image name (relative to image root)", ONE_DASH}, {{"mipsel-boot", required_argument, NULL, OPTION_BOOTMIPSEL}, '\0', "FILE", "Set mipsel boot image name (relative to image root)", ONE_DASH}, #ifdef JIGDO_TEMPLATE {{"jigdo-jigdo", required_argument, NULL, OPTION_JTJ_OUTPUT}, '\0', "FILE", "Produce a jigdo .jigdo file as well as the .iso", ONE_DASH }, {{"jigdo-template", required_argument, NULL, OPTION_JTT_OUTPUT}, '\0', "FILE", "Produce a jigdo .template file as well as the .iso", ONE_DASH }, {{"jigdo-min-file-size", required_argument, NULL, OPTION_JT_MIN_SIZE}, '\0', "SIZE", "Minimum size for a file to be listed in the jigdo file", ONE_DASH }, {{"jigdo-force-md5", required_argument, NULL, OPTION_JT_INCLUDE}, '\0', "PATTERN", "Pattern(s) where files MUST match an externally-supplied MD5sum", ONE_DASH }, {{"jigdo-exclude", required_argument, NULL, OPTION_JT_EXCLUDE}, '\0', "PATTERN", "Pattern(s) to exclude from the jigdo file", ONE_DASH }, {{"jigdo-map", required_argument, NULL, OPTION_JT_PATH_MAP}, '\0', "PATTERN1=PATTERN2", "Pattern(s) to map paths (e.g. Debian=/mirror/debian)", ONE_DASH }, {{"md5-list", required_argument, NULL, OPTION_JT_MD5_LIST}, '\0', "FILE", "File containing MD5 sums of the files that should be checked", ONE_DASH }, {{"jigdo-template-compress", required_argument, NULL, OPTION_JT_COMPRESS_ALGO}, '\0', "ALGORITHM", "Choose to use gzip or bzip2 compression for template data; default is gzip", ONE_DASH }, {{"checksum_algorithm_iso", required_argument, NULL, OPTION_JT_CHECKSUM_ALGO_ISO}, '\0', "alg1,alg2,...", "Specify the checksum types desired for the output image", ONE_DASH}, {{"checksum_algorithm_template", required_argument, NULL, OPTION_JT_CHECKSUM_ALGO_TMPL}, '\0', "alg1,alg2,...", "Specify the checksum types desired for the output jigdo template", ONE_DASH}, #endif #ifdef SORTING { {"sort", required_argument, NULL, OPTION_SORT}, '\0', "FILE", "Sort file content locations according to rules in FILE", ONE_DASH }, #endif /* SORTING */ {{"split-output", no_argument, NULL, OPTION_SPLIT_OUTPUT}, '\0', NULL, "Split output into files of approx. 1GB size", ONE_DASH}, {{"stream-file-name", required_argument, NULL, OPTION_STREAM_FILE_NAME}, '\0', "FILE_NAME", "Set the stream file ISO9660 name (incl. version)", ONE_DASH}, {{"stream-media-size", required_argument, NULL, OPTION_STREAM_CD_SIZE}, '\0', "#", "Set the size of your CD media in sectors", ONE_DASH}, {{"sysid", required_argument, NULL, OPTION_SYSID}, '\0', "ID", "Set System ID", ONE_DASH}, {{"translation-table", no_argument, NULL, 'T'}, 'T', NULL, "Generate translation tables for systems that don't understand long filenames", ONE_DASH}, {{"table-name", required_argument, NULL, OPTION_TRANS_TBL}, '\0', "TABLE_NAME", "Translation table file name", ONE_DASH}, {{"ucs-level", required_argument, NULL, OPTION_UCS_LEVEL}, '\0', "LEVEL", "Set Joliet UCS level (1..3)", ONE_DASH}, #ifdef UDF {{"udf", no_argument, NULL, OPTION_UDF}, '\0', NULL, "Generate UDF file system", ONE_DASH}, #endif #ifdef DVD_VIDEO {{"dvd-video", no_argument, NULL, OPTION_DVD}, '\0', NULL, "Generate DVD-Video compliant UDF file system", ONE_DASH}, #endif {{"uid", required_argument, NULL, OPTION_UID}, '\0', "uid", "Make the owner of all files this uid.", ONE_DASH}, {{"untranslated-filenames", no_argument, NULL, 'U'}, /* CSTYLED */ 'U', NULL, "Allow Untranslated filenames (for HPUX & AIX - violates ISO9660). Forces -l, -d, -N, -allow-leading-dots, -relaxed-filenames, -allow-lowercase, -allow-multidot", ONE_DASH}, {{"relaxed-filenames", no_argument, NULL, OPTION_RELAXED_FILENAMES}, '\0', NULL, "Allow 7 bit ASCII except lower case characters (violates ISO9660)", ONE_DASH}, {{"no-iso-translate", no_argument, NULL, OPTION_ISO_TRANSLATE}, '\0', NULL, "Do not translate illegal ISO characters '~', '-' and '#' (violates ISO9660)", ONE_DASH}, {{"allow-lowercase", no_argument, NULL, OPTION_ALLOW_LOWERCASE}, '\0', NULL, "Allow lower case characters in addition to the current character set (violates ISO9660)", ONE_DASH}, {{"allow-multidot", no_argument, NULL, OPTION_ALLOW_MULTIDOT}, '\0', NULL, "Allow more than one dot in filenames (e.g. .tar.gz) (violates ISO9660)", ONE_DASH}, {{"use-fileversion", no_argument, NULL, OPTION_USE_FILEVERSION}, '\0', "LEVEL", "Use file version # from filesystem", ONE_DASH}, {{"verbose", no_argument, NULL, 'v'}, 'v', NULL, "Verbose", ONE_DASH}, {{"version", no_argument, NULL, OPTION_PVERSION}, '\0', NULL, "Print the current version", ONE_DASH}, {{"volid", required_argument, NULL, 'V'}, 'V', "ID", "Set Volume ID", ONE_DASH}, {{"volset", required_argument, NULL, OPTION_VOLSET}, '\0', "ID", "Set Volume set ID", ONE_DASH}, {{"volset-size", required_argument, NULL, OPTION_VOLSET_SIZE}, '\0', "#", "Set Volume set size", ONE_DASH}, {{"volset-seqno", required_argument, NULL, OPTION_VOLSET_SEQ_NUM}, '\0', "#", "Set Volume set sequence number", ONE_DASH}, {{"old-exclude", required_argument, NULL, 'x'}, 'x', "FILE", "Exclude file name(depreciated)", ONE_DASH}, {{"hard-disk-boot", no_argument, NULL, OPTION_HARD_DISK_BOOT}, '\0', NULL, "Boot image is a hard disk image", ONE_DASH}, {{"no-emul-boot", no_argument, NULL, OPTION_NO_EMUL_BOOT}, '\0', NULL, "Boot image is 'no emulation' image", ONE_DASH}, {{"no-boot", no_argument, NULL, OPTION_NO_BOOT}, '\0', NULL, "Boot image is not bootable", ONE_DASH}, {{"boot-load-seg", required_argument, NULL, OPTION_BOOT_LOAD_ADDR}, '\0', "#", "Set load segment for boot image", ONE_DASH}, {{"boot-load-size", required_argument, NULL, OPTION_BOOT_LOAD_SIZE}, '\0', "#", "Set numbers of load sectors", ONE_DASH}, {{"boot-info-table", no_argument, NULL, OPTION_BOOT_INFO_TABLE}, '\0', NULL, "Patch boot image with info table", ONE_DASH}, {{"XA", no_argument, NULL, OPTION_XA}, '\0', NULL, "Generate XA directory attruibutes", ONE_DASH}, {{"xa", no_argument, NULL, OPTION_XA_RATIONALIZED}, '\0', NULL, "Generate rationalized XA directory attruibutes", ONE_DASH}, {{"transparent-compression", no_argument, NULL, 'z'}, 'z', NULL, "Enable transparent compression of files", ONE_DASH}, #ifdef APPLE_HYB {{"hfs-type", required_argument, NULL, OPTION_HFS_TYPE}, '\0', "TYPE", "Set HFS default TYPE", ONE_DASH}, {{"hfs-creator", required_argument, NULL, OPTION_HFS_CREATOR}, '\0', "CREATOR", "Set HFS default CREATOR", ONE_DASH}, {{"apple", no_argument, NULL, 'g'}, 'g', NULL, "Add Apple ISO9660 extensions", ONE_DASH}, {{"hfs", no_argument, NULL, 'h'}, 'h', NULL, "Create ISO9660/HFS hybrid", ONE_DASH}, {{"map", required_argument, NULL, OPTION_MAP_FILE}, '\0', "MAPPING_FILE", "Map file extensions to HFS TYPE/CREATOR", ONE_DASH}, {{"map", required_argument, NULL, 'H'}, 'H', "MAPPING_FILE", "Map file extensions to HFS TYPE/CREATOR", ONE_DASH}, {{"magic", required_argument, NULL, OPTION_MAGIC_FILE}, '\0', "FILE", "Magic file for HFS TYPE/CREATOR", ONE_DASH}, {{"probe", no_argument, NULL, OPTION_PROBE}, '\0', NULL, "Probe all files for Apple/Unix file types", ONE_DASH}, {{"mac-name", no_argument, NULL, OPTION_MACNAME}, '\0', NULL, "Use Macintosh name for ISO9660/Joliet/RockRidge file name", ONE_DASH}, {{"no-mac-files", no_argument, NULL, OPTION_NOMACFILES}, '\0', NULL, "Do not look for Unix/Mac files (depreciated)", ONE_DASH}, {{"boot-hfs-file", required_argument, NULL, OPTION_BOOT_HFS_FILE}, '\0', "FILE", "Set HFS boot image name", ONE_DASH}, {{"part", no_argument, NULL, OPTION_GEN_PT}, '\0', NULL, "Generate HFS partition table", ONE_DASH}, {{"cluster-size", required_argument, NULL, OPTION_BSIZE}, '\0', "SIZE", "Cluster size for PC Exchange Macintosh files", ONE_DASH}, {{"auto", required_argument, NULL, OPTION_AUTOSTART}, '\0', "FILE", "Set HFS AutoStart file name", ONE_DASH}, {{"no-desktop", no_argument, NULL, OPTION_CREATE_DT}, '\0', NULL, "Do not create the HFS (empty) Desktop files", ONE_DASH}, {{"hide-hfs", required_argument, NULL, OPTION_HFS_HIDE}, '\0', "GLOBFILE", "Hide HFS file", ONE_DASH}, {{"hide-hfs-list", required_argument, NULL, OPTION_HFS_LIST}, '\0', "FILE", "List of HFS files to hide", ONE_DASH}, {{"hfs-volid", required_argument, NULL, OPTION_HFS_VOLID}, '\0', "HFS_VOLID", "Volume name for the HFS partition", ONE_DASH}, {{"icon-position", no_argument, NULL, OPTION_ICON_POS}, '\0', NULL, "Keep HFS icon position", ONE_DASH}, {{"root-info", required_argument, NULL, OPTION_ROOT_INFO}, '\0', "FILE", "finderinfo for root folder", ONE_DASH}, {{"input-hfs-charset", required_argument, NULL, OPTION_HFS_INPUT_CHARSET}, '\0', "CHARSET", "Local input charset for HFS file name conversion", ONE_DASH}, {{"output-hfs-charset", required_argument, NULL, OPTION_HFS_OUTPUT_CHARSET}, '\0', "CHARSET", "Output charset for HFS file name conversion", ONE_DASH}, {{"hfs-unlock", no_argument, NULL, OPTION_HFS_UNLOCK}, '\0', NULL, "Leave HFS Volume unlocked", ONE_DASH}, {{"hfs-bless", required_argument, NULL, OPTION_HFS_BLESS}, '\0', "FOLDER_NAME", "Name of Folder to be blessed", ONE_DASH}, {{"hfs-parms", required_argument, NULL, OPTION_HFS_PARMS}, '\0', "PARAMETERS", "Comma separated list of HFS parameters", ONE_DASH}, #ifdef PREP_BOOT {{"prep-boot", required_argument, NULL, OPTION_PREP_BOOT}, '\0', "FILE", "PReP boot image file -- up to 4 are allowed", ONE_DASH}, {{"chrp-boot", no_argument, NULL, OPTION_CHRP_BOOT}, '\0', NULL, "Add CHRP boot header", ONE_DASH}, #endif /* PREP_BOOT */ {{"cap", no_argument, NULL, OPTION_CAP}, '\0', NULL, "Look for AUFS CAP Macintosh files", TWO_DASHES}, {{"netatalk", no_argument, NULL, OPTION_NETA}, '\0', NULL, "Look for NETATALK Macintosh files", TWO_DASHES}, {{"double", no_argument, NULL, OPTION_DBL}, '\0', NULL, "Look for AppleDouble Macintosh files", TWO_DASHES}, {{"ethershare", no_argument, NULL, OPTION_ESH}, '\0', NULL, "Look for Helios EtherShare Macintosh files", TWO_DASHES}, {{"exchange", no_argument, NULL, OPTION_FE}, '\0', NULL, "Look for PC Exchange Macintosh files", TWO_DASHES}, {{"sgi", no_argument, NULL, OPTION_SGI}, '\0', NULL, "Look for SGI Macintosh files", TWO_DASHES}, {{"macbin", no_argument, NULL, OPTION_MBIN}, '\0', NULL, "Look for MacBinary Macintosh files", TWO_DASHES}, {{"single", no_argument, NULL, OPTION_SGL}, '\0', NULL, "Look for AppleSingle Macintosh files", TWO_DASHES}, {{"ushare", no_argument, NULL, OPTION_USH}, '\0', NULL, "Look for IPT UShare Macintosh files", TWO_DASHES}, {{"xinet", no_argument, NULL, OPTION_XIN}, '\0', NULL, "Look for XINET Macintosh files", TWO_DASHES}, {{"dave", no_argument, NULL, OPTION_DAVE}, '\0', NULL, "Look for DAVE Macintosh files", TWO_DASHES}, {{"sfm", no_argument, NULL, OPTION_SFM}, '\0', NULL, "Look for SFM Macintosh files", TWO_DASHES}, {{"osx-double", no_argument, NULL, OPTION_XDBL}, '\0', NULL, "Look for MacOS X AppleDouble Macintosh files", TWO_DASHES}, {{"osx-hfs", no_argument, NULL, OPTION_XHFS}, '\0', NULL, "Look for MacOS X HFS Macintosh files", TWO_DASHES}, #endif /* APPLE_HYB */ }; #define OPTION_COUNT (sizeof ld_options / sizeof (ld_options[0])) static void read_rcfile(char *appname); static void susage(int excode); static void usage(int excode); int iso9660_date(char *result, time_t crtime); static void hide_reloc_dir(void); static char *get_pnames(int argc, char **argv, int opt, char *pname, int pnsize, FILE *fp); char *findgequal(char *s); static char *escstrcpy(char *to, char *from); void *e_malloc(size_t size); static int read_one_rcfile(char *filename) { int linum = 0; char linebuffer[256]; FILE *fp; if (!filename) return 0; fp = fopen(filename, "r"); if (!fp) { if (errno == ENOENT) return 0; #ifdef USE_LIBSCHILY errmsg("Cannot open '%s'.\n", filename); #else perror(filename); #endif return 0; } if (verbose > 0) fprintf(stderr, "Using \"%s\"\n", filename); while (fgets(linebuffer, sizeof(linebuffer), fp)) { char *name, *p, *p1; struct rcopts *rco; ++linum; /* skip any leading white space */ for (p = linebuffer; *p == ' ' || *p == '\t'; p++) ; /* Skip comments and blank lines */ if (!*p || *p == '\n' || *p == '\r' || *p == '#') continue; /* * The name should begin in the left margin. Make sure it is * in upper case. Stop when we see white space or a comment. */ name = p; while (*p && (isalpha((unsigned char) *p) || *p == '_')) *p++ = toupper((unsigned char) *p); if (name == p) { fprintf(stderr, "%s:%d: name required\n", filename, linum); continue; } p1 = p; /* Skip past white space after the name */ while (*p == ' ' || *p == '\t') p++; /* silently ignore errors in the rc file. */ if (*p != '=') { fprintf(stderr, "%s:%d: equals sign required after '%.*s'\n", filename, linum, (int)(p1-name), name); continue; } *p1 = 0; /* Skip pas the = sign, and any white space following it */ p++; while (*p == ' ' || *p == '\t') p++; /* Get rid of trailing newline */ for (p1 = p; *p1 && *p1 != '\n' && *p1 != '\r'; p1++) ; *p1 = 0; /* Figure out which option we have */ for (rco = rcopt; rco->tag; rco++) if (strcmp(rco->tag, name) == 0) { /* memleak if we ever do this more than once */ *rco->variable = strdup(p); break; } if (!rco->tag) { fprintf(stderr, "%s:%d: field name '%s' unknown\n", filename, linum, name); } } if (ferror(fp)) { #ifdef USE_LIBSCHILY errmsg("Read error on '%s'.\n", filename); #else perror(filename); #endif fclose(fp); return 0; } fclose(fp); return 1; } #define ETCDIR "/etc" #define RCFILENAME "genisoimagerc" #define OLD_RCFILENAME "mkisofsrc" static void read_rcfile(char *appname) { char *p; char filename[1000]; if (read_one_rcfile(getenv("GENISOIMAGERC"))) return; if (read_one_rcfile(getenv("MKISOFSRC"))) return; if (read_one_rcfile("." RCFILENAME)) return; if (read_one_rcfile("." OLD_RCFILENAME)) return; p = getenv("HOME"); if (p && strlen(p) + 1 + sizeof(RCFILENAME) < sizeof(filename)) { strcpy(filename, p); p = filename + strlen(filename); *p++ = PATH_SEPARATOR; strcpy(p, "." RCFILENAME); if (read_one_rcfile(filename)) return; strcpy(p, "." OLD_RCFILENAME); if (read_one_rcfile(filename)) return; } if (read_one_rcfile(ETCDIR SPATH_SEPARATOR RCFILENAME)) return; if (appname && strlen(appname) + 1 + sizeof(RCFILENAME) < sizeof(filename)) { strcpy(filename, appname); p = strrchr(filename, PATH_SEPARATOR); if (p) { strcpy(p + 1, RCFILENAME); if (read_one_rcfile(filename)) return; } } } char *path_table_l = NULL; char *path_table_m = NULL; char *jpath_table_l = NULL; char *jpath_table_m = NULL; int goof = 0; #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif static void susage(int excode) { const char *program_name = "genisoimage"; fprintf(stderr, "Usage: %s [options] -o file directory ...\n", program_name); fprintf(stderr, "\nUse %s -help\n", program_name); fprintf(stderr, "to get a list of valid options.\n"); fprintf(stderr, "\nReport problems to debburn-devel@lists.alioth.debian.org.\n"); exit(excode); } static void usage(int excode) { const char *program_name = "genisoimage"; int i; /* const char **targets, **pp;*/ fprintf(stderr, "Usage: %s [options] file...\n", program_name); fprintf(stderr, "Options:\n"); for (i = 0; i < (int)OPTION_COUNT; i++) { if (ld_options[i].doc != NULL) { int comma; int len; int j; fprintf(stderr, " "); comma = FALSE; len = 2; j = i; do { if (ld_options[j].shortopt != '\0' && ld_options[j].control != NO_HELP) { fprintf(stderr, "%s-%c", comma ? ", " : "", ld_options[j].shortopt); len += (comma ? 2 : 0) + 2; if (ld_options[j].arg != NULL) { if (ld_options[j].opt.has_arg != optional_argument) { fprintf(stderr, " "); ++len; } fprintf(stderr, "%s", ld_options[j].arg); len += strlen(ld_options[j].arg); } comma = TRUE; } ++j; } while (j < (int)OPTION_COUNT && ld_options[j].doc == NULL); j = i; do { if (ld_options[j].opt.name != NULL && ld_options[j].control != NO_HELP) { fprintf(stderr, "%s-%s%s", comma ? ", " : "", ld_options[j].control == TWO_DASHES ? "-" : "", ld_options[j].opt.name); len += ((comma ? 2 : 0) + 1 + (ld_options[j].control == TWO_DASHES ? 1 : 0) + strlen(ld_options[j].opt.name)); if (ld_options[j].arg != NULL) { fprintf(stderr, " %s", ld_options[j].arg); len += 1 + strlen(ld_options[j].arg); } comma = TRUE; } ++j; } while (j < (int)OPTION_COUNT && ld_options[j].doc == NULL); if (len >= 30) { fprintf(stderr, "\n"); len = 0; } for (; len < 30; len++) fputc(' ', stderr); fprintf(stderr, "%s\n", ld_options[i].doc); } } fprintf(stderr, "\nReport problems to debburn-devel@lists.alioth.debian.org.\n"); exit(excode); } /* * Fill in date in the iso9660 format * * The standards state that the timezone offset is in multiples of 15 * minutes, and is what you add to GMT to get the localtime. The U.S. * is always at a negative offset, from -5h to -8h (can vary a little * with DST, I guess). The Linux iso9660 filesystem has had the sign * of this wrong for ages (genisoimage had it wrong too for the longest time). */ int iso9660_date(char *result, time_t crtime) { struct tm *local; local = localtime(&crtime); result[0] = local->tm_year; result[1] = local->tm_mon + 1; result[2] = local->tm_mday; result[3] = local->tm_hour; result[4] = local->tm_min; result[5] = local->tm_sec; /* * Must recalculate proper timezone offset each time, as some files use * daylight savings time and some don't... */ result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */ local = gmtime(&crtime); local->tm_year -= result[0]; local->tm_yday -= result[6]; local->tm_hour -= result[3]; local->tm_min -= result[4]; if (local->tm_year < 0) { local->tm_yday = -1; } else { if (local->tm_year > 0) local->tm_yday = 1; } result[6] = -(local->tm_min + 60 * (local->tm_hour + 24 * local->tm_yday)) / 15; return (0); } /* hide "./rr_moved" if all its contents are hidden */ static void hide_reloc_dir() { struct directory_entry *s_entry; for (s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) { if (strcmp(s_entry->name, ".") == 0 || strcmp(s_entry->name, "..") == 0) continue; if ((s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0) return; } /* all entries are hidden, so hide this directory */ reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY; reloc_dir->self->de_flags |= INHIBIT_ISO9660_ENTRY; } /* * get pathnames from the command line, and then from given file */ static char * get_pnames(int argc, char **argv, int opt, char *pname, int pnsize, FILE *fp) { int len; /* we may of already read the first line from the pathnames file */ if (save_pname) { save_pname = 0; return (pname); } if (opt < argc) return (argv[opt]); if (fp == NULL) return ((char *) 0); if (fgets(pname, pnsize, fp)) { /* Discard newline */ len = strlen(pname); if (pname[len - 1] == '\n') { pname[len - 1] = '\0'; } return (pname); } return ((char *) 0); } extern char *cdrecord_data; int main(int argc, char *argv[]) { struct directory_entry de; #ifdef HAVE_SBRK unsigned long mem_start; #endif struct stat statbuf; char *merge_image = NULL; char *reloc_root = NULL; char *reloc_old_root = NULL; struct iso_directory_record *mrootp = NULL; struct output_fragment *opnt; int longind; char shortopts[OPTION_COUNT * 3 + 2]; struct option longopts[OPTION_COUNT + 1]; int c; int n; char *log_file = 0; char *node = NULL; char *pathnames = 0; FILE *pfp = NULL; char pname[2*PATH_MAX + 1 + 1]; /* may be too short */ char *arg; /* if '\\' present */ char nodename[PATH_MAX + 1]; int no_path_names = 1; int warn_violate = 0; int have_cmd_line_pathspec = 0; int rationalize_all = 0; char *mkisofs_call = 0; /* use as pointer and boolean */ #ifdef APPLE_HYB char *afpfile = ""; /* mapping file for TYPE/CREATOR */ int hfs_ct = 0; char *root_info = 0; #endif /* APPLE_HYB */ /* abusing arg */ mkisofs_call=strstr(argv[0], "mkisofs"); if(mkisofs_call && '\0' == mkisofs_call[7]) /* lame cheater detected */ argv[0]="genisoimage"; #ifdef __EMX__ /* This gives wildcard expansion with Non-Posix shells with EMX */ _wildcard(&argc, &argv); #endif save_args(argc, argv); if (argc < 2) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Missing pathspec.\n"); #endif susage(1); } /* Get the defaults from the .genisoimagerc file */ read_rcfile(argv[0]); outfile = NULL; /* * Copy long option initialization from GNU-ld. */ /* * Starting the short option string with '-' is for programs that * expect options and other ARGV-elements in any order and that care * about the ordering of the two. We describe each non-option * ARGV-element as if it were the argument of an option with * character code 1. */ { int i, is, il; shortopts[0] = '-'; is = 1; il = 0; for (i = 0; i < (int)OPTION_COUNT; i++) { if (ld_options[i].shortopt != '\0') { shortopts[is] = ld_options[i].shortopt; ++is; if (ld_options[i].opt.has_arg == required_argument || ld_options[i].opt.has_arg == optional_argument) { shortopts[is] = ':'; ++is; if (ld_options[i].opt.has_arg == optional_argument) { shortopts[is] = ':'; ++is; } } } if (ld_options[i].opt.name != NULL) { longopts[il] = ld_options[i].opt; ++il; } } shortopts[is] = '\0'; longopts[il].name = NULL; } while ((c = getopt_long_only(argc, argv, shortopts, longopts, &longind)) != EOF) switch (c) { case 1: /* A filename that we take as input. */ optind--; have_cmd_line_pathspec = 1; goto parse_input_files; case OPTION_USE_GRAFT: use_graft_ptrs = 1; break; case 'C': /* * This is a temporary hack until cdrecord gets the * proper hooks in it. */ cdrecord_data = optarg; break; case OPTION_GUI: gui++; break; case 'i': #ifdef USE_LIBSCHILY comerrno(EX_BAD, "-i option no longer supported.\n"); #else fprintf(stderr, "-i option no longer supported.\n"); exit(1); #endif break; case OPTION_ISO_LEVEL: iso9660_level = atoi(optarg); switch (iso9660_level) { case 1: /* * Only on file section * 8.3 d or d1 characters for files * 8 d or d1 characters for directories */ break; case 2: /* * Only on file section */ break; case 3: /* * No restrictions */ break; case 4: /* * This is ISO-9660:1988 (ISO-9660 version 2) */ iso9660_namelen = MAX_ISONAME_V2; /* allow 207 chars */ full_iso9660_filenames++; /* 31+ chars */ omit_version_number++; RR_relocation_depth = 32767; /* * From -U ... */ omit_period++; /* trailing dot */ allow_leading_dots++; relaxed_filenames++; /* all chars */ allow_lowercase++; /* even lowcase */ allow_multidot++; /* > 1 dots */ break; default: comerrno(EX_BAD, "Illegal iso9660 Level %d, use 1..3 or 4.\n", iso9660_level); } break; case 'J': use_Joliet++; break; case OPTION_JLONG: use_Joliet++; jlen = JLONGMAX; break; case OPTION_JCHARSET: use_Joliet++; /* FALLTHROUGH */ case OPTION_INPUT_CHARSET: icharset = optarg; break; case OPTION_OUTPUT_CHARSET: ocharset = optarg; break; #ifdef JIGDO_TEMPLATE case OPTION_JTT_OUTPUT: jtemplate_out = optarg; break; case OPTION_JTJ_OUTPUT: jjigdo_out = optarg; break; case OPTION_JT_MD5_LIST: jmd5_list = optarg; break; case OPTION_JT_MIN_SIZE: jte_min_size = atoi(optarg); if (jte_min_size < MIN_JIGDO_FILE_SIZE) { fprintf(stderr, "Jigdo min size %d too small; using default %d instead\n", jte_min_size, MIN_JIGDO_FILE_SIZE); jte_min_size = MIN_JIGDO_FILE_SIZE; } break; case OPTION_JT_INCLUDE: if (jte_add_include(optarg)) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Failed to build jigdo-include list\n"); #else fprintf(stderr, "Failed to build jigdo-include list\n"); exit(1); #endif } break; case OPTION_JT_EXCLUDE: if (jte_add_exclude(optarg)) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Failed to build jigdo-exclude list\n"); #else fprintf(stderr, "Failed to build jigdo-exclude list\n"); exit(1); #endif } break; case OPTION_JT_PATH_MAP: if (jte_add_mapping(optarg)) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Failed to build jigdo mapping list\n"); #else fprintf(stderr, "Failed to build jigdo mapping list\n"); exit(1); #endif } break; case OPTION_JT_COMPRESS_ALGO: if (!strcasecmp(optarg, "gzip")) jte_template_compression = JTE_TEMP_GZIP; else if (!strcasecmp(optarg, "bzip2")) jte_template_compression = JTE_TEMP_BZIP2; else { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Compression algorithm %s unknown\n", optarg); #else fprintf(stderr, "Compression algorithm %s unknown\n", optarg); exit(1); #endif } break; case OPTION_JT_CHECKSUM_ALGO_ISO: if (parse_checksum_algo(optarg, &checksum_algo_iso)) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Problem with ISO checksum choices: %s \n", optarg); #else fprintf(stderr, "Problem with ISO checksum choices: %s\n", optarg); exit(1); #endif } break; case OPTION_JT_CHECKSUM_ALGO_TMPL: if (parse_checksum_algo(optarg, &checksum_algo_tmpl)) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Problem with template checksum choices: %s \n", optarg); #else fprintf(stderr, "Problem with template checksum choices: %s\n", optarg); exit(1); #endif } break; #endif /* JIGDO_TEMPLATE */ case OPTION_NOBAK: all_files = 0; break; case 'b': do_sort++; /* We sort bootcat/botimage */ use_eltorito++; boot_image = optarg; /* pathname of the boot image */ /* on disk */ if (boot_image == NULL) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Required Eltorito boot image pathname missing\n"); #else fprintf(stderr, "Required Eltorito boot image pathname missing\n"); exit(1); #endif } get_boot_entry(); current_boot_entry->boot_image = boot_image; break; case OPTION_ALT_BOOT: /* * Start new boot entry parameter list. */ new_boot_entry(); break; case OPTION_BOOTALPHA: use_alphaboot++; /* list of pathnames of boot images */ add_boot_alpha_filename(optarg); break; case OPTION_HPPA_CMDLINE: use_hppaboot++; add_boot_hppa_cmdline(optarg); break; case OPTION_HPPA_KERNEL_32: use_hppaboot++; add_boot_hppa_kernel_32(optarg); break; case OPTION_HPPA_KERNEL_64: use_hppaboot++; add_boot_hppa_kernel_64(optarg); break; case OPTION_HPPA_BOOTLOADER: use_hppaboot++; add_boot_hppa_bootloader(optarg); break; case OPTION_HPPA_RAMDISK: use_hppaboot++; /* list of pathnames of boot images */ add_boot_hppa_ramdisk(optarg); break; case OPTION_BOOTMIPS: use_mipsboot++; /* list of pathnames of boot images */ add_boot_mips_filename(optarg); break; case OPTION_BOOTMIPSEL: use_mipselboot++; add_boot_mipsel_filename(optarg); break; case 'B': if (use_sunx86boot) comerrno(EX_BAD, "-sparc-boot and -sunx86-boot are mutual exclusive.\n"); use_sparcboot++; /* list of pathnames of boot images */ scan_sparc_boot(optarg); break; case OPTION_SUNX86BOOT: if (use_sparcboot) comerrno(EX_BAD, "-sparc-boot and -sunx86-boot are mutual exclusive.\n"); use_sunx86boot++; /* list of pathnames of boot images */ scan_sunx86_boot(optarg); break; case 'G': use_genboot++; /* pathname of the boot image on disk */ genboot_image = optarg; if (genboot_image == NULL) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Required generic boot image pathname missing\n"); #else fprintf(stderr, "Required generic boot image pathname missing\n"); exit(1); #endif } break; case OPTION_SPARCLABEL: /* Sun disk label string */ sparc_boot_label(optarg); break; case OPTION_SUNX86LABEL: /* Sun disk label string */ sunx86_boot_label(optarg); break; case 'c': use_eltorito++; /* pathname of the boot image on cd */ boot_catalog = optarg; if (boot_catalog == NULL) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Required boot catalog pathname missing\n"); #else fprintf(stderr, "Required boot catalog pathname missing\n"); exit(1); #endif } break; case OPTION_ABSTRACT: abstract = optarg; if (strlen(abstract) > 37) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Abstract filename string too long\n"); #else fprintf(stderr, "Abstract filename string too long\n"); exit(1); #endif } break; case 'A': appid = optarg; if (strlen(appid) > 128) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Application-id string too long\n"); #else fprintf(stderr, "Application-id string too long\n"); exit(1); #endif } break; case OPTION_BIBLIO: biblio = optarg; if (strlen(biblio) > 37) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Bibliographic filename string too long\n"); #else fprintf(stderr, "Bibliographic filename string too long\n"); exit(1); #endif } break; case OPTION_CACHE_INODES: cache_inodes = 1; break; case OPTION_NOCACHE_INODES: cache_inodes = 0; break; case OPTION_CHECK_OLDNAMES: check_oldnames++; break; case OPTION_CHECK_SESSION: check_session++; check_oldnames++; merge_image = optarg; outfile = "/dev/null"; /* * cdrecord_data is handled specially in multi.c * as we cannot write to all strings. * If genisoimage is called with -C xx,yy * our default is overwritten. */ /* cdrecord_data = "0,0";*/ break; case OPTION_COPYRIGHT: copyright = optarg; if (strlen(copyright) > 37) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Copyright filename string too long\n"); #else fprintf(stderr, "Copyright filename string too long\n"); exit(1); #endif } break; case OPTION_DEBUG: debug++; break; case 'd': omit_period++; warn_violate++; break; case 'D': RR_relocation_depth = 32767; break; case 'f': follow_links++; break; case 'l': full_iso9660_filenames++; break; case OPTION_MAX_FILENAMES: iso9660_namelen = MAX_ISONAME_V1; /* allow 37 chars */ full_iso9660_filenames++; omit_version_number++; warn_violate++; break; case 'L': /* FALLTHRU */ case OPTION_ALLOW_LEADING_DOTS: allow_leading_dots++; warn_violate++; break; case OPTION_LOG_FILE: log_file = optarg; break; case 'M': merge_image = optarg; break; case OPTION_RELOC_ROOT: reloc_root = optarg; break; case OPTION_RELOC_OLD_ROOT: reloc_old_root = optarg; break; case 'N': omit_version_number++; warn_violate++; break; case OPTION_FORCE_RR: force_rr++; break; case OPTION_NO_RR: no_rr++; break; case 'o': outfile = optarg; break; case OPTION_PAD: dopad++; break; case OPTION_NOPAD: dopad = 0; break; case OPTION_P_LIST: pathnames = optarg; break; case 'p': preparer = optarg; if (strlen(preparer) > 128) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Preparer string too long\n"); #else fprintf(stderr, "Preparer string too long\n"); exit(1); #endif } break; case OPTION_PRINT_SIZE: print_size++; break; case 'P': /* FALLTHRU */ case OPTION_PUBLISHER: publisher = optarg; if (strlen(publisher) > 128) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Publisher string too long\n"); #else fprintf(stderr, "Publisher string too long\n"); exit(1); #endif } break; case OPTION_QUIET: verbose = 0; break; case 'R': use_RockRidge++; break; case 'r': rationalize_all++; use_RockRidge++; break; case OPTION_XA: use_XA++; break; case OPTION_XA_RATIONALIZED: rationalize_all++; use_XA++; break; case 's': if (strcmp(optarg, "data") == 0) osecsize = 2048; else if (strcmp(optarg, "xa1") == 0) osecsize = 2056; else if (strcmp(optarg, "raw") == 0) { osecsize = 2352; comerrno(EX_BAD, "Unsupported sector type '%s'.\n", optarg); } break; case 'S': #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Option -%c is reserved for future use.\n", c); #else fprintf(stderr, "Option -%c is reserved for future use.\n", c); #endif susage(1); /* NOTREACHED */ case OPTION_NEW_DIR_MODE: rationalize++; { char *end = 0; new_dir_mode = strtol(optarg, &end, 8); if (!end || *end != 0 || new_dir_mode < 0 || new_dir_mode > 07777) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Bad mode for -new-dir-mode\n"); #else fprintf(stderr, "Bad mode for -new-dir-mode\n"); exit(1); #endif } break; } case OPTION_UID: rationalize++; use_RockRidge++; rationalize_uid++; { char *end = 0; uid_to_use = strtol(optarg, &end, 0); if (!end || *end != 0) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Bad value for -uid\n"); #else fprintf(stderr, "Bad value for -uid\n"); exit(1); #endif } break; } case OPTION_GID: rationalize++; use_RockRidge++; rationalize_gid++; { char *end = 0; gid_to_use = strtol(optarg, &end, 0); if (!end || *end != 0) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Bad value for -gid\n"); #else fprintf(stderr, "Bad value for -gid\n"); exit(1); #endif } break; } case OPTION_FILEMODE: rationalize++; use_RockRidge++; rationalize_filemode++; { char *end = 0; filemode_to_use = strtol(optarg, &end, 8); if (!end || *end != 0 || filemode_to_use < 0 || filemode_to_use > 07777) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Bad mode for -file-mode\n"); #else fprintf(stderr, "Bad mode for -file-mode\n"); exit(1); #endif } break; } case OPTION_DIRMODE: rationalize++; use_RockRidge++; rationalize_dirmode++; { char *end = 0; dirmode_to_use = strtol(optarg, &end, 8); if (!end || *end != 0 || dirmode_to_use < 0 || dirmode_to_use > 07777) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Bad mode for -dir-mode\n"); #else fprintf(stderr, "Bad mode for -dir-mode\n"); exit(1); #endif } break; } #ifdef SORTING case OPTION_SORT: do_sort++; add_sort_list(optarg); break; #endif /* SORTING */ case OPTION_SPLIT_OUTPUT: split_output++; break; case OPTION_STREAM_FILE_NAME: stream_filename = optarg; break; case OPTION_STREAM_CD_SIZE: stream_media_size = atoi(optarg); break; case OPTION_SYSID: system_id = optarg; if (strlen(system_id) > 32) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "System ID string too long\n"); #else fprintf(stderr, "System ID string too long\n"); exit(1); #endif } break; case OPTION_TRANS_TBL: trans_tbl = optarg; /* FALLTHRU */ case 'T': generate_tables++; break; case OPTION_UCS_LEVEL: ucs_level = atoi(optarg); if (ucs_level < 1 || ucs_level > 3) comerrno(EX_BAD, "Illegal UCS Level %d, use 1..3.\n", ucs_level); break; #ifdef UDF case OPTION_UDF: use_udf++; break; #endif #ifdef DVD_VIDEO case OPTION_DVD: use_udf++; dvd_video++; break; #endif case OPTION_USE_FILEVERSION: use_fileversion++; break; case 'U': /* * Minimal (only truncation of 31+ characters) * translation of filenames. * * Forces -l, -d, -N, -allow-leading-dots, * -relaxed-filenames, * -allow-lowercase, -allow-multidot * * This is for HP-UX, which does not recognize ANY * extentions (Rock Ridge, Joliet), causing pain when * loading software. pfs_mount can be used to read the * extensions, but the untranslated filenames can be * read by the "native" cdfs mounter. Completely * violates iso9660. */ full_iso9660_filenames++; /* 31 chars */ omit_period++; /* trailing dot */ allow_leading_dots++; omit_version_number++; relaxed_filenames++; /* all chars */ allow_lowercase++; /* even lowcase */ allow_multidot++; /* > 1 dots */ warn_violate++; break; case OPTION_RELAXED_FILENAMES: relaxed_filenames++; warn_violate++; break; case OPTION_ALLOW_LOWERCASE: allow_lowercase++; warn_violate++; break; case OPTION_ALLOW_MULTIDOT: allow_multidot++; warn_violate++; break; case OPTION_ISO_TRANSLATE: iso_translate = 0; warn_violate++; break; case 'V': volume_id = optarg; if (strlen(volume_id) > 32) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Volume ID string too long\n"); #else fprintf(stderr, "Volume ID string too long\n"); exit(1); #endif } break; case OPTION_VOLSET: volset_id = optarg; if (strlen(volset_id) > 128) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Volume set ID string too long\n"); #else fprintf(stderr, "Volume set ID string too long\n"); exit(1); #endif } break; case OPTION_VOLSET_SIZE: volume_set_size = atoi(optarg); if (volume_set_size <= 0) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Illegal Volume Set Size %s\n", optarg); #else fprintf(stderr, "Illegal Volume Set Size %s\n", optarg); exit(1); #endif } if (volume_set_size > 1) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Volume Set Size > 1 not yet supported\n"); #else fprintf(stderr, "Volume Set Size > 1 not yet supported\n"); exit(1); #endif } break; case OPTION_VOLSET_SEQ_NUM: volume_sequence_number = atoi(optarg); if (volume_sequence_number > volume_set_size) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Volume set sequence number too big\n"); #else fprintf(stderr, "Volume set sequence number too big\n"); exit(1); #endif } break; case 'v': verbose++; break; case 'z': #ifdef VMS #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Transparent compression not supported with VMS\n"); #else fprintf(stderr, "Transparent compression not supported with VMS\n"); exit(1); #endif #else transparent_compression++; #endif break; case 'x': case 'm': /* * Somehow two options to do basically the same thing * got added somewhere along the way. The 'match' * code supports limited globbing, so this is the one * that got selected. Unfortunately the 'x' switch is * probably more intuitive. */ add_match(optarg); break; case OPTION_X_LIST: add_list(optarg); break; case OPTION_I_HIDE: i_add_match(optarg); break; case OPTION_I_LIST: i_add_list(optarg); break; case OPTION_H_HIDE: h_add_match(optarg); break; case OPTION_H_LIST: h_add_list(optarg); break; case OPTION_J_HIDE: j_add_match(optarg); break; case OPTION_J_LIST: j_add_list(optarg); break; case OPTION_HIDE_TRANS_TBL: jhide_trans_tbl++; break; case OPTION_HIDE_RR_MOVED: hide_rr_moved++; break; case OPTION_HELP: usage(0); break; case OPTION_PVERSION: if(mkisofs_call) printf("mkisofs 2.01 is not what you see here. This line is only a fake for too clever\n" "GUIs and other frontend applications. In fact, this program is:\n"); printf("%s (%s)\n", version_string, HOST_SYSTEM); exit(0); break; case OPTION_NOSPLIT_SL_COMPONENT: split_SL_component = 0; break; case OPTION_NOSPLIT_SL_FIELD: split_SL_field = 0; break; case OPTION_HARD_DISK_BOOT: use_eltorito++; hard_disk_boot++; get_boot_entry(); current_boot_entry->hard_disk_boot = 1; break; case OPTION_NO_EMUL_BOOT: use_eltorito++; no_emul_boot++; get_boot_entry(); current_boot_entry->no_emul_boot = 1; break; case OPTION_NO_BOOT: use_eltorito++; not_bootable++; get_boot_entry(); current_boot_entry->not_bootable = 1; break; case OPTION_BOOT_LOAD_ADDR: use_eltorito++; { long val; char *ptr; val = strtol(optarg, &ptr, 0); if (*ptr || val < 0 || val >= 0x10000) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Boot image load address invalid.\n"); #else fprintf(stderr, "Boot image load address invalid.\n"); exit(1); #endif } load_addr = val; } get_boot_entry(); current_boot_entry->load_addr = load_addr; break; case OPTION_BOOT_LOAD_SIZE: use_eltorito++; { long val; char *ptr; val = strtol(optarg, &ptr, 0); if (*ptr || val < 0 || val >= 0x10000) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Boot image load size invalid.\n"); #else fprintf(stderr, "Boot image load size invalid.\n"); exit(1); #endif } load_size = val; } get_boot_entry(); current_boot_entry->load_size = load_size; break; case OPTION_BOOT_INFO_TABLE: use_eltorito++; boot_info_table++; get_boot_entry(); current_boot_entry->boot_info_table = 1; break; #ifdef APPLE_HYB case OPTION_HFS_TYPE: deftype = optarg; hfs_ct++; if (strlen(deftype) != 4) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "HFS default TYPE string has illegal length.\n"); #else fprintf(stderr, "HFS default TYPE string has illegal length.\n"); exit(1); #endif } break; case OPTION_HFS_CREATOR: defcreator = optarg; hfs_ct++; if (strlen(defcreator) != 4) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "HFS default CREATOR string has illegal length.\n"); #else fprintf(stderr, "HFS default CREATOR string has illegal length.\n"); exit(1); #endif } break; case 'H': /* FALLTHRU */ case OPTION_MAP_FILE: afpfile = optarg; hfs_last = MAP_LAST; break; case 'h': apple_hyb = 1; break; case 'g': apple_ext = 1; break; case OPTION_PROBE: probe = 1; break; case OPTION_MACNAME: use_mac_name = 1; break; case OPTION_NOMACFILES: #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Warning: -no-mac-files no longer used ... ignoring\n"); #else fprintf(stderr, "Warning: -no-mac-files no longer used ... ignoring\n"); #endif break; case OPTION_BOOT_HFS_FILE: hfs_boot_file = optarg; /* FALLTHRU */ case OPTION_GEN_PT: gen_pt = 1; break; case OPTION_MAGIC_FILE: #ifndef USE_MAGIC fprintf(stderr, "This program has been compiled without magic library support.\n" "Ignoring the -magic option.\n"); #endif magic_filename = optarg; hfs_last = MAG_LAST; break; case OPTION_AUTOSTART: autoname = optarg; /* gen_pt = 1; */ break; case OPTION_BSIZE: afe_size = atoi(optarg); hfs_select |= DO_FEU; hfs_select |= DO_FEL; break; case OPTION_HFS_VOLID: hfs_volume_id = optarg; break; case OPTION_ROOT_INFO: root_info = optarg; /* FALLTHRU */ case OPTION_ICON_POS: icon_pos = 1; break; /* Mac/Unix types to include */ case OPTION_CAP: hfs_select |= DO_CAP; break; case OPTION_NETA: hfs_select |= DO_NETA; break; case OPTION_DBL: hfs_select |= DO_DBL; break; case OPTION_ESH: case OPTION_USH: hfs_select |= DO_ESH; break; case OPTION_FE: hfs_select |= DO_FEU; hfs_select |= DO_FEL; break; case OPTION_SGI: case OPTION_XIN: hfs_select |= DO_SGI; break; case OPTION_MBIN: hfs_select |= DO_MBIN; break; case OPTION_SGL: hfs_select |= DO_SGL; break; case OPTION_DAVE: hfs_select |= DO_DAVE; break; case OPTION_SFM: hfs_select |= DO_SFM; break; case OPTION_XDBL: hfs_select |= DO_XDBL; break; case OPTION_XHFS: #ifdef IS_MACOS_X hfs_select |= DO_XHFS; #else /* IS_MACOS_X */ #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Warning: --osx-hfs only works on MacOS X ... ignoring\n"); #else /* USE_LIBSCHILY */ fprintf(stderr, "Warning: --osx-hfs only works on MacOS X ... ignoring\n"); #endif /* USE_LIBSCHILY */ #endif /* IS_MACOS_X */ break; case OPTION_CREATE_DT: create_dt = 0; break; case OPTION_HFS_HIDE: hfs_add_match(optarg); break; case OPTION_HFS_LIST: hfs_add_list(optarg); break; case OPTION_HFS_INPUT_CHARSET: use_mac_name = 1; hfs_icharset = optarg; break; case OPTION_HFS_OUTPUT_CHARSET: hfs_ocharset = optarg; break; case OPTION_HFS_UNLOCK: hfs_lock = 0; break; case OPTION_HFS_BLESS: hfs_bless = optarg; break; case OPTION_HFS_PARMS: hfs_parms = strdup(optarg); break; #ifdef PREP_BOOT case OPTION_PREP_BOOT: use_prep_boot++; if (use_prep_boot > 4 - use_chrp_boot) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Maximum of 4 PRep+CHRP partition entries are allowed\n"); #else fprintf(stderr, "Maximum of 4 PRep+CHRP partition entries are allowed\n"); #endif exit(1); } /* pathname of the boot image on cd */ prep_boot_image[use_prep_boot - 1] = optarg; if (prep_boot_image[use_prep_boot - 1] == NULL) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Required PReP boot image pathname missing\n"); #else fprintf(stderr, "Required PReP boot image pathname missing\n"); #endif exit(1); } break; case OPTION_CHRP_BOOT: if (use_chrp_boot) break; /* silently allow duplicates */ use_chrp_boot = 1; if (use_prep_boot > 3) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Maximum of 4 PRep+CHRP partition entries are allowed\n"); #else fprintf(stderr, "Maximum of 4 PRep+CHRP partition entries are allowed\n"); #endif exit(1); } break; #endif /* PREP_BOOT */ #endif /* APPLE_HYB */ case OPTION_ALLOW_LIMITED_SIZE: allow_limited_size++; use_udf++; break; default: susage(1); } /* * "--" was found, the next argument is a pathspec */ if (argc != optind) have_cmd_line_pathspec = 1; parse_input_files: path_ind = optind; /* * XXX This is a hack until we have a decent separate name handling * XXX for UDF filenames. */ if (dvd_video && use_Joliet) { use_Joliet = 0; fprintf(stderr, "Warning: Disabling Joliet support for DVD-Video.\n"); } if (use_udf && !use_Joliet) jlen = 255; if (preparer) { if (strlen(preparer) > 128) { comerrno(EX_BAD, "Preparer string too long\n"); } } if (publisher) { if (strlen(publisher) > 128) { comerrno(EX_BAD, "Publisher string too long\n"); } } if (stream_filename) { if (strlen(stream_filename) > MAX_ISONAME) comerrno(EX_BAD, "stream-file-name too long (%d), max is %d.\n", (int)strlen(stream_filename), (int)MAX_ISONAME); if (strchr(stream_filename, '/')) comerrno(EX_BAD, "Illegal character '/' in stream-file-name.\n"); iso9660_level = 4; } else { stream_filename = "STREAM.IMG;1"; } if (system_id) { if (strlen(system_id) > 32) { comerrno(EX_BAD, "System ID string too long\n"); } } if (use_RockRidge && (iso9660_namelen > MAX_ISONAME_V2_RR)) iso9660_namelen = MAX_ISONAME_V2_RR; if (warn_violate) /* this one is enough for quiet mode, print others warnings only in more verbose modes */ fprintf(stderr, "Warning: creating filesystem that does not conform to ISO-9660.\n"); if (iso9660_level > 3 && verbose>0) fprintf(stderr, "Warning: Creating ISO-9660:1999 (version 2) filesystem.\n"); if (iso9660_namelen > LEN_ISONAME && verbose>0) fprintf(stderr, "Warning: ISO-9660 filenames longer than %d may cause buffer overflows in the OS.\n", LEN_ISONAME); if (use_Joliet && !use_RockRidge && verbose>0) { fprintf(stderr, "Warning: creating filesystem with Joliet extensions but without Rock Ridge\n" " extensions. It is highly recommended to add Rock Ridge.\n"); } if (transparent_compression && verbose>0) { fprintf(stderr, "Warning: using transparent compression. This is a nonstandard Rock Ridge\n"); fprintf(stderr, " extension. The resulting filesystem can only be transparently\n"); fprintf(stderr, " read on Linux. On other operating systems you need to call\n"); fprintf(stderr, " mkzftree by hand to decompress the files.\n"); } if (transparent_compression && !use_RockRidge && verbose>0) { fprintf(stderr, "Warning: transparent decompression is a Linux Rock Ridge extension, but\n"); fprintf(stderr, " creating filesystem without Rock Ridge attributes; files\n"); fprintf(stderr, " will not be transparently decompressed.\n"); } if(follow_links && verbose>0) fprintf(stderr, "Warning: -follow-links does not always work correctly; be careful.\n"); init_unls(); /* Initialize UNICODE tables */ /* initialize code tables from a file - if they exists */ init_unls_file(icharset); init_unls_file(ocharset); #ifdef APPLE_HYB init_unls_file(hfs_icharset); init_unls_file(hfs_ocharset); #endif /* APPLE_HYB */ #ifdef USE_ICONV iconv_possible = !(iso9660_level >= 4 || ((ocharset && strcmp(ocharset, icharset ? icharset : "")) && use_RockRidge) || apple_ext || apple_hyb); setlocale(LC_CTYPE, ""); if (icharset == NULL && iconv_possible) { char *charset = nl_langinfo(CODESET); /* set to detected value but only if it is not pure US-ASCII */ if(charset) { /* workaround for SunOS, iconv is case-sensitive */ char *t; charset = strdup(charset); for(t=charset;*t!='\0';t++) *t=tolower(*t); } if(strcmp(charset, "ansi_x3.4-1968") != 0) icharset = charset; if(icharset && verbose > 0) fprintf(stderr, "I: -input-charset not specified, using %s (detected in locale settings)\n", icharset); } if(iconv_possible) { /* * don't care if initialization fails */ init_nls_iconv(icharset); init_nls_iconv(ocharset); } #endif if (icharset == NULL) { #if (defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__DJGPP__)) && !defined(IS_CYGWIN_1) in_nls = load_unls("cp437"); #else in_nls = load_unls("iso8859-1"); #endif } else { if (strcmp(icharset, "default") == 0) in_nls = load_unls_default(); else in_nls = load_unls(icharset); } /* * set the output charset to the same as the input or the given output * charset */ if (ocharset == NULL) { out_nls = in_nls; } else { if (strcmp(ocharset, "default") == 0) out_nls = load_unls_default(); else out_nls = load_unls(ocharset); } if (in_nls == NULL || out_nls == NULL) { /* Unknown charset specified */ fprintf(stderr, "Unknown charset\nKnown charsets are:\n"); list_unls(); /* List all known charset names */ #ifdef USE_ICONV fprintf(stderr, "\nAdditional input charsets are available for Joliet through the iconv support." "\nRun \"iconv -l\" to display them. Iconv charsets cannot be used with HFS, Apple" "\nextension, ISO9660 version 2 or Rock Ridge.\n"); #endif exit(1); } #ifdef APPLE_HYB if (hfs_icharset == NULL || strcmp(hfs_icharset, "mac-roman")) { hfs_inls = load_unls("cp10000"); } else { if (strcmp(hfs_icharset, "default") == 0) hfs_inls = load_unls_default(); else hfs_inls = load_unls(hfs_icharset); } if (hfs_ocharset == NULL) { hfs_onls = hfs_inls; } else { if (strcmp(hfs_ocharset, "default") == 0) hfs_onls = load_unls_default(); else if (strcmp(hfs_ocharset, "mac-roman") == 0) hfs_onls = load_unls("cp10000"); else hfs_onls = load_unls(hfs_ocharset); } if (hfs_inls == NULL || hfs_onls == NULL) { fprintf(stderr, "Unknown HFS charset\nKnown charsets are:\n"); list_unls(); exit(1); } #endif /* APPLE_HYB */ if (merge_image != NULL) { if (open_merge_image(merge_image) < 0) { /* Complain and die. */ #ifdef USE_LIBSCHILY comerr("Unable to open previous session image '%s'.\n", merge_image); #else fprintf(stderr, "Unable to open previous session image '%s'.\n", merge_image); exit(1); #endif } } /* We don't need root privilleges anymore. */ #ifdef HAVE_SETREUID if (setreuid(-1, getuid()) < 0) #else #ifdef HAVE_SETEUID if (seteuid(getuid()) < 0) #else if (setuid(getuid()) < 0) #endif #endif #ifdef USE_LIBSCHILY comerr("Panic cannot set back effective uid.\n"); #else { perror("Panic cannot set back effective uid."); exit(1); } #endif #ifdef no_more_needed #ifdef __NetBSD__ { int resource; struct rlimit rlp; if (getrlimit(RLIMIT_DATA, &rlp) == -1) perror("Warning: getrlimit failed"); else { rlp.rlim_cur = 33554432; if (setrlimit(RLIMIT_DATA, &rlp) == -1) perror("Warning: setrlimit failed"); } } #endif #endif /* no_more_needed */ #ifdef HAVE_SBRK mem_start = (unsigned long) sbrk(0); #endif /* * if the -hide-joliet option has been given, set the Joliet option */ if (!use_Joliet && j_ishidden()) use_Joliet++; #ifdef APPLE_HYB if (apple_hyb && apple_ext) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Can't have both -apple and -hfs options"); #else fprintf(stderr, "Can't have both -apple and -hfs options"); exit(1); #endif } /* * if -probe, -macname, any hfs selection and/or mapping file is given, * but no HFS option, then select apple_hyb */ if (!apple_hyb && !apple_ext) { if (*afpfile || probe || use_mac_name || hfs_select || hfs_boot_file || magic_filename || hfs_ishidden() || gen_pt || autoname || afe_size || icon_pos || hfs_ct || hfs_icharset || hfs_ocharset) { apple_hyb = 1; } } if (apple_ext && hfs_boot_file) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Can't have -hfs-boot-file with -apple\n"); #else fprintf(stderr, "Can't have -hfs-boot-file with -apple\n"); exit(1); #endif } if (apple_ext && autoname) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Can't have -auto with -apple\n"); #else fprintf(stderr, "Can't have -auto with -apple\n"); exit(1); #endif } if (apple_hyb && (use_sparcboot || use_sunx86boot)) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Can't have -hfs with -sparc-boot/-sunx86-boot\n"); #else fprintf(stderr, "Can't have -hfs with -sparc-boot/-sunx86-boot\n"); exit(1); #endif } if (apple_hyb && use_genboot) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Can't have -hfs with -generic-boot\n"); #else fprintf(stderr, "Can't have -hfs with -generic-boot\n"); exit(1); #endif } #ifdef PREP_BOOT if (apple_ext && use_prep_boot) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Can't have -prep-boot with -apple\n"); #else fprintf(stderr, "Can't have -prep-boot with -apple\n"); exit(1); #endif } #endif /* PREP_BOOT */ if (apple_hyb || apple_ext) apple_both = 1; if (probe) /* we need to search for all types of Apple/Unix files */ hfs_select = ~0; if (apple_both && verbose && !(hfs_select || *afpfile || magic_filename)) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Warning: no Apple/Unix files will be decoded/mapped\n"); #else fprintf(stderr, "Warning: no Apple/Unix files will be decoded/mapped\n"); #endif } if (apple_both && verbose && !afe_size && (hfs_select & (DO_FEU | DO_FEL))) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Warning: assuming PC Exchange cluster size of 512 bytes\n"); #else fprintf(stderr, "Warning: assuming PC Exchange cluster size of 512 bytes\n"); #endif afe_size = 512; } if (apple_both) { /* set up the TYPE/CREATOR mappings */ hfs_init(afpfile, 0, hfs_select); } if (apple_ext && !use_RockRidge) { #ifdef nonono /* use RockRidge to set the SystemUse field ... */ use_RockRidge++; rationalize_all++; #else /* EMPTY */ #endif } if (apple_ext && !(use_XA || use_RockRidge)) { comerrno(EX_BAD, "Need either -XA/-xa or -R/-r for -apple to become active.\n"); } #endif /* APPLE_HYB */ if (rationalize_all) { rationalize++; rationalize_uid++; rationalize_gid++; rationalize_filemode++; rationalize_dirmode++; } if (verbose > 1) { fprintf(stderr, "%s (%s)\n", version_string, HOST_SYSTEM); } if (cdrecord_data == NULL && !check_session && merge_image != NULL) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Multisession usage bug: Must specify -C if -M is used.\n"); #else fprintf(stderr, "Multisession usage bug: Must specify -C if -M is used.\n"); exit(1); #endif } if (cdrecord_data != NULL && merge_image == NULL) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Warning: -C specified without -M: old session data will not be merged.\n"); #else fprintf(stderr, "Warning: -C specified without -M: old session data will not be merged.\n"); #endif } #ifdef APPLE_HYB if (merge_image != NULL && apple_hyb) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Warning: files from previous sessions will not be included in the HFS volume.\n"); #else fprintf(stderr, "Warning: files from previous sessions will not be included in the HFS volume.\n"); #endif } #endif /* APPLE_HYB */ /* * see if we have a list of pathnames to process */ if (pathnames) { /* "-" means take list from the standard input */ if (strcmp(pathnames, "-")) { if ((pfp = fopen(pathnames, "r")) == NULL) { #ifdef USE_LIBSCHILY comerr("Unable to open pathname list %s.\n", pathnames); #else fprintf(stderr, "Unable to open pathname list %s.\n", pathnames); exit(1); #endif } } else pfp = stdin; } /* The first step is to scan the directory tree, and take some notes */ if ((arg = get_pnames(argc, argv, optind, pname, sizeof (pname), pfp)) == NULL) { if (check_session == 0 && !stream_media_size) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Missing pathspec.\n"); #endif susage(1); } } /* * if we don't have a pathspec, then save the pathspec found * in the pathnames file (stored in pname) - we don't want * to skip this pathspec when we read the pathnames file again */ if (!have_cmd_line_pathspec && !stream_media_size) { save_pname = 1; } if (stream_media_size) { if (use_XA || use_RockRidge || use_udf || use_Joliet) comerrno(EX_BAD, "Cannot use XA, Rock Ridge, UDF or Joliet with -stream-media-size\n"); if (merge_image) comerrno(EX_BAD, "Cannot use multi session with -stream-media-size\n"); if (use_eltorito || use_sparcboot || use_sunx86boot || use_genboot || use_prep_boot || hfs_boot_file) comerrno(EX_BAD, "Cannot use boot options with -stream-media-size\n"); if (apple_hyb) comerrno(EX_BAD, "Cannot use Apple hybrid options with -stream-media-size\n"); } if (use_RockRidge) { /* BEGIN CSTYLED */ #if 1 extension_record = generate_rr_extension_record("RRIP_1991A", "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size); #else extension_record = generate_rr_extension_record("IEEE_P1282", "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size); #endif /* END CSTYLED */ } if (log_file) { FILE *lfp; int i; /* open log file - test that we can open OK */ if ((lfp = fopen(log_file, "w")) == NULL) { #ifdef USE_LIBSCHILY comerr("Can't open logfile: '%s'.\n", log_file); #else fprintf(stderr, "Can't open logfile: '%s'.\n", log_file); exit(1); #endif } fclose(lfp); /* redirect all stderr message to log_file */ fprintf(stderr, "re-directing all messages to %s\n", log_file); fflush(stderr); /* associate stderr with the log file */ if (freopen(log_file, "w", stderr) == NULL) { #ifdef USE_LIBSCHILY comerr("Can't open logfile: '%s'.\n", log_file); #else fprintf(stderr, "Can't open logfile: '%s'.\n", log_file); exit(1); #endif } if (verbose > 1) { for (i = 0; i < argc; i++) fprintf(stderr, "%s ", argv[i]); fprintf(stderr, "\n%s (%s)\n", version_string, HOST_SYSTEM); } } /* Find name of root directory. */ if (arg != NULL) node = findgequal(arg); if (!use_graft_ptrs) node = NULL; if (node == NULL) { if (use_graft_ptrs && arg != NULL) node = escstrcpy(nodename, arg); else node = arg; } else { /* * Remove '\\' escape chars which are located * before '\\' and '=' chars */ node = escstrcpy(nodename, ++node); } /* * See if boot catalog file exists in root directory, if not we will * create it. */ if (use_eltorito) init_boot_catalog(node); /* * Find the device and inode number of the root directory. Record this * in the hash table so we don't scan it more than once. */ stat_filter(node, &statbuf); add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); memset(&de, 0, sizeof (de)); /* * PO: * Isn't root NULL at this time anyway? * I think it is created by the first call to * find_or_create_directory() below. */ de.filedir = root; /* We need this to bootstrap */ if (cdrecord_data != NULL && merge_image == NULL) { /* * in case we want to add a new session, but don't want to * merge old one */ get_session_start(NULL); } if (merge_image != NULL) { char sector[SECTOR_SIZE]; errno = 0; mrootp = merge_isofs(merge_image); if (mrootp == NULL) { /* Complain and die. */ #ifdef USE_LIBSCHILY if (errno == 0) errno = -1; comerr("Unable to find previous session PVD '%s'.\n", merge_image); #else fprintf(stderr, "Unable to find previous session PVD '%s'.\n", merge_image); exit(1); #endif } memcpy(de.isorec.extent, mrootp->extent, 8); /* * Look for RR Attributes in '.' entry of root dir. * This is the first ISO directory entry in the root dir. */ c = isonum_733((unsigned char *)mrootp->extent); #ifdef USE_SCG readsecs(c, sector, 1); #else lseek(fileno(in_image), c*2048, SEEK_SET); read(fileno(in_image), sector, sizeof (sector)); #endif c = rr_flags((struct iso_directory_record *)sector); if (c & RR_FLAG_XA) fprintf(stderr, "XA signatures found\n"); if (c & RR_FLAG_AA) fprintf(stderr, "AA signatures found\n"); if (c & ~(RR_FLAG_XA|RR_FLAG_AA)) { if (c & RR_FLAG_SP) { fprintf(stderr, "Rock Ridge signatures found\n"); } else { fprintf(stderr, "Bad Rock Ridge signatures found (SU record missing)\n"); if (!force_rr) no_rr++; } } else { fprintf(stderr, "NO Rock Ridge present\n"); if ((c & (RR_FLAG_XA|RR_FLAG_AA)) == 0) { if (!force_rr) no_rr++; } } if (no_rr) fprintf(stderr, "Disabling Rock Ridge / XA / AA\n"); } /* * Create an empty root directory. If we ever scan it for real, * we will fill in the contents. */ find_or_create_directory(NULL, "", &de, TRUE, NULL); #ifdef APPLE_HYB /* may need to set window layout of the volume */ if (root_info) set_root_info(root_info); #endif /* APPLE_HYB */ if(optind < argc-1) merge_warn_msg="NOTE: multiple source directories have been specified and merged into the root\n" "of the filesystem. Check your program arguments. genisoimage is not tar.\n"; /* * Scan the actual directory (and any we find below it) for files to * write out to the output image. Note - we take multiple source * directories and keep merging them onto the image. */ if (check_session == 0) while ((arg = get_pnames(argc, argv, optind, pname, sizeof (pname), pfp)) != NULL) { struct directory *graft_dir; struct stat st; char *short_name; int status; char graft_point[PATH_MAX + 1]; /* * We would like a syntax like: * * /tmp=/usr/tmp/xxx * * where the user can specify a place to graft each component * of the tree. To do this, we may have to create directories * along the way, of course. Secondly, I would like to allow * the user to do something like: * * /home/baz/RMAIL=/u3/users/baz/RMAIL * * so that normal files could also be injected into the tree * at an arbitrary point. * * The idea is that the last component of whatever is being * entered would take the name from the last component of * whatever the user specifies. * * The default will be that the file is injected at the root of * the image tree. */ node = findgequal(arg); if (!use_graft_ptrs) node = NULL; /* * Remove '\\' escape chars which are located * before '\\' and '=' chars ---> below in escstrcpy() */ short_name = NULL; if (node != NULL || reloc_root) { char *pnt; char *xpnt; size_t len; int node_is_dir; /* insert -root prefix */ if (reloc_root != NULL) { strcpy(graft_point, reloc_root); len = strlen(graft_point); if (graft_point[len] != '/') { graft_point[len++] = '/'; graft_point[len] = '\0'; } } else { len = 0; } if (node) { *node = '\0'; escstrcpy(&graft_point[len], arg); *node = '='; } /* * Remove unwanted "./" & "/" sequences from start... */ do { xpnt = graft_point; while (xpnt[0] == '.' && xpnt[1] == '/') xpnt += 2; while (*xpnt == PATH_SEPARATOR) { xpnt++; } memmove(graft_point, xpnt, strlen(xpnt)+1); } while (xpnt > graft_point); if (node) { node = escstrcpy(nodename, ++node); } else { node = arg; } graft_dir = root; xpnt = graft_point; /* * If "node" points to a directory, then graft_point * needs to point to a directory too. */ if (follow_links) status = stat_filter(node, &st); else status = lstat_filter(node, &st); node_is_dir = S_ISDIR(st.st_mode); if (status == 0 && node_is_dir) { len = strlen(graft_point); if ((len <= (sizeof (graft_point) -1)) && graft_point[len-1] != '/') { graft_point[len++] = '/'; graft_point[len] = '\0'; } } if (debug) fprintf(stderr, "GRAFT:'%s'\n", xpnt); /* * Loop down deeper and deeper until we find the * correct insertion spot. * Canonicalize the filename while parsing it. */ for (;;) { struct stat* stat_template; do { while (xpnt[0] == '.' && xpnt[1] == '/') xpnt += 2; while (xpnt[0] == '/') xpnt += 1; if (xpnt[0] == '.' && xpnt[1] == '.' && xpnt[2] == '/') { if (graft_dir && graft_dir != root) { graft_dir = graft_dir->parent; xpnt += 2; } } } while ((xpnt[0] == '/') || (xpnt[0] == '.' && xpnt[1] == '/')); pnt = strchr(xpnt, PATH_SEPARATOR); if (pnt == NULL) { if (*xpnt != '\0') { short_name = xpnt; } break; } *pnt = '\0'; if (debug) { fprintf(stderr, "GRAFT Point:'%s' in '%s : %s' (%s)\n", xpnt, graft_dir->whole_name, graft_dir->de_name, graft_point); } /* * If the node being grafted is a * directory, then we want the last * directory in this graft chain to have * the ownership and permissions of the * source node. Other directories in the * chain get default ownership and * permissions. */ stat_template = (pnt[1] == '\0' && node_is_dir) ? &st : 0; graft_dir = find_or_create_directory(graft_dir, graft_point, NULL, TRUE, stat_template); *pnt = PATH_SEPARATOR; xpnt = pnt + 1; } } else { graft_dir = root; if (use_graft_ptrs) node = escstrcpy(nodename, arg); else node = arg; } /* * Get information on the node */ if (follow_links) status = stat_filter(node, &st); else status = lstat_filter(node, &st); if (status != 0) { /* * This is a fatal error - the user won't be getting * what they want if we were to proceed. */ #ifdef USE_LIBSCHILY comerr("Invalid node - '%s'.\n", node); #else fprintf(stderr, "Invalid node - '%s'.\n", node); exit(1); #endif } else { /* * Now see whether the user wants to add a regular * file or a directory at this point. */ if (S_ISDIR(st.st_mode)) { if (debug) { fprintf(stderr, "graft_dir: '%s : %s', node: '%s', (scan)\n", graft_dir->whole_name, graft_dir->de_name, node); } if (!scan_directory_tree(graft_dir, node, &de)) { exit(1); } if (debug) { fprintf(stderr, "scan done\n"); } } else { if (short_name == NULL) { short_name = strrchr(node, PATH_SEPARATOR); if (short_name == NULL || short_name < node) { short_name = node; } else { short_name++; } } if (debug) { fprintf(stderr, "graft_dir: '%s : %s', node: '%s', short_name: '%s'\n", graft_dir->whole_name, graft_dir->de_name, node, short_name); } #ifdef APPLE_HYB if (!insert_file_entry(graft_dir, node, short_name, 0)) #else if (!insert_file_entry(graft_dir, node, short_name)) #endif /* APPLE_HYB */ { /* * Should we ignore this? */ /* exit(1);*/ /* EMPTY */ } } } optind++; no_path_names = 0; } if (pfp && pfp != stdin) fclose(pfp); /* * exit if we don't have any pathnames to process * - not going to happen at the moment as we have to have at least one * path on the command line */ if (no_path_names && !check_session && !stream_media_size) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "No pathnames found.\n"); #endif susage(1); } /* * Now merge in any previous sessions. This is driven on the source * side, since we may need to create some additional directories. */ if (merge_image != NULL) { if (merge_previous_session(root, mrootp, reloc_root, reloc_old_root) < 0) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Cannot merge previous session.\n"); #else fprintf(stderr, "Cannot merge previous session.\n"); exit(1); #endif } close_merge_image(); /* * set up parent_dir and filedir in relocated entries which * were read from previous session so that * finish_cl_pl_entries can do its job */ match_cl_re_entries(); } #ifdef APPLE_HYB /* free up any HFS filename mapping memory */ if (apple_both) clean_hfs(); #endif /* APPLE_HYB */ /* hide "./rr_moved" if all its contents have been hidden */ if (reloc_dir && i_ishidden()) hide_reloc_dir(); /* insert the boot catalog if required */ if (use_eltorito) insert_boot_cat(); /* * Free up any matching memory */ for (n = 0; n < MAX_MAT; n++) gen_del_match(n); #ifdef SORTING del_sort(); #endif /* SORTING */ /* * Sort the directories in the required order (by ISO9660). Also, * choose the names for the 8.3 filesystem if required, and do any * other post-scan work. */ goof += sort_tree(root); if (goof) { fprintf(stderr, "ISO9660/Rock Ridge tree sort failed.\n"); if(merge_warn_msg) fprintf(stderr, merge_warn_msg); exit(1); } #ifdef UDF if (use_Joliet || use_udf) { #else if (use_Joliet) { #endif goof += joliet_sort_tree(root); } if (goof) { fprintf(stderr, "Joliet tree sort failed. The -joliet-long switch may help you.\n"); if(merge_warn_msg) fprintf(stderr, merge_warn_msg); exit(1); } /* * Fix a couple of things in the root directory so that everything is * self consistent. Fix this up so that the path tables get done right. */ root->self = root->contents; /* OK, ready to write the file. Open it up, and generate the thing. */ if (print_size) { discimage = fopen("/dev/null", "wb"); if (!discimage) { #ifdef USE_LIBSCHILY comerr("Unable to open /dev/null\n"); #else fprintf(stderr, "Unable to open /dev/null\n"); exit(1); #endif } } else if (outfile && (strcmp (outfile, "-")) != 0) { discimage = fopen(outfile, "wb"); if (!discimage) { #ifdef USE_LIBSCHILY comerr("Unable to open disc image file '%s'.\n", outfile); #else fprintf(stderr, "Unable to open disc image file '%s'.\n", outfile); exit(1); #endif } if (jtemplate_out || jjigdo_out) { if (!jtemplate_out || !jjigdo_out || !jmd5_list) { #ifdef USE_LIBSCHILY comerr("Bad options - need to specify output names for jigdo and template file, and also the md5-list input file!\n"); #else fprintf(stderr, "Bad options - need to specify output names for jigdo and template file, and also the md5-list input file!\n"); exit(1); #endif } jtjigdo = fopen(jjigdo_out, "wb"); jttemplate = fopen(jtemplate_out, "wb"); if (!jtjigdo || !jttemplate) { #ifdef USE_LIBSCHILY comerr("Unable to open jigdo template image file\n"); #else fprintf(stderr, "Unable to open jigdo template image file\n"); exit(1); #endif } write_jt_header(jttemplate, jtjigdo); } } else if ((outfile == NULL) && isatty (fileno (stdout))) { /* FIXME: a cleaner way to override this check? */ fputs (("image not written to a terminal.\n" "Use -o - to force the output.\n"), stderr); exit (1); } else { discimage = stdout; #ifdef NEED_O_BINARY setmode(fileno(stdout), O_BINARY); #endif } /* Now assign addresses on the disc for the path table. */ path_blocks = ISO_BLOCKS(path_table_size); if (path_blocks & 1) path_blocks++; jpath_blocks = ISO_BLOCKS(jpath_table_size); if (jpath_blocks & 1) jpath_blocks++; /* * Start to set up the linked list that we use to track the contents * of the disc. */ #ifdef APPLE_HYB #ifdef PREP_BOOT if (apple_hyb || use_prep_boot || use_chrp_boot) #else /* PREP_BOOT */ if (apple_hyb) #endif /* PREP_BOOT */ outputlist_insert(&hfs_desc); #endif /* APPLE_HYB */ if (use_sparcboot || use_sunx86boot) outputlist_insert(&sunlabel_desc); if (use_alphaboot) outputlist_insert(&alphaboot_desc); if (use_hppaboot) outputlist_insert(&hppaboot_desc); if (use_alphaboot || use_hppaboot) outputlist_insert(&alpha_hppa_boot_desc); if (use_mipsboot) outputlist_insert(&mipsboot_desc); if (use_mipselboot) outputlist_insert(&mipselboot_desc); if (use_genboot) outputlist_insert(&genboot_desc); outputlist_insert(&startpad_desc); /* PVD for disc. */ outputlist_insert(&voldesc_desc); /* SVD for El Torito. MUST be immediately after the PVD! */ if (use_eltorito) { outputlist_insert(&torito_desc); } /* Enhanced PVD for disc. neded if we write ISO-9660:1999 */ if (iso9660_level > 3) outputlist_insert(&xvoldesc_desc); /* SVD for Joliet. */ if (use_Joliet) { outputlist_insert(&joliet_desc); } /* Finally the last volume descriptor. */ outputlist_insert(&end_vol); #ifdef UDF if (use_udf) { outputlist_insert(&udf_vol_recognition_area_frag); } #endif /* Insert the version descriptor. */ outputlist_insert(&version_desc); #ifdef UDF if (use_udf) { /* * Most of the space before sector 256 is wasted when * UDF is turned on. The waste could be reduced by * putting the ISO9660/Joliet structures before the * pad_to_sector_256; the problem is that they might * overshoot sector 256, so there would have to be some * ugly logic to detect this case and rearrange things * appropriately. I don't know if it's worth it. */ outputlist_insert(&udf_pad_to_sector_32_frag); outputlist_insert(&udf_main_seq_frag); outputlist_insert(&udf_main_seq_copy_frag); outputlist_insert(&udf_integ_seq_frag); outputlist_insert(&udf_pad_to_sector_256_frag); outputlist_insert(&udf_anchor_vol_desc_frag); outputlist_insert(&udf_file_set_desc_frag); outputlist_insert(&udf_dirtree_frag); outputlist_insert(&udf_file_entries_frag); } #endif /* Now start with path tables and directory tree info. */ if (!stream_media_size) outputlist_insert(&pathtable_desc); else outputlist_insert(&strpath_desc); if (use_Joliet) { outputlist_insert(&jpathtable_desc); } if (!stream_media_size) outputlist_insert(&dirtree_desc); if (use_Joliet) { outputlist_insert(&jdirtree_desc); } outputlist_insert(&dirtree_clean); if (extension_record) { outputlist_insert(&extension_desc); } if (!stream_media_size) { outputlist_insert(&files_desc); } else { outputlist_insert(&strfile_desc); outputlist_insert(&strdir_desc); } /* * Allow room for the various headers we will be writing. * There will always be a primary and an end volume descriptor. */ last_extent = session_start; /* * Calculate the size of all of the components of the disc, and assign * extent numbers. */ for (opnt = out_list; opnt; opnt = opnt->of_next) { opnt->of_start_extent = last_extent; if (opnt->of_size != NULL) { (*opnt->of_size) (last_extent); } } /* * Generate the contents of any of the sections that we want to * generate. Not all of the fragments will do anything here * - most will generate the data on the fly when we get to the write * pass. */ for (opnt = out_list; opnt; opnt = opnt->of_next) { if (opnt->of_generate != NULL) { (*opnt->of_generate) (); } } /* * Padding just after the ISO-9660 filesystem. * * files_desc does not have an of_size function. For this * reason, we must insert us after the files content has been * generated. */ #ifdef UDF if (use_udf) { /* Single anchor volume descriptor pointer at end */ outputlist_insert(&udf_end_anchor_vol_desc_frag); if (udf_end_anchor_vol_desc_frag.of_size != NULL) { (*udf_end_anchor_vol_desc_frag.of_size) (last_extent); } if (dopad) { /* * Pad with anchor volume descriptor pointer * blocks instead of zeroes. */ outputlist_insert(&udf_padend_avdp_frag); if (udf_padend_avdp_frag.of_size != NULL) { (*udf_padend_avdp_frag.of_size) (last_extent); } } } else #endif if (dopad && !(use_sparcboot || use_sunx86boot)) { outputlist_insert(&endpad_desc); if (endpad_desc.of_size != NULL) { (*endpad_desc.of_size) (last_extent); } } c = 0; if (use_sparcboot) { if (dopad) { /* Padding before the boot partitions. */ outputlist_insert(&interpad_desc); if (interpad_desc.of_size != NULL) { (*interpad_desc.of_size) (last_extent); } } c = make_sun_label(); last_extent += c; outputlist_insert(&sunboot_desc); if (dopad) { outputlist_insert(&endpad_desc); if (endpad_desc.of_size != NULL) { (*endpad_desc.of_size) (last_extent); } } } else if (use_sunx86boot) { if (dopad) { /* Padding before the boot partitions. */ outputlist_insert(&interpad_desc); if (interpad_desc.of_size != NULL) { (*interpad_desc.of_size) (last_extent); } } c = make_sunx86_label(); last_extent += c; outputlist_insert(&sunboot_desc); if (dopad) { outputlist_insert(&endpad_desc); if (endpad_desc.of_size != NULL) { (*endpad_desc.of_size) (last_extent); } } } if (print_size > 0) { if (verbose > 0) fprintf(stderr, "Total extents scheduled to be written = %u\n", (last_extent - session_start)); printf("%u\n", (last_extent - session_start)); exit(0); } /* * Now go through the list of fragments and write the data that * corresponds to each one. */ for (opnt = out_list; opnt; opnt = opnt->of_next) { Uint oext; oext = last_extent_written; if (opnt->of_start_extent != 0 && opnt->of_start_extent != last_extent_written) { /* * Consistency check. * XXX Should make sure that all entries have * XXXX of_start_extent set up correctly. */ comerrno(EX_BAD, "Implementation botch: %s should start at %u but starts at %u.\n", opnt->of_name, opnt->of_start_extent, last_extent_written); } if (opnt->of_write != NULL) { if (verbose > 1) fprintf(stderr, "Writing: %-40sStart Block %u\n", opnt->of_name, last_extent_written); (*opnt->of_write) (discimage); if (verbose > 1) fprintf(stderr, "Done with: %-40sBlock(s) %u\n", opnt->of_name, last_extent_written-oext); } } if (last_extent != last_extent_written) { comerrno(EX_BAD, "Implementation botch: FS should end at %u but ends at %u.\n", last_extent, last_extent_written); } if (jttemplate) { write_jt_footer(); fclose(jttemplate); } if (jtjigdo) fclose(jtjigdo); if (verbose > 0) { #ifdef HAVE_SBRK fprintf(stderr, "Max brk space used %x\n", (unsigned int)(((unsigned long) sbrk(0)) - mem_start)); #endif fprintf(stderr, "%u extents written (%u MB)\n", last_extent, last_extent >> 9); } #ifdef VMS return (1); #else return (0); #endif } /* * Find unescaped equal sign in graft pointer string. */ char * findgequal(char *s) { char *p = s; while ((p = strchr(p, '=')) != NULL) { if (p > s && p[-1] != '\\') return (p); p++; } return (NULL); } /* * Find unescaped equal sign in string. */ static char * escstrcpy(char *to, char *from) { char *p = to; if (debug) fprintf(stderr, "FROM: '%s'\n", from); while ((*p = *from++) != '\0') { if (*p == '\\') { if ((*p = *from++) == '\0') break; if (*p != '\\' && *p != '=') { p[1] = p[0]; *p++ = '\\'; } } p++; } if (debug) fprintf(stderr, "ESC: '%s'\n", to); return (to); } void * e_malloc(size_t size) { void *pt = 0; if ((size > 0) && ((pt = malloc(size)) == NULL)) { #ifdef USE_LIBSCHILY comerr("Not enough memory\n"); #else fprintf(stderr, "Not enough memory\n"); exit(1); #endif } /* * Not all code is clean yet. * Filling all allocated data with zeroes will help * to avoid core dumps. */ if (size > 0) /* a workaround for gcc bug gcc.gnu.org/PR25639 */ memset(pt, 0, size); return (pt); }