diff options
Diffstat (limited to 'gnu/usr.sbin/mkisofs/mkisofs.c')
-rw-r--r-- | gnu/usr.sbin/mkisofs/mkisofs.c | 661 |
1 files changed, 661 insertions, 0 deletions
diff --git a/gnu/usr.sbin/mkisofs/mkisofs.c b/gnu/usr.sbin/mkisofs/mkisofs.c new file mode 100644 index 00000000000..5c72ca8ceab --- /dev/null +++ b/gnu/usr.sbin/mkisofs/mkisofs.c @@ -0,0 +1,661 @@ +/* $OpenBSD: mkisofs.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * Program mkisofs.c - generate iso9660 filesystem based upon directory + * tree on hard disk. + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + 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. */ + +static char rcsid[] ="$From: mkisofs.c,v 1.9 1997/04/10 02:45:09 eric Rel $"; + +/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ + +#include <errno.h> +#include "mkisofs.h" +#include "config.h" + +#ifdef linux +#include <getopt.h> +#endif + +#include "iso9660.h" +#include <ctype.h> + +#ifndef VMS +#include <time.h> +#else +#include <sys/time.h> +#include "vms.h" +#endif + +#include <stdlib.h> +#include <sys/stat.h> + +#ifndef VMS +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#endif + +#include "exclude.h" + +#ifdef __NetBSD__ +#include <sys/time.h> +#include <sys/resource.h> +#endif + +struct directory * root = NULL; + +static char version_string[] = "mkisofs v1.11"; + +FILE * discimage; +unsigned int next_extent = 0; +unsigned int last_extent = 0; +unsigned int session_start = 0; +unsigned int path_table_size = 0; +unsigned int path_table[4] = {0,}; +unsigned int path_blocks = 0; +struct iso_directory_record root_record; +char * extension_record = NULL; +int extension_record_extent = 0; +static int extension_record_size = 0; + +/* These variables are associated with command line options */ +int use_eltorito = 0; +int use_RockRidge = 0; +int verbose = 0; +int all_files = 0; +int follow_links = 0; +int rationalize = 0; +int generate_tables = 0; +char * preparer = PREPARER_DEFAULT; +char * publisher = PUBLISHER_DEFAULT; +char * appid = APPID_DEFAULT; +char * copyright = COPYRIGHT_DEFAULT; +char * biblio = BIBLIO_DEFAULT; +char * abstract = ABSTRACT_DEFAULT; +char * volset_id = VOLSET_ID_DEFAULT; +char * volume_id = VOLUME_ID_DEFAULT; +char * system_id = SYSTEM_ID_DEFAULT; +char * boot_catalog = BOOT_CATALOG_DEFAULT; +char * boot_image = BOOT_IMAGE_DEFAULT; + +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 RR_relocation_depth = 6; /* Violates iso9660, but most systems work */ +int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with + DOS */ +int allow_leading_dots = 0; /* DOS cannot read names with leading dots */ + +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}, + {NULL, NULL} +}; + +#if defined(ultrix) || defined(_AUX_SOURCE) +char *strdup(s) +char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;} +#endif + +void FDECL1(read_rcfile, char *, appname) +{ + FILE * rcfile; + struct rcopts * rco; + char * pnt, *pnt1; + char linebuffer[256]; + static char rcfn[] = ".mkisofsrc"; + char filename[1000]; + int linum; + + strcpy(filename, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + + if (!rcfile) + { + pnt = getenv("MKISOFSRC"); + if (pnt && strlen(pnt) <= sizeof(filename)) + { + strcpy(filename, pnt); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + + if (!rcfile) + { + pnt = getenv("HOME"); + if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename)) + { + strcpy(filename, pnt); + strcat(filename, "/"); + strcat(filename, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename)) + { + strcpy(filename, appname); + pnt = strrchr(filename, '/'); + if (pnt) + { + strcpy(pnt + 1, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + if (!rcfile) + return; + 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(*pnt)) + { + if(islower(*pnt)) + *pnt = toupper(*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\n", filename, linum); + 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 = strdup(pnt); + break; + }; + } + if (rco->tag == NULL) + { + fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum, + name); + } + } + if (ferror(rcfile)) + perror(filename); + fclose(rcfile); +} + +char * path_table_l = NULL; +char * path_table_m = NULL; +int goof = 0; + +void usage(){ + fprintf(stderr,"Usage:\n"); + fprintf(stderr, +"mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \ +[-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]" +#ifdef ADD_FILES +"[-i file] \n" +#endif +"[-P publisher] [ -A app_id ] [-z] \n \ +[-b boot_image_name] [-c boot_catalog-name] \ +[-x path -x path ...] path\n"); + exit(1); +} + + +/* + * Fill in date in the iso9660 format + * + * The standards state that the timezone offset is in multiples of 15 + * minutes, and is what you add to GMT to get the localtime. The U.S. + * is always at a negative offset, from -5h to -8h (can vary a little + * with DST, I guess). The Linux iso9660 filesystem has had the sign + * of this wrong for ages (mkisofs had it wrong too for the longest time). + */ +int FDECL2(iso9660_date,char *, result, time_t, ctime){ + struct tm *local; + local = localtime(&ctime); + result[0] = local->tm_year; + result[1] = local->tm_mon + 1; + result[2] = local->tm_mday; + result[3] = local->tm_hour; + result[4] = local->tm_min; + result[5] = local->tm_sec; + + /* + * Must recalculate proper timezone offset each time, + * as some files use daylight savings time and some don't... + */ + result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */ + local = gmtime(&ctime); + local->tm_year -= result[0]; + local->tm_yday -= result[6]; + local->tm_hour -= result[3]; + local->tm_min -= result[4]; + if (local->tm_year < 0) + { + local->tm_yday = -1; + } + else + { + if (local->tm_year > 0) local->tm_yday = 1; + } + + result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15; + + return 0; +} + + +extern char * cdwrite_data; + +int FDECL2(main, int, argc, char **, argv){ + char * outfile; + struct directory_entry de; + unsigned long mem_start; + struct stat statbuf; + char * scan_tree; + char * merge_image = NULL; + struct iso_directory_record * mrootp = NULL; + int c; +#ifdef ADD_FILES + char *add_file_file = NULL; +#endif + + if (argc < 2) + usage(); + + /* Get the defaults from the .mkisofsrc file */ + read_rcfile(argv[0]); + + outfile = NULL; + while ((c = getopt(argc, argv, "i:o:V:RrfvaTp:P:b:c:x:dDlLNzA:M:m:C:")) != EOF) + switch (c) + { + case 'C': + /* + * This is a temporary hack until cdwrite gets the proper hooks in + * it. + */ + cdwrite_data = optarg; + break; + case 'a': + all_files++; + break; + case 'b': + use_eltorito++; + boot_image = optarg; /* pathname of the boot image on cd */ + if (boot_image == NULL) { + fprintf(stderr,"Required boot image pathname missing\n"); + exit(1); + } + break; + case 'c': + use_eltorito++; + boot_catalog = optarg; /* pathname of the boot image on cd */ + if (boot_catalog == NULL) { + fprintf(stderr,"Required boot catalog pathname missing\n"); + exit(1); + } + break; + case 'A': + appid = optarg; + if(strlen(appid) > 128) { + fprintf(stderr,"Application-id string too long\n"); + exit(1); + }; + break; + case 'd': + omit_period++; + break; + case 'D': + RR_relocation_depth = 32767; + break; + case 'f': + follow_links++; + break; + case 'i': +#ifdef ADD_FILES + add_file_file = optarg; + break; +#else + usage(); + exit(1); +#endif + case 'l': + full_iso9660_filenames++; + break; + case 'L': + allow_leading_dots++; + break; + case 'M': + merge_image = optarg; + break; + case 'N': + omit_version_number++; + break; + case 'o': + outfile = optarg; + break; + case 'p': + preparer = optarg; + if(strlen(preparer) > 128) { + fprintf(stderr,"Preparer string too long\n"); + exit(1); + }; + break; + case 'P': + publisher = optarg; + if(strlen(publisher) > 128) { + fprintf(stderr,"Publisher string too long\n"); + exit(1); + }; + break; + case 'R': + use_RockRidge++; + break; + case 'r': + rationalize++; + use_RockRidge++; + break; + case 'T': + generate_tables++; + break; + case 'V': + volume_id = optarg; + break; + case 'v': + verbose++; + break; + case 'z': +#ifdef VMS + fprintf(stderr,"Transparent compression not supported with VMS\n"); + exit(1); +#else + transparent_compression++; +#endif + break; + case 'm': + add_match(optarg); + break; + case 'x': + exclude(optarg); + break; + default: + usage(); + exit(1); + } +#ifdef __NetBSD__ + { + int resource; + struct rlimit rlp; + if (getrlimit(RLIMIT_DATA,&rlp) == -1) + perror("Warning: getrlimit"); + else { + rlp.rlim_cur=33554432; + if (setrlimit(RLIMIT_DATA,&rlp) == -1) + perror("Warning: setrlimit"); + } + } +#endif +#ifdef HAVE_SBRK + mem_start = (unsigned long) sbrk(0); +#endif + + if(verbose) fprintf(stderr,"%s\n", version_string); + + if( (cdwrite_data != NULL && merge_image == NULL) + || (cdwrite_data == NULL && merge_image != NULL) ) + { + fprintf(stderr,"Multisession usage bug - both -C and -M must be specified.\n"); + exit(0); + } + + /* The first step is to scan the directory tree, and take some notes */ + + scan_tree = argv[optind]; + +#ifdef ADD_FILES + if (add_file_file) { + add_file(add_file_file); + } + add_file_list (argc, argv, optind+1); +#endif + + if(!scan_tree){ + usage(); + exit(1); + }; + +#ifndef VMS + if(scan_tree[strlen(scan_tree)-1] != '/') { + scan_tree = (char *) e_malloc(strlen(argv[optind])+2); + strcpy(scan_tree, argv[optind]); + strcat(scan_tree, "/"); + }; +#endif + + if(use_RockRidge){ +#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 + } + + /* + * See if boot catalog file exists in root directory, if not + * we will create it. + */ + if (use_eltorito) + init_boot_catalog(argv[optind]); + + /* + * 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(argv[optind], &statbuf); + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + + memset(&de, 0, sizeof(de)); + + de.filedir = root; /* We need this to bootstrap */ + + if( merge_image != NULL ) + { + mrootp = merge_isofs(merge_image); + if( mrootp == NULL ) + { + /* + * Complain and die. + */ + fprintf(stderr,"Unable to open previous session image %s\n", + merge_image); + exit(1); + } + + memcpy(&de.isorec.extent, mrootp->extent, 8); + } + + /* + * Scan the actual directory (and any we find below it) + * for files to write out to the output image. + */ + if (!scan_directory_tree(argv[optind], &de, mrootp)) + { + exit(1); + } + + /* + * Fix a couple of things in the root directory so that everything + * is self consistent. + */ + root->self = root->contents; /* Fix this up so that the path tables get done right */ + + if(reloc_dir) sort_n_finish(reloc_dir); + + if (goof) exit(1); + + /* + * OK, ready to write the file. Open it up, and generate the thing. + */ + if (outfile){ + discimage = fopen(outfile, "w"); + if (!discimage){ + fprintf(stderr,"Unable to open disc image file\n"); + exit(1); + + }; + } else + discimage = stdout; + + /* Now assign addresses on the disc for the path table. */ + + path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11; + if (path_blocks & 1) path_blocks++; + + path_table[0] = session_start + 0x14; + path_table[1] = 0; + path_table[2] = path_table[0] + path_blocks; + path_table[3] = 0; + + last_extent += path_table[2] - session_start + path_blocks; + /* The next free block */ + + /* The next step is to go through the directory tree and assign extent + numbers for all of the directories */ + + assign_directory_addresses(root); + + if(extension_record) { + struct directory_entry * s_entry; + extension_record_extent = last_extent++; + s_entry = root->contents; + set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24, + extension_record_extent); + set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8, + extension_record_size); + }; + + if (use_RockRidge && reloc_dir) + finish_cl_pl_entries(); + + /* Now we generate the path tables that are used by DOS to improve directory + access times. */ + generate_path_tables(); + + /* Generate root record for volume descriptor. */ + generate_root_record(); + + if (verbose) + dump_tree(root); + + if( in_image != NULL ) + { + fclose(in_image); + } + + iso_write(discimage); + +#ifdef HAVE_SBRK + fprintf(stderr,"Max brk space used %x\n", + (unsigned int)(((unsigned long)sbrk(0)) - mem_start)); +#endif + fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9); +#ifdef VMS + return 1; +#else + return 0; +#endif +} + +void * +FDECL1(e_malloc, size_t, size) +{ +void* pt = 0; + if( (size > 0) && ((pt=malloc(size))==NULL) ) { + fprintf(stderr, "Not enough memory\n"); + exit (1); + } +return pt; +} |