|
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 |
}
|