Blame src/cd-read.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2011 Rocky Bernstein
Packit dd8086
  <rocky@gnu.org>
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086
Packit dd8086
/* Program to debug read routines audio, auto, mode1, mode2 forms 1 & 2. */
Packit dd8086
Packit dd8086
#include "util.h"
Packit dd8086
#include <cdio/mmc.h>
Packit dd8086
Packit dd8086
#ifdef HAVE_SYS_STAT_H
Packit dd8086
#include <sys/stat.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_FCNTL_H
Packit dd8086
#include <fcntl.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_ERRNO_H
Packit dd8086
#include <errno.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include "getopt.h"
Packit dd8086
Packit dd8086
#ifndef O_BINARY
Packit dd8086
#define O_BINARY 0
Packit dd8086
#endif
Packit dd8086
Packit dd8086
/* Configuration option codes */
Packit dd8086
enum {
Packit dd8086
  OP_HANDLED = 0,
Packit dd8086
Packit dd8086
  /* NOTE: libpopt version associated these with drivers.  That
Packit dd8086
     appeared to be an unused historical artifact.
Packit dd8086
  */
Packit dd8086
  OP_SOURCE_AUTO,
Packit dd8086
  OP_SOURCE_BIN,
Packit dd8086
  OP_SOURCE_CUE,
Packit dd8086
  OP_SOURCE_NRG,
Packit dd8086
  OP_SOURCE_CDRDAO,
Packit dd8086
  OP_SOURCE_DEVICE,
Packit dd8086
Packit dd8086
  OP_USAGE,
Packit dd8086
Packit dd8086
  /* These are the remaining configuration options */
Packit dd8086
  OP_READ_MODE,
Packit dd8086
  OP_VERSION,
Packit dd8086
Packit dd8086
};
Packit dd8086
Packit dd8086
typedef enum
Packit dd8086
{
Packit dd8086
  READ_AUDIO = CDIO_READ_MODE_AUDIO,
Packit dd8086
  READ_M1F1  = CDIO_READ_MODE_M1F1,
Packit dd8086
  READ_M1F2  = CDIO_READ_MODE_M1F2,
Packit dd8086
  READ_M2F1  = CDIO_READ_MODE_M2F1,
Packit dd8086
  READ_M2F2  = CDIO_READ_MODE_M2F2,
Packit dd8086
  READ_MODE_UNINIT,
Packit dd8086
  READ_ANY
Packit dd8086
} read_mode_t;
Packit dd8086
Packit dd8086
/* Structure used so we can binary sort and set the --mode switch. */
Packit dd8086
typedef struct
Packit dd8086
{
Packit dd8086
  char name[30];
Packit dd8086
  read_mode_t read_mode;
Packit dd8086
} subopt_entry_t;
Packit dd8086
Packit dd8086
Packit dd8086
/* Sub-options for --mode.  Note: entries must be sorted! */
Packit dd8086
static const subopt_entry_t modes_sublist[] = {
Packit dd8086
  {"any",        READ_ANY},
Packit dd8086
  {"audio",      READ_AUDIO},
Packit dd8086
  {"m1f1",       READ_M1F1},
Packit dd8086
  {"m1f2",       READ_M1F2},
Packit dd8086
  {"m2f1",       READ_M2F1},
Packit dd8086
  {"m2f2",       READ_M2F2},
Packit dd8086
  {"mode1form1", READ_M1F1},
Packit dd8086
  {"mode1form2", READ_M1F2},
Packit dd8086
  {"mode2form1", READ_M2F1},
Packit dd8086
  {"mode2form2", READ_M2F2},
Packit dd8086
  {"red",        READ_AUDIO},
Packit dd8086
};
Packit dd8086
Packit dd8086
/* Used by `main' to communicate with `parse_opt'. And global options
Packit dd8086
 */
Packit dd8086
static struct arguments
Packit dd8086
{
Packit dd8086
  char          *access_mode; /* Access method driver should use for control */
Packit dd8086
  char          *output_file; /* file to output blocks if not NULL. */
Packit dd8086
  int            debug_level;
Packit dd8086
  int            hexdump;     /* Show output as a hexdump */
Packit dd8086
  int            nohexdump;   /* Don't output as a hexdump. I don't know
Packit dd8086
				 how to get popt to combine these as
Packit dd8086
				 one variable.
Packit dd8086
			       */
Packit dd8086
  int            just_hex;    /* Don't try to print "printable" characters
Packit dd8086
				 in hex dump.    */
Packit dd8086
  read_mode_t    read_mode;
Packit dd8086
  int            version_only;
Packit dd8086
  int            no_header;
Packit dd8086
  int            print_iso9660;
Packit dd8086
  source_image_t source_image;
Packit dd8086
  lsn_t          start_lsn;
Packit dd8086
  lsn_t          end_lsn;
Packit dd8086
  int            num_sectors;
Packit dd8086
} opts;
Packit dd8086
Packit dd8086
static void
Packit dd8086
hexdump (FILE *stream,  uint8_t * buffer, unsigned int len,
Packit dd8086
	 int just_hex)
Packit dd8086
{
Packit dd8086
  unsigned int i;
Packit dd8086
  for (i = 0; i < len; i++, buffer++)
Packit dd8086
    {
Packit dd8086
      if (i % 16 == 0)
Packit dd8086
	fprintf (stream, "0x%04x: ", i);
Packit dd8086
      fprintf (stream, "%02x", *buffer);
Packit dd8086
      if (i % 2 == 1)
Packit dd8086
	fprintf (stream, " ");
Packit dd8086
      if (i % 16 == 15) {
Packit dd8086
	if (!just_hex) {
Packit dd8086
	  uint8_t *p;
Packit dd8086
	  fprintf (stream, "  ");
Packit dd8086
	  for (p=buffer-15; p <= buffer; p++) {
Packit dd8086
	    fprintf(stream, "%c", isprint(*p) ?  *p : '.');
Packit dd8086
	  }
Packit dd8086
	}
Packit dd8086
	fprintf (stream, "\n");
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  fprintf (stream, "\n");
Packit dd8086
  fflush (stream);
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Comparison function called by bearch() to find sub-option record. */
Packit dd8086
static int
Packit dd8086
compare_subopts(const void *key1, const void *key2)
Packit dd8086
{
Packit dd8086
  subopt_entry_t *a = (subopt_entry_t *) key1;
Packit dd8086
  subopt_entry_t *b = (subopt_entry_t *) key2;
Packit dd8086
  return (strncmp(a->name, b->name, 30));
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Do processing of a --mode sub option.
Packit dd8086
   Basically we find the option in the array, set it's corresponding
Packit dd8086
   flag variable to true as well as the "show.all" false.
Packit dd8086
*/
Packit dd8086
static void
Packit dd8086
process_suboption(const char *subopt, const subopt_entry_t *sublist, const int num,
Packit dd8086
                  const char *subopt_name)
Packit dd8086
{
Packit dd8086
  subopt_entry_t *subopt_rec =
Packit dd8086
    bsearch(subopt, sublist, num, sizeof(subopt_entry_t),
Packit dd8086
            &compare_subopts);
Packit dd8086
  if (subopt_rec != NULL) {
Packit dd8086
    opts.read_mode = subopt_rec->read_mode;
Packit dd8086
    return;
Packit dd8086
  } else {
Packit dd8086
    unsigned int i;
Packit dd8086
    bool is_help=strcmp(subopt, "help")==0;
Packit dd8086
    if (is_help) {
Packit dd8086
      report( stderr, "The list of sub options for \"%s\" are:\n",
Packit dd8086
	      subopt_name );
Packit dd8086
    } else {
Packit dd8086
      report( stderr, "Invalid option following \"%s\": %s.\n",
Packit dd8086
	      subopt_name, subopt );
Packit dd8086
      report( stderr, "Should be one of: " );
Packit dd8086
    }
Packit dd8086
    for (i=0; i
Packit dd8086
      report( stderr, "%s, ", sublist[i].name );
Packit dd8086
    }
Packit dd8086
    report( stderr, "or %s.\n", sublist[num-1].name );
Packit dd8086
    exit (is_help ? EXIT_SUCCESS : EXIT_FAILURE);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/* Parse source options. */
Packit dd8086
static void
Packit dd8086
parse_source(int opt)
Packit dd8086
{
Packit dd8086
  /* NOTE: The libpopt version made use of an extra temporary
Packit dd8086
     variable (psz_my_source) for all sources _except_ devices.
Packit dd8086
     This distinction seemed to serve no purpose.
Packit dd8086
  */
Packit dd8086
  /* NOTE: The libpopt version had a bug which kept it from
Packit dd8086
     processing toc-file inputs
Packit dd8086
  */
Packit dd8086
Packit dd8086
  if (opts.source_image != INPUT_UNKNOWN) {
Packit dd8086
    report( stderr, "%s: another source type option given before.\n",
Packit dd8086
	    program_name );
Packit dd8086
    report( stderr, "%s: give only one source type option.\n",
Packit dd8086
	    program_name );
Packit dd8086
    return;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* For all input sources which are not a DEVICE, we need to make
Packit dd8086
     a copy of the string; for a DEVICE the fill-out routine makes
Packit dd8086
     the copy.
Packit dd8086
  */
Packit dd8086
  if (OP_SOURCE_DEVICE != opt)
Packit dd8086
    if (optarg != NULL) source_name = strdup(optarg);
Packit dd8086
Packit dd8086
  switch (opt) {
Packit dd8086
  case OP_SOURCE_BIN:
Packit dd8086
    opts.source_image  = INPUT_BIN;
Packit dd8086
    break;
Packit dd8086
  case OP_SOURCE_CUE:
Packit dd8086
    opts.source_image  = INPUT_CUE;
Packit dd8086
    break;
Packit dd8086
  case OP_SOURCE_NRG:
Packit dd8086
    opts.source_image  = INPUT_NRG;
Packit dd8086
    break;
Packit dd8086
  case OP_SOURCE_AUTO:
Packit dd8086
    opts.source_image  = INPUT_AUTO;
Packit dd8086
    break;
Packit dd8086
  case OP_SOURCE_DEVICE:
Packit dd8086
    opts.source_image  = INPUT_DEVICE;
Packit dd8086
    if (optarg != NULL) source_name = fillout_device_name(optarg);
Packit dd8086
    break;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/* Parse a options. */
Packit dd8086
static bool
Packit dd8086
parse_options (int argc, char *argv[])
Packit dd8086
{
Packit dd8086
  int opt;
Packit dd8086
  int rc = EXIT_FAILURE;
Packit dd8086
Packit dd8086
  static const char helpText[] =
Packit dd8086
    "Usage: %s [OPTION...]\n"
Packit dd8086
    "  -a, --access-mode=STRING        Set CD control access mode\n"
Packit dd8086
    "  -m, --mode=MODE-TYPE            set CD-ROM read mode (audio, auto, m1f1, m1f2,\n"
Packit dd8086
    "                                  m2mf1, m2f2)\n"
Packit dd8086
    "  -d, --debug=INT                 Set debugging to LEVEL\n"
Packit dd8086
    "  -x, --hexdump                   Show output as a hex dump. The default is a\n"
Packit dd8086
    "                                  hex dump when output goes to stdout and no\n"
Packit dd8086
    "                                  hex dump when output is to a file.\n"
Packit dd8086
    "  -j, --just-hex                  Don't display printable chars on hex\n"
Packit dd8086
    "                                  dump. The default is print chars too.\n"
Packit dd8086
    "  --no-header                     Don't display header and copyright (for\n"
Packit dd8086
    "                                  regression testing)\n"
Packit dd8086
    "  --no-hexdump                    Don't show output as a hex dump.\n"
Packit dd8086
    "  -s, --start=INT                 Set LBA to start reading from\n"
Packit dd8086
    "  -e, --end=INT                   Set LBA to end reading from\n"
Packit dd8086
    "  -n, --number=INT                Set number of sectors to read\n"
Packit dd8086
    "  -b, --bin-file[=FILE]           set \"bin\" CD-ROM disk image file as source\n"
Packit dd8086
    "  -c, --cue-file[=FILE]           set \"cue\" CD-ROM disk image file as source\n"
Packit dd8086
    "  -i, --input[=FILE]              set source and determine if \"bin\" image or\n"
Packit dd8086
    "                                  device\n"
Packit dd8086
    "  -C, --cdrom-device[=DEVICE]     set CD-ROM device as source\n"
Packit dd8086
    "  -N, --nrg-file[=FILE]           set Nero CD-ROM disk image file as source\n"
Packit dd8086
    "  -t, --toc-file[=FILE]           set \"TOC\" CD-ROM disk image file as source\n"
Packit dd8086
    "  -o, --output-file=FILE          Output blocks to file rather than give a\n"
Packit dd8086
    "                                  hexdump.\n"
Packit dd8086
    "  -V, --version                   display version and copyright information\n"
Packit dd8086
    "                                  and exit\n"
Packit dd8086
    "\n"
Packit dd8086
    "Help options:\n"
Packit dd8086
    "  -?, --help                      Show this help message\n"
Packit dd8086
    "  --usage                         Display brief usage message\n";
Packit dd8086
Packit dd8086
  static const char usageText[] =
Packit dd8086
    "Usage: %s [-a|--access-mode STRING] [-m|--mode MODE-TYPE]\n"
Packit dd8086
    "        [-d|--debug INT] [-x|--hexdump] [--no-header] [--no-hexdump]\n"
Packit dd8086
    "        [-s|--start INT] [-e|--end INT] [-n|--number INT] [-b|--bin-file FILE]\n"
Packit dd8086
    "        [-c|--cue-file FILE] [-i|--input FILE] [-C|--cdrom-device DEVICE]\n"
Packit dd8086
    "        [-N|--nrg-file FILE] [-t|--toc-file FILE] [-o|--output-file FILE]\n"
Packit dd8086
    "        [-V|--version] [-?|--help] [--usage]\n";
Packit dd8086
Packit dd8086
  /* Command-line options */
Packit dd8086
  static const char optionsString[] = "a:m:d:xjs:e:n:b::c::i::C::N::t::o:V?";
Packit dd8086
  static const struct option optionsTable[] = {
Packit dd8086
Packit dd8086
    {"access-mode", required_argument, NULL, 'a'},
Packit dd8086
    {"mode", required_argument, NULL, 'm'},
Packit dd8086
    {"debug", required_argument, NULL, 'd'},
Packit dd8086
    {"hexdump", no_argument, NULL, 'x'},
Packit dd8086
    {"no-header", no_argument, &opts.no_header, 1},
Packit dd8086
    {"no-hexdump", no_argument, &opts.nohexdump, 1},
Packit dd8086
    {"just-hex", no_argument, &opts.just_hex, 'j'},
Packit dd8086
    {"start", required_argument, NULL, 's'},
Packit dd8086
    {"end", required_argument, NULL, 'e'},
Packit dd8086
    {"number", required_argument, NULL, 'n'},
Packit dd8086
    {"bin-file", optional_argument, NULL, 'b'},
Packit dd8086
    {"cue-file", optional_argument, NULL, 'c'},
Packit dd8086
    {"input", optional_argument, NULL, 'i'},
Packit dd8086
    {"cdrom-device", optional_argument, NULL, 'C'},
Packit dd8086
    {"nrg-file", optional_argument, NULL, 'N'},
Packit dd8086
    {"toc-file", optional_argument, NULL, 't'},
Packit dd8086
    {"output-file", required_argument, NULL, 'o'},
Packit dd8086
    {"version", no_argument, NULL, 'V'},
Packit dd8086
Packit dd8086
    {"help", no_argument, NULL, '?' },
Packit dd8086
    {"usage", no_argument, NULL, OP_USAGE },
Packit dd8086
    { NULL, 0, NULL, 0 }
Packit dd8086
  };
Packit dd8086
Packit dd8086
  program_name = strrchr(argv[0],'/');
Packit dd8086
  program_name = program_name ? strdup(program_name+1) : strdup(argv[0]);
Packit dd8086
Packit dd8086
  while ((opt = getopt_long(argc, argv, optionsString, optionsTable, NULL)) >= 0)
Packit dd8086
    switch (opt)
Packit dd8086
      {
Packit dd8086
      case 'a': opts.access_mode = strdup(optarg); break;
Packit dd8086
      case 'd': opts.debug_level = atoi(optarg); break;
Packit dd8086
      case 'x': opts.hexdump = 1; break;
Packit dd8086
      case 's': opts.start_lsn = atoi(optarg); break;
Packit dd8086
      case 'e': opts.end_lsn = atoi(optarg); break;
Packit dd8086
      case 'n': opts.num_sectors = atoi(optarg); break;
Packit dd8086
      case 'b': parse_source(OP_SOURCE_BIN); break;
Packit dd8086
      case 'c': parse_source(OP_SOURCE_CUE); break;
Packit dd8086
      case 'i': parse_source(OP_SOURCE_AUTO); break;
Packit dd8086
      case 'C': parse_source(OP_SOURCE_DEVICE); break;
Packit dd8086
      case 'N': parse_source(OP_SOURCE_NRG); break;
Packit dd8086
      case 't': parse_source(OP_SOURCE_CDRDAO); break;
Packit dd8086
      case 'o': opts.output_file = strdup(optarg); break;
Packit dd8086
Packit dd8086
      case 'm':
Packit dd8086
	process_suboption(optarg, modes_sublist,
Packit dd8086
			  sizeof(modes_sublist) / sizeof(subopt_entry_t),
Packit dd8086
                            "--mode");
Packit dd8086
        break;
Packit dd8086
Packit dd8086
      case 'V':
Packit dd8086
        print_version(program_name, VERSION, 0, true);
Packit dd8086
	rc = EXIT_SUCCESS;
Packit dd8086
	goto error_exit;
Packit dd8086
Packit dd8086
      case '?':
Packit dd8086
	fprintf(stdout, helpText, program_name);
Packit dd8086
	rc = EXIT_INFO;
Packit dd8086
	goto error_exit;
Packit dd8086
Packit dd8086
      case OP_USAGE:
Packit dd8086
	fprintf(stderr, usageText, program_name);
Packit dd8086
	goto error_exit;
Packit dd8086
Packit dd8086
      case OP_HANDLED:
Packit dd8086
	break;
Packit dd8086
      }
Packit dd8086
Packit dd8086
  if (optind < argc) {
Packit dd8086
    const char *remaining_arg = argv[optind++];
Packit dd8086
Packit dd8086
    /* NOTE: A bug in the libpopt version checked source_image, which
Packit dd8086
       rendered the subsequent source_image test useless.
Packit dd8086
    */
Packit dd8086
    if (source_name != NULL) {
Packit dd8086
      report( stderr, "%s: Source specified in option %s and as %s\n",
Packit dd8086
	      program_name, source_name, remaining_arg );
Packit dd8086
      goto error_exit;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    if (opts.source_image == INPUT_DEVICE)
Packit dd8086
      source_name = fillout_device_name(remaining_arg);
Packit dd8086
    else
Packit dd8086
      source_name = strdup(remaining_arg);
Packit dd8086
Packit dd8086
    if (optind < argc) {
Packit dd8086
      report( stderr, "%s: Source specified in previously %s and %s\n",
Packit dd8086
	      program_name, source_name, remaining_arg );
Packit dd8086
      goto error_exit;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (opts.debug_level == 3) {
Packit dd8086
    cdio_loglevel_default = CDIO_LOG_INFO;
Packit dd8086
  } else if (opts.debug_level >= 4) {
Packit dd8086
    cdio_loglevel_default = CDIO_LOG_DEBUG;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (opts.read_mode == READ_MODE_UNINIT) {
Packit dd8086
    report( stderr,
Packit dd8086
	    "%s: Need to give a read mode "
Packit dd8086
	    "(audio, m1f1, m1f2, m2f1, m2f2, or auto)\n",
Packit dd8086
	    program_name );
Packit dd8086
    rc = 10;
Packit dd8086
    goto error_exit;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* Check consistency between start_lsn, end_lsn and num_sectors. */
Packit dd8086
Packit dd8086
  if (opts.nohexdump && opts.hexdump != 2) {
Packit dd8086
    report( stderr,
Packit dd8086
	    "%s: don't give both --hexdump and --no-hexdump together\n",
Packit dd8086
	    program_name );
Packit dd8086
    rc = 11;
Packit dd8086
    goto error_exit;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (opts.nohexdump) opts.hexdump = 0;
Packit dd8086
Packit dd8086
  if (opts.start_lsn == CDIO_INVALID_LSN) {
Packit dd8086
    /* Maybe we derive the start from the end and num sectors. */
Packit dd8086
    if (opts.end_lsn == CDIO_INVALID_LSN) {
Packit dd8086
      /* No start or end LSN, so use 0 for the start */
Packit dd8086
      opts.start_lsn = 0;
Packit dd8086
      if (opts.num_sectors == 0) opts.num_sectors = 1;
Packit dd8086
    } else if (opts.num_sectors != 0) {
Packit dd8086
      if (opts.end_lsn <= opts.num_sectors) {
Packit dd8086
	report( stderr, "%s: end LSN (%lu) needs to be greater than "
Packit dd8086
		" the sector to read (%lu)\n",
Packit dd8086
		program_name, (unsigned long) opts.end_lsn,
Packit dd8086
		(unsigned long) opts.num_sectors );
Packit dd8086
	rc = 12;
Packit dd8086
	goto error_exit;
Packit dd8086
      }
Packit dd8086
      opts.start_lsn = opts.end_lsn - opts.num_sectors + 1;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* opts.start_lsn has been set somehow or we've aborted. */
Packit dd8086
Packit dd8086
  if (opts.end_lsn == CDIO_INVALID_LSN) {
Packit dd8086
    if (0 == opts.num_sectors) opts.num_sectors = 1;
Packit dd8086
    opts.end_lsn = opts.start_lsn + opts.num_sectors - 1;
Packit dd8086
  } else {
Packit dd8086
    /* We were given an end lsn. */
Packit dd8086
    if (opts.end_lsn < opts.start_lsn) {
Packit dd8086
      report( stderr,
Packit dd8086
	      "%s: end LSN (%lu) needs to be grater than start LSN (%lu)\n",
Packit dd8086
	      program_name, (unsigned long) opts.start_lsn,
Packit dd8086
	      (unsigned long) opts.end_lsn );
Packit dd8086
      rc = 13;
Packit dd8086
      goto error_exit;
Packit dd8086
    }
Packit dd8086
    if (opts.num_sectors != opts.end_lsn - opts.start_lsn + 1)
Packit dd8086
      if (opts.num_sectors != 0) {
Packit dd8086
	 report( stderr,
Packit dd8086
		 "%s: inconsistency between start LSN (%lu), end (%lu), "
Packit dd8086
		 "and count (%d)\n",
Packit dd8086
		 program_name, (unsigned long) opts.start_lsn,
Packit dd8086
		 (unsigned long) opts.end_lsn, opts.num_sectors );
Packit dd8086
	 rc = 14;
Packit dd8086
	 goto error_exit;
Packit dd8086
	}
Packit dd8086
    opts.num_sectors = opts.end_lsn - opts.start_lsn + 1;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
 error_exit:
Packit dd8086
  free(program_name);
Packit dd8086
  exit(rc);
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
log_handler (cdio_log_level_t level, const char message[])
Packit dd8086
{
Packit dd8086
  if (level == CDIO_LOG_DEBUG && opts.debug_level < 2)
Packit dd8086
    return;
Packit dd8086
Packit dd8086
  if (level == CDIO_LOG_INFO  && opts.debug_level < 1)
Packit dd8086
    return;
Packit dd8086
Packit dd8086
  if (level == CDIO_LOG_WARN  && opts.debug_level < 0)
Packit dd8086
    return;
Packit dd8086
Packit dd8086
  gl_default_cdio_log_handler (level, message);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
static void
Packit dd8086
init(void)
Packit dd8086
{
Packit dd8086
  opts.debug_level   = 0;
Packit dd8086
  opts.start_lsn     = CDIO_INVALID_LSN;
Packit dd8086
  opts.end_lsn       = CDIO_INVALID_LSN;
Packit dd8086
  opts.num_sectors   = 0;
Packit dd8086
  opts.read_mode     = READ_MODE_UNINIT;
Packit dd8086
  opts.source_image  = INPUT_UNKNOWN;
Packit dd8086
  opts.hexdump       = 2;         /* Not set. */
Packit dd8086
Packit dd8086
  gl_default_cdio_log_handler = cdio_log_set_handler (log_handler);
Packit dd8086
}
Packit dd8086
Packit dd8086
int
Packit dd8086
main(int argc, char *argv[])
Packit dd8086
{
Packit dd8086
  uint8_t buffer[CDIO_CD_FRAMESIZE_RAW] = { 0, };
Packit dd8086
  unsigned int blocklen=CDIO_CD_FRAMESIZE_RAW;
Packit dd8086
  CdIo *p_cdio=NULL;
Packit dd8086
  int output_fd=-1;
Packit dd8086
  FILE *output_stream;
Packit dd8086
Packit dd8086
  init();
Packit dd8086
Packit dd8086
  /* Parse our arguments; every option seen by `parse_opt' will
Packit dd8086
     be reflected in `arguments'. */
Packit dd8086
  parse_options(argc, argv);
Packit dd8086
Packit dd8086
  print_version(program_name, VERSION, opts.no_header, opts.version_only);
Packit dd8086
Packit dd8086
  p_cdio = open_input(source_name, opts.source_image, opts.access_mode);
Packit dd8086
Packit dd8086
  if (opts.output_file!=NULL) {
Packit dd8086
Packit dd8086
    /* If hexdump not explicitly set, then don't produce hexdump
Packit dd8086
       when writing to a file.
Packit dd8086
     */
Packit dd8086
    if (opts.hexdump == 2) opts.hexdump = 0;
Packit dd8086
Packit dd8086
    output_fd = open(opts.output_file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
Packit dd8086
    if (-1 == output_fd) {
Packit dd8086
      err_exit("Error opening output file %s: %s\n",
Packit dd8086
	       opts.output_file, strerror(errno));
Packit dd8086
Packit dd8086
    }
Packit dd8086
  } else
Packit dd8086
    /* If we are writing to stdout, then the default is to produce
Packit dd8086
       a hexdump.
Packit dd8086
     */
Packit dd8086
    if (opts.hexdump == 2) opts.hexdump = 1;
Packit dd8086
Packit dd8086
Packit dd8086
  for ( ; opts.start_lsn <= opts.end_lsn; opts.start_lsn++ ) {
Packit dd8086
    switch (opts.read_mode) {
Packit dd8086
    case READ_AUDIO:
Packit dd8086
    case READ_M1F1:
Packit dd8086
    case READ_M1F2:
Packit dd8086
    case READ_M2F1:
Packit dd8086
    case READ_M2F2:
Packit dd8086
      if (DRIVER_OP_SUCCESS !=
Packit dd8086
	  cdio_read_sector(p_cdio, &buffer,
Packit dd8086
			   opts.start_lsn,
Packit dd8086
			   (cdio_read_mode_t) opts.read_mode)) {
Packit dd8086
	report( stderr, "error reading block %u\n",
Packit dd8086
		(unsigned int) opts.start_lsn );
Packit dd8086
	blocklen = 0;
Packit dd8086
      } else {
Packit dd8086
	switch (opts.read_mode) {
Packit dd8086
	case READ_M1F1:
Packit dd8086
	  blocklen=CDIO_CD_FRAMESIZE;
Packit dd8086
	  break;
Packit dd8086
	case READ_M1F2:
Packit dd8086
	  blocklen=M2RAW_SECTOR_SIZE;
Packit dd8086
	  break;
Packit dd8086
	case READ_M2F1:
Packit dd8086
	  blocklen=CDIO_CD_FRAMESIZE;
Packit dd8086
	  break;
Packit dd8086
	case READ_M2F2:
Packit dd8086
	  blocklen=M2F2_SECTOR_SIZE;
Packit dd8086
	  break;
Packit dd8086
	default: ;
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    case READ_ANY:
Packit dd8086
      {
Packit dd8086
	driver_id_t driver_id = cdio_get_driver_id(p_cdio);
Packit dd8086
	if (cdio_is_device(source_name, driver_id)) {
Packit dd8086
	  if (DRIVER_OP_SUCCESS !=
Packit dd8086
	      mmc_read_sectors(p_cdio, &buffer,
Packit dd8086
			       opts.start_lsn, CDIO_MMC_READ_TYPE_ANY, 1)) {
Packit dd8086
	    report( stderr, "error reading block %u\n",
Packit dd8086
		    (unsigned int) opts.start_lsn );
Packit dd8086
	    blocklen = 0;
Packit dd8086
	  }
Packit dd8086
	} else {
Packit dd8086
	  err_exit(
Packit dd8086
		   "%s: mode 'any' must be used with a real CD-ROM, not an image file.\n", program_name);
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
      break;
Packit dd8086
Packit dd8086
      case READ_MODE_UNINIT:
Packit dd8086
      err_exit("%s: Reading mode not set\n", program_name);
Packit dd8086
      break;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    if (!opts.output_file) {
Packit dd8086
      output_stream = stdout;
Packit dd8086
    } else {
Packit dd8086
      output_stream = fdopen(output_fd, "w");
Packit dd8086
    }
Packit dd8086
Packit dd8086
    if (opts.hexdump)
Packit dd8086
      hexdump(output_stream, buffer, blocklen, opts.just_hex);
Packit dd8086
    else if (opts.output_file) {
Packit dd8086
      ssize_t bytes_ret;
Packit dd8086
      bytes_ret = write(output_fd, buffer, blocklen);
Packit dd8086
      (void)bytes_ret; /* Silence unused warnings */
Packit dd8086
    } else {
Packit dd8086
      unsigned int i;
Packit dd8086
      for (i=0; i
Packit dd8086
    }
Packit dd8086
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (opts.output_file) close(output_fd);
Packit dd8086
Packit dd8086
  myexit(p_cdio, EXIT_SUCCESS);
Packit dd8086
  /* Not reached:*/
Packit dd8086
  return(EXIT_SUCCESS);
Packit dd8086
Packit dd8086
}