Blame src/cd-paranoia.c

Packit cb6d3d
/*
Packit cb6d3d
  Copyright (C) 2004-2012, 2014-2015, 2017 Rocky Bernstein <rocky@gnu.org>
Packit cb6d3d
  Copyright (C) 2014 Robert Kausch <robert.kausch@freac.org>
Packit cb6d3d
  Copyright (C) 1998 Monty <xiphmont@mit.edu>
Packit cb6d3d
Packit cb6d3d
  This program is free software: you can redistribute it and/or modify
Packit cb6d3d
  it under the terms of the GNU General Public License as published by
Packit cb6d3d
  the Free Software Foundation, either version 3 of the License, or
Packit cb6d3d
  (at your option) any later version.
Packit cb6d3d
Packit cb6d3d
  This program is distributed in the hope that it will be useful,
Packit cb6d3d
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cb6d3d
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit cb6d3d
  GNU General Public License for more details.
Packit cb6d3d
Packit cb6d3d
  You should have received a copy of the GNU General Public License
Packit cb6d3d
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit cb6d3d
Packit cb6d3d
  See ChangeLog for recent changes.
Packit cb6d3d
*/
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_CONFIG_H
Packit cb6d3d
# include "config.h"
Packit cb6d3d
# define __CDIO_CONFIG_H__ 1
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_STDIO_H
Packit cb6d3d
# include <stdio.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_STDARG_H
Packit cb6d3d
# include <stdarg.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_LIMITS_H
Packit cb6d3d
#include <limits.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifndef PATH_MAX
Packit cb6d3d
# ifdef MAXPATHLEN
Packit cb6d3d
#  define PATH_MAX MAXPATHLEN
Packit cb6d3d
# else
Packit cb6d3d
#  define PATH_MAX 4096
Packit cb6d3d
# endif
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_STDLIB_H
Packit cb6d3d
# include <stdlib.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_UNISTD_H
Packit cb6d3d
# include <unistd.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_STRING_H
Packit cb6d3d
# include <string.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_FCNTL_H
Packit cb6d3d
#include <fcntl.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#include "getopt.h"
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_ERRNO_H
Packit cb6d3d
#include <errno.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifndef ENOMEDIUM
Packit cb6d3d
#define ENOMEDIUM -1
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#include <math.h>
Packit cb6d3d
#include <sys/time.h>
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_SYS_STAT_H
Packit cb6d3d
# include <sys/stat.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#if !defined(HAVE_GETTIMEOFDAY)
Packit cb6d3d
/* MinGW uses sys/time.h and sys/timeb.h to roll its own gettimeofday() */
Packit cb6d3d
# if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_TIMEB_H)
Packit cb6d3d
# include <sys/time.h>
Packit cb6d3d
# include <sys/timeb.h>
Packit cb6d3d
static void gettimeofday(struct timeval* tv, void* timezone);
Packit cb6d3d
# endif
Packit cb6d3d
#endif /* !defined(HAVE_GETTIMEOFDAY) */
Packit cb6d3d
Packit cb6d3d
#include <cdio/cdio.h>
Packit cb6d3d
#include <cdio/cd_types.h>
Packit cb6d3d
#include <cdio/paranoia/cdda.h>
Packit cb6d3d
#include <cdio/paranoia/paranoia.h>
Packit cb6d3d
#include <cdio/bytesex.h>
Packit cb6d3d
#include <cdio/mmc.h>
Packit cb6d3d
#include "utils.h"
Packit cb6d3d
#include "report.h"
Packit cb6d3d
#include "version.h"
Packit cb6d3d
#include "header.h"
Packit cb6d3d
#include "buffering_write.h"
Packit cb6d3d
#include "cachetest.h"
Packit cb6d3d
Packit cb6d3d
#ifndef O_BINARY
Packit cb6d3d
#define O_BINARY 0
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
/* I wonder how many alignment issues this is gonna trip in the
Packit cb6d3d
   future...  it shouldn't trip any...  I guess we'll find out :) */
Packit cb6d3d
Packit cb6d3d
static int
Packit cb6d3d
bigendianp(void)
Packit cb6d3d
{
Packit cb6d3d
  int test=1;
Packit cb6d3d
  char *hack=(char *)(&test);
Packit cb6d3d
  if(hack[0])return(0);
Packit cb6d3d
  return(1);
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
static long
Packit cb6d3d
parse_offset(cdrom_drive_t *d, char *offset, int begin)
Packit cb6d3d
{
Packit cb6d3d
  track_t i_track= CDIO_INVALID_TRACK;
Packit cb6d3d
  long hours   = -1;
Packit cb6d3d
  long minutes = -1;
Packit cb6d3d
  long seconds = -1;
Packit cb6d3d
  long sectors = -1;
Packit cb6d3d
  char *time   = NULL;
Packit cb6d3d
  char *temp   = NULL;
Packit cb6d3d
  long ret;
Packit cb6d3d
Packit cb6d3d
  if (!offset) return -1;
Packit cb6d3d
Packit cb6d3d
  /* separate track from time offset */
Packit cb6d3d
  temp=strchr(offset,']');
Packit cb6d3d
  if(temp){
Packit cb6d3d
    *temp='\0';
Packit cb6d3d
    temp=strchr(offset,'[');
Packit cb6d3d
    if(temp==NULL){
Packit cb6d3d
      report("Error parsing span argument");
Packit cb6d3d
      exit(1);
Packit cb6d3d
    }
Packit cb6d3d
    *temp='\0';
Packit cb6d3d
    time=temp+1;
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  /* parse track */
Packit cb6d3d
  {
Packit cb6d3d
    int chars=strspn(offset,"0123456789");
Packit cb6d3d
    if(chars>0){
Packit cb6d3d
      offset[chars]='\0';
Packit cb6d3d
      i_track=atoi(offset);
Packit cb6d3d
      if ( i_track > d->tracks ) {
Packit cb6d3d
        /*take track i_first_track-1 as pre-gap of 1st track*/
Packit cb6d3d
	report("Track #%d does not exist.",i_track);
Packit cb6d3d
        exit(1);
Packit cb6d3d
      }
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  while(time){
Packit cb6d3d
    long val,chars;
Packit cb6d3d
    char *sec=strrchr(time,'.');
Packit cb6d3d
    if(!sec)sec=strrchr(time,':');
Packit cb6d3d
    if(!sec)sec=time-1;
Packit cb6d3d
Packit cb6d3d
    chars=strspn(sec+1,"0123456789");
Packit cb6d3d
    if(chars)
Packit cb6d3d
      val=atoi(sec+1);
Packit cb6d3d
    else
Packit cb6d3d
      val=0;
Packit cb6d3d
Packit cb6d3d
    switch(*sec){
Packit cb6d3d
    case '.':
Packit cb6d3d
      if(sectors!=-1){
Packit cb6d3d
        report("Error parsing span argument");
Packit cb6d3d
        exit(1);
Packit cb6d3d
      }
Packit cb6d3d
      sectors=val;
Packit cb6d3d
      break;
Packit cb6d3d
    default:
Packit cb6d3d
      if(seconds==-1)
Packit cb6d3d
        seconds=val;
Packit cb6d3d
      else
Packit cb6d3d
        if(minutes==-1)
Packit cb6d3d
          minutes=val;
Packit cb6d3d
        else
Packit cb6d3d
          if(hours==-1)
Packit cb6d3d
            hours=val;
Packit cb6d3d
          else{
Packit cb6d3d
            report("Error parsing span argument");
Packit cb6d3d
            exit(1);
Packit cb6d3d
          }
Packit cb6d3d
      break;
Packit cb6d3d
    }
Packit cb6d3d
Packit cb6d3d
    if (sec<=time) break;
Packit cb6d3d
    *sec='\0';
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if (i_track == CDIO_INVALID_TRACK) {
Packit cb6d3d
    if (seconds==-1 && sectors==-1) return -1;
Packit cb6d3d
    if (begin==-1) {
Packit cb6d3d
      ret=cdda_disc_firstsector(d);
Packit cb6d3d
    } else
Packit cb6d3d
      ret = begin;
Packit cb6d3d
  } else {
Packit cb6d3d
    if ( seconds==-1 && sectors==-1 ) {
Packit cb6d3d
      if (begin==-1){
Packit cb6d3d
        /* first half of a span */
Packit cb6d3d
        return(cdda_track_firstsector(d, i_track));
Packit cb6d3d
      }else{
Packit cb6d3d
        return(cdda_track_lastsector(d, i_track));
Packit cb6d3d
      }
Packit cb6d3d
    } else {
Packit cb6d3d
      /* relative offset into a track */
Packit cb6d3d
      ret=cdda_track_firstsector(d, i_track);
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  /* OK, we had some sort of offset into a track */
Packit cb6d3d
Packit cb6d3d
  if (sectors != -1) ret += sectors;
Packit cb6d3d
  if (seconds != -1) ret += seconds*CDIO_CD_FRAMES_PER_SEC;
Packit cb6d3d
  if (minutes != -1) ret += minutes*CDIO_CD_FRAMES_PER_MIN;
Packit cb6d3d
  if (hours   != -1) ret += hours  *60*CDIO_CD_FRAMES_PER_MIN;
Packit cb6d3d
Packit cb6d3d
  /* We don't want to outside of the track; if it's relative, that's OK... */
Packit cb6d3d
  if( i_track != CDIO_INVALID_TRACK ){
Packit cb6d3d
    if (cdda_sector_gettrack(d,ret) != i_track) {
Packit cb6d3d
      report("Time/sector offset goes beyond end of specified track.");
Packit cb6d3d
      exit(1);
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  /* Don't pass up end of session */
Packit cb6d3d
Packit cb6d3d
  if( ret>cdda_disc_lastsector(d) ) {
Packit cb6d3d
    report("Time/sector offset goes beyond end of disc.");
Packit cb6d3d
    exit(1);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  return(ret);
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
static void
Packit cb6d3d
display_toc(cdrom_drive_t *d)
Packit cb6d3d
{
Packit cb6d3d
  long audiolen=0;
Packit cb6d3d
  track_t i;
Packit cb6d3d
Packit cb6d3d
  report("\nTable of contents (audio tracks only):\n"
Packit cb6d3d
         "track        length               begin        copy pre ch\n"
Packit cb6d3d
         "===========================================================");
Packit cb6d3d
Packit cb6d3d
  for( i=1; i<=d->tracks; i++)
Packit cb6d3d
    if ( cdda_track_audiop(d,i) > 0 ) {
Packit cb6d3d
Packit cb6d3d
      lsn_t sec=cdda_track_firstsector(d,i);
Packit cb6d3d
      lsn_t off=cdda_track_lastsector(d,i)-sec+1;
Packit cb6d3d
Packit cb6d3d
      report("%3d.  %7ld [%02d:%02d.%02d]  %7ld [%02d:%02d.%02d]  %s %s %s",
Packit cb6d3d
	     i,
Packit cb6d3d
	     (long int) off,
Packit cb6d3d
             (int) (off/(CDIO_CD_FRAMES_PER_MIN)),
Packit cb6d3d
             (int) ((off/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN),
Packit cb6d3d
             (int) (off % CDIO_CD_FRAMES_PER_SEC),
Packit cb6d3d
	     (long int) sec,
Packit cb6d3d
             (int) (sec/(CDIO_CD_FRAMES_PER_MIN)),
Packit cb6d3d
             (int) ((sec/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN),
Packit cb6d3d
             (int) (sec % CDIO_CD_FRAMES_PER_SEC),
Packit cb6d3d
	     cdda_track_copyp(d,i)?"  OK":"  no",
Packit cb6d3d
	     cdda_track_preemp(d,i)?" yes":"  no",
Packit cb6d3d
	     cdda_track_channels(d,i)==2?" 2":" 4");
Packit cb6d3d
      audiolen+=off;
Packit cb6d3d
    }
Packit cb6d3d
  report("TOTAL %7ld [%02d:%02d.%02d]    (audio only)",
Packit cb6d3d
	 audiolen,
Packit cb6d3d
         (int) (audiolen/(CDIO_CD_FRAMES_PER_MIN)),
Packit cb6d3d
         (int) ((audiolen/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN),
Packit cb6d3d
	 (int) (audiolen % CDIO_CD_FRAMES_PER_SEC));
Packit cb6d3d
  report(" ");
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
#include "usage.h"
Packit cb6d3d
static void usage(FILE *f)
Packit cb6d3d
{
Packit cb6d3d
  fprintf( f, usage_help);
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
static long callbegin;
Packit cb6d3d
static long callend;
Packit cb6d3d
static long callscript=0;
Packit cb6d3d
Packit cb6d3d
static int skipped_flag=0;
Packit cb6d3d
static int abort_on_skip=0;
Packit cb6d3d
static FILE *logfile = NULL;
Packit cb6d3d
static int logfile_open=0;
Packit cb6d3d
static int reportfile_open=0;
Packit cb6d3d
Packit cb6d3d
#if TRACE_PARANOIA
Packit cb6d3d
static void
Packit cb6d3d
callback(long int inpos, paranoia_cb_mode_t function)
Packit cb6d3d
{
Packit cb6d3d
}
Packit cb6d3d
#else
Packit cb6d3d
static const char *callback_strings[16]={
Packit cb6d3d
  "read",
Packit cb6d3d
  "verify",
Packit cb6d3d
  "jitter",
Packit cb6d3d
  "correction",
Packit cb6d3d
  "scratch",
Packit cb6d3d
  "scratch repair",
Packit cb6d3d
  "skip",
Packit cb6d3d
  "drift",
Packit cb6d3d
  "backoff",
Packit cb6d3d
  "overlap",
Packit cb6d3d
  "dropped",
Packit cb6d3d
  "duped",
Packit cb6d3d
  "transport error",
Packit cb6d3d
  "cache error",
Packit cb6d3d
  "wrote",
Packit cb6d3d
  "finished",
Packit cb6d3d
};
Packit cb6d3d
Packit cb6d3d
static void
Packit cb6d3d
callback(long int inpos, paranoia_cb_mode_t function)
Packit cb6d3d
{
Packit cb6d3d
  /*
Packit cb6d3d
Packit cb6d3d
 (== PROGRESS == [--+!---x-------------->           | 007218 01 ] == :-) . ==)
Packit cb6d3d
Packit cb6d3d
 */
Packit cb6d3d
Packit cb6d3d
  int graph=30;
Packit cb6d3d
  char buffer[256];
Packit cb6d3d
  static long c_sector=0, v_sector=0;
Packit cb6d3d
  static char dispcache[]="                              ";
Packit cb6d3d
  static int last=0;
Packit cb6d3d
  static long lasttime=0;
Packit cb6d3d
  long int sector, osector=0;
Packit cb6d3d
  struct timeval thistime;
Packit cb6d3d
  static char heartbeat=' ';
Packit cb6d3d
  int position=0,aheadposition=0;
Packit cb6d3d
  static int overlap=0;
Packit cb6d3d
  static int printit=-1;
Packit cb6d3d
Packit cb6d3d
  static int slevel=0;
Packit cb6d3d
  static int slast=0;
Packit cb6d3d
  static int stimeout=0;
Packit cb6d3d
  static int cacheerr=0;
Packit cb6d3d
  const char *smilie="= :-)";
Packit cb6d3d
Packit cb6d3d
  if (callscript)
Packit cb6d3d
    fprintf(stderr, "##: %d [%s] @ %ld\n",
Packit cb6d3d
            function, ((int) function >= 0 && (int) function < 16 ?
Packit cb6d3d
                       callback_strings[function] : ""),
Packit cb6d3d
            inpos);
Packit cb6d3d
  else{
Packit cb6d3d
    if(function==PARANOIA_CB_CACHEERR){
Packit cb6d3d
      if(!cacheerr){
Packit cb6d3d
	fprintf(stderr,
Packit cb6d3d
		"\rWARNING: The CDROM drive appears to be seeking impossibly quickly.\n"
Packit cb6d3d
		"This could be due to timer bugs, a drive that really is improbably fast,\n"
Packit cb6d3d
		"or, most likely, a bug in cdparanoia's cache modelling.\n\n"
Packit cb6d3d
		"Please consider using the -A option to perform an analysis run, then mail\n"
Packit cb6d3d
		"the cdparanoia.log file produced by the analysis to paranoia-dev@xiph.org\n"
Packit cb6d3d
		"to assist developers in correcting the problem.\n\n");
Packit cb6d3d
      }
Packit cb6d3d
      cacheerr++;
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(!quiet){
Packit cb6d3d
    long test;
Packit cb6d3d
    osector=inpos;
Packit cb6d3d
    sector=inpos/CD_FRAMEWORDS;
Packit cb6d3d
Packit cb6d3d
    if(printit==-1){
Packit cb6d3d
       if(isatty(STDERR_FILENO) || (logfile != NULL)){
Packit cb6d3d
        printit=1;
Packit cb6d3d
      }else{
Packit cb6d3d
        printit=0;
Packit cb6d3d
      }
Packit cb6d3d
    }
Packit cb6d3d
Packit cb6d3d
    if(printit==1){  /* else don't bother; it's probably being
Packit cb6d3d
                        redirected */
Packit cb6d3d
      position=((float)(sector-callbegin)/
Packit cb6d3d
                (callend-callbegin))*graph;
Packit cb6d3d
Packit cb6d3d
      aheadposition=((float)(c_sector-callbegin)/
Packit cb6d3d
                     (callend-callbegin))*graph;
Packit cb6d3d
Packit cb6d3d
      if(function == PARANOIA_CB_WROTE){
Packit cb6d3d
        v_sector=sector;
Packit cb6d3d
        return;
Packit cb6d3d
      }
Packit cb6d3d
      if (function == PARANOIA_CB_FINISHED) {
Packit cb6d3d
        last=8;
Packit cb6d3d
        heartbeat='*';
Packit cb6d3d
        slevel=0;
Packit cb6d3d
        v_sector=sector;
Packit cb6d3d
      } else
Packit cb6d3d
        if(position<graph && position>=0)
Packit cb6d3d
          switch(function){
Packit cb6d3d
          case PARANOIA_CB_VERIFY:
Packit cb6d3d
            if(stimeout>=30){
Packit cb6d3d
              if(overlap>CD_FRAMEWORDS)
Packit cb6d3d
                slevel=2;
Packit cb6d3d
              else
Packit cb6d3d
                slevel=1;
Packit cb6d3d
            }
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_READ:
Packit cb6d3d
            if(sector>c_sector)c_sector=sector;
Packit cb6d3d
            break;
Packit cb6d3d
Packit cb6d3d
          case PARANOIA_CB_FIXUP_EDGE:
Packit cb6d3d
            if(stimeout>=5){
Packit cb6d3d
              if(overlap>CD_FRAMEWORDS)
Packit cb6d3d
                slevel=2;
Packit cb6d3d
              else
Packit cb6d3d
                slevel=1;
Packit cb6d3d
            }
Packit cb6d3d
            if(dispcache[position]==' ')
Packit cb6d3d
              dispcache[position]='-';
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_FIXUP_ATOM:
Packit cb6d3d
            if(slevel<3 || stimeout>5)slevel=3;
Packit cb6d3d
            if(dispcache[position]==' ' ||
Packit cb6d3d
               dispcache[position]=='-')
Packit cb6d3d
              dispcache[position]='+';
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_READERR:
Packit cb6d3d
            slevel=6;
Packit cb6d3d
	    if(dispcache[position]!='V' && dispcache[position]!='C')
Packit cb6d3d
              dispcache[position]='e';
Packit cb6d3d
            break;
Packit cb6d3d
	  case PARANOIA_CB_CACHEERR:
Packit cb6d3d
	    slevel=8;
Packit cb6d3d
	    dispcache[position]='C';
Packit cb6d3d
	    break;
Packit cb6d3d
          case PARANOIA_CB_SKIP:
Packit cb6d3d
            slevel=8;
Packit cb6d3d
	    if(dispcache[position]!='C')
Packit cb6d3d
	      dispcache[position]='V';
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_OVERLAP:
Packit cb6d3d
            overlap=osector;
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_SCRATCH:
Packit cb6d3d
            slevel=7;
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_DRIFT:
Packit cb6d3d
            if(slevel<4 || stimeout>5)slevel=4;
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_FIXUP_DROPPED:
Packit cb6d3d
          case PARANOIA_CB_FIXUP_DUPED:
Packit cb6d3d
            slevel=5;
Packit cb6d3d
            if(dispcache[position]==' ' ||
Packit cb6d3d
               dispcache[position]=='-' ||
Packit cb6d3d
               dispcache[position]=='+')
Packit cb6d3d
              dispcache[position]='!';
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_REPAIR:
Packit cb6d3d
          case PARANOIA_CB_BACKOFF:
Packit cb6d3d
            break;
Packit cb6d3d
          case PARANOIA_CB_WROTE:
Packit cb6d3d
          case PARANOIA_CB_FINISHED:
Packit cb6d3d
	    /* Handled above */
Packit cb6d3d
	    ;
Packit cb6d3d
          }
Packit cb6d3d
Packit cb6d3d
      switch(slevel){
Packit cb6d3d
      case 0:  /* finished, or no jitter */
Packit cb6d3d
        if(skipped_flag)
Packit cb6d3d
          smilie=" 8-X";
Packit cb6d3d
        else
Packit cb6d3d
          smilie=" :^D";
Packit cb6d3d
        break;
Packit cb6d3d
      case 1:  /* normal.  no atom, low jitter */
Packit cb6d3d
        smilie=" :-)";
Packit cb6d3d
        break;
Packit cb6d3d
      case 2:  /* normal, overlap > 1 */
Packit cb6d3d
        smilie=" :-|";
Packit cb6d3d
        break;
Packit cb6d3d
      case 4:  /* drift */
Packit cb6d3d
        smilie=" :-/";
Packit cb6d3d
        break;
Packit cb6d3d
      case 3:  /* unreported loss of streaming */
Packit cb6d3d
        smilie=" :-P";
Packit cb6d3d
        break;
Packit cb6d3d
      case 5:  /* dropped/duped bytes */
Packit cb6d3d
        smilie=" 8-|";
Packit cb6d3d
        break;
Packit cb6d3d
      case 6:  /* scsi error */
Packit cb6d3d
        smilie=" :-0";
Packit cb6d3d
        break;
Packit cb6d3d
      case 7:  /* scratch */
Packit cb6d3d
        smilie=" :-(";
Packit cb6d3d
        break;
Packit cb6d3d
      case 8:  /* skip */
Packit cb6d3d
        smilie=" ;-(";
Packit cb6d3d
        skipped_flag=1;
Packit cb6d3d
        break;
Packit cb6d3d
Packit cb6d3d
      }
Packit cb6d3d
Packit cb6d3d
      gettimeofday(&thistime,NULL);
Packit cb6d3d
      test=thistime.tv_sec*10+thistime.tv_usec/100000;
Packit cb6d3d
Packit cb6d3d
      if (lasttime!=test || function == PARANOIA_CB_FINISHED
Packit cb6d3d
	  || slast!=slevel ) {
Packit cb6d3d
        if (lasttime!=test || function == PARANOIA_CB_FINISHED) {
Packit cb6d3d
          last++;
Packit cb6d3d
          lasttime=test;
Packit cb6d3d
          if(last>7)last=0;
Packit cb6d3d
          stimeout++;
Packit cb6d3d
          switch(last){
Packit cb6d3d
          case 0:
Packit cb6d3d
            heartbeat=' ';
Packit cb6d3d
            break;
Packit cb6d3d
          case 1:case 7:
Packit cb6d3d
            heartbeat='.';
Packit cb6d3d
            break;
Packit cb6d3d
          case 2:case 6:
Packit cb6d3d
            heartbeat='o';
Packit cb6d3d
            break;
Packit cb6d3d
          case 3:case 5:
Packit cb6d3d
            heartbeat='0';
Packit cb6d3d
            break;
Packit cb6d3d
          case 4:
Packit cb6d3d
            heartbeat='O';
Packit cb6d3d
            break;
Packit cb6d3d
          }
Packit cb6d3d
          if(function == PARANOIA_CB_FINISHED)
Packit cb6d3d
            heartbeat='*';
Packit cb6d3d
Packit cb6d3d
        }
Packit cb6d3d
        if(slast!=slevel){
Packit cb6d3d
          stimeout=0;
Packit cb6d3d
        }
Packit cb6d3d
        slast=slevel;
Packit cb6d3d
Packit cb6d3d
        if (abort_on_skip && skipped_flag
Packit cb6d3d
	    && function != PARANOIA_CB_FINISHED ) {
Packit cb6d3d
          sprintf(buffer,
Packit cb6d3d
                  "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==)   ",
Packit cb6d3d
                  "  ...aborting; please wait... ",
Packit cb6d3d
                  v_sector,overlap/CD_FRAMEWORDS,smilie,heartbeat);
Packit cb6d3d
        }else{
Packit cb6d3d
          if(v_sector==0)
Packit cb6d3d
            sprintf(buffer,
Packit cb6d3d
                    "\r (== PROGRESS == [%s| ...... %02d ] ==%s %c ==)   ",
Packit cb6d3d
                    dispcache,overlap/CD_FRAMEWORDS,smilie,heartbeat);
Packit cb6d3d
Packit cb6d3d
          else
Packit cb6d3d
            sprintf(buffer,
Packit cb6d3d
                    "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==)   ",
Packit cb6d3d
                    dispcache,v_sector,overlap/CD_FRAMEWORDS,smilie,heartbeat);
Packit cb6d3d
Packit cb6d3d
          if ( aheadposition>=0 && aheadposition
Packit cb6d3d
	       !(function == PARANOIA_CB_FINISHED) )
Packit cb6d3d
            buffer[aheadposition+19]='>';
Packit cb6d3d
        }
Packit cb6d3d
Packit cb6d3d
        if(isatty(STDERR_FILENO))
Packit cb6d3d
            fprintf(stderr, "%s", buffer);
Packit cb6d3d
Packit cb6d3d
        if (logfile != NULL && function == PARANOIA_CB_FINISHED) {
Packit cb6d3d
          fprintf(logfile, "%s", buffer+1);
Packit cb6d3d
          fprintf(logfile,"\n\n");
Packit cb6d3d
          fflush(logfile);
Packit cb6d3d
        }
Packit cb6d3d
      }
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  /* clear the indicator for next batch */
Packit cb6d3d
  if(function == PARANOIA_CB_FINISHED)
Packit cb6d3d
    memset(dispcache,' ',graph);
Packit cb6d3d
}
Packit cb6d3d
#endif /* !TRACE_PARANOIA */
Packit cb6d3d
Packit cb6d3d
static const char optstring[] = "aBcCd:eEfFg:k:hi:l:L:Am:n:o:O:pqQrRsS:Tt:VvwWx:XYZz::";
Packit cb6d3d
Packit cb6d3d
static const struct option options [] = {
Packit cb6d3d
        {"abort-on-skip",             no_argument,       NULL, 'X'},
Packit cb6d3d
	{"analyze-drive",             no_argument,       NULL, 'A'},
Packit cb6d3d
        {"batch",                     no_argument,       NULL, 'B'},
Packit cb6d3d
        {"disable-extra-paranoia",    no_argument,       NULL, 'Y'},
Packit cb6d3d
        {"disable-fragmentation",     no_argument,       NULL, 'F'},
Packit cb6d3d
        {"disable-paranoia",          no_argument,       NULL, 'Z'},
Packit cb6d3d
        {"force-cdrom-big-endian",    no_argument,       NULL, 'C'},
Packit cb6d3d
        {"force-cdrom-device",        required_argument, NULL, 'd'},
Packit cb6d3d
        {"force-cdrom-little-endian", no_argument,       NULL, 'c'},
Packit cb6d3d
        {"force-default-sectors",     required_argument, NULL, 'n'},
Packit cb6d3d
        {"force-cooked-device",       required_argument, NULL, 'k'},
Packit cb6d3d
        {"force-generic-device",      required_argument, NULL, 'g'},
Packit cb6d3d
        {"force-read-speed",          required_argument, NULL, 'S'},
Packit cb6d3d
        {"force-search-overlap",      required_argument, NULL, 'o'},
Packit cb6d3d
	{"force-overread",            no_argument,       NULL, 'E'},
Packit cb6d3d
        {"help",                      no_argument,       NULL, 'h'},
Packit cb6d3d
        {"log-summary",               required_argument, NULL, 'l'},
Packit cb6d3d
        {"log-debug",                 required_argument, NULL, 'L'},
Packit cb6d3d
        {"mmc-timeout",               required_argument, NULL, 'm'},
Packit cb6d3d
        {"never-skip",                optional_argument, NULL, 'z'},
Packit cb6d3d
        {"output-aifc",               no_argument,       NULL, 'a'},
Packit cb6d3d
        {"output-aiff",               no_argument,       NULL, 'f'},
Packit cb6d3d
        {"output-raw",                no_argument,       NULL, 'p'},
Packit cb6d3d
        {"output-raw-big-endian",     no_argument,       NULL, 'R'},
Packit cb6d3d
        {"output-raw-little-endian",  no_argument,       NULL, 'r'},
Packit cb6d3d
        {"output-wav",                no_argument,       NULL, 'w'},
Packit cb6d3d
        {"query",                     no_argument,       NULL, 'Q'},
Packit cb6d3d
        {"quiet",                     no_argument,       NULL, 'q'},
Packit cb6d3d
        {"sample-offset",             required_argument, NULL, 'O'},
Packit cb6d3d
        {"stderr-progress",           no_argument,       NULL, 'e'},
Packit cb6d3d
        {"test-mode",                 required_argument, NULL, 'x'},
Packit cb6d3d
        {"toc-bias",                  no_argument,       NULL, 'T'},
Packit cb6d3d
        {"toc-offset",                required_argument, NULL, 't'},
Packit cb6d3d
        {"verbose",                   no_argument,       NULL, 'v'},
Packit cb6d3d
        {"version",                   no_argument,       NULL, 'V'},
Packit cb6d3d
Packit cb6d3d
        {NULL,0,NULL,0}
Packit cb6d3d
};
Packit cb6d3d
Packit cb6d3d
static cdrom_drive_t    *d        = NULL;
Packit cb6d3d
static cdrom_paranoia_t *p        = NULL;
Packit cb6d3d
static char             *span     = NULL;
Packit cb6d3d
static char *force_cdrom_device   = NULL;
Packit cb6d3d
Packit cb6d3d
#define free_and_null(p) \
Packit cb6d3d
  free(p);               \
Packit cb6d3d
  p=NULL;
Packit cb6d3d
Packit cb6d3d
#if !defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_TIMEB_H)
Packit cb6d3d
static void
Packit cb6d3d
gettimeofday(struct timeval* tv, void* timezone)
Packit cb6d3d
{
Packit cb6d3d
  struct timeb timebuffer;
Packit cb6d3d
  ftime( &timebuffer );
Packit cb6d3d
  tv->tv_sec=timebuffer.time;
Packit cb6d3d
  tv->tv_usec=1000*timebuffer.millitm;
Packit cb6d3d
}
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
/* This is run automatically before leaving the program.
Packit cb6d3d
   Free allocated resources.
Packit cb6d3d
*/
Packit cb6d3d
static void
Packit cb6d3d
cleanup (void)
Packit cb6d3d
{
Packit cb6d3d
  if (p) paranoia_free(p);
Packit cb6d3d
  if (d) cdda_close(d);
Packit cb6d3d
  free_and_null(force_cdrom_device);
Packit cb6d3d
  free_and_null(span);
Packit cb6d3d
  if(logfile_open) {
Packit cb6d3d
      fclose(logfile);
Packit cb6d3d
      logfile = NULL;
Packit cb6d3d
    }
Packit cb6d3d
  if(reportfile_open) {
Packit cb6d3d
      fclose(reportfile);
Packit cb6d3d
      reportfile = NULL;
Packit cb6d3d
    }
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
/* Returns true if we have an integer argument.
Packit cb6d3d
   If so, pi_arg is set.
Packit cb6d3d
   If no argument or integer argument found, we give an error
Packit cb6d3d
   message and return false.
Packit cb6d3d
*/
Packit cb6d3d
static bool
Packit cb6d3d
get_int_arg(char c, long int *pi_arg)
Packit cb6d3d
{
Packit cb6d3d
  long int i_arg;
Packit cb6d3d
  char *p_end;
Packit cb6d3d
  if (!optarg) {
Packit cb6d3d
    /* This shouldn't happen, but we'll check anyway. */
Packit cb6d3d
    fprintf(stderr,
Packit cb6d3d
            "An (integer) argument for option -%c was expected "
Packit cb6d3d
            " but not found. Option ignored\n", c);
Packit cb6d3d
    return false;
Packit cb6d3d
  }
Packit cb6d3d
  errno = 0;
Packit cb6d3d
  i_arg = strtol(optarg, &p_end, 10);
Packit cb6d3d
  if ( (LONG_MIN == i_arg || LONG_MAX == i_arg) && (0 != errno) ) {
Packit cb6d3d
    fprintf(stderr,
Packit cb6d3d
            "Value '%s' for option -%c out of range. Value %ld "
Packit cb6d3d
            "used instead.\n", optarg, c, i_arg);
Packit cb6d3d
    *pi_arg = i_arg;
Packit cb6d3d
    return false;
Packit cb6d3d
  } else if (*p_end) {
Packit cb6d3d
    fprintf(stderr,
Packit cb6d3d
            "Can't convert '%s' for option -%c completely into an integer. "
Packit cb6d3d
            "Option ignored.\n", optarg, c);
Packit cb6d3d
    return false;
Packit cb6d3d
  } else {
Packit cb6d3d
    *pi_arg = i_arg;
Packit cb6d3d
    return true;
Packit cb6d3d
  }
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
int
Packit cb6d3d
main(int argc,char *argv[])
Packit cb6d3d
{
Packit cb6d3d
  int   toc_bias             =  0;
Packit cb6d3d
  int   force_cdrom_endian   = -1;
Packit cb6d3d
  int   output_type          =  1; /* 0=raw, 1=wav, 2=aifc */
Packit cb6d3d
  int   output_endian        =  0; /* -1=host, 0=little, 1=big */
Packit cb6d3d
  int   query_only           =  0;
Packit cb6d3d
  int   batch                =  0;
Packit cb6d3d
  int   run_cache_test       =  0;
Packit cb6d3d
  long int force_cdrom_overlap  = -1;
Packit cb6d3d
  long int force_cdrom_sectors  = -1;
Packit cb6d3d
  long int force_cdrom_speed    =  0;
Packit cb6d3d
  long int force_overread       =  0;
Packit cb6d3d
  long int sample_offset        =  0;
Packit cb6d3d
  long int test_flags           =  0;
Packit cb6d3d
  long int toc_offset           =  0;
Packit cb6d3d
  long int max_retries          = 20;
Packit cb6d3d
Packit cb6d3d
  char *logfile_name=NULL;
Packit cb6d3d
  char *reportfile_name=NULL;
Packit cb6d3d
Packit cb6d3d
  /* full paranoia, but allow skipping */
Packit cb6d3d
  int paranoia_mode=PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;
Packit cb6d3d
Packit cb6d3d
  int out;
Packit cb6d3d
Packit cb6d3d
  int c,long_option_index;
Packit cb6d3d
Packit cb6d3d
  atexit(cleanup);
Packit cb6d3d
Packit cb6d3d
  while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
Packit cb6d3d
    switch(c){
Packit cb6d3d
    case 'a':
Packit cb6d3d
      output_type=2;
Packit cb6d3d
      output_endian=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'B':
Packit cb6d3d
      batch=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'c':
Packit cb6d3d
      force_cdrom_endian=0;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'C':
Packit cb6d3d
      force_cdrom_endian=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'e':
Packit cb6d3d
      callscript=1;
Packit cb6d3d
      fprintf(stderr,
Packit cb6d3d
              "Sending all callback output to stderr for wrapper script\n");
Packit cb6d3d
      break;
Packit cb6d3d
    case 'f':
Packit cb6d3d
      output_type=3;
Packit cb6d3d
      output_endian=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'F':
Packit cb6d3d
      paranoia_mode&=~(PARANOIA_MODE_FRAGMENT);
Packit cb6d3d
      break;
Packit cb6d3d
    case 'g':
Packit cb6d3d
    case 'k':
Packit cb6d3d
    case 'd':
Packit cb6d3d
      if (force_cdrom_device) {
Packit cb6d3d
        fprintf(stderr,
Packit cb6d3d
                "Multiple cdrom devices given. Previous device %s ignored\n",
Packit cb6d3d
                force_cdrom_device);
Packit cb6d3d
        free(force_cdrom_device);
Packit cb6d3d
      }
Packit cb6d3d
      force_cdrom_device=strdup(optarg);
Packit cb6d3d
      break;
Packit cb6d3d
    case 'h':
Packit cb6d3d
      usage(stdout);
Packit cb6d3d
      exit(0);
Packit cb6d3d
    case 'l':
Packit cb6d3d
      if(logfile_name)free(logfile_name);
Packit cb6d3d
      logfile_name=NULL;
Packit cb6d3d
      if(optarg)
Packit cb6d3d
	logfile_name=strdup(optarg);
Packit cb6d3d
      logfile_open=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'L':
Packit cb6d3d
      if(reportfile_name)free(reportfile_name);
Packit cb6d3d
      reportfile_name=NULL;
Packit cb6d3d
      if(optarg)
Packit cb6d3d
	reportfile_name=strdup(optarg);
Packit cb6d3d
      reportfile_open=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'm':
Packit cb6d3d
      {
Packit cb6d3d
        long int mmc_timeout_sec;
Packit cb6d3d
        if (get_int_arg(c, &mmc_timeout_sec)) {
Packit cb6d3d
          mmc_timeout_ms = 1000*mmc_timeout_sec;
Packit cb6d3d
        }
Packit cb6d3d
      }
Packit cb6d3d
      break;
Packit cb6d3d
    case 'n':
Packit cb6d3d
      get_int_arg(c, &force_cdrom_sectors);
Packit cb6d3d
      break;
Packit cb6d3d
    case 'o':
Packit cb6d3d
      get_int_arg(c, &force_cdrom_overlap);
Packit cb6d3d
      break;
Packit cb6d3d
    case 'O':
Packit cb6d3d
      get_int_arg(c, &sample_offset);
Packit cb6d3d
      break;
Packit cb6d3d
    case 'p':
Packit cb6d3d
      output_type=0;
Packit cb6d3d
      output_endian=-1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'r':
Packit cb6d3d
      output_type=0;
Packit cb6d3d
      output_endian=0;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'q':
Packit cb6d3d
      verbose=CDDA_MESSAGE_FORGETIT;
Packit cb6d3d
      quiet=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'Q':
Packit cb6d3d
      query_only=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'R':
Packit cb6d3d
      output_type=0;
Packit cb6d3d
      output_endian=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'S':
Packit cb6d3d
      get_int_arg(c, &force_cdrom_speed);
Packit cb6d3d
      break;
Packit cb6d3d
    case 't':
Packit cb6d3d
      get_int_arg(c, &toc_offset);
Packit cb6d3d
      break;
Packit cb6d3d
    case 'T':
Packit cb6d3d
      toc_bias=-1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'v':
Packit cb6d3d
      verbose=CDDA_MESSAGE_PRINTIT;
Packit cb6d3d
      quiet=0;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'V':
Packit cb6d3d
      fprintf(stderr,PARANOIA_VERSION);
Packit cb6d3d
      fprintf(stderr,"\n");
Packit cb6d3d
      exit(0);
Packit cb6d3d
      break;
Packit cb6d3d
    case 'w':
Packit cb6d3d
      output_type=1;
Packit cb6d3d
      output_endian=0;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'W':
Packit cb6d3d
      paranoia_mode&=~PARANOIA_MODE_REPAIR;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'x':
Packit cb6d3d
      get_int_arg(c, &test_flags);
Packit cb6d3d
      break;
Packit cb6d3d
    case 'X':
Packit cb6d3d
      /*paranoia_mode&=~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);*/
Packit cb6d3d
      abort_on_skip=1;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'Y':
Packit cb6d3d
      paranoia_mode|=PARANOIA_MODE_OVERLAP; /* cdda2wav style overlap
Packit cb6d3d
                                                check only */
Packit cb6d3d
      paranoia_mode&=~PARANOIA_MODE_VERIFY;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'Z':
Packit cb6d3d
      paranoia_mode=PARANOIA_MODE_DISABLE;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'A':
Packit cb6d3d
      run_cache_test=1;
Packit cb6d3d
      query_only=1;
Packit cb6d3d
      reportfile_open=1;
Packit cb6d3d
      verbose=CDDA_MESSAGE_PRINTIT;
Packit cb6d3d
      break;
Packit cb6d3d
    case 'z':
Packit cb6d3d
      if (optarg) {
Packit cb6d3d
        get_int_arg(c, &max_retries);
Packit cb6d3d
        paranoia_mode&=~PARANOIA_MODE_NEVERSKIP;
Packit cb6d3d
      } else {
Packit cb6d3d
        paranoia_mode|=PARANOIA_MODE_NEVERSKIP;
Packit cb6d3d
      }
Packit cb6d3d
      break;
Packit cb6d3d
    case 'E':
Packit cb6d3d
      force_overread=1;
Packit cb6d3d
      break;
Packit cb6d3d
    default:
Packit cb6d3d
      usage(stderr);
Packit cb6d3d
      exit(1);
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(logfile_open){
Packit cb6d3d
    if(logfile_name==NULL)
Packit cb6d3d
      logfile_name=strdup("cdparanoia.log");
Packit cb6d3d
    if(!strcmp(logfile_name,"-")){
Packit cb6d3d
      logfile=stdout;
Packit cb6d3d
      logfile_open=0;
Packit cb6d3d
    }else{
Packit cb6d3d
      logfile=fopen(logfile_name,"w");
Packit cb6d3d
      if(logfile==NULL){
Packit cb6d3d
	report("Cannot open log summary file %s: %s",logfile_name,
Packit cb6d3d
	       strerror(errno));
Packit cb6d3d
	exit(1);
Packit cb6d3d
      }
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
  if(reportfile_open){
Packit cb6d3d
    if(reportfile_name==NULL)
Packit cb6d3d
      reportfile_name=strdup("cdparanoia.log");
Packit cb6d3d
    if(!strcmp(reportfile_name,"-")){
Packit cb6d3d
      reportfile=stdout;
Packit cb6d3d
      reportfile_open=0;
Packit cb6d3d
    }else{
Packit cb6d3d
      if(logfile_name && !strcmp(reportfile_name,logfile_name)){
Packit cb6d3d
	reportfile=logfile;
Packit cb6d3d
	reportfile_open=0;
Packit cb6d3d
      }else{
Packit cb6d3d
	reportfile=fopen(reportfile_name,"w");
Packit cb6d3d
	if(reportfile==NULL){
Packit cb6d3d
	  report("Cannot open debug log file %s: %s",reportfile_name,
Packit cb6d3d
		 strerror(errno));
Packit cb6d3d
	  exit(1);
Packit cb6d3d
	}
Packit cb6d3d
      }
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(logfile){
Packit cb6d3d
    /* log command line and version */
Packit cb6d3d
    int i;
Packit cb6d3d
    for (i = 0; i < argc; i++)
Packit cb6d3d
      fprintf(logfile,"%s ",argv[i]);
Packit cb6d3d
    fprintf(logfile,"\n");
Packit cb6d3d
Packit cb6d3d
    if(reportfile!=logfile){
Packit cb6d3d
      fprintf(logfile,VERSION);
Packit cb6d3d
      fprintf(logfile,"\n");
Packit cb6d3d
      fprintf(logfile,"Using cdda library version: %s\n",cdda_version());
Packit cb6d3d
      fprintf(logfile,"Using paranoia library version: %s\n",paranoia_version());
Packit cb6d3d
    }
Packit cb6d3d
    fflush(logfile);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(reportfile && reportfile!=logfile){
Packit cb6d3d
    /* log command line */
Packit cb6d3d
    int i;
Packit cb6d3d
    for (i = 0; i < argc; i++)
Packit cb6d3d
      fprintf(reportfile,"%s ",argv[i]);
Packit cb6d3d
    fprintf(reportfile,"\n");
Packit cb6d3d
    fflush(reportfile);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(optind>=argc && !query_only){
Packit cb6d3d
    if(batch)
Packit cb6d3d
      span=NULL;
Packit cb6d3d
    else{
Packit cb6d3d
      /* D'oh.  No span. Fetch me a brain, Igor. */
Packit cb6d3d
      usage(stderr);
Packit cb6d3d
      exit(1);
Packit cb6d3d
    }
Packit cb6d3d
  }else
Packit cb6d3d
    if (argv[optind]) span=strdup(argv[optind]);
Packit cb6d3d
Packit cb6d3d
  report(PARANOIA_VERSION);
Packit cb6d3d
  if(verbose){
Packit cb6d3d
    report("Using cdda library version: %s",cdda_version());
Packit cb6d3d
    report("Using paranoia library version: %s",paranoia_version());
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  /* Query the cdrom/disc; we may need to override some settings */
Packit cb6d3d
Packit cb6d3d
  if(force_cdrom_device)
Packit cb6d3d
    d=cdda_identify(force_cdrom_device,verbose,NULL);
Packit cb6d3d
  else {
Packit cb6d3d
    driver_id_t driver_id;
Packit cb6d3d
    char **ppsz_cd_drives = cdio_get_devices_with_cap_ret(NULL,
Packit cb6d3d
                                                          CDIO_FS_AUDIO,
Packit cb6d3d
                                                          false,
Packit cb6d3d
                                                          &driver_id);
Packit cb6d3d
    if (ppsz_cd_drives && *ppsz_cd_drives) {
Packit cb6d3d
      d=cdda_identify(*ppsz_cd_drives,verbose, NULL);
Packit cb6d3d
    } else {
Packit cb6d3d
      report("\nUnable find or access a CD-ROM drive with an audio CD"
Packit cb6d3d
             " in it.");
Packit cb6d3d
      report("\nYou might try specifying the drive, especially if it has"
Packit cb6d3d
             " mixed-mode (and non-audio) format tracks");
Packit cb6d3d
      exit(1);
Packit cb6d3d
    }
Packit cb6d3d
Packit cb6d3d
    cdio_free_device_list(ppsz_cd_drives);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(!d){
Packit cb6d3d
    if(!verbose)
Packit cb6d3d
      report("\nUnable to open cdrom drive; -v might give more information.");
Packit cb6d3d
    exit(1);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(verbose)
Packit cb6d3d
    cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_PRINTIT);
Packit cb6d3d
  else
Packit cb6d3d
    cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_FORGETIT);
Packit cb6d3d
Packit cb6d3d
  /* possibly force hand on endianness of drive, sector request size */
Packit cb6d3d
  if(force_cdrom_endian!=-1){
Packit cb6d3d
    d->bigendianp=force_cdrom_endian;
Packit cb6d3d
    switch(force_cdrom_endian){
Packit cb6d3d
    case 0:
Packit cb6d3d
      report("Forcing CDROM sense to little-endian; ignoring preset and autosense");
Packit cb6d3d
      break;
Packit cb6d3d
    case 1:
Packit cb6d3d
      report("Forcing CDROM sense to big-endian; ignoring preset and autosense");
Packit cb6d3d
      break;
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
  if (force_cdrom_sectors!=-1) {
Packit cb6d3d
    if(force_cdrom_sectors<0 || force_cdrom_sectors>100){
Packit cb6d3d
      report("Default sector read size must be 1<= n <= 100\n");
Packit cb6d3d
      cdda_close(d);
Packit cb6d3d
      d=NULL;
Packit cb6d3d
      exit(1);
Packit cb6d3d
    }
Packit cb6d3d
    report("Forcing default to read %ld sectors; "
Packit cb6d3d
	   "ignoring preset and autosense",force_cdrom_sectors);
Packit cb6d3d
    d->nsectors=force_cdrom_sectors;
Packit cb6d3d
  }
Packit cb6d3d
  if (force_cdrom_overlap!=-1) {
Packit cb6d3d
    if (force_cdrom_overlap<0 || force_cdrom_overlap>CDIO_CD_FRAMES_PER_SEC) {
Packit cb6d3d
      report("Search overlap sectors must be 0<= n <=75\n");
Packit cb6d3d
      cdda_close(d);
Packit cb6d3d
      d=NULL;
Packit cb6d3d
      if(logfile && logfile != stdout)
Packit cb6d3d
        fclose(logfile);
Packit cb6d3d
      exit(1);
Packit cb6d3d
    }
Packit cb6d3d
    report("Forcing search overlap to %ld sectors; "
Packit cb6d3d
	   "ignoring autosense",force_cdrom_overlap);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  switch( cdda_open(d) ) {
Packit cb6d3d
  case -2:case -3:case -4:case -5:
Packit cb6d3d
    report("\nUnable to open disc.  Is there an audio CD in the drive?");
Packit cb6d3d
    exit(1);
Packit cb6d3d
  case -6:
Packit cb6d3d
    report("\nCdparanoia could not find a way to read audio from this drive.");
Packit cb6d3d
    exit(1);
Packit cb6d3d
  case 0:
Packit cb6d3d
    break;
Packit cb6d3d
  default:
Packit cb6d3d
    report("\nUnable to open disc.");
Packit cb6d3d
    exit(1);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  d->i_test_flags = test_flags;
Packit cb6d3d
Packit cb6d3d
  if (force_cdrom_speed == 0) force_cdrom_speed = -1;
Packit cb6d3d
Packit cb6d3d
  if (force_cdrom_speed != -1) {
Packit cb6d3d
    report("\nAttempting to set speed to %ldx... ", force_cdrom_speed);
Packit cb6d3d
  } else {
Packit cb6d3d
    if (verbose)
Packit cb6d3d
      report("\nAttempting to set cdrom to full speed... ");
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if (cdda_speed_set(d, force_cdrom_speed)) {
Packit cb6d3d
    if (verbose || force_cdrom_speed != -1)
Packit cb6d3d
      report("\tCDROM speed set FAILED. Continuing anyway...");
Packit cb6d3d
  } else {
Packit cb6d3d
    if (verbose)
Packit cb6d3d
      report("\tdrive returned OK.");
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(run_cache_test){
Packit cb6d3d
    int warn=analyze_cache(d, stderr, reportfile, force_cdrom_speed);
Packit cb6d3d
Packit cb6d3d
    if(warn==0){
Packit cb6d3d
      reportC("\nDrive tests OK with Paranoia.\n\n");
Packit cb6d3d
      return 0;
Packit cb6d3d
    }
Packit cb6d3d
Packit cb6d3d
    if(warn==1)
Packit cb6d3d
      reportC("\nWARNING! PARANOIA MAY NOT BE TRUSTWORTHY WITH THIS DRIVE!\n"
Packit cb6d3d
	      "\nThe Paranoia library may not model this CDROM drive's cache"
Packit cb6d3d
	      "\ncorrectly according to this analysis run. Analysis is not"
Packit cb6d3d
	      "\nalways accurate (it can be fooled by machine load or random"
Packit cb6d3d
	      "\nkernel latencies), but if a failed result happens more often"
Packit cb6d3d
	      "\nthan one time in twenty on an unloaded machine, please mail"
Packit cb6d3d
	      "\nthe %s file produced by this failed analysis to"
Packit cb6d3d
	      "\nparanoia-dev@xiph.org to assist developers in extending"
Packit cb6d3d
	      "\nParanoia to handle this CDROM properly.\n\n",reportfile_name);
Packit cb6d3d
    return 1;
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
Packit cb6d3d
  /* Dump the TOC */
Packit cb6d3d
  if (query_only || verbose ) display_toc(d);
Packit cb6d3d
Packit cb6d3d
  if (query_only) exit(0);
Packit cb6d3d
Packit cb6d3d
  /* bias the disc.  A hack.  Of course. this is never the default. */
Packit cb6d3d
  /*
Packit cb6d3d
     Some CD-ROM/CD-R drives will add an offset to the position on
Packit cb6d3d
     reading audio data. This is usually around 500-700 audio samples
Packit cb6d3d
     (ca. 1/75 second) on reading. So when this program queries a
Packit cb6d3d
     specific sector, it might not receive exactly that sector, but
Packit cb6d3d
     shifted by some amount.
Packit cb6d3d
Packit cb6d3d
     Note that if ripping includes the end of the CD, this will this
Packit cb6d3d
     cause this program to attempt to read partial sectors before or
Packit cb6d3d
     past the known user data area of the disc, probably causing read
Packit cb6d3d
     errors on most drives and possibly even hard lockups on some
Packit cb6d3d
     buggy hardware.
Packit cb6d3d
Packit cb6d3d
     [Note to libcdio driver hackers: make sure all CD-drivers don't
Packit cb6d3d
     try to read outside of the stated disc boundaries.]
Packit cb6d3d
  */
Packit cb6d3d
  if(sample_offset){
Packit cb6d3d
    toc_offset+=sample_offset/588;
Packit cb6d3d
    sample_offset%=588;
Packit cb6d3d
    if(sample_offset<0){
Packit cb6d3d
      sample_offset+=588;
Packit cb6d3d
      toc_offset--;
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if (toc_bias) {
Packit cb6d3d
    toc_offset = -cdda_track_firstsector(d,1);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  {
Packit cb6d3d
    int i;
Packit cb6d3d
    for( i=0; i < d->tracks+1; i++ )
Packit cb6d3d
      d->disc_toc[i].dwStartSector+=toc_offset;
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if (d->nsectors==1) {
Packit cb6d3d
    report("WARNING: The autosensed/selected sectors per read value is\n"
Packit cb6d3d
           "         one sector, making it very unlikely Paranoia can \n"
Packit cb6d3d
           "         work.\n\n"
Packit cb6d3d
           "         Attempting to continue...\n\n");
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  /* parse the span, set up begin and end sectors */
Packit cb6d3d
Packit cb6d3d
  {
Packit cb6d3d
    long i_first_lsn;
Packit cb6d3d
    long i_last_lsn;
Packit cb6d3d
    long batch_first;
Packit cb6d3d
    long batch_last;
Packit cb6d3d
    int batch_track;
Packit cb6d3d
Packit cb6d3d
    if (span) {
Packit cb6d3d
      /* look for the hyphen */
Packit cb6d3d
      char *span2=strchr(span,'-');
Packit cb6d3d
      if(strrchr(span,'-')!=span2){
Packit cb6d3d
        report("Error parsing span argument");
Packit cb6d3d
        exit(1);
Packit cb6d3d
      }
Packit cb6d3d
Packit cb6d3d
      if (span2!=NULL) {
Packit cb6d3d
        *span2='\0';
Packit cb6d3d
        span2++;
Packit cb6d3d
      }
Packit cb6d3d
Packit cb6d3d
      i_first_lsn=parse_offset(d, span, -1);
Packit cb6d3d
Packit cb6d3d
      if(i_first_lsn==-1)
Packit cb6d3d
        i_last_lsn=parse_offset(d, span2, cdda_disc_firstsector(d));
Packit cb6d3d
Packit cb6d3d
      else
Packit cb6d3d
        i_last_lsn=parse_offset(d, span2, i_first_lsn);
Packit cb6d3d
Packit cb6d3d
      if (i_first_lsn == -1) {
Packit cb6d3d
        if (i_last_lsn == -1) {
Packit cb6d3d
          report("Error parsing span argument");
Packit cb6d3d
          exit(1);
Packit cb6d3d
        } else {
Packit cb6d3d
          i_first_lsn=cdda_disc_firstsector(d);
Packit cb6d3d
        }
Packit cb6d3d
      } else {
Packit cb6d3d
        if (i_last_lsn==-1) {
Packit cb6d3d
          if (span2) { /* There was a hyphen */
Packit cb6d3d
            i_last_lsn=cdda_disc_lastsector(d);
Packit cb6d3d
          } else {
Packit cb6d3d
            i_last_lsn=
Packit cb6d3d
              cdda_track_lastsector(d,cdda_sector_gettrack(d, i_first_lsn));
Packit cb6d3d
          }
Packit cb6d3d
        }
Packit cb6d3d
      }
Packit cb6d3d
    } else {
Packit cb6d3d
      i_first_lsn = cdda_disc_firstsector(d);
Packit cb6d3d
      i_last_lsn  = cdda_disc_lastsector(d);
Packit cb6d3d
    }
Packit cb6d3d
Packit cb6d3d
    {
Packit cb6d3d
      int track1 = cdda_sector_gettrack(d, i_first_lsn);
Packit cb6d3d
      int track2 = cdda_sector_gettrack(d, i_last_lsn);
Packit cb6d3d
      long off1  = i_first_lsn - cdda_track_firstsector(d, track1);
Packit cb6d3d
      long off2  = i_last_lsn  - cdda_track_firstsector(d, track2);
Packit cb6d3d
      int i;
Packit cb6d3d
Packit cb6d3d
      for( i=track1; i<=track2; i++ )
Packit cb6d3d
        if(i != 0 && !cdda_track_audiop(d,i)){
Packit cb6d3d
	  report("Selected span contains non audio track at track %02d.  Aborting.\n\n", i);
Packit cb6d3d
          exit(1);
Packit cb6d3d
        }
Packit cb6d3d
Packit cb6d3d
      report("Ripping from sector %7ld (track %2d [%d:%02d.%02d])\n"
Packit cb6d3d
	     "\t  to sector %7ld (track %2d [%d:%02d.%02d])\n",
Packit cb6d3d
	     i_first_lsn,
Packit cb6d3d
	     track1,
Packit cb6d3d
	     (int) (off1/(CDIO_CD_FRAMES_PER_MIN)),
Packit cb6d3d
	     (int) ((off1/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN),
Packit cb6d3d
	     (int)(off1 % CDIO_CD_FRAMES_PER_SEC),
Packit cb6d3d
	     i_last_lsn,
Packit cb6d3d
	     track2,
Packit cb6d3d
	     (int) (off2/(CDIO_CD_FRAMES_PER_MIN)),
Packit cb6d3d
	     (int) ((off2/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN),
Packit cb6d3d
	     (int)(off2 % CDIO_CD_FRAMES_PER_SEC));
Packit cb6d3d
Packit cb6d3d
    }
Packit cb6d3d
Packit cb6d3d
    if (toc_offset && !force_overread) {
Packit cb6d3d
	d->disc_toc[d->tracks].dwStartSector -= toc_offset;
Packit cb6d3d
	if (i_last_lsn > cdda_track_lastsector(d, d->tracks))
Packit cb6d3d
		i_last_lsn -= toc_offset;
Packit cb6d3d
    }
Packit cb6d3d
    {
Packit cb6d3d
      long cursor;
Packit cb6d3d
      int16_t offset_buffer[1176];
Packit cb6d3d
      int offset_buffer_used=0;
Packit cb6d3d
      int offset_skip=sample_offset*4;
Packit cb6d3d
      off_t sectorlen;
Packit cb6d3d
Packit cb6d3d
#if defined(HAVE_GETUID) && (defined(HAVE_SETEUID) || defined(HAVE_SETEGID))
Packit cb6d3d
      int dummy __attribute__((unused));
Packit cb6d3d
#endif
Packit cb6d3d
      p=paranoia_init(d);
Packit cb6d3d
      paranoia_modeset(p,paranoia_mode);
Packit cb6d3d
      if(force_cdrom_overlap!=-1)paranoia_overlapset(p,force_cdrom_overlap);
Packit cb6d3d
Packit cb6d3d
      if(verbose) {
Packit cb6d3d
        cdda_verbose_set(d,CDDA_MESSAGE_LOGIT,CDDA_MESSAGE_LOGIT);
Packit cb6d3d
        cdio_loglevel_default = CDIO_LOG_INFO;
Packit cb6d3d
      } else
Packit cb6d3d
        cdda_verbose_set(d,CDDA_MESSAGE_FORGETIT,CDDA_MESSAGE_FORGETIT);
Packit cb6d3d
Packit cb6d3d
      paranoia_seek(p,cursor=i_first_lsn,SEEK_SET);
Packit cb6d3d
Packit cb6d3d
      /* this is probably a good idea in general */
Packit cb6d3d
#if defined(HAVE_GETUID) && defined(HAVE_SETEUID)
Packit cb6d3d
      dummy = seteuid(getuid());
Packit cb6d3d
#endif
Packit cb6d3d
#if defined(HAVE_GETGID) && defined(HAVE_SETEGID)
Packit cb6d3d
      dummy = setegid(getgid());
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
      /* we'll need to be able to read one sector past user data if we
Packit cb6d3d
         have a sample offset in order to pick up the last bytes.  We
Packit cb6d3d
         need to set the disc length forward here so that the libs are
Packit cb6d3d
         willing to read past, assuming that works on the hardware, of
Packit cb6d3d
         course */
Packit cb6d3d
      if(sample_offset && force_overread)
Packit cb6d3d
        d->disc_toc[d->tracks].dwStartSector++;
Packit cb6d3d
Packit cb6d3d
      while(cursor<=i_last_lsn){
Packit cb6d3d
        char outfile_name[PATH_MAX];
Packit cb6d3d
        if ( batch ){
Packit cb6d3d
          batch_first = cursor;
Packit cb6d3d
          batch_track = cdda_sector_gettrack(d,cursor);
Packit cb6d3d
          batch_last  = cdda_track_lastsector(d, batch_track);
Packit cb6d3d
          if (batch_last>i_last_lsn) batch_last=i_last_lsn;
Packit cb6d3d
        } else {
Packit cb6d3d
          batch_first = i_first_lsn;
Packit cb6d3d
          batch_last  = i_last_lsn;
Packit cb6d3d
          batch_track = -1;
Packit cb6d3d
        }
Packit cb6d3d
Packit cb6d3d
        callbegin=batch_first;
Packit cb6d3d
        callend=batch_last;
Packit cb6d3d
Packit cb6d3d
        /* argv[optind] is the span, argv[optind+1] (if exists) is outfile */
Packit cb6d3d
Packit cb6d3d
        if (optind+1
Packit cb6d3d
          if (!strcmp(argv[optind+1],"-") ){
Packit cb6d3d
            out = dup(fileno(stdout));
Packit cb6d3d
            if(out==-1){
Packit cb6d3d
              report("Cannot dupplicate stdout: %s",
Packit cb6d3d
                     strerror(errno));
Packit cb6d3d
              exit(1);
Packit cb6d3d
            }
Packit cb6d3d
            if(batch)
Packit cb6d3d
              report("Are you sure you wanted 'batch' "
Packit cb6d3d
                     "(-B) output with stdout?");
Packit cb6d3d
            report("outputting to stdout\n");
Packit cb6d3d
            if(logfile){
Packit cb6d3d
              fprintf(logfile,"outputting to stdout\n");
Packit cb6d3d
              fflush(logfile);
Packit cb6d3d
            }
Packit cb6d3d
            outfile_name[0]='\0';
Packit cb6d3d
          } else {
Packit cb6d3d
            char dirname[PATH_MAX];
Packit cb6d3d
            char *basename=split_base_dir(argv[optind+1], dirname,
Packit cb6d3d
					  PATH_MAX);
Packit cb6d3d
Packit cb6d3d
	    if (NULL == basename) {
Packit cb6d3d
	      report("Output filename too long");
Packit cb6d3d
	      exit(1);
Packit cb6d3d
	    }
Packit cb6d3d
Packit cb6d3d
            if(batch) {
Packit cb6d3d
	      if (strlen(argv[optind+1]) - 10 > PATH_MAX) {
Packit cb6d3d
		report("Output filename too long");
Packit cb6d3d
		exit(1);
Packit cb6d3d
	      }
Packit cb6d3d
              snprintf(outfile_name, PATH_MAX,
Packit cb6d3d
		       " %strack%02d.%s", dirname,
Packit cb6d3d
                       batch_track, basename);
Packit cb6d3d
            } else
Packit cb6d3d
              snprintf(outfile_name, PATH_MAX, "%s%s", dirname, basename);
Packit cb6d3d
Packit cb6d3d
            if(basename[0]=='\0'){
Packit cb6d3d
              switch (output_type) {
Packit cb6d3d
              case 0: /* raw */
Packit cb6d3d
                strncat(outfile_name, "cdda.raw", sizeof("cdda.raw"));
Packit cb6d3d
                break;
Packit cb6d3d
              case 1:
Packit cb6d3d
                strncat(outfile_name, "cdda.wav", sizeof("cdda.wav"));
Packit cb6d3d
                break;
Packit cb6d3d
              case 2:
Packit cb6d3d
                strncat(outfile_name, "cdda.aifc", sizeof("cdda.aifc"));
Packit cb6d3d
                break;
Packit cb6d3d
              case 3:
Packit cb6d3d
                strncat(outfile_name, "cdda.aiff", sizeof("cdda.aiff"));
Packit cb6d3d
                break;
Packit cb6d3d
              }
Packit cb6d3d
            }
Packit cb6d3d
Packit cb6d3d
            out=open(outfile_name,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,0666);
Packit cb6d3d
            if(out==-1){
Packit cb6d3d
              report("Cannot open specified output file %s: %s",
Packit cb6d3d
                      outfile_name, strerror(errno));
Packit cb6d3d
              exit(1);
Packit cb6d3d
            }
Packit cb6d3d
            report("outputting to %s\n", outfile_name);
Packit cb6d3d
            if(logfile){
Packit cb6d3d
              fprintf(logfile,"outputting to %s\n",outfile_name);
Packit cb6d3d
              fflush(logfile);
Packit cb6d3d
            }
Packit cb6d3d
          }
Packit cb6d3d
        } else {
Packit cb6d3d
          /* default */
Packit cb6d3d
          if (batch)
Packit cb6d3d
            sprintf(outfile_name,"track%02d.", batch_track);
Packit cb6d3d
          else
Packit cb6d3d
            outfile_name[0]='\0';
Packit cb6d3d
Packit cb6d3d
          switch(output_type){
Packit cb6d3d
          case 0: /* raw */
Packit cb6d3d
            strncat(outfile_name, "cdda.raw", sizeof("cdda.raw"));
Packit cb6d3d
            break;
Packit cb6d3d
          case 1:
Packit cb6d3d
            strncat(outfile_name, "cdda.wav", sizeof("cdda.wav"));
Packit cb6d3d
            break;
Packit cb6d3d
          case 2:
Packit cb6d3d
            strncat(outfile_name, "cdda.aifc", sizeof("cdda.aifc"));
Packit cb6d3d
            break;
Packit cb6d3d
          case 3:
Packit cb6d3d
            strncat(outfile_name, "cdda.aiff", sizeof("cdda.aiff"));
Packit cb6d3d
            break;
Packit cb6d3d
          }
Packit cb6d3d
Packit cb6d3d
          out = open(outfile_name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
Packit cb6d3d
          if(out==-1){
Packit cb6d3d
            report("Cannot open default output file %s: %s", outfile_name,
Packit cb6d3d
                    strerror(errno));
Packit cb6d3d
            exit(1);
Packit cb6d3d
          }
Packit cb6d3d
          report("outputting to %s\n", outfile_name);
Packit cb6d3d
          if(logfile){
Packit cb6d3d
            fprintf(logfile,"outputting to %s\n",outfile_name);
Packit cb6d3d
            fflush(logfile);
Packit cb6d3d
          }
Packit cb6d3d
Packit cb6d3d
        }
Packit cb6d3d
Packit cb6d3d
	sectorlen = batch_last - batch_first + 1;
Packit cb6d3d
	if (cdda_sector_gettrack(d, cursor) == d->tracks &&
Packit cb6d3d
		toc_offset > 0 && !force_overread){
Packit cb6d3d
		sectorlen += toc_offset;
Packit cb6d3d
	}
Packit cb6d3d
        switch(output_type) {
Packit cb6d3d
        case 0: /* raw */
Packit cb6d3d
          break;
Packit cb6d3d
        case 1: /* wav */
Packit cb6d3d
	  WriteWav(out, sectorlen * CD_FRAMESIZE_RAW);
Packit cb6d3d
          break;
Packit cb6d3d
        case 2: /* aifc */
Packit cb6d3d
	  WriteAifc(out, sectorlen * CD_FRAMESIZE_RAW);
Packit cb6d3d
          break;
Packit cb6d3d
        case 3: /* aiff */
Packit cb6d3d
	  WriteAiff(out, sectorlen * CD_FRAMESIZE_RAW);
Packit cb6d3d
          break;
Packit cb6d3d
        }
Packit cb6d3d
Packit cb6d3d
        /* Off we go! */
Packit cb6d3d
Packit cb6d3d
        if(offset_buffer_used){
Packit cb6d3d
          /* partial sector from previous batch read */
Packit cb6d3d
          cursor++;
Packit cb6d3d
          if (buffering_write(out,
Packit cb6d3d
                              ((char *)offset_buffer)+offset_buffer_used,
Packit cb6d3d
                              CDIO_CD_FRAMESIZE_RAW-offset_buffer_used)){
Packit cb6d3d
            report("Error writing output: %s", strerror(errno));
Packit cb6d3d
            exit(1);
Packit cb6d3d
          }
Packit cb6d3d
        }
Packit cb6d3d
Packit cb6d3d
        skipped_flag=0;
Packit cb6d3d
        while(cursor<=batch_last){
Packit cb6d3d
          /* read a sector */
Packit cb6d3d
          int16_t *readbuf=paranoia_read_limited(p, callback, max_retries);
Packit cb6d3d
          char *err=cdda_errors(d);
Packit cb6d3d
          char *mes=cdda_messages(d);
Packit cb6d3d
Packit cb6d3d
          if(mes || err)
Packit cb6d3d
            fprintf(stderr,"\r                               "
Packit cb6d3d
                    "                                           \r%s%s\n",
Packit cb6d3d
                    mes?mes:"",err?err:"");
Packit cb6d3d
Packit cb6d3d
          if (err) free(err);
Packit cb6d3d
          if (mes) free(mes);
Packit cb6d3d
          if( readbuf==NULL) {
Packit cb6d3d
	    if(errno==EBADF || errno==ENOMEDIUM){
Packit cb6d3d
	      report("\nparanoia_read: CDROM drive unavailable, bailing.\n");
Packit cb6d3d
	      exit(1);
Packit cb6d3d
	    }
Packit cb6d3d
            skipped_flag=1;
Packit cb6d3d
            report("\nparanoia_read: Unrecoverable error, bailing.\n");
Packit cb6d3d
            break;
Packit cb6d3d
          }
Packit cb6d3d
          if(skipped_flag && abort_on_skip){
Packit cb6d3d
            cursor=batch_last+1;
Packit cb6d3d
            break;
Packit cb6d3d
          }
Packit cb6d3d
Packit cb6d3d
          skipped_flag=0;
Packit cb6d3d
          cursor++;
Packit cb6d3d
Packit cb6d3d
          if (output_endian!=bigendianp()) {
Packit cb6d3d
            int i;
Packit cb6d3d
            for (i=0; i
Packit cb6d3d
              readbuf[i]=UINT16_SWAP_LE_BE_C(readbuf[i]);
Packit cb6d3d
          }
Packit cb6d3d
Packit cb6d3d
          callback(cursor*(CD_FRAMEWORDS)-1, PARANOIA_CB_WROTE);
Packit cb6d3d
Packit cb6d3d
          if (buffering_write(out,((char *)readbuf)+offset_skip,
Packit cb6d3d
                             CDIO_CD_FRAMESIZE_RAW-offset_skip)){
Packit cb6d3d
            report("Error writing output: %s", strerror(errno));
Packit cb6d3d
            exit(1);
Packit cb6d3d
          }
Packit cb6d3d
          offset_skip=0;
Packit cb6d3d
Packit cb6d3d
          if (output_endian != bigendianp()){
Packit cb6d3d
            int i;
Packit cb6d3d
            for (i=0; i
Packit cb6d3d
              readbuf[i] = UINT16_SWAP_LE_BE_C(readbuf[i]);
Packit cb6d3d
          }
Packit cb6d3d
Packit cb6d3d
          /* One last bit of silliness to deal with sample offsets */
Packit cb6d3d
          if(sample_offset && cursor>batch_last){
Packit cb6d3d
	    if (cdda_sector_gettrack(d, batch_last) < d->tracks || force_overread) {
Packit cb6d3d
	      int i;
Packit cb6d3d
Packit cb6d3d
	      /* Need to flush the buffer when overreading into the leadout */
Packit cb6d3d
	      if (cdda_sector_gettrack(d, batch_last) == d->tracks)
Packit cb6d3d
		paranoia_seek(p, cursor, SEEK_SET);
Packit cb6d3d
Packit cb6d3d
	      /* read a sector and output the partial offset.  Save the
Packit cb6d3d
		 rest for the next batch iteration */
Packit cb6d3d
	      readbuf=paranoia_read_limited(p,callback,max_retries);
Packit cb6d3d
	      err=cdda_errors(d);mes=cdda_messages(d);
Packit cb6d3d
Packit cb6d3d
	      if(mes || err)
Packit cb6d3d
		fprintf(stderr,"\r                               "
Packit cb6d3d
			"                                           \r%s%s\n",
Packit cb6d3d
			mes?mes:"",err?err:"");
Packit cb6d3d
Packit cb6d3d
	      if(err)free(err);if(mes)free(mes);
Packit cb6d3d
	      if(readbuf==NULL){
Packit cb6d3d
		skipped_flag=1;
Packit cb6d3d
		report("\nparanoia_read: Unrecoverable error reading through "
Packit cb6d3d
		       "sample_offset shift\n\tat end of track, bailing.\n");
Packit cb6d3d
		break;
Packit cb6d3d
	      }
Packit cb6d3d
	      if (skipped_flag && abort_on_skip) break;
Packit cb6d3d
	      skipped_flag=0;
Packit cb6d3d
	      /* do not move the cursor */
Packit cb6d3d
Packit cb6d3d
	      if(output_endian!=bigendianp())
Packit cb6d3d
		for(i=0;i
Packit cb6d3d
		  offset_buffer[i]=UINT16_SWAP_LE_BE_C(readbuf[i]);
Packit cb6d3d
	      else
Packit cb6d3d
		memcpy(offset_buffer,readbuf,CD_FRAMESIZE_RAW);
Packit cb6d3d
	      offset_buffer_used=sample_offset*4;
Packit cb6d3d
	      callback(cursor* (CD_FRAMEWORDS), PARANOIA_CB_WROTE);
Packit cb6d3d
	    } else {
Packit cb6d3d
	      memset(offset_buffer, 0, sizeof(offset_buffer));
Packit cb6d3d
	      offset_buffer_used = sample_offset * 4;
Packit cb6d3d
	    }
Packit cb6d3d
Packit cb6d3d
	    if(buffering_write(out,(char *)offset_buffer,
Packit cb6d3d
			       offset_buffer_used)){
Packit cb6d3d
	      report("Error writing output: %s", strerror(errno));
Packit cb6d3d
	      exit(1);
Packit cb6d3d
	    }
Packit cb6d3d
	  }
Packit cb6d3d
        }
Packit cb6d3d
Packit cb6d3d
	/* Write sectors of silent audio to compensate for
Packit cb6d3d
	   missing samples that would be in the leadout */
Packit cb6d3d
	if (cdda_sector_gettrack(d, batch_last) == d->tracks &&
Packit cb6d3d
		toc_offset > 0 && !force_overread)
Packit cb6d3d
	{
Packit cb6d3d
		char *silence;
Packit cb6d3d
		size_t missing_sector_bytes = CD_FRAMESIZE_RAW * toc_offset;
Packit cb6d3d
Packit cb6d3d
		silence = calloc(toc_offset, CD_FRAMESIZE_RAW);
Packit cb6d3d
		if (!silence || buffering_write(out, silence, missing_sector_bytes)) {
Packit cb6d3d
		      report("Error writing output: %s", strerror(errno));
Packit cb6d3d
		      exit(1);
Packit cb6d3d
		}
Packit cb6d3d
		free(silence);
Packit cb6d3d
	}
Packit cb6d3d
Packit cb6d3d
        callback(cursor* (CDIO_CD_FRAMESIZE_RAW/2)-1,
Packit cb6d3d
		 PARANOIA_CB_FINISHED);
Packit cb6d3d
        buffering_close(out);
Packit cb6d3d
        if(skipped_flag){
Packit cb6d3d
          /* remove the file */
Packit cb6d3d
          report("\nRemoving aborted file: %s", outfile_name);
Packit cb6d3d
          unlink(outfile_name);
Packit cb6d3d
          /* make the cursor correct if we have another track */
Packit cb6d3d
          if(batch_track!=-1){
Packit cb6d3d
            batch_track++;
Packit cb6d3d
            cursor=cdda_track_firstsector(d,batch_track);
Packit cb6d3d
            paranoia_seek(p,cursor, SEEK_SET);
Packit cb6d3d
            offset_skip=sample_offset*4;
Packit cb6d3d
            offset_buffer_used=0;
Packit cb6d3d
          }
Packit cb6d3d
        }
Packit cb6d3d
        report("\n");
Packit cb6d3d
      }
Packit cb6d3d
Packit cb6d3d
      paranoia_free(p);
Packit cb6d3d
      p=NULL;
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  report("Done.\n\n");
Packit cb6d3d
Packit cb6d3d
  return 0;
Packit cb6d3d
}