/* ReadCD - Read a CD. * * * Modification History. * * Carsten Koch, 2-Oct-1995. * Original Version. * Carsten Koch, 17-Dec-1995. * Extend program to process digital data, too. * Carsten Koch, 27-Jul-1996. Version 1.0. * Make program more tolerant against faulty discs and CD-ROM/CD-writer firmware bugs. * Carsten Koch, 4-Jan-1997. Version 1.1. * Scan all devices in all SCSI buses until first ENOENT error. * Carsten Koch, 28-Apr-1997. Version 1.6. * Synchronize version number with WriteCDR. */ #include #include #include #include #include #include #include #include #include #include #include #include "read_cd.h" #include "util.h" boolean_t identify_device(dsreq_t *dsp, char *device_id) { struct { /* 0 */ unchar peripheral_device_type; /* 1 */ unsigned rmb: 1; unsigned device_type_qualifier: 7; /* 2 */ unsigned iso_version: 2; unsigned ecma_version: 3; unsigned ansi_approved_version: 3; /* 3 */ unsigned aenc: 1; unsigned trmio: 1; unsigned reserved1: 2; unsigned response_data_format: 4; /* 4 */ unchar additional_length; /* 5 */ unchar reserved2; /* 6 */ unchar reserved3; /* 7 */ unsigned relad: 1; unsigned wb32: 1; unsigned wb16: 1; unsigned sync: 1; unsigned link: 1; unsigned reserved4: 1; unsigned cmdq: 1; unsigned srst: 1; /* 8 */ char vendor_identification[8]; /* 16 */ char product_identification[16]; /* 32 */ char product_revision_level[4]; /* 36 */ unchar vendor_specific[20]; /* 56 */ unchar reserved5[40]; } inquiry_data; bzero(&inquiry_data, sizeof(inquiry_data)); inquiry12(dsp, (caddr_t)&inquiry_data, sizeof(inquiry_data), 0); if ((STATUS(dsp) == STA_GOOD) && ((inquiry_data.peripheral_device_type == 4) || (inquiry_data.peripheral_device_type == 5))) { sprintf(device_id, "%.8s %.16s", inquiry_data.vendor_identification, inquiry_data.product_identification); return B_FALSE; } return B_TRUE; } /* top level routines. * ------------------- */ static boolean_t process_options(int argc, char *argv[], boolean_t *audiop, boolean_t *binaryp, char **devp, boolean_t *playp, boolean_t *stdoutwp, boolean_t *track_selected, uint_t *verbosep, boolean_t *write_to_filep) { int c, i; boolean_t tracks = B_FALSE; *devp = 0; *verbosep = 0; *audiop = B_FALSE; *binaryp = B_FALSE; *stdoutwp = B_FALSE; *playp = B_FALSE; *write_to_filep = B_FALSE; for (i = 0; i < 100; i++) track_selected[i] = B_FALSE; while ((c = getopt(argc, argv, "abd:opt:vw")) != EOF) switch (c) { case 'a': *audiop = B_TRUE; break; case 'b': *binaryp = B_TRUE; break; case 'd': *devp = strdup(optarg); break; case 'o': *stdoutwp = B_TRUE; break; case 'p': *playp = B_TRUE; *audiop = B_TRUE; break; case 't': { char *ptr = optarg-1; int f = 0, n = 0; tracks = B_TRUE; do { ptr++; switch (*ptr) { case '-': if (f != 0) return B_TRUE; if (n == 0) f = 1; else f = n; n = 0; break; case 0: case ',': if (f != 0) { if (n == 0) n = 99; for (i = f; i <= n; i++) track_selected[i] = B_TRUE; f = 0; } else track_selected[n] = B_TRUE; n = 0; break; default: if ((*ptr < '0') || (*ptr > '9')) return B_TRUE; n = 10*n + *ptr - '0'; if (n > 100) return B_TRUE; } } while (*ptr != 0); } break; case 'v': (*verbosep)++; break; case 'w': *write_to_filep = B_TRUE; break; default: return B_TRUE; } if (!tracks) for (i = 0; i < 100; i++) track_selected[i] = B_TRUE; if ((!*audiop) && (!*binaryp)) { *audiop = (boolean_t)!*stdoutwp; *binaryp = B_TRUE; } if (*playp && (!*audiop)) { fprintf(stderr, "-p requires -a.\n"); return B_TRUE; } if ((!*playp) && (!*write_to_filep)) fprintf(stderr, "Warning - no operation ('-p' or '-w') specified.\n"); if (optind != argc) return B_TRUE; return B_FALSE; } static void usage(char *name) { fprintf(stderr, "\ Usage:\n\ \n\ %s [-a] [-b] [-d dev] [-o] [-p] [-t list] [-v] [-w]\n\ \n\ Option Meaning\n\ -a Process audio tracks.\n\ If neither -b nor -a are specified, both will be turned on.\n\ \n\ -b Process binary (data, non-audio) tracks.\n\ If neither -b nor -a are specified, both will be turned on.\n\ \n\ -d dev CD ROM device.\n\ -d not specified: Find available CD ROM automatically.\n\ -d U: Use CD ROM on SCSI controller 0, unit U.\n\ -d /dev/scsi/scCdUl0: Use CD ROM on SCSI controller C, unit U.\n\ \n\ -o write data to stdout (ignored for audio).\n\ \n\ -p Play audio as it is being read.\n\ -p turns on -a automatically.\n\ \n\ -t list process listed tracks.\n\ -t not specified: Process all tracks that match -a and -b options.\n\ -t list: Process only tracks that match the list.\n\ List may consist of comma-separated single\n\ track numbers and of dash-separated\n\ start and end track numbers.\n\ \n\ -v Level of verbosity.\n\ -v not specified: Error information only.\n\ -v specified once: Status and Error information.\n\ -v specified twice: Debug, Status and Error information.\n\ \n\ -w Write audio tracks to AIFF-C files.\n\ Track 'nn' goes to file 'nn.aifc'.\n\ Write binary tracks to binary files.\n\ Track 'nn' goes to file 'nn.img'.\n\ ", name); } /* Main program. * ------------- */ int main(int argc, char *argv[]) { char *dev; /* CD ROM SCSI device name */ dsreq_t *dsp; /* CD ROM SCSI device handle */ boolean_t audio; /* process audio tracks */ boolean_t binary; /* process binary data tracks */ boolean_t play; /* play audio data */ boolean_t stdoutw; /* write binary data to stdout */ uint_t verbose; /* 0 = errors, 1 = status, 2 = debug */ boolean_t write_to_file;/* write track data to AIFF-C file */ boolean_t track_selected[100]; /* tracks selected for processing */ char device_id[25];/* vendor and product identification */ if (process_options(argc, argv, &audio, &binary, &dev, &play, &stdoutw, track_selected, &verbose, &write_to_file)) { usage(argv[0]); return 1; } if (verbose > 0) fprintf(stderr, "ReadCD Version " VERSION ".\n"); if (verbose > 1) dsdebug = 1; if (find_device(dev, verbose, &dsp, device_id)) { usage(argv[0]); return 2; } if (verbose > 0) fprintf(stderr, "%s.\n", device_id); if (read_cd(dsp, verbose, audio, binary, play, stdoutw, write_to_file, track_selected)) return 3; eject_disc(dsp); return 0; }