3993 lines
104 KiB
C
3993 lines
104 KiB
C
/* @(#)mkisofs.c 1.289 17/01/05 joerg */
|
|
#include <schily/mconfig.h>
|
|
#ifndef lint
|
|
static UConst char sccsid[] =
|
|
"@(#)mkisofs.c 1.289 17/01/05 joerg";
|
|
#endif
|
|
/*
|
|
* Program mkisofs.c - generate iso9660 filesystem based upon directory
|
|
* tree on hard disk.
|
|
*
|
|
* Written by Eric Youngdale (1993).
|
|
*
|
|
* Copyright 1993 Yggdrasil Computing, Incorporated
|
|
* Copyright (c) 1997-2017 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 */
|
|
/* MAC UDF images by HELIOS Software GmbH support@helios.de */
|
|
/* HFS+ by HELIOS Software GmbH support@helios.de */
|
|
|
|
/* DUPLICATES_ONCE Alex Kopylov cdrtools@bootcd.ru 19.06.2004 */
|
|
|
|
#ifdef USE_FIND
|
|
#include <schily/walk.h>
|
|
#include <schily/find.h>
|
|
#endif
|
|
#include "mkisofs.h"
|
|
#include "rock.h"
|
|
#include <schily/errno.h>
|
|
#include <schily/time.h>
|
|
#include <schily/fcntl.h>
|
|
#include <schily/ctype.h>
|
|
#include "match.h"
|
|
#include <schily/schily.h>
|
|
#include <schily/nlsdefs.h>
|
|
#include <schily/checkerr.h>
|
|
#ifdef UDF
|
|
#include "udf.h"
|
|
#endif
|
|
|
|
#include <schily/io.h> /* for setmode() prototype */
|
|
#include <schily/getargs.h>
|
|
|
|
#ifdef VMS
|
|
#include "vms.h"
|
|
#endif
|
|
|
|
#ifdef no_more_needed
|
|
#include <schily/resource.h>
|
|
#endif /* no_more_needed */
|
|
|
|
#include "../cdrecord/version.h"
|
|
|
|
struct directory *root = NULL;
|
|
int path_ind;
|
|
|
|
char version_string[] = VERSION;
|
|
|
|
char *outfile;
|
|
FILE *discimage;
|
|
UInt32_t next_extent = 0;
|
|
UInt32_t last_extent = 0;
|
|
UInt32_t 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;
|
|
UInt32_t extension_record_extent = 0;
|
|
int extension_record_size = 0;
|
|
BOOL archive_isreg;
|
|
dev_t archive_dev;
|
|
ino_t archive_ino;
|
|
|
|
/* 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_sparcboot = 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 */
|
|
/*
|
|
* Verbose levels currently used:
|
|
*
|
|
* 1+ Boot information
|
|
* 1+ Rcfile information
|
|
* 1+ Name mapping information
|
|
* 1+ Progress information
|
|
* 2+ Version informaton
|
|
* 2+ Output Extent (of_write) information
|
|
* 2+ PReP boot information
|
|
* 3+ HFS warnings
|
|
* 3+ Dump dirtree
|
|
*/
|
|
int verbose = 1;
|
|
int debug = 0;
|
|
int gui = 0;
|
|
BOOL legacy = FALSE; /* Implement legacy support for historic CLI */
|
|
int all_files = 1; /* New default is to include all files */
|
|
BOOL Hflag = FALSE; /* Follow links on cmdline (-H) */
|
|
BOOL follow_links = FALSE; /* Follow all links (-L) */
|
|
#if defined(__MINGW32__) || defined(_MSC_VER)
|
|
/*
|
|
* Never cache inodes on DOS or Win-DOS.
|
|
*/
|
|
int cache_inodes = 0;
|
|
#else
|
|
int cache_inodes = -1; /* Cache inodes if OS has unique inodes */
|
|
#endif
|
|
int rationalize = 0; /* Need to call stat_fix() */
|
|
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; /* neither -new-dir-mode nor -dir-mode used */
|
|
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;
|
|
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;
|
|
/* -------------------------------------------------------------------------- */
|
|
char *merge_image; /* CLI Parameter for -M option */
|
|
char *check_image; /* CLI Parameter for -check-session option */
|
|
char *reloc_root = NULL; /* CLI Parameter for -root option */
|
|
char *reloc_old_root = NULL; /* CLI Parameter for -oldroot option */
|
|
extern char *cdrecord_data; /* CLI Parameter for -C option */
|
|
int disable_deep_reloc; /* CLI Parameter for -D option */
|
|
char *dirmode_str; /* CLI Parameter for -dir-mode option */
|
|
char *filemode_str; /* CLI Parameter for -file-mode option */
|
|
char *gid_str; /* CLI Parameter for -gid option */
|
|
int help; /* CLI Parameter for -help option */
|
|
int joliet_long; /* CLI Parameter for -joliet-long option */
|
|
char *jcharset; /* CLI Parameter for -jcharset option */
|
|
int max_filenames; /* CLI Parameter for -max-iso9660-filenames option */
|
|
char *log_file; /* CLI Parameter for -log-file option */
|
|
char *new_dirmode_str; /* CLI Parameter for -new-dir-mode option */
|
|
char *pathnames; /* CLI Parameter for -help option */
|
|
int rationalize_rr; /* CLI Parameter for -path-list option */
|
|
char *sectype; /* CLI Parameter for -s option */
|
|
char *uid_str; /* CLI Parameter for -uid option */
|
|
int untranslated_filenames; /* CLI Parameter for -U option */
|
|
int pversion; /* CLI Parameter for -version option */
|
|
int rationalize_xa; /* CLI Parameter for -xa option */
|
|
ldate modification_date; /* CLI Parameter for -modification-date */
|
|
#ifdef APPLE_HYB
|
|
char *afpfile = ""; /* CLI Parameter for -map option */
|
|
char *root_info; /* CLI Parameter for -root-info option */
|
|
#endif
|
|
BOOL nodesc = FALSE; /* Whether not to descend directories */
|
|
#ifdef USE_FIND
|
|
BOOL dofind = FALSE; /* -find option found */
|
|
int find_ac = 0; /* ac past -find option */
|
|
char *const *find_av = NULL; /* av past -find option */
|
|
int find_pac = 0; /* ac for first find primary */
|
|
char *const *find_pav = NULL; /* av for first find primary */
|
|
findn_t *find_node; /* syntaxtree from find_parse() */
|
|
void *plusp; /* residual for -exec ...{} + */
|
|
int find_patlen; /* len for -find pattern state */
|
|
|
|
LOCAL int walkflags = WALK_CHDIR | WALK_PHYS | WALK_NOEXIT;
|
|
LOCAL int maxdepth = -1;
|
|
LOCAL int mindepth = -1;
|
|
EXPORT struct WALK walkstate;
|
|
#else
|
|
LOCAL int walkflags = 0;
|
|
#endif
|
|
|
|
extern time_t begun;
|
|
extern struct timeval tv_begun;
|
|
|
|
LOCAL BOOL data_change_warn;
|
|
|
|
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 match_igncase; /* Ignore case with -exclude-list and -hide* */
|
|
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 do_largefiles = 0; /* Whether to allow multi-extent files */
|
|
off_t maxnonlarge = (off_t)0xFFFFFFFF;
|
|
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 nolimitpathtables = 0; /* Don't limit size of pathtable. Violates iso9660 */
|
|
int relaxed_filenames = 0; /* For Amiga. Disc will not work with DOS */
|
|
int allow_lowercase = 0; /* Allow lower case letters */
|
|
int no_allow_lowercase = 0; /* Do not 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 */
|
|
#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; /* default name for translation table */
|
|
int stream_media_size = 0; /* # of blocks on the media */
|
|
char *stream_filename; /* Default stream file name */
|
|
|
|
#ifdef APPLE_HYB
|
|
int donotwrite_macpart = 0; /* Do not write "hfs" hybrid with UDF */
|
|
int apple_hyb = 0; /* -hfs HFS hybrid flag */
|
|
int no_apple_hyb = 0; /* -no-hfs 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/mkisofs 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_file = 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; /* default Apple TYPE */
|
|
char *defcreator; /* 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 */
|
|
#else /* APPLE_HYB */
|
|
int donotwrite_macpart = 1; /* Do not write "hfs" hybrid with UDF */
|
|
#endif /* APPLE_HYB */
|
|
|
|
#ifdef UDF
|
|
int rationalize_udf = 0; /* -udf (rationalized UDF) */
|
|
int use_udf = 0; /* -udf or -UDF */
|
|
int create_udfsymlinks = 1; /* include symlinks in UDF */
|
|
#endif
|
|
|
|
#ifdef DVD_AUD_VID
|
|
int dvd_audio = 0;
|
|
int dvd_hybrid = 0;
|
|
int dvd_video = 0;
|
|
int dvd_aud_vid_flag = DVD_SPEC_NONE;
|
|
#endif
|
|
|
|
#ifdef SORTING
|
|
int do_sort = 0; /* sort file data */
|
|
#endif /* SORTING */
|
|
|
|
/*
|
|
* inode numbers for zero sized files start from this number and count
|
|
* backwards. This is done to allow unique inode numbers even on multi-session
|
|
* disks.
|
|
*/
|
|
UInt32_t null_inodes = NULL_INO_MAX;
|
|
BOOL correct_inodes = TRUE; /* TRUE: add a "correct inodes" fingerprint */
|
|
BOOL rrip112 = TRUE; /* TRUE: create Rock Ridge V 1.12 */
|
|
BOOL long_rr_time = FALSE; /* TRUE: use long (17 Byte) time format */
|
|
|
|
#ifdef DUPLICATES_ONCE
|
|
int duplicates_once = 0; /* encode duplicate files once */
|
|
#endif
|
|
|
|
siconvt_t *in_nls = NULL; /* input UNICODE conversion table */
|
|
siconvt_t *out_nls = NULL; /* output UNICODE conversion table */
|
|
#ifdef APPLE_HYB
|
|
siconvt_t *hfs_inls = NULL; /* input HFS UNICODE conversion table */
|
|
siconvt_t *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}
|
|
};
|
|
|
|
#ifdef USE_FIND
|
|
LOCAL int getfind __PR((char *arg, long *valp,
|
|
int *pac, char *const **pav));
|
|
#endif
|
|
|
|
LOCAL int getH __PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
|
|
LOCAL int getL __PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
|
|
LOCAL int getP __PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
|
|
LOCAL int dolegacy __PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
|
|
|
|
LOCAL int get_boot_image __PR((char *opt_arg));
|
|
LOCAL int get_hd_boot __PR((char *opt_arg));
|
|
LOCAL int get_ne_boot __PR((char *opt_arg));
|
|
LOCAL int get_no_boot __PR((char *opt_arg));
|
|
LOCAL int get_boot_addr __PR((char *opt_arg));
|
|
LOCAL int get_boot_size __PR((char *opt_arg));
|
|
LOCAL int get_boot_platid __PR((char *opt_arg));
|
|
LOCAL int get_boot_table __PR((char *opt_arg));
|
|
#ifdef APPLE_HYB
|
|
#ifdef PREP_BOOT
|
|
LOCAL int get_prep_boot __PR((char *opt_arg));
|
|
LOCAL int get_chrp_boot __PR((char *opt_arg));
|
|
#endif
|
|
LOCAL int get_bsize __PR((char *opt_arg));
|
|
|
|
LOCAL int hfs_cap __PR((void));
|
|
LOCAL int hfs_neta __PR((void));
|
|
LOCAL int hfs_dbl __PR((void));
|
|
LOCAL int hfs_esh __PR((void));
|
|
LOCAL int hfs_fe __PR((void));
|
|
LOCAL int hfs_sgi __PR((void));
|
|
LOCAL int hfs_mbin __PR((void));
|
|
LOCAL int hfs_sgl __PR((void));
|
|
LOCAL int hfs_dave __PR((void));
|
|
LOCAL int hfs_sfm __PR((void));
|
|
LOCAL int hfs_xdbl __PR((void));
|
|
LOCAL int hfs_xhfs __PR((void));
|
|
LOCAL int hfs_nohfs __PR((void));
|
|
#endif /* APPLE_HYB */
|
|
|
|
LOCAL void ldate_error __PR((char *arg));
|
|
LOCAL char *strntoi __PR((char *p, int n, int *ip));
|
|
LOCAL int mosize __PR((int y, int m));
|
|
LOCAL char *parse_date __PR((char *arg, struct tm *tp));
|
|
LOCAL int get_ldate __PR((char *opt_arg, void *valp));
|
|
|
|
LOCAL int
|
|
get_boot_image(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
do_sort++; /* We sort bootcat/botimage */
|
|
use_eltorito++;
|
|
boot_image = opt_arg; /* pathname of the boot image */
|
|
/* on disk */
|
|
if (boot_image == NULL || *boot_image == '\0') {
|
|
comerrno(EX_BAD,
|
|
_("Required Eltorito boot image pathname missing\n"));
|
|
}
|
|
get_boot_entry();
|
|
current_boot_entry->boot_image = boot_image;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
get_hd_boot(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
use_eltorito++;
|
|
hard_disk_boot++;
|
|
get_boot_entry();
|
|
current_boot_entry->hard_disk_boot = 1;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
get_ne_boot(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
use_eltorito++;
|
|
no_emul_boot++;
|
|
get_boot_entry();
|
|
current_boot_entry->no_emul_boot = 1;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
get_no_boot(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
use_eltorito++;
|
|
not_bootable++;
|
|
get_boot_entry();
|
|
current_boot_entry->not_bootable = 1;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
get_boot_addr(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
long val;
|
|
char *ptr;
|
|
|
|
use_eltorito++;
|
|
val = strtol(opt_arg, &ptr, 0);
|
|
if (*ptr || val < 0 || val >= 0x10000) {
|
|
comerrno(EX_BAD, _("Boot image load address invalid.\n"));
|
|
}
|
|
load_addr = val;
|
|
get_boot_entry();
|
|
current_boot_entry->load_addr = load_addr;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
get_boot_size(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
long val;
|
|
char *ptr;
|
|
|
|
use_eltorito++;
|
|
val = strtol(opt_arg, &ptr, 0);
|
|
if (*ptr || val < 0 || val >= 0x10000) {
|
|
comerrno(EX_BAD,
|
|
_("Boot image load size invalid.\n"));
|
|
}
|
|
load_size = val;
|
|
get_boot_entry();
|
|
current_boot_entry->load_size = load_size;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
get_boot_platid(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
long val;
|
|
char *ptr;
|
|
|
|
use_eltorito++;
|
|
if (streql(opt_arg, "x86")) {
|
|
val = EL_TORITO_ARCH_x86;
|
|
} else if (streql(opt_arg, "PPC")) {
|
|
val = EL_TORITO_ARCH_PPC;
|
|
} else if (streql(opt_arg, "Mac")) {
|
|
val = EL_TORITO_ARCH_MAC;
|
|
} else if (streql(opt_arg, "efi")) {
|
|
val = EL_TORITO_ARCH_EFI;
|
|
} else {
|
|
val = strtol(opt_arg, &ptr, 0);
|
|
if (*ptr || val < 0 || val >= 0x100) {
|
|
comerrno(EX_BAD, _("Bad boot system ID.\n"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If there is already a boot entry and the boot file name has been set
|
|
* for this boot entry and the new platform id differs from the
|
|
* previous value, we start a new boot section.
|
|
*/
|
|
if (current_boot_entry &&
|
|
current_boot_entry->boot_image != NULL &&
|
|
current_boot_entry->boot_platform != val) {
|
|
new_boot_entry();
|
|
}
|
|
get_boot_entry();
|
|
current_boot_entry->type |= ELTORITO_BOOT_ID;
|
|
current_boot_entry->boot_platform = val;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
get_boot_table(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
use_eltorito++;
|
|
boot_info_table++;
|
|
get_boot_entry();
|
|
current_boot_entry->boot_info_table = 1;
|
|
return (1);
|
|
}
|
|
|
|
#ifdef APPLE_HYB
|
|
#ifdef PREP_BOOT
|
|
LOCAL int
|
|
get_prep_boot(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
use_prep_boot++;
|
|
if (use_prep_boot > 4 - use_chrp_boot) {
|
|
comerrno(EX_BAD,
|
|
_("Maximum of 4 PRep+CHRP partition entries are allowed\n"));
|
|
}
|
|
/* pathname of the boot image on cd */
|
|
prep_boot_image[use_prep_boot - 1] = opt_arg;
|
|
if (prep_boot_image[use_prep_boot - 1] == NULL) {
|
|
comerrno(EX_BAD,
|
|
_("Required PReP boot image pathname missing\n"));
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
get_chrp_boot(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
if (use_chrp_boot)
|
|
return (1); /* silently allow duplicates */
|
|
use_chrp_boot = 1;
|
|
if (use_prep_boot > 3) {
|
|
comerrno(EX_BAD,
|
|
_("Maximum of 4 PRep+CHRP partition entries are allowed\n"));
|
|
}
|
|
return (1);
|
|
}
|
|
#endif /* PREP_BOOT */
|
|
|
|
|
|
LOCAL int
|
|
get_bsize(opt_arg)
|
|
char *opt_arg;
|
|
{
|
|
afe_size = atoi(opt_arg);
|
|
hfs_select |= DO_FEU;
|
|
hfs_select |= DO_FEL;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_cap()
|
|
{
|
|
hfs_select |= DO_CAP;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_neta()
|
|
{
|
|
hfs_select |= DO_NETA;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_dbl()
|
|
{
|
|
hfs_select |= DO_DBL;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_esh()
|
|
{
|
|
hfs_select |= DO_ESH;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_fe()
|
|
{
|
|
hfs_select |= DO_FEU;
|
|
hfs_select |= DO_FEL;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_sgi()
|
|
{
|
|
hfs_select |= DO_SGI;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_mbin()
|
|
{
|
|
hfs_select |= DO_MBIN;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_sgl()
|
|
{
|
|
hfs_select |= DO_SGL;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_dave()
|
|
{
|
|
hfs_select |= DO_DAVE;
|
|
return (1);
|
|
}
|
|
|
|
|
|
LOCAL int
|
|
hfs_sfm()
|
|
{
|
|
hfs_select |= DO_SFM;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_xdbl()
|
|
{
|
|
hfs_select |= DO_XDBL;
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_xhfs()
|
|
{
|
|
#ifdef IS_MACOS_X
|
|
hfs_select |= DO_XHFS;
|
|
#else
|
|
errmsgno(EX_BAD,
|
|
_("Warning: --osx-hfs only works on MacOS X ... ignoring\n"));
|
|
#endif
|
|
return (1);
|
|
}
|
|
|
|
LOCAL int
|
|
hfs_nohfs()
|
|
{
|
|
no_apple_hyb = 1;
|
|
return (1);
|
|
}
|
|
|
|
#endif /* APPLE_HYB */
|
|
|
|
LOCAL void
|
|
ldate_error(arg)
|
|
char *arg;
|
|
{
|
|
comerrno(EX_BAD, _("Ilegal date specification '%s'.\n"), arg);
|
|
}
|
|
|
|
LOCAL char *
|
|
strntoi(p, n, ip)
|
|
char *p;
|
|
int n;
|
|
int *ip;
|
|
{
|
|
int i = 0;
|
|
int digits = 0;
|
|
int c;
|
|
|
|
while (*p) {
|
|
if (digits >= n)
|
|
break;
|
|
c = *p;
|
|
if (c < '0' || c > '9')
|
|
break;
|
|
p++;
|
|
digits++;
|
|
i *= 10;
|
|
i += c - '0';
|
|
}
|
|
*ip = i;
|
|
|
|
return (p);
|
|
}
|
|
|
|
#define dysize(A) (((A)%4)? 365 : (((A)%100) == 0 && ((A)%400)) ? 365 : 366)
|
|
|
|
static int dmsize[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
LOCAL int
|
|
mosize(y, m)
|
|
int y;
|
|
int m;
|
|
{
|
|
|
|
if (m == 1 && dysize(y) == 366)
|
|
return (29);
|
|
return (dmsize[m]);
|
|
}
|
|
|
|
LOCAL char *
|
|
parse_date(arg, tp)
|
|
char *arg;
|
|
struct tm *tp;
|
|
{
|
|
char *oarg = arg;
|
|
char *p;
|
|
|
|
tp->tm_mon = tp->tm_hour = tp->tm_min = tp->tm_sec = 0;
|
|
tp->tm_mday = 1;
|
|
tp->tm_isdst = -1;
|
|
|
|
p = strchr(arg, '/');
|
|
if (p == NULL)
|
|
p = strchr(arg, '-');
|
|
if (p) {
|
|
if ((p - arg) != 2 && (p - arg) != 4)
|
|
ldate_error(oarg);
|
|
p = strntoi(arg, 4, &tp->tm_year);
|
|
if ((p - arg) != 2 && (p - arg) != 4)
|
|
ldate_error(oarg);
|
|
if ((p - arg) == 2) {
|
|
if (tp->tm_year < 69)
|
|
tp->tm_year += 100;
|
|
} else {
|
|
tp->tm_year -= 1900;
|
|
}
|
|
if (*p == '/' || *p == '-')
|
|
p++;
|
|
} else if (strlen(arg) < 4) {
|
|
ldate_error(oarg);
|
|
} else {
|
|
p = strntoi(arg, 4, &tp->tm_year);
|
|
if ((p - arg) != 4)
|
|
ldate_error(oarg);
|
|
tp->tm_year -= 1900;
|
|
}
|
|
if (*p == '\0' || strchr(".+-", *p))
|
|
return (p);
|
|
arg = p;
|
|
p = strntoi(arg, 2, &tp->tm_mon);
|
|
if ((p - arg) != 2)
|
|
ldate_error(oarg);
|
|
tp->tm_mon -= 1;
|
|
if (tp->tm_mon < 0 || tp->tm_mon >= 12)
|
|
ldate_error(oarg);
|
|
if (*p == '/' || *p == '-')
|
|
p++;
|
|
if (*p == '\0' || strchr(".+-", *p))
|
|
return (p);
|
|
arg = p;
|
|
p = strntoi(arg, 2, &tp->tm_mday);
|
|
if ((p - arg) != 2)
|
|
ldate_error(oarg);
|
|
if (tp->tm_mday < 1 || tp->tm_mday > mosize(tp->tm_year+1900, tp->tm_mon))
|
|
ldate_error(oarg);
|
|
if (*p == ' ')
|
|
p++;
|
|
if (*p == '\0' || strchr(".+-", *p))
|
|
return (p);
|
|
arg = p;
|
|
p = strntoi(arg, 2, &tp->tm_hour);
|
|
if ((p - arg) != 2)
|
|
ldate_error(oarg);
|
|
if (tp->tm_hour > 23)
|
|
ldate_error(oarg);
|
|
if (*p == ':')
|
|
p++;
|
|
if (*p == '\0' || strchr(".+-", *p))
|
|
return (p);
|
|
arg = p;
|
|
p = strntoi(arg, 2, &tp->tm_min);
|
|
if ((p - arg) != 2)
|
|
ldate_error(oarg);
|
|
if (tp->tm_min > 59)
|
|
ldate_error(oarg);
|
|
if (*p == ':')
|
|
p++;
|
|
if (*p == '\0' || strchr(".+-", *p))
|
|
return (p);
|
|
arg = p;
|
|
p = strntoi(arg, 2, &tp->tm_sec);
|
|
if ((p - arg) != 2)
|
|
ldate_error(oarg);
|
|
if (tp->tm_sec > 61)
|
|
ldate_error(oarg);
|
|
return (p);
|
|
}
|
|
|
|
/*
|
|
* Parse a date spec similar to:
|
|
* YYYY[MM[DD[HH[MM[SS]]]]][.hh][+-GHGM]
|
|
*/
|
|
LOCAL int
|
|
get_ldate(opt_arg, valp)
|
|
char *opt_arg;
|
|
void *valp;
|
|
{
|
|
time_t t;
|
|
int usec = 0;
|
|
int gmtoff = -100;
|
|
struct tm tm;
|
|
char *p;
|
|
char *arg;
|
|
|
|
p = parse_date(opt_arg, &tm);
|
|
if (*p == '.') {
|
|
p++;
|
|
arg = p;
|
|
p = strntoi(arg, 2, &usec);
|
|
if ((p - arg) != 2)
|
|
ldate_error(opt_arg);
|
|
if (usec > 99)
|
|
ldate_error(opt_arg);
|
|
usec *= 10000;
|
|
}
|
|
if (*p == ' ')
|
|
p++;
|
|
if (*p == '+' || *p == '-') {
|
|
int i;
|
|
char *s = p++;
|
|
|
|
arg = p;
|
|
p = strntoi(arg, 2, &gmtoff);
|
|
if ((p - arg) != 2)
|
|
ldate_error(opt_arg);
|
|
arg = p;
|
|
p = strntoi(arg, 2, &i);
|
|
if ((p - arg) != 2)
|
|
ldate_error(opt_arg);
|
|
if (i > 59)
|
|
ldate_error(opt_arg);
|
|
gmtoff *= 60;
|
|
gmtoff += i;
|
|
if (gmtoff % 15)
|
|
ldate_error(opt_arg);
|
|
if (*s == '-')
|
|
gmtoff *= -1;
|
|
gmtoff /= 15;
|
|
if (gmtoff < -48 || gmtoff > 52)
|
|
ldate_error(opt_arg);
|
|
}
|
|
if (*p != '\0')
|
|
ldate_error(opt_arg);
|
|
|
|
seterrno(0);
|
|
t = mktime(&tm);
|
|
if (t == -1 && geterrno() != 0)
|
|
comerr(_("Date '%s' is out of range.\n"), opt_arg);
|
|
|
|
((ldate *)valp)->l_sec = t;
|
|
((ldate *)valp)->l_usec = usec;
|
|
((ldate *)valp)->l_gmtoff = gmtoff;
|
|
|
|
return (1);
|
|
}
|
|
|
|
#ifdef USE_FIND
|
|
/* ARGSUSED */
|
|
LOCAL int
|
|
getfind(arg, valp, pac, pav)
|
|
char *arg;
|
|
long *valp; /* Not used until we introduce a ptr to opt struct */
|
|
int *pac;
|
|
char *const **pav;
|
|
{
|
|
dofind = TRUE;
|
|
find_ac = *pac;
|
|
find_av = *pav;
|
|
find_ac--, find_av++;
|
|
return (NOARGS);
|
|
}
|
|
#endif
|
|
|
|
/* ARGSUSED */
|
|
LOCAL int
|
|
getH(arg, valp, pac, pav, opt) /* Follow symlinks encountered on cmdline */
|
|
const char *arg;
|
|
void *valp;
|
|
int *pac;
|
|
char *const **pav;
|
|
const char *opt;
|
|
{
|
|
/*error("getH\n");*/
|
|
if (opt[0] == '-' && opt[1] == 'H' && opt[2] == '\0') {
|
|
#ifdef APPLE_HYB
|
|
if (legacy) {
|
|
errmsgno(EX_BAD, _("The option '-H' is deprecated since 2002.\n"));
|
|
errmsgno(EX_BAD, _("The option '-H' was disabled in 2006.\n"));
|
|
errmsgno(EX_BAD, _("Use '-map' instead of '-H' as documented instead of using the legacy mode.\n"));
|
|
afpfile = (char *)arg;
|
|
return (1);
|
|
}
|
|
#endif
|
|
return (BADFLAG); /* POSIX -H is not yet active */
|
|
}
|
|
follow_links = FALSE;
|
|
Hflag = TRUE;
|
|
#ifdef USE_FIND
|
|
*(int *)valp |= WALK_ARGFOLLOW;
|
|
#endif
|
|
return (1);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
LOCAL int
|
|
getL(arg, valp, pac, pav, opt) /* Follow all symlinks */
|
|
const char *arg;
|
|
void *valp;
|
|
int *pac;
|
|
char *const **pav;
|
|
const char *opt;
|
|
{
|
|
/*error("getL\n");*/
|
|
if (opt[0] == '-' && opt[1] == 'L' && opt[2] == '\0') {
|
|
if (legacy) {
|
|
errmsgno(EX_BAD, _("The option '-L' is deprecated since 2002.\n"));
|
|
errmsgno(EX_BAD, _("The option '-L' was disabled in 2006.\n"));
|
|
errmsgno(EX_BAD,
|
|
_("Use '-allow-leading-dots' instead of '-L' as documented instead of using the legacy mode.\n"));
|
|
allow_leading_dots = TRUE;
|
|
return (1);
|
|
}
|
|
return (BADFLAG); /* POSIX -L is not yet active */
|
|
}
|
|
follow_links = TRUE;
|
|
Hflag = FALSE;
|
|
#ifdef USE_FIND
|
|
*(int *)valp |= WALK_ALLFOLLOW;
|
|
#endif
|
|
return (1);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
LOCAL int
|
|
getP(arg, valp, pac, pav, opt) /* Do not follow symlinks */
|
|
const char *arg;
|
|
void *valp;
|
|
int *pac;
|
|
char *const **pav;
|
|
const char *opt;
|
|
{
|
|
/*error("getP\n");*/
|
|
if (opt[0] == '-' && opt[1] == 'P' && opt[2] == '\0') {
|
|
if (legacy) {
|
|
errmsgno(EX_BAD, _("The option '-P' is deprecated since 2002.\n"));
|
|
errmsgno(EX_BAD, _("The option '-P' was disabled in 2006.\n"));
|
|
errmsgno(EX_BAD, _("Use '-publisher' instead of '-P' as documented instead of using the legacy mode.\n"));
|
|
publisher = (char *)arg;
|
|
return (1);
|
|
}
|
|
return (BADFLAG); /* POSIX -P is not yet active */
|
|
}
|
|
follow_links = FALSE;
|
|
Hflag = FALSE;
|
|
#ifdef USE_FIND
|
|
*(int *)valp &= ~(WALK_ARGFOLLOW | WALK_ALLFOLLOW);
|
|
#endif
|
|
return (1);
|
|
}
|
|
|
|
LOCAL struct ga_flags *gl_flags;
|
|
/* ARGSUSED */
|
|
LOCAL int
|
|
dolegacy(arg, valp, pac, pav, opt) /* Follow symlinks encountered on cmdline */
|
|
const char *arg;
|
|
void *valp;
|
|
int *pac;
|
|
char *const **pav;
|
|
const char *opt;
|
|
{
|
|
legacy = TRUE;
|
|
#ifdef APPLE_HYB
|
|
gl_flags[2].ga_format = "H&"; /* Apple Hybrid "-map" */
|
|
#endif
|
|
#ifdef OPT_L_HAS_ARG /* never ;-) */
|
|
gl_flags[4].ga_format = "L&"; /* -allow-leading-dots */
|
|
#endif
|
|
gl_flags[6].ga_format = "P&"; /* -publisher */
|
|
return (1);
|
|
}
|
|
|
|
struct mki_option {
|
|
/*
|
|
* The long option information.
|
|
*/
|
|
struct ga_flags opt;
|
|
/*
|
|
* The documentation string. If this is NULL or empty, this is a
|
|
* synonym for the previous option.
|
|
*
|
|
* If the string starts with a '-', the (long) option is a
|
|
* double dash option.
|
|
*
|
|
* If the next character in the string is a ^A (\1), then the following
|
|
* characters are the argument name for the option. The arg string ends
|
|
* before a \1 or a \2 is seen. A \1 is skipped.
|
|
*
|
|
* The rest of the string is the real documentation string. If it
|
|
* starts with \2, then the option is hidden from the online help.
|
|
*/
|
|
const char *doc;
|
|
};
|
|
|
|
|
|
LOCAL int save_pname = 0;
|
|
|
|
LOCAL const struct mki_option mki_options[] =
|
|
{
|
|
#ifdef USE_FIND
|
|
{{"find~", NULL, (getpargfun)getfind },
|
|
__("\1file... [find expr.]\1Option separator: Use find command line to the right")},
|
|
#endif
|
|
/*
|
|
* The options -H/-L/-P did have different meaning in old releases of
|
|
* mkisofs. In October 2002, mkisofs introduced a warning that the
|
|
* short options -H/-L/-P should not be used with the old meaning
|
|
* anymore. The long options should be used instead. The options
|
|
* -H/-L/-P previously have been associated with the following long
|
|
* options:
|
|
*
|
|
* -H -map 2000..2002
|
|
* -L -allow-leading-dots 1995..2002
|
|
* -P -publisher 1993..2002
|
|
*
|
|
* Since December 2006, the short options -H/-L/-P have been disabled
|
|
* for their old meaning.
|
|
*
|
|
* Warning: for the -legacy mode, the entries for -H/-L/-P need to stay
|
|
* at their current index in mki_options[] or dolegacy() needs to be
|
|
* changed to fit the modification.
|
|
*/
|
|
{{"posix-H~", &walkflags, getH },
|
|
__("Follow symbolic links encountered on command line")},
|
|
{{"H~", &walkflags, getH },
|
|
#ifdef LATER
|
|
NULL},
|
|
#else
|
|
__("\2")},
|
|
#endif
|
|
{{"posix-L~", &walkflags, getL },
|
|
__("Follow all symbolic links")},
|
|
{{"L~", &walkflags, getL },
|
|
#ifdef LATER
|
|
NULL},
|
|
#else
|
|
__("\2")},
|
|
#endif
|
|
{{"posix-P~", &walkflags, getP },
|
|
__("Do not follow symbolic links (default)")},
|
|
{{"P~", &walkflags, getP },
|
|
#ifdef LATER
|
|
NULL},
|
|
#else
|
|
__("\2")},
|
|
#endif
|
|
|
|
{{"abstract*", &abstract },
|
|
__("\1FILE\1Set Abstract filename")},
|
|
{{"A*,appid*", &appid },
|
|
__("\1ID\1Set Application ID")},
|
|
{{"biblio*", &biblio },
|
|
__("\1FILE\1Set Bibliographic filename")},
|
|
/*
|
|
* If this includes UWIN, we need to modify the condition.
|
|
*/
|
|
#if !defined(__MINGW32__) && !defined(_MSC_VER)
|
|
{{"cache-inodes", &cache_inodes },
|
|
__("Cache inodes (needed to detect hard links)")},
|
|
#endif
|
|
{{"no-cache-inodes%0", &cache_inodes },
|
|
__("Do not cache inodes (if filesystem has no unique inodes)")},
|
|
{{"rrip110%0", &rrip112 },
|
|
__("Create old Rock Ridge V 1.10")},
|
|
{{"rrip112", &rrip112 },
|
|
__("Create new Rock Ridge V 1.12 (default)")},
|
|
#ifdef DUPLICATES_ONCE
|
|
{{"duplicates-once", &duplicates_once},
|
|
__("Optimize storage by encoding duplicate files once")},
|
|
#endif
|
|
{{"check-oldnames", &check_oldnames },
|
|
__("Check all imported ISO9660 names from old session")},
|
|
{{"check-session*", &check_image },
|
|
__("\1FILE\1Check all ISO9660 names from previous session")},
|
|
{{"copyright*", ©right },
|
|
__("\1FILE\1Set Copyright filename")},
|
|
{{"debug+", &debug },
|
|
__("Set debug flag")},
|
|
{{"ignore-error", &ignerr },
|
|
__("Ignore errors")},
|
|
{{"b& ,eltorito-boot&", NULL, (getpargfun)get_boot_image },
|
|
__("\1FILE\1Set El Torito boot image name")},
|
|
{{"eltorito-alt-boot~", NULL, (getpargfun)new_boot_entry },
|
|
__("Start specifying alternative El Torito boot parameters")},
|
|
{{"eltorito-platform&", NULL, (getpargfun)get_boot_platid },
|
|
__("\1ID\1Set El Torito platform id for the next boot entry")},
|
|
{{"B&,sparc-boot&", NULL, (getpargfun)scan_sparc_boot },
|
|
__("\1FILES\1Set sparc boot image names")},
|
|
{{"sunx86-boot&", NULL, (getpargfun)scan_sunx86_boot },
|
|
__("\1FILES\1Set sunx86 boot image names")},
|
|
{{"G*,generic-boot*", &genboot_image },
|
|
__("\1FILE\1Set generic boot image name")},
|
|
{{"sparc-label&", NULL, (getpargfun)sparc_boot_label },
|
|
__("\1label text\1Set sparc boot disk label")},
|
|
{{"sunx86-label&", NULL, (getpargfun)sunx86_boot_label },
|
|
__("\1label text\1Set sunx86 boot disk label")},
|
|
{{"c* ,eltorito-catalog*", &boot_catalog },
|
|
__("\1FILE\1Set El Torito boot catalog name")},
|
|
{{"C*,cdrecord-params*", &cdrecord_data },
|
|
__("\1PARAMS\1Magic paramters from cdrecord")},
|
|
{{"d,omit-period", &omit_period },
|
|
__("Omit trailing periods from filenames (violates ISO9660)")},
|
|
{{"data-change-warn", &data_change_warn },
|
|
__("Treat data/size changes as warning only")},
|
|
{{"dir-mode*", &dirmode_str },
|
|
__("\1mode\1Make the mode of all directories this mode.")},
|
|
{{"D,disable-deep-relocation", &disable_deep_reloc },
|
|
__("Disable deep directory relocation (violates ISO9660)")},
|
|
{{"file-mode*", &filemode_str },
|
|
__("\1mode\1Make the mode of all plain files this mode.")},
|
|
{{"errctl&", NULL, (getpargfun)errconfig },
|
|
__("\1name\1Read error control defs from file or inline.")},
|
|
{{"f,follow-links", &follow_links },
|
|
__("Follow symbolic links")},
|
|
{{"gid*", &gid_str },
|
|
__("\1gid\1Make the group owner of all files this gid.")},
|
|
{{"graft-points", &use_graft_ptrs },
|
|
__("Allow to use graft points for filenames")},
|
|
{{"root*", &reloc_root },
|
|
__("\1DIR\1Set root directory for all new files and directories")},
|
|
{{"old-root*", &reloc_old_root },
|
|
__("\1DIR\1Set root directory in previous session that is searched for files")},
|
|
{{"help", &help },
|
|
__("Print option help")},
|
|
{{"hide& ", NULL, (getpargfun)i_add_match },
|
|
__("\1GLOBFILE\1Hide ISO9660/RR file")},
|
|
{{"hide-list&", NULL, (getpargfun)i_add_list },
|
|
__("\1FILE\1File with list of ISO9660/RR files to hide")},
|
|
{{"hidden& ", NULL, (getpargfun)h_add_match },
|
|
__("\1GLOBFILE\1Set hidden attribute on ISO9660 file")},
|
|
{{"hidden-list&", NULL, (getpargfun)h_add_list },
|
|
__("\1FILE\1File with list of ISO9660 files with hidden attribute")},
|
|
{{"hide-joliet& ", NULL, (getpargfun)j_add_match },
|
|
__("\1GLOBFILE\1Hide Joliet file")},
|
|
{{"hide-joliet-list&", NULL, (getpargfun)j_add_list },
|
|
__("\1FILE\1File with list of Joliet files to hide")},
|
|
#ifdef UDF
|
|
{{"hide-udf& ", NULL, (getpargfun)u_add_match },
|
|
__("\1GLOBFILE\1Hide UDF file")},
|
|
{{"hide-udf-list&", NULL, (getpargfun)u_add_list },
|
|
__("\1FILE\1File with list of UDF files to hide")},
|
|
#endif
|
|
{{"hide-joliet-trans-tbl", &jhide_trans_tbl},
|
|
__("Hide TRANS.TBL from Joliet tree")},
|
|
{{"hide-rr-moved", &hide_rr_moved },
|
|
__("Rename RR_MOVED to .rr_moved in Rock Ridge tree")},
|
|
{{"gui", &gui},
|
|
__("Switch behaviour for GUI")},
|
|
{{"input-charset*", &icharset },
|
|
__("\1CHARSET\1Local input charset for file name conversion")},
|
|
{{"output-charset*", &ocharset },
|
|
__("\1CHARSET\1Output charset for file name conversion")},
|
|
{{"iso-level#", &iso9660_level },
|
|
__("\1LEVEL\1Set ISO9660 conformance level (1..3) or 4 for ISO9660 version 2")},
|
|
{{"J,joliet", &use_Joliet },
|
|
__("Generate Joliet directory information")},
|
|
{{"joliet-long", &joliet_long },
|
|
__("Allow Joliet file names to be 103 Unicode characters")},
|
|
{{"jcharset*", &jcharset },
|
|
__("\1CHARSET\1Local charset for Joliet directory information")},
|
|
{{"l,full-iso9660-filenames", &full_iso9660_filenames },
|
|
__("Allow full 31 character filenames for ISO9660 names")},
|
|
{{"max-iso9660-filenames", &max_filenames },
|
|
__("Allow 37 character filenames for ISO9660 names (violates ISO9660)")},
|
|
|
|
{{"allow-leading-dots", &allow_leading_dots },
|
|
__("Allow ISO9660 filenames to start with '.' (violates ISO9660)")},
|
|
{{"ldots", &allow_leading_dots },
|
|
__("Allow ISO9660 filenames to start with '.' (violates ISO9660)")},
|
|
|
|
{{"log-file*", &log_file },
|
|
__("\1LOG_FILE\1Re-direct messages to LOG_FILE")},
|
|
{{"long-rr-time%1", &long_rr_time },
|
|
__("Use long Rock Ridge time format")},
|
|
{{"m& ,exclude& ", NULL, (getpargfun)add_match },
|
|
__("\1GLOBFILE\1Exclude file name")},
|
|
{{"exclude-list&", NULL, (getpargfun)add_list},
|
|
__("\1FILE\1File with list of file names to exclude")},
|
|
|
|
{{"hide-ignorecase", &match_igncase },
|
|
__("Ignore case with -exclude-list and -hide* options")},
|
|
{{"exclude-ignorecase", &match_igncase },
|
|
NULL},
|
|
|
|
{{"modification-date&", &modification_date, (getpargfun)get_ldate },
|
|
__("\1DATE\1Set the modification date field of the PVD")},
|
|
{{"nobak%0", &all_files },
|
|
__("Do not include backup files")},
|
|
{{"no-bak%0", &all_files},
|
|
__("Do not include backup files")},
|
|
{{"pad", &dopad },
|
|
__("Pad output to a multiple of 32k (default)")},
|
|
{{"no-pad%0", &dopad },
|
|
__("Do not pad output to a multiple of 32k")},
|
|
{{"no-limit-pathtables", &nolimitpathtables },
|
|
__("Allow more than 65535 parent directories (violates ISO9660)")},
|
|
{{"no-long-rr-time%0", &long_rr_time },
|
|
__("Use short Rock Ridge time format")},
|
|
{{"M*,prev-session*", &merge_image },
|
|
__("\1FILE\1Set path to previous session to merge")},
|
|
{{"dev*", &merge_image },
|
|
__("\1SCSIdev\1Set path to previous session to merge")},
|
|
{{"N,omit-version-number", &omit_version_number },
|
|
__("Omit version number from ISO9660 filename (violates ISO9660)")},
|
|
{{"new-dir-mode*", &new_dirmode_str },
|
|
__("\1mode\1Mode used when creating new directories.")},
|
|
{{"force-rr", &force_rr },
|
|
__("Inhibit automatic Rock Ridge detection for previous session")},
|
|
{{"no-rr", &no_rr },
|
|
__("Inhibit reading of Rock Ridge attributes from previous session")},
|
|
{{"no-split-symlink-components%0", &split_SL_component },
|
|
__("Inhibit splitting symlink components")},
|
|
{{"no-split-symlink-fields%0", &split_SL_field },
|
|
__("Inhibit splitting symlink fields")},
|
|
{{"o* ,output* ", &outfile },
|
|
__("\1FILE\1Set output file name")},
|
|
{{"path-list*", &pathnames },
|
|
__("\1FILE\1File with list of pathnames to process")},
|
|
{{"p* ,preparer*", &preparer },
|
|
__("\1PREP\1Set Volume preparer")},
|
|
{{"print-size", &print_size },
|
|
__("Print estimated filesystem size and exit")},
|
|
{{"publisher*", &publisher },
|
|
__("\1PUB\1Set Volume publisher")},
|
|
{{"quiet%0", &verbose },
|
|
__("Run quietly")},
|
|
{{"r,rational-rock", &rationalize_rr },
|
|
__("Generate rationalized Rock Ridge directory information")},
|
|
{{"R,rock", &use_RockRidge },
|
|
__("Generate Rock Ridge directory information")},
|
|
{{"s* ,sectype*", §ype },
|
|
__("\1TYPE\1Set output sector type to e.g. data/xa1/raw")},
|
|
{{"short-rr-time%0", &long_rr_time },
|
|
__("Use short Rock Ridge time format")},
|
|
|
|
#ifdef SORTING
|
|
{ {"sort&", NULL, add_sort_list },
|
|
__("\1FILE\1Sort file content locations according to rules in FILE")},
|
|
{ {"isort&", NULL, add_sort_list },
|
|
__("\1FILE\1Sort file content locations according to rules in FILE (ignore case)")},
|
|
#endif /* SORTING */
|
|
|
|
{{"split-output", &split_output },
|
|
__("Split output into files of approx. 1GB size")},
|
|
{{"stream-file-name*", &stream_filename },
|
|
__("\1FILE_NAME\1Set the stream file ISO9660 name (incl. version)")},
|
|
{{"stream-media-size#", &stream_media_size },
|
|
__("\1#\1Set the size of your CD media in sectors")},
|
|
{{"sysid*", &system_id },
|
|
__("\1ID\1Set System ID")},
|
|
{{"T,translation-table", &generate_tables },
|
|
__("Generate translation tables for systems that don't understand long filenames")},
|
|
{{"table-name*", &trans_tbl },
|
|
__("\1TABLE_NAME\1Translation table file name")},
|
|
{{"ucs-level#", &ucs_level },
|
|
__("\1LEVEL\1Set Joliet UCS level (1..3)")},
|
|
|
|
#ifdef UDF
|
|
{{"udf", &rationalize_udf },
|
|
__("Generate rationalized UDF file system")},
|
|
{{"UDF", &use_udf },
|
|
__("Generate UDF file system")},
|
|
{{"udf-symlinks", &create_udfsymlinks },
|
|
__("Create symbolic links on UDF image (default)")},
|
|
{{"no-udf-symlinks%0", &create_udfsymlinks },
|
|
__("Do not reate symbolic links on UDF image")},
|
|
#endif
|
|
|
|
#ifdef DVD_AUD_VID
|
|
{{"dvd-audio", &dvd_audio },
|
|
"Generate DVD-Audio compliant UDF file system"},
|
|
{{"dvd-hybrid", &dvd_hybrid },
|
|
"Generate a hybrid (DVD-Audio and DVD-Video) compliant UDF file system"},
|
|
{{"dvd-video", &dvd_video },
|
|
__("Generate DVD-Video compliant UDF file system")},
|
|
#endif
|
|
|
|
{{"uid*", &uid_str },
|
|
__("\1uid\1Make the owner of all files this uid.")},
|
|
{{"U,untranslated-filenames", &untranslated_filenames },
|
|
/* CSTYLED */
|
|
__("Allow Untranslated filenames (for HPUX & AIX - violates ISO9660). Forces -l, -d, -N, -allow-leading-dots, -relaxed-filenames, -allow-lowercase, -allow-multidot")},
|
|
{{"relaxed-filenames", &relaxed_filenames },
|
|
__("Allow 7 bit ASCII except lower case characters (violates ISO9660)")},
|
|
{{"no-iso-translate%0", &iso_translate },
|
|
__("Do not translate illegal ISO characters '~', '-' and '#' (violates ISO9660)")},
|
|
{{"allow-lowercase", &allow_lowercase },
|
|
__("Allow lower case characters in addition to the current character set (violates ISO9660)")},
|
|
{{"no-allow-lowercase", &no_allow_lowercase },
|
|
__("Do not allow lower case characters in addition to the current character set.")},
|
|
{{"+allow-lowercase", &no_allow_lowercase },
|
|
NULL},
|
|
{{"allow-multidot", &allow_multidot },
|
|
__("Allow more than one dot in filenames (e.g. .tar.gz) (violates ISO9660)")},
|
|
{{"use-fileversion", &use_fileversion },
|
|
__("\1LEVEL\1Use file version # from filesystem")},
|
|
{{"v+,verbose+", &verbose },
|
|
__("Verbose")},
|
|
{{"version", &pversion },
|
|
__("Print the current version")},
|
|
{{"V*,volid*", &volume_id },
|
|
__("\1ID\1Set Volume ID")},
|
|
{{"volset* ", &volset_id },
|
|
__("\1ID\1Set Volume set ID")},
|
|
{{"volset-size#", &volume_set_size },
|
|
__("\1#\1Set Volume set size")},
|
|
{{"volset-seqno#", &volume_sequence_number },
|
|
__("\1#\1Set Volume set sequence number")},
|
|
{{"x& ,old-exclude&", NULL, (getpargfun)add_match },
|
|
__("\1FILE\1Exclude file name(depreciated)")},
|
|
{{"hard-disk-boot~", NULL, (getpargfun)get_hd_boot },
|
|
__("Boot image is a hard disk image")},
|
|
{{"no-emul-boot~", NULL, (getpargfun)get_ne_boot },
|
|
__("Boot image is 'no emulation' image")},
|
|
{{"no-boot~", NULL, (getpargfun)get_no_boot },
|
|
__("Boot image is not bootable")},
|
|
{{"boot-load-seg&", NULL, (getpargfun)get_boot_addr },
|
|
__("\1#\1Set load segment for boot image")},
|
|
{{"boot-load-size&", NULL, (getpargfun)get_boot_size },
|
|
__("\1#\1Set numbers of load sectors")},
|
|
{{"boot-info-table~", NULL, (getpargfun)get_boot_table },
|
|
__("Patch boot image with info table")},
|
|
{{"XA", &use_XA },
|
|
__("Generate XA directory attributes")},
|
|
{{"xa", &rationalize_xa },
|
|
__("Generate rationalized XA directory attributes")},
|
|
{{"z,transparent-compression", &transparent_compression },
|
|
__("Enable transparent compression of files")},
|
|
|
|
#ifdef APPLE_HYB
|
|
{{"hfs-type*", &deftype },
|
|
__("\1TYPE\1Set HFS default TYPE")},
|
|
{{"hfs-creator", &defcreator },
|
|
__("\1CREATOR\1Set HFS default CREATOR")},
|
|
{{"g,apple", &apple_ext },
|
|
__("Add Apple ISO9660 extensions")},
|
|
{{"h,hfs", &apple_hyb },
|
|
__("Create ISO9660/HFS hybrid")},
|
|
{{"map*", &afpfile },
|
|
__("\1MAPPING_FILE\1Map file extensions to HFS TYPE/CREATOR")},
|
|
{{"magic*", &magic_file },
|
|
__("\1FILE\1Magic file for HFS TYPE/CREATOR")},
|
|
{{"probe", &probe },
|
|
__("Probe all files for Apple/Unix file types")},
|
|
{{"mac-name", &use_mac_name },
|
|
__("Use Macintosh name for ISO9660/Joliet/RockRidge file name")},
|
|
{{"no-mac-files", &nomacfiles },
|
|
__("Do not look for Unix/Mac files (depreciated)")},
|
|
{{"boot-hfs-file*", &hfs_boot_file },
|
|
__("\1FILE\1Set HFS boot image name")},
|
|
{{"part", &gen_pt },
|
|
__("Generate HFS partition table")},
|
|
{{"cluster-size&", NULL, (getpargfun)get_bsize },
|
|
__("\1SIZE\1Cluster size for PC Exchange Macintosh files")},
|
|
{{"auto*", &autoname },
|
|
__("\1FILE\1Set HFS AutoStart file name")},
|
|
{{"no-desktop%0", &create_dt },
|
|
__("Do not create the HFS (empty) Desktop files")},
|
|
{{"hide-hfs& ", NULL, (getpargfun)hfs_add_match },
|
|
__("\1GLOBFILE\1Hide HFS file")},
|
|
{{"hide-hfs-list&", NULL, (getpargfun)hfs_add_list },
|
|
__("\1FILE\1List of HFS files to hide")},
|
|
{{"hfs-volid*", &hfs_volume_id },
|
|
__("\1HFS_VOLID\1Volume name for the HFS partition")},
|
|
{{"icon-position", &icon_pos },
|
|
__("Keep HFS icon position")},
|
|
{{"root-info*", &root_info },
|
|
__("\1FILE\1finderinfo for root folder")},
|
|
{{"input-hfs-charset*", &hfs_icharset },
|
|
__("\1CHARSET\1Local input charset for HFS file name conversion")},
|
|
{{"output-hfs-charset*", &hfs_ocharset },
|
|
__("\1CHARSET\1Output charset for HFS file name conversion")},
|
|
{{"hfs-unlock%0", &hfs_lock },
|
|
__("Leave HFS Volume unlocked")},
|
|
{{"hfs-bless*", &hfs_bless },
|
|
__("\1FOLDER_NAME\1Name of Folder to be blessed")},
|
|
{{"hfs-parms*", &hfs_parms },
|
|
__("\1PARAMETERS\1Comma separated list of HFS parameters")},
|
|
#ifdef PREP_BOOT
|
|
{{"prep-boot&", NULL, (getpargfun)get_prep_boot },
|
|
__("\1FILE\1PReP boot image file -- up to 4 are allowed")},
|
|
{{"chrp-boot&", NULL, (getpargfun)get_chrp_boot },
|
|
__("Add CHRP boot header")},
|
|
#endif /* PREP_BOOT */
|
|
{{"cap~", NULL, (getpargfun)hfs_cap },
|
|
__("-Look for AUFS CAP Macintosh files")},
|
|
{{"netatalk~", NULL, (getpargfun)hfs_neta},
|
|
__("-Look for NETATALK Macintosh files")},
|
|
{{"double~", NULL, (getpargfun)hfs_dbl },
|
|
__("-Look for AppleDouble Macintosh files")},
|
|
{{"ethershare~", NULL, (getpargfun)hfs_esh },
|
|
__("-Look for Helios EtherShare Macintosh files")},
|
|
{{"exchange~", NULL, (getpargfun)hfs_fe },
|
|
__("-Look for PC Exchange Macintosh files")},
|
|
{{"sgi~", NULL, (getpargfun)hfs_sgi },
|
|
__("-Look for SGI Macintosh files")},
|
|
{{"macbin~", NULL, (getpargfun)hfs_mbin },
|
|
__("-Look for MacBinary Macintosh files")},
|
|
{{"single~", NULL, (getpargfun)hfs_sgl },
|
|
__("-Look for AppleSingle Macintosh files")},
|
|
{{"ushare~", NULL, (getpargfun)hfs_esh },
|
|
__("-Look for IPT UShare Macintosh files")},
|
|
{{"xinet~", NULL, (getpargfun)hfs_sgi },
|
|
__("-Look for XINET Macintosh files")},
|
|
{{"dave~", NULL, (getpargfun)hfs_dave },
|
|
__("-Look for DAVE Macintosh files")},
|
|
{{"sfm~", NULL, (getpargfun)hfs_sfm },
|
|
__("-Look for SFM Macintosh files")},
|
|
{{"osx-double~", NULL, (getpargfun)hfs_xdbl },
|
|
__("-Look for MacOS X AppleDouble Macintosh files")},
|
|
{{"osx-hfs~", NULL, (getpargfun)hfs_xhfs },
|
|
__("-Look for MacOS X HFS Macintosh files")},
|
|
{{"no-hfs~", NULL, (getpargfun)hfs_nohfs },
|
|
__("Do not create ISO9660/HFS hybrid")},
|
|
#endif /* APPLE_HYB */
|
|
{{"legacy~", NULL, dolegacy },
|
|
__("\2")},
|
|
};
|
|
|
|
#define OPTION_COUNT (sizeof mki_options / sizeof (mki_options[0]))
|
|
|
|
LOCAL void read_rcfile __PR((char *appname));
|
|
LOCAL void susage __PR((int excode));
|
|
LOCAL void usage __PR((int excode));
|
|
EXPORT int iso9660_date __PR((char *result, time_t crtime));
|
|
LOCAL void hide_reloc_dir __PR((void));
|
|
LOCAL char *get_pnames __PR((int argc, char *const *argv, int opt,
|
|
char *pname, int pnsize, FILE *fp));
|
|
EXPORT int main __PR((int argc, char *argv[]));
|
|
LOCAL void list_locales __PR((void));
|
|
EXPORT char *findgequal __PR((char *s));
|
|
LOCAL char *escstrcpy __PR((char *to, size_t tolen, char *from));
|
|
struct directory *get_graft __PR((char *arg, char *graft_point, size_t glen,
|
|
char *nodename, size_t nlen,
|
|
char **short_namep, BOOL do_insert));
|
|
EXPORT void *e_malloc __PR((size_t size));
|
|
EXPORT char *e_strdup __PR((const char *s));
|
|
LOCAL void ovstrcpy __PR((char *p2, char *p1));
|
|
LOCAL void checkarch __PR((char *name));
|
|
|
|
LOCAL void
|
|
read_rcfile(appname)
|
|
char *appname;
|
|
{
|
|
FILE *rcfile = (FILE *)NULL;
|
|
struct rcopts *rco;
|
|
char *pnt,
|
|
*pnt1;
|
|
char linebuffer[256];
|
|
static char rcfn[] = ".mkisofsrc";
|
|
char filename[1000];
|
|
int linum;
|
|
|
|
strlcpy(filename, rcfn, sizeof (filename));
|
|
if (access(filename, R_OK) == 0)
|
|
rcfile = fopen(filename, "r");
|
|
if (!rcfile && errno != ENOENT)
|
|
errmsg(_("Cannot open '%s'.\n"), filename);
|
|
|
|
if (!rcfile) {
|
|
pnt = getenv("MKISOFSRC");
|
|
if (pnt && strlen(pnt) <= sizeof (filename)) {
|
|
strlcpy(filename, pnt, sizeof (filename));
|
|
if (access(filename, R_OK) == 0)
|
|
rcfile = fopen(filename, "r");
|
|
if (!rcfile && errno != ENOENT)
|
|
errmsg(_("Cannot open '%s'.\n"), filename);
|
|
}
|
|
}
|
|
if (!rcfile) {
|
|
pnt = getenv("HOME");
|
|
if (pnt && strlen(pnt) + strlen(rcfn) + 2 <=
|
|
sizeof (filename)) {
|
|
strlcpy(filename, pnt, sizeof (filename));
|
|
if (strlen(rcfn) + 2 <=
|
|
(sizeof (filename) - strlen(filename))) {
|
|
strcat(filename, "/");
|
|
strcat(filename, rcfn);
|
|
}
|
|
if (access(filename, R_OK) == 0)
|
|
rcfile = fopen(filename, "r");
|
|
if (!rcfile && errno != ENOENT)
|
|
errmsg(_("Cannot open '%s'.\n"), filename);
|
|
}
|
|
}
|
|
if (!rcfile && strlen(appname) + sizeof (rcfn) + 2 <=
|
|
sizeof (filename)) {
|
|
strlcpy(filename, appname, sizeof (filename));
|
|
pnt = strrchr(filename, '/');
|
|
if (pnt) {
|
|
strlcpy(pnt + 1, rcfn,
|
|
sizeof (filename) - (pnt + 1 - filename));
|
|
if (access(filename, R_OK) == 0)
|
|
rcfile = fopen(filename, "r");
|
|
if (!rcfile && errno != ENOENT)
|
|
errmsg(_("Cannot open '%s'.\n"), filename);
|
|
}
|
|
}
|
|
if (!rcfile)
|
|
return;
|
|
if (verbose > 0) {
|
|
fprintf(stderr, _("Using \"%s\"\n"), filename);
|
|
}
|
|
/* OK, we got it. Now read in the lines and parse them */
|
|
linum = 0;
|
|
while (fgets(linebuffer, sizeof (linebuffer), rcfile)) {
|
|
char *name;
|
|
char *name_end;
|
|
|
|
++linum;
|
|
/* skip any leading white space */
|
|
pnt = linebuffer;
|
|
while (*pnt == ' ' || *pnt == '\t')
|
|
++pnt;
|
|
/*
|
|
* If we are looking at a # character, this line is a comment.
|
|
*/
|
|
if (*pnt == '#')
|
|
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 = pnt;
|
|
while (*pnt && (isalpha((unsigned char) *pnt) || *pnt == '_')) {
|
|
if (islower((unsigned char) *pnt))
|
|
*pnt = toupper((unsigned char) *pnt);
|
|
pnt++;
|
|
}
|
|
if (name == pnt) {
|
|
fprintf(stderr, _("%s:%d: name required\n"), filename,
|
|
linum);
|
|
continue;
|
|
}
|
|
name_end = pnt;
|
|
/* Skip past white space after the name */
|
|
while (*pnt == ' ' || *pnt == '\t')
|
|
pnt++;
|
|
/* silently ignore errors in the rc file. */
|
|
if (*pnt != '=') {
|
|
fprintf(stderr, _("%s:%d: equals sign required after '%.*s'\n"),
|
|
filename, linum,
|
|
/* XXX Should not be > int */
|
|
(int)(name_end-name), name);
|
|
continue;
|
|
}
|
|
/* Skip pas the = sign, and any white space following it */
|
|
pnt++; /* Skip past '=' sign */
|
|
while (*pnt == ' ' || *pnt == '\t')
|
|
pnt++;
|
|
|
|
/* now it is safe to NUL terminate the name */
|
|
|
|
*name_end = 0;
|
|
|
|
/* Now get rid of trailing newline */
|
|
|
|
pnt1 = pnt;
|
|
while (*pnt1) {
|
|
if (*pnt1 == '\n') {
|
|
*pnt1 = 0;
|
|
break;
|
|
}
|
|
pnt1++;
|
|
}
|
|
/* OK, now figure out which option we have */
|
|
for (rco = rcopt; rco->tag; rco++) {
|
|
if (strcmp(rco->tag, name) == 0) {
|
|
*rco->variable = e_strdup(pnt);
|
|
break;
|
|
}
|
|
}
|
|
if (rco->tag == NULL) {
|
|
fprintf(stderr, _("%s:%d: field name \"%s\" unknown\n"),
|
|
filename, linum,
|
|
name);
|
|
}
|
|
}
|
|
if (ferror(rcfile))
|
|
errmsg(_("Read error on '%s'.\n"), filename);
|
|
fclose(rcfile);
|
|
}
|
|
|
|
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
|
|
|
|
LOCAL void
|
|
susage(excode)
|
|
int excode;
|
|
{
|
|
const char *program_name = "mkisofs";
|
|
|
|
#ifdef USE_FIND
|
|
fprintf(stderr, _("Usage: %s [options] [-find] file... [find expression]\n"), program_name);
|
|
#else
|
|
fprintf(stderr, _("Usage: %s [options] file...\n"), program_name);
|
|
#endif
|
|
fprintf(stderr, _("\nUse %s -help\n"), program_name);
|
|
fprintf(stderr, _("to get a list all of valid options.\n"));
|
|
#ifdef USE_FIND
|
|
fprintf(stderr, _("\nUse %s -find -help\n"), program_name);
|
|
fprintf(stderr, _("to get a list of all valid -find options.\n"));
|
|
#endif
|
|
error(_("\nMost important Options:\n"));
|
|
error(_(" -posix-H Follow sylinks encountered on command line\n"));
|
|
error(_(" -posix-L Follow all symlinks\n"));
|
|
error(_(" -posix-P Do not follow symlinks (default)\n"));
|
|
error(_(" -o FILE, -output FILE Set output file name\n"));
|
|
error(_(" -R, -rock Generate Rock Ridge directory information\n"));
|
|
error(_(" -r, -rational-rock Generate rationalized Rock Ridge directory info\n"));
|
|
error(_(" -J, -joliet Generate Joliet directory information\n"));
|
|
error(_(" -print-size Print estimated filesystem size and exit\n"));
|
|
#ifdef UDF
|
|
error(_(" -UDF Generate UDF file system\n"));
|
|
#endif
|
|
#ifdef DVD_AUD_VID
|
|
error(_(" -dvd-audio Generate DVD-Audio compliant UDF file system\n"));
|
|
error(_(" -dvd-video Generate DVD-Video compliant UDF file system\n"));
|
|
error(_(" -dvd-hybrid Generate a hybrid (DVD-Audio/DVD-Video) compliant UDF file system\n"));
|
|
#endif
|
|
error(_(" -iso-level LEVEL Set ISO9660 level (1..3) or 4 for ISO9660 v 2\n"));
|
|
error(_(" -V ID, -volid ID Set Volume ID\n"));
|
|
error(_(" -graft-points Allow to use graft points for filenames\n"));
|
|
error(_(" -M FILE, -prev-session FILE Set path to previous session to merge\n"));
|
|
|
|
exit(excode);
|
|
}
|
|
|
|
const char *optend __PR((const char *fmt));
|
|
const char *
|
|
optend(fmt)
|
|
const char *fmt;
|
|
{
|
|
int c;
|
|
const char *ofmt = fmt;
|
|
|
|
for (; *fmt != '\0'; fmt++) {
|
|
c = *fmt;
|
|
if (c == '\\') {
|
|
if (*++fmt == '\0')
|
|
break;
|
|
continue;
|
|
}
|
|
if (c == ',' || c == '%' || c == '*' || c == '?' ||
|
|
c == '#' || c == '&' || c == '~')
|
|
break;
|
|
if (fmt > ofmt && c == '+')
|
|
break;
|
|
|
|
}
|
|
return (fmt);
|
|
}
|
|
|
|
int printopts __PR((FILE *f, const char *fmt, const char *arg, int twod));
|
|
int
|
|
printopts(f, fmt, arg, twod)
|
|
FILE *f;
|
|
const char *fmt;
|
|
const char *arg;
|
|
int twod;
|
|
{
|
|
const char *p;
|
|
int len = 0;
|
|
int optlen;
|
|
int arglen = 0;
|
|
|
|
if (arg) {
|
|
if (*arg == '-' || *arg == '\\')
|
|
arg++;
|
|
|
|
if (*arg == '\1') {
|
|
p = ++arg;
|
|
while (*p != '\0' && *p != '\1' && *p != '\2')
|
|
p++;
|
|
arglen = p - arg;
|
|
if (arglen == 0)
|
|
arg = NULL;
|
|
} else {
|
|
arg = NULL;
|
|
}
|
|
}
|
|
for (p = optend(fmt); p > fmt; p = optend(fmt)) {
|
|
optlen = p - fmt;
|
|
len += fprintf(f, "%s%.*s%s%.*s",
|
|
*fmt == '+' ? "" :
|
|
(optlen > 1 && twod) ? "--" : "-",
|
|
(int)(p - fmt), fmt,
|
|
arg != NULL ? " " : "",
|
|
arglen, arg != NULL ? arg : "");
|
|
fmt = p;
|
|
while (*fmt != '\0' && *fmt != ',')
|
|
fmt++;
|
|
if (*fmt == ',') {
|
|
fmt++;
|
|
len += fprintf(f, ", ");
|
|
}
|
|
}
|
|
return (len);
|
|
}
|
|
|
|
const char *docstr __PR((const char *str, int *no_help));
|
|
const char *
|
|
docstr(str, no_help)
|
|
const char *str;
|
|
int *no_help;
|
|
{
|
|
if (no_help)
|
|
*no_help = 0;
|
|
if (str == NULL)
|
|
return (str);
|
|
|
|
if (*str == '-' || *str == '\\')
|
|
str++;
|
|
|
|
if (*str == '\1') {
|
|
str++;
|
|
while (*str != '\0' && *str != '\1' && *str != '\2')
|
|
str++;
|
|
}
|
|
if (*str == '\1') {
|
|
str++;
|
|
} else if (*str == '\2') {
|
|
str++;
|
|
if (no_help)
|
|
*no_help = 1;
|
|
}
|
|
|
|
if (*str == '\0')
|
|
return (NULL);
|
|
return (str);
|
|
}
|
|
|
|
LOCAL void
|
|
usage(excode)
|
|
int excode;
|
|
{
|
|
const char *program_name = "mkisofs";
|
|
|
|
int i;
|
|
|
|
#ifdef USE_FIND
|
|
fprintf(stderr, _("Usage: %s [options] [-find] file... [find expression]\n"), program_name);
|
|
#else
|
|
fprintf(stderr, _("Usage: %s [options] file...\n"), program_name);
|
|
#endif
|
|
|
|
fprintf(stderr, _("Options:\n"));
|
|
for (i = 0; i < (int)OPTION_COUNT; i++) {
|
|
if (docstr(mki_options[i].doc, NULL) != NULL) {
|
|
int len;
|
|
int j;
|
|
|
|
fprintf(stderr, " ");
|
|
len = 2;
|
|
j = i;
|
|
do {
|
|
int twodash;
|
|
int no_help;
|
|
const char *doc;
|
|
|
|
doc = mki_options[j].doc;
|
|
twodash = (doc != NULL && *doc == '-');
|
|
doc = docstr(doc, &no_help);
|
|
|
|
if (!no_help) {
|
|
/*
|
|
* If more options for one doc, then
|
|
* print a comma as separator.
|
|
*/
|
|
if (j > i)
|
|
len += fprintf(stderr, ", ");
|
|
len += printopts(stderr,
|
|
mki_options[j].opt.ga_format,
|
|
mki_options[j].doc,
|
|
twodash);
|
|
}
|
|
++j;
|
|
}
|
|
while (j < (int)OPTION_COUNT &&
|
|
docstr(mki_options[j].doc, NULL) == NULL);
|
|
|
|
if (len >= 30) {
|
|
fprintf(stderr, "\n");
|
|
len = 0;
|
|
}
|
|
for (; len < 30; len++)
|
|
fputc(' ', stderr);
|
|
|
|
fprintf(stderr, "%s\n",
|
|
docstr(mki_options[i].doc, NULL));
|
|
}
|
|
}
|
|
exit(excode);
|
|
}
|
|
|
|
|
|
/*
|
|
* Fill in date in the iso9660 format
|
|
* This takes 7 bytes and supports year 1900 .. 2155 with 1 second granularity
|
|
*
|
|
* 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 (mkisofs had it wrong too until February 1997).
|
|
*/
|
|
EXPORT int
|
|
iso9660_date(result, crtime)
|
|
char *result;
|
|
time_t crtime;
|
|
{
|
|
struct tm local;
|
|
struct tm gmt;
|
|
|
|
local = *localtime(&crtime);
|
|
gmt = *gmtime(&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;
|
|
|
|
local.tm_min -= gmt.tm_min;
|
|
local.tm_hour -= gmt.tm_hour;
|
|
local.tm_yday -= gmt.tm_yday;
|
|
local.tm_year -= gmt.tm_year;
|
|
if (local.tm_year) /* Hit new-year limit */
|
|
local.tm_yday = local.tm_year; /* yday = +-1 */
|
|
|
|
result[6] = (local.tm_min + 60 *
|
|
(local.tm_hour + 24 * local.tm_yday)) / 15;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Fill in date in the iso9660 long format
|
|
* This takes 17 bytes and supports year 0 .. 9999 with 10ms granularity
|
|
* If iso9660_ldate() is called with gmtoff set to -100, the gmtoffset for
|
|
* the related time is computed via localtime(). For the modification
|
|
* date in the PVD, the date and the GMT offset may be defined via the
|
|
* -modification-date command line option.
|
|
*/
|
|
EXPORT int
|
|
iso9660_ldate(result, crtime, nsec, gmtoff)
|
|
char *result;
|
|
time_t crtime;
|
|
int nsec;
|
|
int gmtoff;
|
|
{
|
|
struct tm local;
|
|
struct tm gmt;
|
|
|
|
local = *localtime(&crtime);
|
|
gmt = *gmtime(&crtime);
|
|
|
|
/*
|
|
* There was a comment here about breaking in the year 2000.
|
|
* That's not true, in 2000 tm_year == 100, so 1900+tm_year == 2000.
|
|
*/
|
|
sprintf(result, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d%2.2d",
|
|
1900 + local.tm_year,
|
|
local.tm_mon + 1, local.tm_mday,
|
|
local.tm_hour, local.tm_min, local.tm_sec,
|
|
nsec / 10000000);
|
|
|
|
if (gmtoff == -100) {
|
|
local.tm_min -= gmt.tm_min;
|
|
local.tm_hour -= gmt.tm_hour;
|
|
local.tm_yday -= gmt.tm_yday;
|
|
local.tm_year -= gmt.tm_year;
|
|
if (local.tm_year) /* Hit new-year limit */
|
|
local.tm_yday = local.tm_year; /* yday = +-1 */
|
|
|
|
result[16] = (local.tm_min + 60 *
|
|
(local.tm_hour + 24 * local.tm_yday)) / 15;
|
|
} else {
|
|
result[16] = gmtoff;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/* hide "./rr_moved" if all its contents are hidden */
|
|
LOCAL 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
|
|
*/
|
|
LOCAL char *
|
|
get_pnames(argc, argv, opt, pname, pnsize, fp)
|
|
int argc;
|
|
char * const *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);
|
|
}
|
|
|
|
#ifdef USE_FIND
|
|
if (dofind && opt < (find_pav - argv))
|
|
return (argv[opt]);
|
|
else if (!dofind && opt < argc)
|
|
return (argv[opt]);
|
|
#else
|
|
if (opt < argc)
|
|
return (argv[opt]);
|
|
#endif
|
|
|
|
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);
|
|
}
|
|
|
|
EXPORT int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int cac = argc;
|
|
char * const *cav = argv;
|
|
|
|
struct directory_entry de;
|
|
|
|
#ifdef HAVE_SBRK
|
|
unsigned long mem_start;
|
|
#endif
|
|
struct stat statbuf;
|
|
struct iso_directory_record *mrootp = NULL;
|
|
struct output_fragment *opnt;
|
|
struct ga_flags flags[OPTION_COUNT + 1];
|
|
int c;
|
|
int n;
|
|
char *node = NULL;
|
|
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;
|
|
int argind = 0;
|
|
#ifdef APPLE_HYB
|
|
int hfs_ct = 0;
|
|
#endif /* APPLE_HYB */
|
|
|
|
|
|
#ifdef __EMX__
|
|
/* This gives wildcard expansion with Non-Posix shells with EMX */
|
|
_wildcard(&argc, &argv);
|
|
#endif
|
|
save_args(argc, argv);
|
|
|
|
#if defined(USE_NLS)
|
|
setlocale(LC_ALL, "");
|
|
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
|
|
#define TEXT_DOMAIN "mkisofs" /* Use this only if it weren't */
|
|
#endif
|
|
arg = searchfileinpath("share/locale", F_OK,
|
|
SIP_ANY_FILE|SIP_NO_PATH, NULL);
|
|
if (arg)
|
|
(void) bindtextdomain(TEXT_DOMAIN, arg);
|
|
else
|
|
#ifdef PROTOTYPES
|
|
(void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
|
|
#else
|
|
(void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
|
|
#endif
|
|
(void) textdomain(TEXT_DOMAIN);
|
|
#endif
|
|
|
|
|
|
if (argc < 2) {
|
|
errmsgno(EX_BAD, _("Missing pathspec.\n"));
|
|
susage(1);
|
|
}
|
|
/* Get the defaults from the .mkisofsrc file */
|
|
read_rcfile(argv[0]);
|
|
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < (int)OPTION_COUNT; i++) {
|
|
flags[i] = mki_options[i].opt;
|
|
}
|
|
flags[i].ga_format = NULL;
|
|
gl_flags = flags;
|
|
}
|
|
time(&begun);
|
|
gettimeofday(&tv_begun, NULL);
|
|
modification_date.l_sec = tv_begun.tv_sec;
|
|
modification_date.l_usec = tv_begun.tv_usec;
|
|
modification_date.l_gmtoff = -100;
|
|
|
|
cac--;
|
|
cav++;
|
|
c = getvargs(&cac, &cav, GA_NO_PROPS, flags);
|
|
if (c < 0) {
|
|
if (c == BADFLAG && strchr(cav[0], '=')) {
|
|
argind = argc - cac;
|
|
goto args_ok;
|
|
}
|
|
error(_("Bad Option '%s' (error %d %s).\n"),
|
|
cav[0], c, getargerror(c));
|
|
susage(EX_BAD);
|
|
}
|
|
args_ok:
|
|
if (argind == 0)
|
|
argind = argc - cac;
|
|
path_ind = argind;
|
|
if (cac > 0)
|
|
have_cmd_line_pathspec = 1;
|
|
if (help)
|
|
usage(0);
|
|
if (pversion) {
|
|
printf(_("mkisofs %s (%s-%s-%s)\n\n\
|
|
Copyright (C) 1993-1997 %s\n\
|
|
Copyright (C) 1997-2017 %s\n"),
|
|
version_string,
|
|
HOST_CPU, HOST_VENDOR, HOST_OS,
|
|
_("Eric Youngdale"),
|
|
_("Joerg Schilling"));
|
|
#ifdef APPLE_HYB
|
|
printf(_("Copyright (C) 1997-2001 James Pearson\n"));
|
|
#endif
|
|
#ifdef UDF
|
|
printf(_("Copyright (C) 2006 HELIOS Software GmbH\n"));
|
|
#endif
|
|
#ifdef OPTION_SILO_BOOT
|
|
printf(_("Warning: this is unofficial (modified) version of mkisofs that incorporates\n"));
|
|
printf(_(" support for a non Sparc compliant boot method called SILO.\n"));
|
|
printf(_(" The official method to create Sparc boot CDs is to use -sparc-boot\n"));
|
|
printf(_(" In case of problems first test with an official version of mkisofs.\n"));
|
|
#endif
|
|
exit(0);
|
|
}
|
|
#ifdef USE_FIND
|
|
if (dofind) {
|
|
finda_t fa;
|
|
|
|
cac = find_ac;
|
|
cav = find_av;
|
|
find_firstprim(&cac, &cav);
|
|
find_pac = cac;
|
|
find_pav = cav;
|
|
argind = argc - find_ac;
|
|
|
|
if (cac > 0) {
|
|
find_argsinit(&fa);
|
|
fa.walkflags = walkflags;
|
|
fa.Argc = cac;
|
|
fa.Argv = (char **)cav;
|
|
find_node = find_parse(&fa);
|
|
if (fa.primtype == FIND_ERRARG)
|
|
comexit(fa.error);
|
|
if (fa.primtype != FIND_ENDARGS)
|
|
comerrno(EX_BAD, _("Incomplete expression.\n"));
|
|
plusp = fa.plusp;
|
|
find_patlen = fa.patlen;
|
|
walkflags = fa.walkflags;
|
|
maxdepth = fa.maxdepth;
|
|
mindepth = fa.mindepth;
|
|
|
|
if (find_node &&
|
|
!(check_image || print_size) &&
|
|
(outfile == NULL ||
|
|
(outfile[0] == '-' && outfile[1] == '\0'))) {
|
|
if (find_pname(find_node, "-exec") ||
|
|
find_pname(find_node, "-exec+") ||
|
|
find_pname(find_node, "-ok"))
|
|
comerrno(EX_BAD,
|
|
_("Cannot -exec with '-o -'.\n"));
|
|
}
|
|
}
|
|
|
|
if (find_ac <= 0 || find_ac == find_pac) {
|
|
errmsgno(EX_BAD, _("Missing pathspec for -find.\n"));
|
|
susage(EX_BAD);
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef DVD_AUD_VID
|
|
|
|
dvd_aud_vid_flag = (dvd_audio ? DVD_SPEC_AUDIO : 0)
|
|
| (dvd_hybrid ? DVD_SPEC_HYBRD : 0)
|
|
| (dvd_video ? DVD_SPEC_VIDEO : 0);
|
|
|
|
#endif
|
|
|
|
if (abstract) {
|
|
if (strlen(abstract) > 37) {
|
|
comerrno(EX_BAD,
|
|
_("Abstract filename string too long (cur. %lld max. 37 chars).\n"),
|
|
(Llong)strlen(abstract));
|
|
}
|
|
}
|
|
if (appid) {
|
|
if (strlen(appid) > 128) {
|
|
comerrno(EX_BAD,
|
|
_("Application-id string too long (cur. %lld max. 128 chars).\n"),
|
|
(Llong)strlen(appid));
|
|
}
|
|
}
|
|
if (biblio) {
|
|
if (strlen(biblio) > 37) {
|
|
comerrno(EX_BAD,
|
|
_("Bibliographic filename string too long (cur. %lld max. 37 chars).\n"),
|
|
(Llong)strlen(biblio));
|
|
}
|
|
}
|
|
#ifdef DUPLICATES_ONCE
|
|
/*
|
|
* If -duplicates-once was specified, do not implicitly enable
|
|
* -cache-inodes.
|
|
*/
|
|
if (cache_inodes < 0 && duplicates_once)
|
|
cache_inodes = 0;
|
|
#endif
|
|
#if defined(IS_CYGWIN)
|
|
/*
|
|
* If we have 64 bit inode numbers, Cygwin should be able to work
|
|
* correctly on NTFS, otherwise disable caching unless it has
|
|
* been enforced via -cache-inodes.
|
|
*/
|
|
if (cache_inodes < 0 && sizeof (ino_t) < 8)
|
|
cache_inodes = 0;
|
|
#endif
|
|
if (cache_inodes < 0)
|
|
cache_inodes = 1;
|
|
#ifdef DUPLICATES_ONCE
|
|
if (!cache_inodes && !duplicates_once) {
|
|
#else
|
|
if (!cache_inodes) {
|
|
#endif
|
|
correct_inodes = FALSE;
|
|
if (use_RockRidge) {
|
|
errmsgno(EX_BAD,
|
|
_("Warning: Cannot write inode/link information with -no-cache-inodes.\n"));
|
|
} else {
|
|
errmsgno(EX_BAD,
|
|
_("Warning: Cannot add inode hints with -no-cache-inodes.\n"));
|
|
}
|
|
}
|
|
#if defined(__MINGW32__)
|
|
if (cache_inodes) {
|
|
cache_inodes = 0;
|
|
correct_inodes = FALSE;
|
|
errmsgno(EX_BAD,
|
|
_("Warning: cannot -cache-inodes on this platform - ignoring.\n"));
|
|
}
|
|
#endif
|
|
if (!correct_inodes)
|
|
rrip112 = FALSE;
|
|
if (check_image) {
|
|
check_session++;
|
|
check_oldnames++;
|
|
merge_image = check_image;
|
|
outfile = DEV_NULL;
|
|
/*
|
|
* cdrecord_data is handled specially in multi.c
|
|
* as we cannot write to all strings.
|
|
* If mkisofs is called with -C xx,yy
|
|
* our default is overwritten.
|
|
*/
|
|
/* cdrecord_data = "0,0";*/
|
|
}
|
|
if (copyright) {
|
|
if (strlen(copyright) > 37) {
|
|
comerrno(EX_BAD,
|
|
_("Copyright filename string too long (cur. %lld max. 37 chars).\n"),
|
|
(Llong)strlen(copyright));
|
|
}
|
|
}
|
|
if (genboot_image)
|
|
use_genboot++;
|
|
if (boot_catalog)
|
|
use_eltorito++;
|
|
else
|
|
boot_catalog = BOOT_CATALOG_DEFAULT;
|
|
if (omit_period && iso9660_level < 4)
|
|
warn_violate++;
|
|
if (data_change_warn)
|
|
errconfig("WARN|GROW|SHRINK *");
|
|
if (dirmode_str) {
|
|
char *end = 0;
|
|
|
|
rationalize++;
|
|
use_RockRidge++;
|
|
rationalize_dirmode++;
|
|
|
|
/*
|
|
* If -new-dir-mode was specified, new_dir_mode is set
|
|
* up later with a value that matches the -new-dir-mode arg.
|
|
*/
|
|
new_dir_mode = dirmode_to_use = strtol(dirmode_str, &end, 8);
|
|
if (!end || *end != 0 ||
|
|
dirmode_to_use < 0 || dirmode_to_use > 07777) {
|
|
comerrno(EX_BAD, _("Bad mode for -dir-mode\n"));
|
|
}
|
|
}
|
|
if (disable_deep_reloc)
|
|
RR_relocation_depth = 0xFFFFFFFF;
|
|
if (filemode_str) {
|
|
char *end = 0;
|
|
|
|
rationalize++;
|
|
use_RockRidge++;
|
|
rationalize_filemode++;
|
|
|
|
filemode_to_use = strtol(filemode_str, &end, 8);
|
|
if (!end || *end != 0 ||
|
|
filemode_to_use < 0 || filemode_to_use > 07777) {
|
|
comerrno(EX_BAD, _("Bad mode for -file-mode\n"));
|
|
}
|
|
}
|
|
#ifdef __warn_follow__
|
|
if (follow_links) {
|
|
errmsgno(EX_BAD,
|
|
_("Warning: -follow-links does not always work correctly; be careful.\n"));
|
|
}
|
|
#endif
|
|
if (gid_str) {
|
|
char *end = 0;
|
|
|
|
rationalize++;
|
|
use_RockRidge++;
|
|
rationalize_gid++;
|
|
|
|
gid_to_use = strtol(gid_str, &end, 0);
|
|
if (!end || *end != 0) {
|
|
comerrno(EX_BAD, _("Bad value for -gid\n"));
|
|
}
|
|
}
|
|
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
|
|
*/
|
|
do_largefiles++;
|
|
break;
|
|
case 4:
|
|
/*
|
|
* This is ISO-9660:1988 (ISO-9660 version 2)
|
|
*/
|
|
do_largefiles++;
|
|
iso9660_namelen = MAX_ISONAME_V2; /* allow 207 chars */
|
|
full_iso9660_filenames++; /* 31+ chars */
|
|
omit_version_number++;
|
|
RR_relocation_depth = 0xFFFFFFFF;
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
if (joliet_long) {
|
|
use_Joliet++;
|
|
jlen = JLONGMAX;
|
|
}
|
|
if (jcharset) {
|
|
use_Joliet++;
|
|
icharset = jcharset;
|
|
}
|
|
if (max_filenames && iso9660_level < 4) {
|
|
iso9660_namelen = MAX_ISONAME_V1; /* allow 37 chars */
|
|
full_iso9660_filenames++;
|
|
omit_version_number++;
|
|
warn_violate++;
|
|
}
|
|
if (allow_leading_dots && iso9660_level < 4)
|
|
warn_violate++;
|
|
if (omit_version_number && iso9660_level < 4)
|
|
warn_violate++;
|
|
if (new_dirmode_str) {
|
|
char *end = 0;
|
|
|
|
rationalize++;
|
|
|
|
new_dir_mode = strtol(new_dirmode_str, &end, 8);
|
|
if (!end || *end != 0 ||
|
|
new_dir_mode < 0 || new_dir_mode > 07777) {
|
|
comerrno(EX_BAD, _("Bad mode for -new-dir-mode\n"));
|
|
}
|
|
}
|
|
if (sectype) {
|
|
if (strcmp(sectype, "data") == 0)
|
|
osecsize = 2048;
|
|
else if (strcmp(sectype, "xa1") == 0)
|
|
osecsize = 2056;
|
|
else if (strcmp(sectype, "raw") == 0) {
|
|
osecsize = 2352;
|
|
comerrno(EX_BAD,
|
|
_("Unsupported sector type '%s'.\n"),
|
|
sectype);
|
|
}
|
|
}
|
|
if (preparer) {
|
|
if (strlen(preparer) > 128) {
|
|
comerrno(EX_BAD, _("Preparer string too long (cur. %lld max. 128 chars).\n"),
|
|
(Llong)strlen(preparer));
|
|
}
|
|
}
|
|
if (publisher) {
|
|
if (strlen(publisher) > 128) {
|
|
comerrno(EX_BAD,
|
|
_("Publisher string too long (cur. %lld max. 128 chars).\n"),
|
|
(Llong)strlen(publisher));
|
|
}
|
|
}
|
|
if (rationalize_rr) {
|
|
rationalize_all++;
|
|
use_RockRidge++;
|
|
}
|
|
if (stream_filename) {
|
|
if (strlen(stream_filename) > MAX_ISONAME)
|
|
comerrno(EX_BAD,
|
|
_("stream-file-name too long (%llu), max is %d.\n"),
|
|
(Ullong)strlen(stream_filename), MAX_ISONAME);
|
|
if (strchr(stream_filename, '/'))
|
|
comerrno(EX_BAD, _("Illegal character '/' in stream-file-name.\n"));
|
|
iso9660_level = 4;
|
|
} else {
|
|
stream_filename = omit_version_number ? "STREAM.IMG" : "STREAM.IMG;1";
|
|
}
|
|
if (system_id) {
|
|
if (strlen(system_id) > 32) {
|
|
comerrno(EX_BAD,
|
|
_("System ID string too long\n"));
|
|
}
|
|
}
|
|
if (trans_tbl)
|
|
generate_tables++;
|
|
else
|
|
trans_tbl = "TRANS.TBL";
|
|
if (ucs_level < 1 || ucs_level > 3)
|
|
comerrno(EX_BAD, _("Illegal UCS Level %d, use 1..3.\n"),
|
|
ucs_level);
|
|
#ifdef DVD_AUD_VID
|
|
if (dvd_aud_vid_flag) {
|
|
if (!use_udf)
|
|
rationalize_udf++;
|
|
}
|
|
#endif
|
|
#ifdef UDF
|
|
if (rationalize_udf) {
|
|
rationalize_all++;
|
|
use_udf++;
|
|
}
|
|
#endif
|
|
if (uid_str) {
|
|
char *end = 0;
|
|
|
|
rationalize++;
|
|
use_RockRidge++;
|
|
rationalize_uid++;
|
|
|
|
uid_to_use = strtol(uid_str, &end, 0);
|
|
if (!end || *end != 0) {
|
|
comerrno(EX_BAD, _("Bad value for -uid\n"));
|
|
}
|
|
}
|
|
if (untranslated_filenames && iso9660_level < 4) {
|
|
/*
|
|
* 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++;
|
|
}
|
|
if (no_allow_lowercase)
|
|
allow_lowercase = 0;
|
|
if (relaxed_filenames && iso9660_level < 4)
|
|
warn_violate++;
|
|
if (iso_translate == 0 && iso9660_level < 4)
|
|
warn_violate++;
|
|
if (allow_lowercase && iso9660_level < 4)
|
|
warn_violate++;
|
|
if (allow_multidot && iso9660_level < 4)
|
|
warn_violate++;
|
|
if (volume_id) {
|
|
if (strlen(volume_id) > 32) {
|
|
comerrno(EX_BAD,
|
|
_("Volume ID string too long (cur. %lld max. 32 chars).\n"),
|
|
(Llong)strlen(volume_id));
|
|
}
|
|
}
|
|
if (volset_id) {
|
|
if (strlen(volset_id) > 128) {
|
|
comerrno(EX_BAD,
|
|
_("Volume set ID string too long (cur. %lld max. 128 chars).\n"),
|
|
(Llong)strlen(volset_id));
|
|
}
|
|
}
|
|
if (volume_set_size) {
|
|
if (volume_set_size <= 0) {
|
|
comerrno(EX_BAD,
|
|
_("Illegal Volume Set Size %d\n"), volume_set_size);
|
|
}
|
|
if (volume_set_size > 1) {
|
|
comerrno(EX_BAD,
|
|
_("Volume Set Size > 1 not yet supported\n"));
|
|
}
|
|
}
|
|
if (volume_sequence_number) {
|
|
if (volume_sequence_number > volume_set_size) {
|
|
comerrno(EX_BAD,
|
|
_("Volume set sequence number too big\n"));
|
|
}
|
|
}
|
|
if (rationalize_xa) {
|
|
rationalize_all++;
|
|
use_XA++;
|
|
}
|
|
if (transparent_compression) {
|
|
#ifdef VMS
|
|
comerrno(EX_BAD,
|
|
_("Transparent compression not supported with VMS\n"));
|
|
#endif
|
|
}
|
|
#ifdef APPLE_HYB
|
|
if (deftype) {
|
|
hfs_ct++;
|
|
if (strlen(deftype) != 4) {
|
|
comerrno(EX_BAD,
|
|
_("HFS default TYPE string has illegal length.\n"));
|
|
}
|
|
} else {
|
|
deftype = APPLE_TYPE_DEFAULT;
|
|
}
|
|
if (defcreator) {
|
|
hfs_ct++;
|
|
if (strlen(defcreator) != 4) {
|
|
comerrno(EX_BAD,
|
|
_("HFS default CREATOR string has illegal length.\n"));
|
|
}
|
|
} else {
|
|
defcreator = APPLE_CREATOR_DEFAULT;
|
|
}
|
|
if (afpfile && *afpfile != '\0')
|
|
hfs_last = MAP_LAST;
|
|
if (magic_file)
|
|
hfs_last = MAG_LAST;
|
|
if (nomacfiles) {
|
|
errmsgno(EX_BAD,
|
|
_("Warning: -no-mac-files no longer used ... ignoring\n"));
|
|
}
|
|
if (hfs_boot_file)
|
|
gen_pt = 1;
|
|
if (root_info)
|
|
icon_pos = 1;
|
|
if (hfs_icharset)
|
|
use_mac_name = 1;
|
|
if (hfs_parms)
|
|
hfs_parms = e_strdup(hfs_parms);
|
|
|
|
if (apple_hyb && apple_ext) {
|
|
comerrno(EX_BAD, _("Can't have both -apple and -hfs options\n"));
|
|
}
|
|
/*
|
|
* 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_file ||
|
|
hfs_ishidden() || gen_pt || autoname ||
|
|
afe_size || icon_pos || hfs_ct ||
|
|
hfs_icharset || hfs_ocharset) {
|
|
apple_hyb = 1;
|
|
#ifdef UDF
|
|
if ((DO_XHFS & hfs_select) && use_udf) {
|
|
donotwrite_macpart = 1;
|
|
if (!no_apple_hyb) {
|
|
error(
|
|
_("Warning: no HFS hybrid will be created with -udf and --osx-hfs\n"));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef UDF
|
|
if (!use_udf && create_udfsymlinks)
|
|
create_udfsymlinks = 0;
|
|
#if 0
|
|
if (use_RockRidge && use_udf && create_udfsymlinks) {
|
|
error(_("Warning: cannot create UDF symlinks with activated Rock Ridge\n"));
|
|
create_udfsymlinks = 0;
|
|
}
|
|
#endif
|
|
#endif
|
|
if (no_apple_hyb) {
|
|
donotwrite_macpart = 1;
|
|
}
|
|
if (apple_hyb && !donotwrite_macpart && do_largefiles > 0) {
|
|
do_largefiles = 0;
|
|
maxnonlarge = (off_t)0x7FFFFFFF;
|
|
error(_("Warning: cannot support large files with -hfs\n"));
|
|
}
|
|
#ifdef UDF
|
|
if (apple_hyb && use_udf && !donotwrite_macpart) {
|
|
comerrno(EX_BAD, _("Can't have -hfs with -udf\n"));
|
|
}
|
|
#endif
|
|
if (apple_ext && hfs_boot_file) {
|
|
comerrno(EX_BAD, _("Can't have -hfs-boot-file with -apple\n"));
|
|
}
|
|
if (apple_ext && autoname) {
|
|
comerrno(EX_BAD, _("Can't have -auto with -apple\n"));
|
|
}
|
|
if (apple_hyb && (use_sparcboot || use_sunx86boot)) {
|
|
comerrno(EX_BAD, _("Can't have -hfs with -sparc-boot/-sunx86-boot\n"));
|
|
}
|
|
if (apple_hyb && use_genboot) {
|
|
comerrno(EX_BAD, _("Can't have -hfs with -generic-boot\n"));
|
|
}
|
|
#ifdef PREP_BOOT
|
|
if (apple_ext && use_prep_boot) {
|
|
comerrno(EX_BAD, _("Can't have -prep-boot with -apple\n"));
|
|
}
|
|
#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_file)) {
|
|
errmsgno(EX_BAD,
|
|
_("Warning: no Apple/Unix files will be decoded/mapped\n"));
|
|
}
|
|
if (apple_both && verbose && !afe_size &&
|
|
(hfs_select & (DO_FEU | DO_FEL))) {
|
|
errmsgno(EX_BAD,
|
|
_("Warning: assuming PC Exchange cluster size of 512 bytes\n"));
|
|
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 the -hide-joliet option has been given, set the Joliet option
|
|
*/
|
|
if (!use_Joliet && j_ishidden())
|
|
use_Joliet++;
|
|
#ifdef UDF
|
|
/*
|
|
* if the -hide-udf option has been given, set the UDF option
|
|
*/
|
|
if (!use_udf && u_ishidden())
|
|
use_udf++;
|
|
#endif
|
|
|
|
if (rationalize_all) {
|
|
rationalize++;
|
|
rationalize_uid++;
|
|
rationalize_gid++;
|
|
rationalize_filemode++;
|
|
rationalize_dirmode++;
|
|
}
|
|
|
|
/*
|
|
* XXX This is a hack until we have a decent separate name handling
|
|
* XXX for UDF filenames.
|
|
*/
|
|
#ifdef DVD_AUD_VID
|
|
if (dvd_aud_vid_flag && use_Joliet) {
|
|
use_Joliet = 0;
|
|
error(_("Warning: Disabling Joliet support for DVD-Video/DVD-Audio.\n"));
|
|
}
|
|
#endif
|
|
#ifdef UDF
|
|
if (use_udf && !use_Joliet)
|
|
jlen = 255;
|
|
#endif
|
|
|
|
if (use_RockRidge && (iso9660_namelen > MAX_ISONAME_V2_RR))
|
|
iso9660_namelen = MAX_ISONAME_V2_RR;
|
|
|
|
if (warn_violate)
|
|
error(_("Warning: creating filesystem that does not conform to ISO-9660.\n"));
|
|
if (iso9660_level > 3)
|
|
error(_("Warning: Creating ISO-9660:1999 (version 2) filesystem.\n"));
|
|
if (iso9660_namelen > LEN_ISONAME)
|
|
error(_("Warning: ISO-9660 filenames longer than %d may cause buffer overflows in the OS.\n"),
|
|
LEN_ISONAME);
|
|
if (use_Joliet && !use_RockRidge) {
|
|
error(_("Warning: creating filesystem with (nonstandard) Joliet extensions\n"));
|
|
error(_(" but without (standard) Rock Ridge extensions.\n"));
|
|
error(_(" It is highly recommended to add Rock Ridge\n"));
|
|
}
|
|
if (transparent_compression) {
|
|
error(_("Warning: using transparent compression. This is a nonstandard Rock Ridge\n"));
|
|
error(_(" extension. The resulting filesystem can only be transparently\n"));
|
|
error(_(" read on Linux. On other operating systems you need to call\n"));
|
|
error(_(" mkzftree by hand to decompress the files.\n"));
|
|
}
|
|
if (transparent_compression && !use_RockRidge) {
|
|
error(_("Warning: transparent decompression is a Linux Rock Ridge extension, but\n"));
|
|
error(_(" creating filesystem without Rock Ridge attributes; files\n"));
|
|
error(_(" will not be transparently decompressed.\n"));
|
|
}
|
|
|
|
#if defined(USE_NLS) && defined(HAVE_NL_LANGINFO) && defined(CODESET)
|
|
/*
|
|
* If the locale has not been set up, nl_langinfo() returns the
|
|
* name of the default codeset. This should be either "646",
|
|
* "ISO-646", "ASCII", or something similar. Unfortunately, the
|
|
* POSIX standard does not include a list of valid locale names,
|
|
* so ne need to find all values in use.
|
|
*
|
|
* Observed:
|
|
* Solaris "646"
|
|
* Linux "ANSI_X3.4-1968" strange value from Linux...
|
|
*/
|
|
if (icharset == NULL) {
|
|
char *codeset = nl_langinfo(CODESET);
|
|
Uchar *p;
|
|
|
|
if (codeset != NULL)
|
|
codeset = e_strdup(codeset);
|
|
if (codeset == NULL) /* Should not happen */
|
|
goto setcharset;
|
|
if (*codeset == '\0') /* Invalid locale */
|
|
goto setcharset;
|
|
|
|
for (p = (Uchar *)codeset; *p != '\0'; p++) {
|
|
if (islower(*p))
|
|
*p = toupper(*p);
|
|
}
|
|
p = (Uchar *)strstr(codeset, "ISO");
|
|
if (p != NULL) {
|
|
if (*p == '_' || *p == '-')
|
|
p++;
|
|
codeset = (char *)p;
|
|
}
|
|
if (strcmp("646", codeset) != 0 &&
|
|
strcmp("ASCII", codeset) != 0 &&
|
|
strcmp("US-ASCII", codeset) != 0 &&
|
|
strcmp("US_ASCII", codeset) != 0 &&
|
|
strcmp("USASCII", codeset) != 0 &&
|
|
strcmp("ANSI_X3.4-1968", codeset) != 0)
|
|
icharset = nl_langinfo(CODESET);
|
|
|
|
if (codeset != NULL)
|
|
free(codeset);
|
|
|
|
if (verbose > 0 && icharset != NULL) {
|
|
error(_("Setting input-charset to '%s' from locale.\n"),
|
|
icharset);
|
|
}
|
|
}
|
|
setcharset:
|
|
/*
|
|
* Allow to switch off locale with -input-charset "".
|
|
*/
|
|
if (icharset != NULL && *icharset == '\0')
|
|
icharset = NULL;
|
|
#endif
|
|
if (icharset == NULL) {
|
|
#if (defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__DJGPP__)) && !defined(IS_CYGWIN_1)
|
|
icharset = "cp437";
|
|
#else
|
|
icharset = "default";
|
|
#endif
|
|
}
|
|
in_nls = sic_open(icharset);
|
|
|
|
/*
|
|
* set the output charset to the same as the input or the given output
|
|
* charset
|
|
*/
|
|
if (ocharset == NULL) {
|
|
ocharset = in_nls ? in_nls->sic_name : NULL;
|
|
}
|
|
out_nls = sic_open(ocharset);
|
|
|
|
if (in_nls == NULL || out_nls == NULL) { /* Unknown charset specified */
|
|
fprintf(stderr, _("Unknown charset '%s'.\nKnown charsets are:\n"),
|
|
in_nls == NULL ? icharset : (ocharset ? ocharset : "NULL"));
|
|
list_locales();
|
|
exit(EX_BAD);
|
|
}
|
|
#ifdef USE_ICONV
|
|
/*
|
|
* XXX If we ever allow this, we neeed to fix the call to conv_charset()
|
|
* XXX in name.c::iso9660_file_length().
|
|
*/
|
|
if ((in_nls->sic_cd2uni != NULL || out_nls->sic_cd2uni != NULL) &&
|
|
(in_nls->sic_name != out_nls->sic_name)) {
|
|
errmsgno(EX_BAD,
|
|
_("Iconv based locales may change file name length.\n"));
|
|
comerrno(EX_BAD,
|
|
_("Cannot yet have different -input-charset/-output-charset.\n"));
|
|
}
|
|
#endif
|
|
|
|
#ifdef APPLE_HYB
|
|
if (hfs_icharset == NULL || strcmp(hfs_icharset, "mac-roman") == 0) {
|
|
hfs_icharset = "cp10000";
|
|
}
|
|
hfs_inls = sic_open(hfs_icharset);
|
|
|
|
if (hfs_ocharset == NULL) {
|
|
hfs_ocharset = hfs_inls ? hfs_inls->sic_name : NULL;
|
|
}
|
|
if (hfs_ocharset == NULL || strcmp(hfs_ocharset, "mac-roman") == 0) {
|
|
hfs_ocharset = "cp10000";
|
|
}
|
|
hfs_onls = sic_open(hfs_ocharset);
|
|
|
|
if (use_mac_name)
|
|
apple_hyb = 1;
|
|
if (apple_hyb && (hfs_inls == NULL || hfs_onls == NULL)) {
|
|
fprintf(stderr, _("Unknown HFS charset '%s'.\nKnown charsets are:\n"),
|
|
hfs_inls == NULL ? hfs_icharset : (hfs_ocharset ? hfs_ocharset : "NULL"));
|
|
list_locales();
|
|
exit(EX_BAD);
|
|
}
|
|
#ifdef USE_ICONV
|
|
if (apple_hyb &&
|
|
((hfs_inls->sic_cd2uni != NULL || hfs_onls->sic_cd2uni != NULL) &&
|
|
(hfs_inls->sic_name != hfs_onls->sic_name))) {
|
|
errmsgno(EX_BAD,
|
|
_("Iconv based locales may change file name length.\n"));
|
|
comerrno(EX_BAD,
|
|
_("Cannot yet have different -input-hfs-charset/-output-hfs-charset.\n"));
|
|
}
|
|
#endif
|
|
#endif /* APPLE_HYB */
|
|
|
|
if (merge_image != NULL) {
|
|
if (open_merge_image(merge_image) < 0) {
|
|
/* Complain and die. */
|
|
comerr(_("Unable to open previous session image '%s'.\n"),
|
|
merge_image);
|
|
}
|
|
}
|
|
/* 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
|
|
comerr(_("Panic cannot set back effective uid.\n"));
|
|
|
|
|
|
#ifdef no_more_needed
|
|
#ifdef __NetBSD__
|
|
{
|
|
int resource;
|
|
struct rlimit rlp;
|
|
|
|
if (getrlimit(RLIMIT_DATA, &rlp) == -1)
|
|
errmsg(_("Warning: Cannot get rlimit.\n"));
|
|
else {
|
|
rlp.rlim_cur = 33554432;
|
|
if (setrlimit(RLIMIT_DATA, &rlp) == -1)
|
|
errmsg(_("Warning: Cannot set rlimit.\n"));
|
|
}
|
|
}
|
|
#endif
|
|
#endif /* no_more_needed */
|
|
#ifdef HAVE_SBRK
|
|
mem_start = (unsigned long) sbrk(0);
|
|
#endif
|
|
|
|
if (verbose > 1) {
|
|
fprintf(stderr, "%s (%s-%s-%s)\n",
|
|
version_string,
|
|
HOST_CPU, HOST_VENDOR, HOST_OS);
|
|
}
|
|
if (cdrecord_data == NULL && !check_session && merge_image != NULL) {
|
|
comerrno(EX_BAD,
|
|
_("Multisession usage bug: Must specify -C if -M is used.\n"));
|
|
}
|
|
if (cdrecord_data != NULL && merge_image == NULL) {
|
|
errmsgno(EX_BAD,
|
|
_("Warning: -C specified without -M: old session data will not be merged.\n"));
|
|
}
|
|
#ifdef APPLE_HYB
|
|
if (merge_image != NULL && apple_hyb) {
|
|
errmsgno(EX_BAD,
|
|
_("Warning: files from previous sessions will not be included in the HFS volume.\n"));
|
|
}
|
|
#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, "-") != 0) {
|
|
if ((pfp = fopen(pathnames, "r")) == NULL) {
|
|
comerr(_("Unable to open pathname list %s.\n"),
|
|
pathnames);
|
|
}
|
|
} else
|
|
pfp = stdin;
|
|
}
|
|
|
|
/* The first step is to scan the directory tree, and take some notes */
|
|
|
|
if ((arg = get_pnames(argc, argv, argind, pname,
|
|
sizeof (pname), pfp)) == NULL) {
|
|
if (check_session == 0 && !stream_media_size) {
|
|
errmsgno(EX_BAD, _("Missing pathspec.\n"));
|
|
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) {
|
|
#ifdef UDF
|
|
if (use_XA || use_RockRidge || use_udf || use_Joliet)
|
|
#else
|
|
if (use_XA || use_RockRidge || use_Joliet)
|
|
#endif
|
|
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 ||
|
|
#ifdef APPLE_HYB
|
|
use_genboot || use_prep_boot || hfs_boot_file)
|
|
#else
|
|
use_genboot)
|
|
#endif
|
|
comerrno(EX_BAD,
|
|
_("Cannot use boot options with -stream-media-size\n"));
|
|
#ifdef APPLE_HYB
|
|
if (apple_hyb)
|
|
comerrno(EX_BAD,
|
|
_("Cannot use Apple hybrid options with -stream-media-size\n"));
|
|
#endif
|
|
}
|
|
|
|
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 */
|
|
}
|
|
checkarch(outfile);
|
|
if (log_file) {
|
|
FILE *lfp;
|
|
int i;
|
|
|
|
/* open log file - test that we can open OK */
|
|
if ((lfp = fopen(log_file, "w")) == NULL) {
|
|
comerr(_("Can't open logfile: '%s'.\n"), log_file);
|
|
}
|
|
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) {
|
|
comerr(_("Can't open logfile: '%s'.\n"), log_file);
|
|
}
|
|
if (verbose > 1) {
|
|
for (i = 0; i < argc; i++)
|
|
fprintf(stderr, "%s ", argv[i]);
|
|
|
|
fprintf(stderr, "\n%s (%s-%s-%s)\n",
|
|
version_string,
|
|
HOST_CPU, HOST_VENDOR, HOST_OS);
|
|
}
|
|
}
|
|
/* 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, sizeof (nodename), arg);
|
|
else
|
|
node = arg;
|
|
} else {
|
|
/*
|
|
* Remove '\\' escape chars which are located
|
|
* before '\\' and '=' chars
|
|
*/
|
|
node = escstrcpy(nodename, sizeof (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];
|
|
UInt32_t extent;
|
|
|
|
errno = 0;
|
|
mrootp = merge_isofs(merge_image);
|
|
if (mrootp == NULL) {
|
|
/* Complain and die. */
|
|
if (errno == 0)
|
|
errno = -1;
|
|
comerr(_("Unable to find previous session PVD '%s'.\n"),
|
|
merge_image);
|
|
}
|
|
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.
|
|
*/
|
|
extent = get_733(mrootp->extent);
|
|
readsecs(extent, sector, 1);
|
|
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)) {
|
|
extern int su_version;
|
|
extern int rr_version;
|
|
extern char er_id[];
|
|
|
|
if (c & RR_FLAG_SP) {
|
|
fprintf(stderr, _("SUSP signatures version %d found\n"), su_version);
|
|
if (c & RR_FLAG_ER) {
|
|
if (rr_version < 1) {
|
|
fprintf(stderr,
|
|
_("No valid Rock Ridge signature found\n"));
|
|
if (!force_rr)
|
|
no_rr++;
|
|
} else {
|
|
fprintf(stderr,
|
|
_("Rock Ridge signatures version %d found\n"),
|
|
rr_version);
|
|
fprintf(stderr,
|
|
_("Rock Ridge id '%s'\n"), er_id);
|
|
}
|
|
}
|
|
} else {
|
|
fprintf(stderr, _("Bad Rock Ridge signatures found (SU record missing)\n"));
|
|
if (!force_rr)
|
|
no_rr++;
|
|
}
|
|
} else {
|
|
fprintf(stderr, _("No SUSP/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);
|
|
|
|
#ifdef APPLE_HYB
|
|
/* may need to set window layout of the volume */
|
|
if (root_info)
|
|
set_root_info(root_info);
|
|
#endif /* APPLE_HYB */
|
|
|
|
/*
|
|
* 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)
|
|
goto path_done;
|
|
|
|
#ifdef USE_FIND
|
|
if (dofind) {
|
|
extern int walkfunc __PR((char *nm, struct stat *fs, int type, struct WALK *state));
|
|
|
|
walkinitstate(&walkstate);
|
|
if (find_patlen > 0) {
|
|
walkstate.patstate = ___malloc(sizeof (int) * find_patlen,
|
|
_("space for pattern state"));
|
|
}
|
|
|
|
find_timeinit(time(0));
|
|
walkstate.walkflags = walkflags;
|
|
walkstate.maxdepth = maxdepth;
|
|
walkstate.mindepth = mindepth;
|
|
walkstate.lname = NULL;
|
|
walkstate.tree = find_node;
|
|
walkstate.err = 0;
|
|
walkstate.pflags = 0;
|
|
|
|
nodesc = TRUE;
|
|
for (;
|
|
(arg = get_pnames(argc, argv, argind, pname, sizeof (pname),
|
|
pfp)) != NULL;
|
|
argind++) {
|
|
/*
|
|
* Make silly GCC happy and double initialize graft_dir.
|
|
*/
|
|
struct directory *graft_dir = NULL;
|
|
char graft_point[PATH_MAX + 1];
|
|
struct wargs wa;
|
|
char *snp;
|
|
|
|
graft_point[0] = '\0';
|
|
snp = NULL;
|
|
if (use_graft_ptrs)
|
|
graft_dir = get_graft(arg,
|
|
graft_point, sizeof (graft_point),
|
|
nodename, sizeof (nodename),
|
|
&snp, FALSE);
|
|
if (graft_point[0] != '\0') {
|
|
arg = nodename;
|
|
wa.dir = graft_dir;
|
|
} else {
|
|
wa.dir = root;
|
|
}
|
|
wa.name = snp;
|
|
walkstate.auxp = &wa;
|
|
walkstate.auxi = strlen(arg);
|
|
treewalk(arg, walkfunc, &walkstate);
|
|
no_path_names = 0;
|
|
}
|
|
find_plusflush(plusp, &walkstate);
|
|
} else
|
|
#endif
|
|
|
|
while ((arg = get_pnames(argc, argv, argind, pname,
|
|
sizeof (pname), pfp)) != NULL) {
|
|
char graft_point[PATH_MAX + 1];
|
|
|
|
get_graft(arg, graft_point, sizeof (graft_point),
|
|
nodename, sizeof (nodename), NULL, TRUE);
|
|
argind++;
|
|
no_path_names = 0;
|
|
}
|
|
|
|
path_done:
|
|
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) {
|
|
errmsgno(EX_BAD, _("No pathnames found.\n"));
|
|
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) {
|
|
comerrno(EX_BAD, _("Cannot merge previous session.\n"));
|
|
}
|
|
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();
|
|
free(mrootp);
|
|
}
|
|
#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) {
|
|
comerrno(EX_BAD, _("ISO9660/Rock Ridge tree sort failed.\n"));
|
|
}
|
|
#ifdef UDF
|
|
if (use_Joliet || use_udf) {
|
|
#else
|
|
if (use_Joliet) {
|
|
#endif
|
|
goof += joliet_sort_tree(root);
|
|
}
|
|
if (goof) {
|
|
comerrno(EX_BAD, _("Joliet tree sort failed.\n"));
|
|
}
|
|
/*
|
|
* 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) {
|
|
comerr(_("Unable to open /dev/null\n"));
|
|
}
|
|
} else if (outfile != NULL &&
|
|
!(outfile[0] == '-' && outfile[1] == '\0')) {
|
|
discimage = fopen(outfile, "wb");
|
|
if (!discimage) {
|
|
comerr(_("Unable to open disc image file '%s'.\n"), outfile);
|
|
}
|
|
} else {
|
|
discimage = stdout;
|
|
setmode(fileno(stdout), O_BINARY);
|
|
}
|
|
#ifdef HAVE_SETVBUF
|
|
setvbuf(discimage, NULL, _IOFBF, 64*1024);
|
|
#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 && !donotwrite_macpart) || use_prep_boot || use_chrp_boot)
|
|
#else /* PREP_BOOT */
|
|
if (apple_hyb && !donotwrite_macpart)
|
|
#endif /* PREP_BOOT */
|
|
outputlist_insert(&hfs_desc);
|
|
#endif /* APPLE_HYB */
|
|
if (use_sparcboot || use_sunx86boot)
|
|
outputlist_insert(&sunlabel_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) {
|
|
if (verbose > 2)
|
|
fprintf(stderr, _("Computing size: %-40sStart Block %u\n"),
|
|
opnt->of_name, last_extent);
|
|
(*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) {
|
|
if (verbose > 2)
|
|
fprintf(stderr, _("Generating content: %-40s\n"),
|
|
opnt->of_name);
|
|
(*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 (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-session_start),
|
|
(last_extent-session_start) >> 9);
|
|
}
|
|
#ifdef VMS
|
|
return (1);
|
|
#else
|
|
return (0);
|
|
#endif
|
|
}
|
|
|
|
LOCAL void
|
|
list_locales()
|
|
{
|
|
int n;
|
|
|
|
n = sic_list(stdout);
|
|
if (n <= 0) {
|
|
const char *ins_base = sic_base();
|
|
|
|
if (ins_base == NULL)
|
|
ins_base = "$INS_BASE/lib/siconv/";
|
|
errmsgno(EX_BAD, _("Installation problem: '%s' %s.\n"),
|
|
ins_base, n < 0 ? _("missing"):_("incomplete"));
|
|
if (n == 0) {
|
|
errmsgno(EX_BAD,
|
|
_("Check '%s' for missing translation tables.\n"),
|
|
ins_base);
|
|
}
|
|
}
|
|
#ifdef USE_ICONV
|
|
if (n > 0) {
|
|
errmsgno(EX_BAD,
|
|
_("'iconv -l' lists more available names.\n"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Find unescaped equal sign in graft pointer string.
|
|
*/
|
|
EXPORT char *
|
|
findgequal(s)
|
|
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.
|
|
*/
|
|
LOCAL char *
|
|
escstrcpy(to, tolen, from)
|
|
char *to;
|
|
size_t tolen;
|
|
char *from;
|
|
{
|
|
char *p = to;
|
|
|
|
if (debug)
|
|
error("FROM: '%s'\n", from);
|
|
|
|
to[0] = '\0';
|
|
if (tolen > 0) {
|
|
to[--tolen] = '\0'; /* Fill in last nul char */
|
|
}
|
|
while ((*p = *from++) != '\0' && tolen-- > 0) {
|
|
if (*p == '\\') {
|
|
if ((*p = *from++) == '\0')
|
|
break;
|
|
if (*p != '\\' && *p != '=') {
|
|
p[1] = p[0];
|
|
*p++ = '\\';
|
|
}
|
|
}
|
|
p++;
|
|
}
|
|
if (debug)
|
|
error("ESC: '%s'\n", to);
|
|
return (to);
|
|
}
|
|
|
|
struct directory *
|
|
get_graft(arg, graft_point, glen, nodename, nlen, short_namep, do_insert)
|
|
char *arg;
|
|
char *graft_point;
|
|
size_t glen;
|
|
char *nodename;
|
|
size_t nlen;
|
|
char **short_namep;
|
|
BOOL do_insert;
|
|
{
|
|
char *node = NULL;
|
|
struct directory_entry de;
|
|
struct directory *graft_dir = root;
|
|
struct stat st;
|
|
char *short_name;
|
|
int status;
|
|
|
|
fillbytes(&de, sizeof (de), '\0');
|
|
/*
|
|
* 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;
|
|
|
|
/* insert -root prefix */
|
|
if (reloc_root != NULL) {
|
|
strlcpy(graft_point, reloc_root, glen);
|
|
len = strlen(graft_point);
|
|
|
|
if ((len < (glen -1)) &&
|
|
(len == 0 || graft_point[len-1] != '/')) {
|
|
graft_point[len++] = '/';
|
|
graft_point[len] = '\0';
|
|
}
|
|
} else {
|
|
len = 0;
|
|
}
|
|
|
|
if (node) {
|
|
*node = '\0';
|
|
escstrcpy(&graft_point[len], glen - len, arg);
|
|
*node = '=';
|
|
}
|
|
|
|
/*
|
|
* Remove unwanted "./" & "/" sequences from start...
|
|
*/
|
|
do {
|
|
xpnt = graft_point;
|
|
while (xpnt[0] == '.' && xpnt[1] == '/')
|
|
xpnt += 2;
|
|
while (*xpnt == PATH_SEPARATOR) {
|
|
xpnt++;
|
|
}
|
|
/*
|
|
* The string becomes shorter, there is no need to check
|
|
* the length. Make sure to support overlapping strings.
|
|
*/
|
|
ovstrcpy(graft_point, xpnt);
|
|
} while (xpnt > graft_point);
|
|
|
|
if (node) {
|
|
node = escstrcpy(nodename, nlen, ++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);
|
|
if (status == 0 && S_ISDIR(st.st_mode)) {
|
|
len = strlen(graft_point);
|
|
|
|
if ((len < (glen -1)) &&
|
|
(len == 0 || graft_point[len-1] != '/')) {
|
|
graft_point[len++] = '/';
|
|
graft_point[len] = '\0';
|
|
}
|
|
}
|
|
if (debug)
|
|
error("GRAFT:'%s'\n", xpnt);
|
|
/*
|
|
* Loop down deeper and deeper until we find the
|
|
* correct insertion spot.
|
|
* Canonicalize the filename while parsing it.
|
|
*/
|
|
for (;;) {
|
|
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;
|
|
if (short_namep)
|
|
*short_namep = xpnt;
|
|
}
|
|
break;
|
|
}
|
|
*pnt = '\0';
|
|
if (debug) {
|
|
error("GRAFT Point:'%s' in '%s : %s' (%s)\n",
|
|
xpnt,
|
|
graft_dir->whole_name,
|
|
graft_dir->de_name,
|
|
graft_point);
|
|
}
|
|
graft_dir = find_or_create_directory(graft_dir,
|
|
graft_point,
|
|
NULL, TRUE);
|
|
*pnt = PATH_SEPARATOR;
|
|
xpnt = pnt + 1;
|
|
}
|
|
} else {
|
|
graft_dir = root;
|
|
if (use_graft_ptrs)
|
|
node = escstrcpy(nodename, nlen, arg);
|
|
else
|
|
node = arg;
|
|
}
|
|
|
|
/*
|
|
* Now see whether the user wants to add a regular file, or a
|
|
* directory at this point.
|
|
*/
|
|
if (follow_links || Hflag)
|
|
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.
|
|
*/
|
|
comerr(_("Invalid node - '%s'.\n"), node);
|
|
} else {
|
|
if (S_ISDIR(st.st_mode)) {
|
|
if (debug) {
|
|
error(_("graft_dir: '%s : %s', node: '%s', (scan)\n"),
|
|
graft_dir->whole_name,
|
|
graft_dir->de_name, node);
|
|
}
|
|
if (!do_insert)
|
|
return (graft_dir);
|
|
if (!scan_directory_tree(graft_dir,
|
|
node, &de)) {
|
|
exit(1);
|
|
}
|
|
if (debug) {
|
|
error(_("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) {
|
|
error(_("graft_dir: '%s : %s', node: '%s', short_name: '%s'\n"),
|
|
graft_dir->whole_name,
|
|
graft_dir->de_name, node,
|
|
short_name);
|
|
}
|
|
if (!do_insert)
|
|
return (graft_dir);
|
|
if (!insert_file_entry(graft_dir, node,
|
|
short_name, NULL, 0)) {
|
|
/*
|
|
* Should we ignore this?
|
|
*/
|
|
/* exit(1);*/
|
|
/* EMPTY */
|
|
}
|
|
}
|
|
}
|
|
return (graft_dir);
|
|
}
|
|
|
|
EXPORT void *
|
|
e_malloc(size)
|
|
size_t size;
|
|
{
|
|
void *pt = 0;
|
|
|
|
if (size == 0)
|
|
size = 1;
|
|
if ((pt = malloc(size)) == NULL) {
|
|
comerr(_("Not enough memory\n"));
|
|
}
|
|
/*
|
|
* Not all code is clean yet.
|
|
* Filling all allocated data with zeroes will help
|
|
* to avoid core dumps.
|
|
*/
|
|
memset(pt, 0, size);
|
|
return (pt);
|
|
}
|
|
|
|
EXPORT char *
|
|
e_strdup(s)
|
|
const char *s;
|
|
{
|
|
char *ret = strdup(s);
|
|
|
|
if (s == NULL)
|
|
comerr(_("Not enough memory for strdup(%s)\n"), s);
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* A strcpy() that works with overlapping buffers
|
|
*/
|
|
LOCAL void
|
|
ovstrcpy(p2, p1)
|
|
register char *p2;
|
|
register char *p1;
|
|
{
|
|
while ((*p2++ = *p1++) != '\0')
|
|
;
|
|
}
|
|
|
|
LOCAL void
|
|
checkarch(name)
|
|
char *name;
|
|
{
|
|
struct stat stbuf;
|
|
|
|
archive_isreg = FALSE;
|
|
archive_dev = (dev_t)0;
|
|
archive_ino = (ino_t)0;
|
|
|
|
if (name == NULL)
|
|
return;
|
|
if (stat(name, &stbuf) < 0)
|
|
return;
|
|
|
|
if (S_ISREG(stbuf.st_mode)) {
|
|
archive_dev = stbuf.st_dev;
|
|
archive_ino = stbuf.st_ino;
|
|
archive_isreg = TRUE;
|
|
} else if (((stbuf.st_mode & S_IFMT) == 0) ||
|
|
S_ISFIFO(stbuf.st_mode) ||
|
|
S_ISSOCK(stbuf.st_mode)) {
|
|
/*
|
|
* This is a pipe or similar on different UNIX implementations.
|
|
* (stbuf.st_mode & S_IFMT) == 0 may happen in stange cases.
|
|
*/
|
|
archive_dev = NODEV;
|
|
archive_ino = (ino_t)-1;
|
|
}
|
|
}
|