Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / icedax / icedax.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)cdda2wav.c       1.64 06/02/19 Copyright 1998-2004 Heiko Eissfeldt, Copyright 2004-2006 J. Schilling */
14 #undef DEBUG_BUFFER_ADDRESSES
15 #undef GPROF
16 #undef DEBUG_FORKED
17 #undef DEBUG_CLEANUP
18 #undef DEBUG_DYN_OVERLAP
19 #undef DEBUG_READS
20 #define DEBUG_ILLLEADOUT        0       /* 0 disables, 1 enables */
21 /*
22  * Copyright: GNU Public License 2 applies
23  *
24  *   This program is free software; you can redistribute it and/or modify
25  *   it under the terms of the GNU General Public License as published by
26  *   the Free Software Foundation; either version 2, or (at your option)
27  *   any later version.
28  *
29  *   This program is distributed in the hope that it will be useful,
30  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
31  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32  *   GNU General Public License for more details.
33  *
34  *   You should have received a copy of the GNU General Public License
35  *   along with this program; if not, write to the Free Software
36  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37  *
38  */
39 /*
40  * parts    (C) Peter Widow
41  * parts    (C) Thomas Niederreiter
42  * parts    (C) RSA Data Security, Inc.
43  *
44  * last changes:
45  *   18.12.93 - first version,  OK
46  *   01.01.94 - generalized & clean up HE
47  *   10.06.94 - first linux version HE
48  *   12.06.94 - wav header alignment problem fixed HE
49  *   12.08.94 - open the cdrom device O_RDONLY makes more sense :-)
50  *              no more floating point math
51  *              change to sector size 2352 which is more common
52  *              sub-q-channel information per kernel ioctl requested
53  *              doesn't work as well as before
54  *              some new options (-max -i)
55  *   01.02.95 - async i/o via semaphores and shared memory
56  *   03.02.95 - overlapped reading on sectors
57  *   03.02.95 - generalized sample rates. all integral divisors are legal
58  *   04.02.95 - sun format added
59  *              more divisors: all integral halves >= 1 allowed
60  *              floating point math needed again
61  *   06.02.95 - bugfix for last track and not d0
62  *              tested with photo-cd with audio tracks
63  *              tested with xa disk 
64  *   29.01.96 - new options for bulk transfer
65  *   01.06.96 - tested with enhanced cd
66  *   01.06.96 - tested with cd-plus
67  *   02.06.96 - support pipes
68  *   02.06.96 - support raw format
69  *   04.02.96 - security hole fixed
70  *   22.04.97 - large parts rewritten
71  *   28.04.97 - make file names DOS compatible
72  *   01.09.97 - add speed control
73  *   20.10.97 - add find mono option
74  *   Jan/Feb 98 - conversion to use Joerg Schillings SCSI library
75  *   see ChangeLog
76  */
77
78 #include "config.h"
79
80 #include <unixstd.h>
81 #include <stdio.h>
82 #include <standard.h>
83 #include <stdxlib.h>
84 #include <strdefs.h>
85 #include <schily.h>
86 #include <signal.h>
87 #include <math.h>
88 #include <fctldefs.h>
89 #include <timedefs.h>
90 #if defined (HAVE_LIMITS_H)
91 #include <limits.h>
92 #endif
93 #if defined (HAVE_SYS_IOCTL_H)
94 #include <sys/ioctl.h>
95 #endif
96 #include <errno.h>
97 #include <statdefs.h>
98 #include <waitdefs.h>
99 #if defined (HAVE_SETPRIORITY)
100 #include <sys/resource.h>
101 #endif
102 #include <vadefs.h>
103
104 #include <usal/scsitransp.h>
105
106 #ifdef  HAVE_AREAS
107 #include <be/kernel/OS.h>
108 #endif
109
110 #include "mytype.h"
111 #include "sndconfig.h"
112
113 #include "semshm.h"     /* semaphore functions */
114 #include "sndfile.h"
115 #include "wav.h"        /* wav file header structures */
116 #include "sun.h"        /* sun audio file header structures */
117 #include "raw.h"        /* raw file handling */
118 #include "aiff.h"       /* aiff file handling */
119 #include "aifc.h"       /* aifc file handling */
120 #ifdef  USE_LAME
121 #include "mp3.h"        /* mp3 file handling */
122 #endif
123 #include "interface.h"  /* low level cdrom interfacing */
124 #include "icedax.h"
125 #include "resample.h"
126 #include "toc.h"
127 #include "setuid.h"
128 #include "ringbuff.h"
129 #include "global.h"
130 #include "exitcodes.h"
131 #ifdef  USE_PARANOIA
132 #include "cdda_paranoia.h"
133 #endif
134 #include "defaults.h"
135
136 static void RestrictPlaybackRate(long newrate);
137 static void output_indices(FILE *fp, index_list *p, unsigned trackstart);
138 static int      write_info_file(char *fname_baseval, unsigned int track, 
139                                                                          unsigned long SamplesDone, int numbered);
140 static void CloseAudio(int channels_val, unsigned long nSamples, 
141                                                           struct soundfile *audio_out);
142 static void CloseAll(void);
143 static void OpenAudio(char *fname, double rate, long nBitsPerSample, 
144                                                          long channels_val, unsigned long expected_bytes, 
145                                                          struct soundfile*audio_out);
146 static void set_offset(myringbuff *p, int offset);
147 static int      get_offset(myringbuff *p);
148 static void usage(void);
149 static void init_globals(void);
150 static int      is_fifo(char *filename);
151
152
153 /* Rules:
154  * unique parameterless options first,
155  * unique parametrized option names next,
156  * ambigious parameterless option names next,
157  * ambigious string parametrized option names last
158  */
159 static const char *opts = "paranoia,paraopts&,version,help,h,\
160 no-write,N,dump-rates,R,bulk,B,alltracks,verbose-scsi+,V+,\
161 find-extremes,F,find-mono,G,no-infofile,H,\
162 deemphasize,T,info-only,J,silent-scsi,Q,\
163 cddbp-server*,cddbp-port*,\
164 scanbus,devices,device*,dev*,D*,auxdevice*,A*,interface*,I*,output-format*,O*,\
165 output-endianess*,E*,cdrom-endianess*,C*,speed#,S#,\
166 playback-realtime#L,p#L,md5#,M#,set-overlap#,P#,sound-device*,K*,\
167 cddb#,L#,channels*,c*,bits-per-sample#,b#,rate#,r#,gui,g,\
168 divider*,a*,track*,t*,index#,i#,duration*,d*,offset#,o#,\
169 sectors-per-request#,n#,verbose-level&,v&,buffers-in-ring#,l#,\
170 stereo,s,mono,m,wait,w,echo,e,quiet,q,max,x\
171 ";
172
173
174 #ifdef  NEED_O_BINARY
175 #include <io.h>         /* for setmode() prototype */
176 #endif
177
178 /* global variables */
179 global_t global;
180
181 /* static variables */
182 static unsigned long nSamplesDone = 0;
183
184 static  int child_pid = -2;
185
186 static unsigned long *nSamplesToDo;
187 static unsigned int current_track;
188 static int bulk = 0;
189
190 unsigned int get_current_track(void);
191
192 unsigned int get_current_track()
193 {
194         return current_track;
195 }
196
197 static void RestrictPlaybackRate(long  newrate)
198 {
199        global.playback_rate = newrate;
200
201        if ( global.playback_rate < 25 ) global.playback_rate = 25;   /* filter out insane values */
202        if ( global.playback_rate > 250 ) global.playback_rate = 250;
203
204        if ( global.playback_rate < 100 )
205                global.nsectors = (global.nsectors*global.playback_rate)/100;
206 }
207
208
209 long SamplesNeeded(long amount, long undersampling_val)
210 {
211   long retval = ((undersampling_val * 2 + Halved)*amount)/2;
212   if (Halved && (*nSamplesToDo & 1))
213     retval += 2;
214   return retval;
215 }
216
217 static int argc2;
218 static int argc3;
219 static char **argv2;
220
221 static void reset_name_iterator(void);
222 static void reset_name_iterator()
223 {
224         argv2 -= argc3 - argc2;
225         argc2 = argc3;
226 }
227
228 static char *get_next_name(void);
229 static char *get_next_name()
230 {
231         if (argc2 > 0) {
232                 argc2--;
233                 return (*argv2++);
234         } else {
235                 return NULL;
236         }
237 }
238
239 static char *cut_extension(char *fname);
240
241 static char *cut_extension(char *fname)
242 {
243         char *pp;
244
245         pp = strrchr(fname, '.');
246
247         if (pp == NULL) {
248                 pp = fname + strlen(fname);
249         }
250         *pp = '\0';
251
252         return pp;
253 }
254
255 #ifdef INFOFILES
256 static void output_indices(FILE *fp, index_list *p, unsigned trackstart)
257 {
258   int ci;
259
260   fprintf(fp, "Index=\t\t");
261
262   if (p == NULL) {
263     fprintf(fp, "0\n");
264     return;
265   }
266
267   for (ci = 1; p != NULL; ci++, p = p->next) {
268     int frameoff = p->frameoffset;
269
270     if (p->next == NULL)
271          fputs("\nIndex0=\t\t", fp);
272 #if 0
273     else if ( ci > 8 && (ci % 8) == 1)
274          fputs("\nIndex =\t\t", fp);
275 #endif
276     if (frameoff != -1)
277          fprintf(fp, "%d ", frameoff - trackstart);
278     else
279          fprintf(fp, "-1 ");
280   }
281   fputs("\n", fp);
282 }
283
284 /*
285  * write information before the start of the sampling process
286  *
287  *
288  * uglyfied for Joerg Schillings ultra dumb line parser
289  */
290 static int write_info_file(char *fname_baseval, unsigned int track, 
291                            unsigned long int SamplesDone, int numbered)
292 {
293   FILE *info_fp;
294   char fname[200];
295   char datetime[30];
296   time_t utc_time;
297   struct tm *tmptr;
298
299   /* write info file */
300   if (!strcmp(fname_baseval,"-")) return 0;
301
302   strncpy(fname, fname_baseval, sizeof(fname) -1);
303   fname[sizeof(fname) -1] = 0;
304   if (numbered)
305     sprintf(cut_extension(fname), "_%02u.inf", track);
306   else
307     strcpy(cut_extension(fname), ".inf");
308
309   info_fp = fopen (fname, "w");
310   if (!info_fp)
311     return -1;
312
313 #if 0
314 #ifdef MD5_SIGNATURES
315   if (global.md5blocksize)
316     MD5Final (global.MD5_result, &global.context);
317 #endif
318 #endif
319
320   utc_time = time(NULL);
321   tmptr = localtime(&utc_time);
322   if (tmptr) {
323     strftime(datetime, sizeof(datetime), "%x %X", tmptr);
324   } else {
325     strncpy(datetime, "unknown", sizeof(datetime));
326   }
327   fprintf(info_fp, "#created by icedax %s %s\n#\n", VERSION
328           , datetime
329           );
330   fprintf(info_fp,
331 "CDINDEX_DISCID=\t'%s'\n" , global.cdindex_id);
332   fprintf(info_fp,
333 "CDDB_DISCID=\t0x%08lx\n\
334 MCN=\t\t%s\n\
335 ISRC=\t\t%15.15s\n\
336 #\n\
337 Albumperformer=\t'%s'\n\
338 Performer=\t'%s'\n\
339 Albumtitle=\t'%s'\n"
340           , (unsigned long) global.cddb_id
341           , Get_MCN()
342           , Get_ISRC(track)
343           , global.creator != NULL ? global.creator : (const unsigned char *)""
344           , global.trackcreator[track] != NULL ? global.trackcreator[track] :
345                 (global.creator != NULL ? global.creator : (const unsigned char *)"")
346           , global.disctitle != NULL ? global.disctitle : (const unsigned char *)""
347           );
348   fprintf(info_fp,
349           "Tracktitle=\t'%s'\n"
350           , global.tracktitle[track] ? global.tracktitle[track] : (const unsigned char *)""
351           );
352   fprintf(info_fp, "Tracknumber=\t%u\n"
353           , track
354           );
355   fprintf(info_fp, 
356           "Trackstart=\t%ld\n"
357           , Get_AudioStartSector(track)
358           );
359   fprintf(info_fp, 
360           "# track length in sectors (1/75 seconds each), rest samples\nTracklength=\t%ld, %d\n"
361           , SamplesDone/588L,(int)(SamplesDone%588));
362   fprintf(info_fp, 
363           "Pre-emphasis=\t%s\n"
364           , Get_Preemphasis(track) && (global.deemphasize == 0) ? "yes" : "no");
365   fprintf(info_fp, 
366           "Channels=\t%d\n"
367           , Get_Channels(track) ? 4 : global.channels == 2 ? 2 : 1);
368         { int cr = Get_Copyright(track);
369                 fputs("Copy_permitted=\t", info_fp);
370                 switch (cr) {
371                         case 0:
372                                 fputs("once (copyright protected)\n", info_fp);
373                         break;
374                         case 1:
375                                 fputs("no (SCMS first copy)\n", info_fp);
376                         break;
377                         case 2:
378                                 fputs("yes (not copyright protected)\n", info_fp);
379                         break;
380                         default:
381                                 fputs("unknown\n", info_fp);
382                 }
383         }
384   fprintf(info_fp, 
385           "Endianess=\t%s\n"
386           , global.need_big_endian ? "big" : "little"
387           );
388   fprintf(info_fp, "# index list\n");
389   output_indices(info_fp, global.trackindexlist[track],
390                  Get_AudioStartSector(track));
391 #if 0
392 /* MD5 checksums in info files are currently broken.
393  *  for on-the-fly-recording the generation of info files has been shifted
394  *  before the recording starts, so there is no checksum at that point.
395  */
396 #ifdef MD5_SIGNATURES
397   fprintf(info_fp, 
398           "#(blocksize) checksum\nMD-5=\t\t(%d) %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n"
399           , global.md5blocksize
400           , global.MD5_result[0]
401           , global.MD5_result[1]
402           , global.MD5_result[2]
403           , global.MD5_result[3]
404           , global.MD5_result[4]
405           , global.MD5_result[5]
406           , global.MD5_result[6]
407           , global.MD5_result[7]
408           , global.MD5_result[8]
409           , global.MD5_result[9]
410           , global.MD5_result[10]
411           , global.MD5_result[11]
412           , global.MD5_result[12]
413           , global.MD5_result[13]
414           , global.MD5_result[14]
415           , global.MD5_result[15]);
416 #endif
417 #endif
418   fclose(info_fp);
419   return 0;
420 }
421 #endif
422
423 static void CloseAudio(int channels_val, unsigned long nSamples, 
424                        struct soundfile *audio_out)
425 {
426       /* define length */
427       audio_out->ExitSound( global.audio, (nSamples-global.SkippedSamples)*global.OutSampleSize*channels_val );
428
429       close (global.audio);
430       global.audio = -1;
431 }
432
433 static unsigned int track = 1;
434
435 /* On terminating:
436  * define size-related entries in audio file header, update and close file */
437 static void CloseAll()
438 {
439         WAIT_T chld_return_status;
440         int amiparent;
441
442         /* terminate child process first */
443         amiparent = child_pid > 0;
444
445         if (global.iloop > 0) {
446                 /* set to zero */
447                 global.iloop = 0;
448         }
449
450 #if     defined HAVE_FORK_AND_SHAREDMEM
451 # ifdef DEBUG_CLEANUP
452         fprintf(stderr, "%s terminating, \n", amiparent ? 
453                 "Parent (READER)" : "Child (WRITER)");
454 #endif
455 #else
456 # ifdef DEBUG_CLEANUP
457         fprintf(stderr, "icedax single process terminating, \n");
458 # endif
459 #endif
460
461         if (amiparent || child_pid < 0) {
462                 /* switch to original mode and close device */
463                 EnableCdda (get_scsi_p(), 0, 0);
464         }
465
466         if (!amiparent) {
467                 /* do general clean up */
468
469                 if (global.audio>=0) {
470                         if (bulk) {
471                                 /* finish sample file for this track */
472                                 CloseAudio(global.channels,
473                                  global.nSamplesDoneInTrack, global.audio_out);
474                         } else {
475                                 /* finish sample file for this track */
476                                 CloseAudio(global.channels,
477                                  (unsigned int) *nSamplesToDo, global.audio_out);
478                         }
479                 }
480
481                 /* tell minimum and maximum amplitudes, if required */
482                 if (global.findminmax) {
483                         fprintf(stderr,
484                         "Right channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767\n", 
485                         global.minamp[0], global.maxamp[0]);
486                         fprintf(stderr,
487                         "Left  channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767\n", 
488                         global.minamp[1], global.maxamp[1]);
489                 }
490
491                 /* tell mono or stereo recording, if required */
492                 if (global.findmono) {
493                         fprintf(stderr, "Audio samples are originally %s.\n", global.ismono ? "mono" : "stereo");
494                 }
495
496                 return; /* end of child or single process */
497         }
498
499
500         if (global.have_forked == 1) {
501 #ifdef DEBUG_CLEANUP
502                 fprintf(stderr, "Parent wait for child death, \n");
503 #endif
504
505                 /* wait for child to terminate */
506                 if (0 > wait(&chld_return_status)) {
507                         perror("");
508                 } else {
509                         if (WIFEXITED(chld_return_status)) {
510                                 if (WEXITSTATUS(chld_return_status)) {
511                                         fprintf(stderr, "\nW Child exited with %d\n", WEXITSTATUS(chld_return_status));
512                                 }
513                         }
514                         if (WIFSIGNALED(chld_return_status)) {
515                                 fprintf(stderr, "\nW Child exited due to signal %d\n", WTERMSIG(chld_return_status));
516                         }
517                         if (WIFSTOPPED(chld_return_status)) {
518                                 fprintf(stderr, "\nW Child is stopped due to signal %d\n", WSTOPSIG(chld_return_status));
519                         }
520                 }
521
522 #ifdef DEBUG_CLEANUP
523                 fprintf(stderr, "\nW Parent child death, state:%d\n", chld_return_status);
524 #endif
525         }
526
527 #ifdef GPROF
528         rename("gmon.out", "gmon.child");
529 #endif
530 }
531
532
533 /* report a usage error and exit */
534 #ifdef  PROTOTYPES
535 static void usage2 (const char *szMessage, ...)
536 #else
537 static void usage2(const char *szMessage, va_dcl va_alist)
538 #endif
539 {
540         va_list marker;
541
542 #ifdef  PROTOTYPES
543         va_start(marker, szMessage);
544 #else
545         va_start(marker);
546 #endif
547
548         vfprintf(stderr, szMessage, marker);
549
550         va_end(marker);
551         fprintf(stderr, "\nPlease use -help or consult the man page for help.\n");
552
553         exit (1);
554 }
555
556
557 /* report a fatal error, clean up and exit */
558 #ifdef  PROTOTYPES
559 void FatalError (const char *szMessage, ...)
560 #else
561 void FatalError(const char *szMessage, va_dcl va_alist)
562 #endif
563 {
564         va_list marker;
565
566 #ifdef  PROTOTYPES
567         va_start(marker, szMessage);
568 #else
569         va_start(marker);
570 #endif
571
572         vfprintf(stderr, szMessage, marker);
573
574         va_end(marker);
575
576         if (child_pid >= 0) {
577                 if (child_pid == 0) {
578                         pid_t   ppid;
579                         /*
580                          * Kill the parent too if we are not orphaned.
581                          */
582                         ppid = getppid();
583                         if (ppid > 1)
584                                 kill(ppid, SIGINT);
585                 } else {
586                         kill(child_pid, SIGINT);
587                 }
588         }
589         exit (1);
590 }
591
592
593 /* open the audio output file and prepare the header. 
594  * the header will be defined on terminating (when the size
595  * is known). So hitting the interrupt key leaves an intact
596  * file.
597  */
598 static void OpenAudio(char *fname, double rate, long nBitsPerSample, 
599                       long channels_val, unsigned long expected_bytes, 
600                       struct soundfile *audio_out)
601 {
602   if (global.audio == -1) {
603
604     global.audio = open (fname, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY
605 #ifdef SYNCHRONOUS_WRITE
606                          | O_SYNC
607 #endif
608                   , 0666);
609     if (global.audio == -1) {
610       if (errno == EAGAIN && is_fifo(fname)) {
611         FatalError ("Could not open fifo %s. Probably no fifo reader present.\n", fname);
612       }
613       perror("open audio sample file");
614       FatalError ("Could not open file %s\n", fname);
615     }
616   }
617   global.SkippedSamples = 0;
618   any_signal = 0;
619   audio_out->InitSound( global.audio, channels_val, (unsigned long)rate, nBitsPerSample, expected_bytes );
620
621 #ifdef MD5_SIGNATURES
622   if (global.md5blocksize)
623     MD5Init (&global.context);
624   global.md5count = global.md5blocksize;
625 #endif
626 }
627
628 #include "scsi_cmds.h"
629
630 static int RealEnd(SCSI *usalp, UINT4 *buff);
631
632 static int RealEnd(SCSI *usalp, UINT4 *buff)
633 {
634         if (usal_cmd_err(usalp) != 0) {
635                 int c,k,q;
636
637                 k = usal_sense_key(usalp);
638                 c = usal_sense_code(usalp);
639                 q = usal_sense_qual(usalp);
640                 if ((k == 0x05 /* ILLEGAL_REQUEST */ &&
641                      c == 0x21 /* lba out of range */ &&
642                      q == 0x00) ||
643                     (k == 0x05 /* ILLEGAL_REQUEST */ &&
644                      c == 0x63 /*end of user area encountered on this track*/ &&
645                      q == 0x00) ||
646                     (k == 0x08 /* BLANK_CHECK */ &&
647                      c == 0x64 /* illegal mode for this track */ &&
648                      q == 0x00)) {
649                         return 1;
650                 }
651         }
652
653         if (usal_getresid(usalp) > 16) return 1;
654
655         {
656                 unsigned char *p;
657                 /* Look into the subchannel data */
658                 buff += CD_FRAMESAMPLES;
659                 p = (unsigned char *)buff;
660                 if (p[0] == 0x21 && p[1] == 0xaa) {
661                         return 1;
662                 }
663         }
664         return 0;
665 }
666
667 static void set_offset(myringbuff *p, int offset)
668 {
669 #ifdef DEBUG_SHM
670   fprintf(stderr, "Write offset %d at %p\n", offset, &p->offset);
671 #endif
672   p->offset = offset;
673 }
674
675
676 static int get_offset(myringbuff *p)
677 {
678 #ifdef DEBUG_SHM
679   fprintf(stderr, "Read offset %d from %p\n", p->offset, &p->offset);
680 #endif
681   return p->offset;
682 }
683
684
685 static void usage()
686 {
687   fputs(
688 "usage: icedax [OPTIONS ...] [trackfilenames ...]\n\
689 OPTIONS:\n\
690         [-c chans] [-s] [-m] [-b bits] [-r rate] [-a divider] [-S speed] [-x]\n\
691         [-t track[+endtrack]] [-i index] [-o offset] [-d duration] [-F] [-G]\n\
692         [-q] [-w] [-v vopts] [-R] [-P overlap] [-B] [-T] [-C input-endianess]\n\
693         [-e] [-n sectors] [-N] [-J] [-L cddbp-mode] [-H] [-g] [-l buffers] [-D cd-device]\n\
694         [-I interface] [-K sound-device] [-O audiotype] [-E output-endianess]\n\
695         [-A auxdevice] [-paranoia] [-cddbp-server=name] [-cddbp-port=port] [-version]\n", stderr);
696   fputs("\
697   (-D) dev=device               set the cdrom or scsi device (as Bus,Id,Lun).\n\
698   (-A) auxdevice=device         set the aux device (typically /dev/cdrom).\n\
699   (-K) sound-device=device      set the sound device to use for -e (typically /dev/dsp).\n\
700   (-I) interface=interface      specify the interface for cdrom access.\n\
701         (generic_scsi or cooked_ioctl).\n\
702   (-c) channels=channels        set 1 for mono, 2 or s for stereo (s: channels swapped).\n\
703   (-s) -stereo                  select stereo recording.\n\
704   (-m) -mono                    select mono recording.\n\
705   (-x) -max                     select maximum quality (stereo/16-bit/44.1 KHz).\n\
706   (-b) bits=bits                set bits per sample per channel (8, 12 or 16 bits).\n\
707   (-r) rate=rate                set rate in samples per second. -R gives all rates\n\
708   (-a) divider=divider          set rate to 44100Hz / divider. -R gives all rates\n\
709   (-R) -dump-rates              dump a table with all available sample rates\n\
710   (-S) speed=speedfactor        set the cdrom drive to a given speed during reading\n\
711   (-P) set-overlap=sectors      set amount of overlap sampling (default is 0)\n\
712   (-n) sectors-per-request=secs read 'sectors' sectors per request.\n\
713   (-l) buffers-in-ring=buffers  use a ring buffer with 'buffers' elements.\n\
714   (-t) track=track[+end track]  select start track (option. end track).\n\
715   (-i) index=index              select start index.\n\
716   (-o) offset=offset            start at 'offset' sectors behind start track/index.\n\
717         one sector equivalents 1/75 second.\n\
718   (-O) output-format=audiotype  set to wav, au (sun), cdr (raw), aiff or aifc format.\n\
719   (-C) cdrom-endianess=endian   set little, big or guess input sample endianess.\n\
720   (-E) output-endianess=endian  set little or big output sample endianess.\n\
721   (-d) duration=seconds         set recording time in seconds or 0 for whole track.\n\
722   (-w) -wait                    wait for audio signal, then start recording.\n\
723   (-F) -find-extremes           find extrem amplitudes in samples.\n\
724   (-G) -find-mono               find if input samples are mono.\n\
725   (-T) -deemphasize             undo pre-emphasis in input samples.\n\
726   (-e) -echo                    echo audio data to sound device (see -K) SOUND_DEV.\n\
727   (-v) verbose-level=optlist    controls verbosity (for a list use -vhelp).\n\
728   (-N) -no-write                do not create audio sample files.\n\
729   (-J) -info-only               give disc information only.\n\
730   (-L) cddb=cddbpmode           do cddbp title lookups.\n\
731         resolve multiple entries according to cddbpmode: 0=interactive, 1=first entry\n\
732   (-H) -no-infofile             no info file generation.\n\
733   (-g) -gui                     generate special output suitable for gui frontends.\n\
734   (-Q) -silent-scsi             do not print status of erreneous scsi-commands.\n\
735        -scanbus                 scan the SCSI bus and exit\n\
736        --devices                scan for system devices and print with native names\n\
737   (-M) md5=count                calculate MD-5 checksum for blocks of 'count' bytes.\n\
738   (-q) -quiet                   quiet operation, no screen output.\n\
739   (-p) playback-realtime=perc   play (echo) audio pitched at perc percent (50%-200%).\n\
740   (-V) -verbose-scsi            each option increases verbosity for SCSI commands.\n\
741   (-h) -help                    show this help screen.\n\
742   (-B) -alltracks, -bulk        record each track into a seperate file.\n\
743        -paranoia                use the lib paranoia for reading.\n\
744        -paraopts=opts           set options for lib paranoia (see -paraopts=help).\n\
745        -cddbp-server=servername set the cddbp server to use for title lookups.\n\
746        -cddbp-port=portnumber   set the cddbp port to use for title lookups.\n\
747        -version                 print version information.\n\
748 \n\
749 Please note: some short options will be phased out soon (disappear)!\n\
750 \n\
751 parameters: (optional) one or more file names or - for standard output.\n\
752 ", stderr);
753   fputs("Version ", stderr);
754   fputs(VERSION, stderr);
755   fprintf(stderr, "\n\
756 defaults        %s, %d bit, %d.%02d Hz, track 1, no offset, one track,\n",
757           CHANNELS-1?"stereo":"mono", BITS_P_S,
758          44100 / UNDERSAMPLING,
759          (4410000 / UNDERSAMPLING) % 100);
760   fprintf(stderr, "\
761           type %s '%s', don't wait for signal, not quiet,\n",
762           AUDIOTYPE, FILENAME);
763   fprintf(stderr, "\
764           use %s, device %s, aux %s\n",
765           DEF_INTERFACE, CD_DEVICE, AUX_DEVICE);
766   exit( SYNTAX_ERROR );
767 }
768
769 static void init_globals()
770 {
771 #ifdef  HISTORICAL_JUNK
772   global.dev_name = CD_DEVICE;  /* device name */
773 #endif
774   global.aux_name = AUX_DEVICE;/* auxiliary cdrom device */
775   strncpy(global.fname_base, FILENAME, sizeof(global.fname_base));/* auxiliary cdrom device */
776   global.have_forked = 0;       /* state variable for clean up */
777   global.parent_died = 0;       /* state variable for clean up */
778   global.audio    = -1;         /* audio file desc */
779   global.cooked_fd  = -1;       /* cdrom file desc */
780   global.no_file  =  0;         /* flag no_file */
781   global.no_infofile  =  0;     /* flag no_infofile */
782   global.no_cddbfile  =  0;     /* flag no_cddbfile */
783   global.quiet    =  0;         /* flag quiet */
784   global.verbose  =  SHOW_TOC + SHOW_SUMMARY + SHOW_STARTPOSITIONS + SHOW_TITLES;       /* verbose level */
785   global.scsi_silent = 0;
786   global.scsi_verbose = 0;              /* SCSI verbose level */
787   global.scanbus = 0;
788   global.scandevs = 0;
789   global.multiname = 0;         /* multiple file names given */
790   global.sh_bits  =  0;         /* sh_bits: sample bit shift */
791   global.Remainder=  0;         /* remainder */
792   global.iloop    =  0;         /* todo counter */
793   global.SkippedSamples =  0;   /* skipped samples */
794   global.OutSampleSize  =  0;   /* output sample size */
795   global.channels = CHANNELS;   /* output sound channels */
796   global.nSamplesDoneInTrack = 0; /* written samples in current track */
797   global.buffers = 4;           /* buffers to use */
798   global.nsectors = NSECTORS;   /* sectors to read in one request */
799   global.overlap = 1;           /* amount of overlapping sectors */
800   global.useroverlap = -1;      /* amount of overlapping sectors user override */
801   global.need_hostorder = 0;    /* processing needs samples in host endianess */
802   global.in_lendian = -1;       /* input endianess from SetupSCSI() */
803   global.outputendianess = NONE; /* user specified output endianess */
804   global.findminmax  =  0;      /* flag find extrem amplitudes */
805 #ifdef HAVE_LIMITS_H
806   global.maxamp[0] = INT_MIN;   /* maximum amplitude */
807   global.maxamp[1] = INT_MIN;   /* maximum amplitude */
808   global.minamp[0] = INT_MAX;   /* minimum amplitude */
809   global.minamp[1] = INT_MAX;   /* minimum amplitude */
810 #else
811   global.maxamp[0] = -32768;    /* maximum amplitude */
812   global.maxamp[1] = -32768;    /* maximum amplitude */
813   global.minamp[0] = 32767;     /* minimum amplitude */
814   global.minamp[1] = 32767;     /* minimum amplitude */
815 #endif
816   global.speed = DEFAULT_SPEED; /* use default */ 
817   global.userspeed = -1;        /* speed user override */
818   global.findmono  =  0;        /* flag find if samples are mono */
819   global.ismono  =  1;          /* flag if samples are mono */
820   global.swapchannels  =  0;    /* flag if channels shall be swapped */
821   global.deemphasize  =  0;     /* flag undo pre-emphasis in samples */
822   global.playback_rate = 100;   /* new fancy selectable sound output rate */
823   global.gui  =  0;             /* flag plain formatting for guis */
824   global.cddb_id = 0;           /* disc identifying id for CDDB database */
825   global.cddb_revision = 0;     /* entry revision for CDDB database */
826   global.cddb_year = 0;         /* disc identifying year for CDDB database */
827   global.cddb_genre[0] = '\0';  /* disc identifying genre for CDDB database */
828   global.cddbp = 0;             /* flag if titles shall be looked up from CDDBP */
829   global.cddbp_server = 0;      /* user supplied CDDBP server */
830   global.cddbp_port = 0;        /* user supplied CDDBP port */
831   global.illleadout_cd = 0;     /* flag if illegal leadout is present */
832   global.reads_illleadout = 0;  /* flag if cdrom drive reads cds with illegal leadouts */
833   global.disctitle = NULL;
834   global.creator = NULL;
835   global.copyright_message = NULL;
836   memset(global.tracktitle, 0, sizeof(global.tracktitle));
837   memset(global.trackindexlist, 0, sizeof(global.trackindexlist));
838
839   global.just_the_toc = 0;
840 #ifdef  USE_PARANOIA
841         global.paranoia_parms.disable_paranoia = 
842         global.paranoia_parms.disable_extra_paranoia = 
843         global.paranoia_parms.disable_scratch_detect =
844         global.paranoia_parms.disable_scratch_repair = 0;
845         global.paranoia_parms.retries = 20;
846         global.paranoia_parms.overlap = -1;
847         global.paranoia_parms.mindynoverlap = -1;
848         global.paranoia_parms.maxdynoverlap = -1;
849 #endif
850 }
851
852 #if !defined (HAVE_STRCASECMP) || (HAVE_STRCASECMP != 1)
853 #include <ctype.h>
854 static int strcasecmp(const char *s1, const char *s2);
855 static int strcasecmp(const char *s1, const char *s2)
856 {
857   if (s1 && s2) {
858     while (*s1 && *s2 && (tolower(*s1) - tolower(*s2) == 0)) {
859       s1++;
860       s2++;
861     }
862     if (*s1 == '\0' && *s2 == '\0') return 0;
863     if (*s1 == '\0') return -1;
864     if (*s2 == '\0') return +1;
865     return tolower(*s1) - tolower(*s2);
866   }
867   return -1;
868 }
869 #endif
870
871 static int is_fifo(char *filename)
872 {
873 #if     defined S_ISFIFO
874   struct stat statstruct;
875
876   if (stat(filename, &statstruct)) {
877     /* maybe the output file does not exist. */
878     if (errno == ENOENT)
879         return 0;
880     else comerr("Error during stat for output file\n");
881   } else {
882     if (S_ISFIFO(statstruct.st_mode)) {
883         return 1;
884     }
885   }
886   return 0;
887 #else
888   return 0;
889 #endif
890 }
891
892
893 #if !defined (HAVE_STRTOUL) || (HAVE_STRTOUL != 1)
894 static unsigned int strtoul(const char *s1, char **s2, int base);
895 static unsigned int strtoul(const char *s1, char **s2, int base)
896 {
897         long retval;
898
899         if (base == 10) {
900                 /* strip zeros in front */
901                 while (*s1 == '0')
902                         s1++;
903         }
904         if (s2 != NULL) {
905                 *s2 = astol(s1, &retval);
906         } else {
907                 (void) astol(s1, &retval);
908         }
909
910         return (unsigned long) retval;  
911 }
912 #endif
913
914 static unsigned long SectorBurst;
915 #if (SENTINEL > CD_FRAMESIZE_RAW)
916 error block size for overlap check has to be < sector size
917 #endif
918
919
920 static void
921 switch_to_realtime_priority(void);
922
923 #ifdef  HAVE_SYS_PRIOCNTL_H
924
925 #include <sys/priocntl.h>
926 #include <sys/rtpriocntl.h>
927 static void switch_to_realtime_priority()
928 {
929         pcinfo_t        info;
930         pcparms_t       param;
931         rtinfo_t        rtinfo;
932         rtparms_t       rtparam;
933         int             pid;
934
935         pid = getpid();
936
937         /* get info */
938         strcpy(info.pc_clname, "RT");
939         if (-1 == priocntl(P_PID, pid, PC_GETCID, (void *)&info)) {
940                 errmsg("Cannot get priority class id priocntl(PC_GETCID)\n");
941                 goto prio_done;
942         }
943
944         memmove(&rtinfo, info.pc_clinfo, sizeof(rtinfo_t));
945
946         /* set priority not to the max */
947         rtparam.rt_pri = rtinfo.rt_maxpri - 2;
948         rtparam.rt_tqsecs = 0;
949         rtparam.rt_tqnsecs = RT_TQDEF;
950         param.pc_cid = info.pc_cid;
951         memmove(param.pc_clparms, &rtparam, sizeof(rtparms_t));
952         priv_on();
953         needroot(0);
954         if (-1 == priocntl(P_PID, pid, PC_SETPARMS, (void *)&param))
955                 errmsg("Cannot set priority class parameters priocntl(PC_SETPARMS)\n");
956 prio_done:
957         priv_off();
958         dontneedroot();
959 }
960 #else
961 #if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING -0 >= 0
962 #define USE_POSIX_PRIORITY_SCHEDULING
963 #endif
964 #ifdef  USE_POSIX_PRIORITY_SCHEDULING
965 #include <sched.h>
966
967 static void switch_to_realtime_priority()
968 {
969 #ifdef  _SC_PRIORITY_SCHEDULING
970         if (sysconf(_SC_PRIORITY_SCHEDULING) == -1) {
971                 errmsg("WARNING: RR-scheduler not available, disabling.\n");
972         } else
973 #endif
974         {
975         int sched_fifo_min, sched_fifo_max;
976         struct sched_param sched_parms;
977
978         sched_fifo_min = sched_get_priority_min(SCHED_FIFO);
979         sched_fifo_max = sched_get_priority_max(SCHED_FIFO);
980         sched_parms.sched_priority = sched_fifo_max - 1;
981         priv_on();
982         needroot(0);
983         if (-1 == sched_setscheduler(getpid(), SCHED_FIFO, &sched_parms)
984                 && global.quiet != 1)
985                 errmsg("cannot set posix realtime scheduling policy\n");
986         priv_off();
987         dontneedroot();
988         }
989 }
990 #else
991 #if defined(__CYGWIN32__)
992
993 /*
994  * NOTE: Base.h from Cygwin-B20 has a second typedef for BOOL.
995  *       We define BOOL to make all local code use BOOL
996  *       from Windows.h and use the hidden __SBOOL for
997  *       our global interfaces.
998  *
999  * NOTE: windows.h from Cygwin-1.x includes a structure field named sample,
1000  *       so me may not define our own 'sample' or need to #undef it now.
1001  *       With a few nasty exceptions, Microsoft assumes that any global
1002  *       defines or identifiers will begin with an Uppercase letter, so
1003  *       there may be more of these problems in the future.
1004  *
1005  * NOTE: windows.h defines interface as an alias for struct, this 
1006  *       is used by COM/OLE2, I guess it is class on C++
1007  *       We man need to #undef 'interface'
1008  */
1009 #define BOOL    WBOOL           /* This is the Win BOOL         */
1010 #define format  __format        /* Avoid format parameter hides global ... */
1011 #include <windows.h>
1012 #undef format
1013 #undef interface
1014
1015 static void switch_to_realtime_priority()
1016 {
1017    /* set priority class */
1018    if (FALSE == SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) {
1019      fprintf(stderr, "No realtime priority possible.\n");
1020      return;
1021    }
1022
1023    /* set thread priority */
1024    if (FALSE == SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
1025      fprintf(stderr, "Could not set realtime priority.\n");
1026    }
1027 }
1028 #else
1029 static void switch_to_realtime_priority()
1030 {
1031 }
1032 #endif
1033 #endif
1034 #endif
1035
1036 /* SCSI cleanup */
1037 int on_exitscsi(void *status);
1038
1039 int on_exitscsi(void *status)
1040 {
1041         exit((intptr_t)status);
1042         return 0;
1043 }
1044
1045 /* wrapper for signal handler exit needed for Mac-OS-X */
1046 static void exit_wrapper(int status);
1047
1048 static void exit_wrapper(int status)
1049 {
1050 #if defined DEBUG_CLEANUP
1051         fprintf( stderr, "Exit(%d) for %s\n", status, child_pid == 0 ? "Child" : "Parent");
1052         fflush(stderr);
1053 #endif
1054
1055         if (child_pid != 0) {
1056                 SCSI *usalp = get_scsi_p();
1057                 if (usalp->running) {
1058                         usalp->cb_fun = on_exitscsi;
1059                         usalp->cb_arg = (void *) (uintptr_t) status;
1060                 } else {
1061                         on_exitscsi((void *) (intptr_t) status);
1062                 } 
1063         } else {
1064                 exit(status);
1065         }
1066 }
1067
1068 /* signal handler for process communication */
1069 static void set_nonforked(int status);
1070
1071 /* ARGSUSED */
1072 static void set_nonforked(int status)
1073 {
1074         global.parent_died = 1;
1075 #if defined DEBUG_CLEANUP
1076 fprintf( stderr, "SIGPIPE received from %s\n.", child_pid == 0 ? "Child" : "Parent");
1077 #endif
1078         if (child_pid == 0) {
1079                 pid_t   ppid;
1080                 /*
1081                  * Kill the parent too if we are not orphaned.
1082                  */
1083                 ppid = getppid();
1084                 if (ppid > 1)
1085                         kill(ppid, SIGINT);
1086         } else {
1087                 kill(child_pid, SIGINT);
1088         }
1089         exit(SIGPIPE_ERROR);
1090 }
1091
1092
1093
1094 #ifdef  USE_PARANOIA
1095 static struct paranoia_statistics
1096 {
1097         long    c_sector;
1098         long    v_sector;
1099         int     last_heartbeatstate;
1100         long    lasttime;
1101         char    heartbeat;
1102         int     minoverlap;
1103         int     curoverlap;
1104         int     maxoverlap;
1105         int     slevel;
1106         int     slastlevel;
1107         int     stimeout;
1108         int     rip_smile_level;
1109         unsigned verifies;
1110         unsigned reads;
1111         unsigned fixup_edges;
1112         unsigned fixup_atoms;
1113         unsigned readerrs;
1114         unsigned skips;
1115         unsigned overlaps;
1116         unsigned scratchs;
1117         unsigned drifts;
1118         unsigned fixup_droppeds;
1119         unsigned fixup_dupeds;
1120 }       *para_stat;
1121
1122
1123 static void paranoia_reset(void);
1124 static void paranoia_reset()
1125 {
1126         para_stat->c_sector = 0;
1127         para_stat->v_sector = 0;
1128         para_stat->last_heartbeatstate = 0;
1129         para_stat->lasttime = 0;
1130         para_stat->heartbeat = ' ';
1131         para_stat->minoverlap = 0x7FFFFFFF;
1132         para_stat->curoverlap = 0;
1133         para_stat->maxoverlap = 0;
1134         para_stat->slevel = 0;
1135         para_stat->slastlevel = 0;
1136         para_stat->stimeout = 0;
1137         para_stat->rip_smile_level = 0;
1138         para_stat->verifies = 0;
1139         para_stat->reads = 0;
1140         para_stat->readerrs = 0;
1141         para_stat->fixup_edges = 0;
1142         para_stat->fixup_atoms = 0;
1143         para_stat->fixup_droppeds = 0;
1144         para_stat->fixup_dupeds = 0;
1145         para_stat->drifts = 0;
1146         para_stat->scratchs = 0;
1147         para_stat->overlaps = 0;
1148         para_stat->skips = 0;
1149 }
1150
1151 static void paranoia_callback(long inpos, int function);
1152
1153 static void paranoia_callback(long inpos, int function)
1154 {
1155         struct timeval thistime;
1156         long    test;
1157
1158         switch (function) {
1159                 case    -2:
1160                         para_stat->v_sector = inpos / CD_FRAMEWORDS;
1161                         return;
1162                 case    -1:
1163                         para_stat->last_heartbeatstate = 8;
1164                         para_stat->heartbeat = '*';
1165                         para_stat->slevel = 0;
1166                         para_stat->v_sector = inpos / CD_FRAMEWORDS;
1167                 break;
1168                 case    PARANOIA_CB_VERIFY:
1169                         if (para_stat->stimeout >= 30) {
1170                                 if (para_stat->curoverlap > CD_FRAMEWORDS) {
1171                                         para_stat->slevel = 2;
1172                                 } else {
1173                                         para_stat->slevel = 1;
1174                                 }
1175                         }
1176                         para_stat->verifies++;
1177                 break;
1178                 case    PARANOIA_CB_READ:
1179                         if (inpos / CD_FRAMEWORDS > para_stat->c_sector) {
1180                                 para_stat->c_sector = inpos / CD_FRAMEWORDS;
1181                         }
1182                         para_stat->reads++;
1183                 break;
1184                 case    PARANOIA_CB_FIXUP_EDGE:
1185                         if (para_stat->stimeout >= 5) {
1186                                 if (para_stat->curoverlap > CD_FRAMEWORDS) {
1187                                         para_stat->slevel = 2;
1188                                 } else {
1189                                         para_stat->slevel = 1;
1190                                 }
1191                         }
1192                         para_stat->fixup_edges++;
1193                 break;
1194                 case    PARANOIA_CB_FIXUP_ATOM:
1195                         if (para_stat->slevel < 3 || para_stat->stimeout > 5) {
1196                                 para_stat->slevel = 3;
1197                         }
1198                         para_stat->fixup_atoms++;
1199                 break;
1200                 case    PARANOIA_CB_READERR:
1201                         para_stat->slevel = 6;
1202                         para_stat->readerrs++;
1203                 break;
1204                 case    PARANOIA_CB_SKIP:
1205                         para_stat->slevel = 8;
1206                         para_stat->skips++;
1207                 break;
1208                 case    PARANOIA_CB_OVERLAP:
1209                         para_stat->curoverlap = inpos;
1210                         if (inpos > para_stat->maxoverlap)
1211                                 para_stat->maxoverlap = inpos;
1212                         if (inpos < para_stat->minoverlap)
1213                                 para_stat->minoverlap = inpos;
1214                         para_stat->overlaps++;
1215                 break;
1216                 case    PARANOIA_CB_SCRATCH:
1217                         para_stat->slevel = 7;
1218                         para_stat->scratchs++;
1219                 break;
1220                 case    PARANOIA_CB_DRIFT:
1221                         if (para_stat->slevel < 4 || para_stat->stimeout > 5) {
1222                                 para_stat->slevel = 4;
1223                         }
1224                         para_stat->drifts++;
1225                 break;
1226                 case    PARANOIA_CB_FIXUP_DROPPED:
1227                         para_stat->slevel = 5;
1228                         para_stat->fixup_droppeds++;
1229                 break;
1230                 case    PARANOIA_CB_FIXUP_DUPED:
1231                         para_stat->slevel = 5;
1232                         para_stat->fixup_dupeds++;
1233                 break;
1234         }
1235
1236         gettimeofday(&thistime, NULL);
1237         /* now in tenth of seconds. */
1238         test = thistime.tv_sec * 10 + thistime.tv_usec / 100000;
1239
1240         if (para_stat->lasttime != test
1241                 || function == -1
1242                 || para_stat->slastlevel != para_stat->slevel) {
1243
1244                 if (function == -1
1245                         || para_stat->slastlevel != para_stat->slevel) {
1246
1247                         static const char hstates[] = " .o0O0o.";
1248
1249                         para_stat->lasttime = test;
1250                         para_stat->stimeout++;
1251
1252                         para_stat->last_heartbeatstate++;
1253                         if (para_stat->last_heartbeatstate > 7) {
1254                                 para_stat->last_heartbeatstate = 0;
1255                         }
1256                         para_stat->heartbeat = hstates[para_stat->last_heartbeatstate];
1257
1258                         if (function == -1) {
1259                                 para_stat->heartbeat = '*';
1260                         }
1261                 }
1262
1263                 if (para_stat->slastlevel != para_stat->slevel) {
1264                         para_stat->stimeout = 0;
1265                 }
1266                 para_stat->slastlevel = para_stat->slevel;
1267         }
1268
1269         if (para_stat->slevel < 8) {
1270                 para_stat->rip_smile_level = para_stat->slevel;
1271         } else {
1272                 para_stat->rip_smile_level = 0;
1273         }
1274 }
1275 #endif
1276
1277 static long lSector;
1278 static long lSector_p2;
1279 static double rate = 44100.0 / UNDERSAMPLING;
1280 static int bits = BITS_P_S;
1281 static char fname[200];
1282 static const char *audio_type;
1283 static long BeginAtSample;
1284 static unsigned long SamplesToWrite; 
1285 static unsigned minover;
1286 static unsigned maxover;
1287
1288 static unsigned long calc_SectorBurst(void);
1289 static unsigned long calc_SectorBurst()
1290 {
1291         unsigned long SectorBurstVal;
1292
1293         SectorBurstVal = min(global.nsectors,
1294                   (global.iloop + CD_FRAMESAMPLES-1) / CD_FRAMESAMPLES);
1295         if ( lSector+(int)SectorBurst-1 >= lSector_p2 )
1296                 SectorBurstVal = lSector_p2 - lSector;
1297         return SectorBurstVal;
1298 }
1299
1300 /* if PERCENTAGE_PER_TRACK is defined, the percentage message will reach
1301  * 100% every time a track end is reached or the time limit is reached.
1302  *
1303  * Otherwise if PERCENTAGE_PER_TRACK is not defined, the percentage message
1304  * will reach 100% once at the very end of the last track.
1305  */
1306 #define PERCENTAGE_PER_TRACK
1307
1308 static int do_read(myringbuff *p, unsigned *total_unsuccessful_retries);
1309 static int do_read(myringbuff *p, unsigned *total_unsuccessful_retries)
1310 {
1311         unsigned char *newbuf;
1312         int offset;
1313         unsigned int added_size;
1314
1315         /* how many sectors should be read */
1316         SectorBurst =  calc_SectorBurst();
1317
1318 #ifdef  USE_PARANOIA
1319         if (global.paranoia_selected) {
1320                 int i;
1321
1322                 for (i = 0; i < SectorBurst; i++) {
1323                         void *dp;
1324
1325                         dp = paranoia_read_limited(global.cdp, paranoia_callback,
1326                                 global.paranoia_parms.retries);
1327 /*
1328                         {
1329                                 char *err;
1330                                 char *msg;
1331                                 err = cdda_errors(global.cdp);
1332                                 msg = cdda_messages(global.cdp);
1333                                 if (err) {
1334                                         fputs(err, stderr);
1335                                         free(err);
1336                                 }
1337                                 if (msg) {
1338                                         fputs(msg, stderr);
1339                                         free(msg);
1340                                 }
1341                         }
1342 */
1343                         if (dp != NULL) {
1344                                 memcpy(p->data + i*CD_FRAMESAMPLES, dp,
1345                                         CD_FRAMESIZE_RAW);
1346                         } else {
1347                                 fputs("E unrecoverable error!", stderr);
1348                                 exit(READ_ERROR);
1349                         }
1350                 }
1351                 newbuf = (unsigned char *)p->data;
1352                 offset = 0;
1353                 set_offset(p,offset);
1354                 added_size = SectorBurst * CD_FRAMESAMPLES;
1355                 global.overlap = 0;
1356                 handle_inputendianess(p->data, added_size);
1357         } else 
1358 #endif
1359         {
1360                 unsigned int retry_count;
1361 #define MAX_READRETRY 12
1362
1363                 retry_count = 0;
1364                 do {
1365                         SCSI *usalp = get_scsi_p();
1366                         int retval;
1367 #ifdef DEBUG_READS
1368 fprintf(stderr, "reading from %lu to %lu, overlap %u\n", lSector, lSector + SectorBurst -1, global.overlap);
1369 #endif
1370
1371 #ifdef DEBUG_BUFFER_ADDRESSES
1372 fprintf(stderr, "%p %l\n", p->data, global.pagesize);
1373 if (((unsigned)p->data) & (global.pagesize -1) != 0) {
1374   fprintf(stderr, "Address %p is NOT page aligned!!\n", p->data);
1375 }
1376 #endif
1377
1378                         if (global.reads_illleadout != 0 && lSector > Get_StartSector(LastTrack())) {
1379                                 int singles = 0;
1380                                 UINT4 bufferSub[CD_FRAMESAMPLES + 24];
1381
1382                                 /* we switch to single sector reads,
1383                                  * in order to handle the remaining sectors. */
1384                                 usalp->silent++;
1385                                 do {
1386                                         ReadCdRomSub( usalp, bufferSub, lSector+singles, 1 );
1387                                         *eorecording = RealEnd( usalp, bufferSub );
1388                                         if (*eorecording) {
1389                                                 break;
1390                                         }
1391                                         memcpy(p->data+singles*CD_FRAMESAMPLES, bufferSub, CD_FRAMESIZE_RAW);
1392                                         singles++;
1393                                 } while (singles < SectorBurst);
1394                                 usalp->silent--;
1395
1396                                 if ( *eorecording ) {
1397                                         patch_real_end(lSector+singles);
1398                                         SectorBurst = singles;
1399 #if     DEBUG_ILLLEADOUT
1400 fprintf(stderr, "iloop=%11lu, nSamplesToDo=%11lu, end=%lu -->\n",
1401 global.iloop, *nSamplesToDo, lSector+singles);
1402 #endif
1403
1404                                         *nSamplesToDo -= global.iloop - SectorBurst*CD_FRAMESAMPLES;
1405                                         global.iloop = SectorBurst*CD_FRAMESAMPLES;
1406 #if     DEBUG_ILLLEADOUT
1407 fprintf(stderr, "iloop=%11lu, nSamplesToDo=%11lu\n\n",
1408 global.iloop, *nSamplesToDo);
1409 #endif
1410
1411                                 }
1412                         } else {
1413                                 retval = ReadCdRom( usalp, p->data, lSector, SectorBurst );
1414                         }
1415                         handle_inputendianess(p->data, SectorBurst * CD_FRAMESAMPLES);
1416                         if (NULL ==
1417                                 (newbuf = synchronize( p->data, SectorBurst*CD_FRAMESAMPLES,
1418                                         *nSamplesToDo-global.iloop ))) {
1419                                 /* could not synchronize!
1420                                  * Try to invalidate the cdrom cache.
1421                                  * Increase overlap setting, if possible.
1422                                  */     
1423                                 /*trash_cache(p->data, lSector, SectorBurst);*/
1424                                 if (global.overlap < global.nsectors - 1) {
1425                                         global.overlap++;
1426                                         lSector--;
1427                                         SectorBurst = calc_SectorBurst();
1428 #ifdef DEBUG_DYN_OVERLAP
1429 fprintf(stderr, "using increased overlap of %u\n", global.overlap);
1430 #endif
1431                                 } else {
1432                                         lSector += global.overlap - 1;
1433                                         global.overlap = 1;
1434                                         SectorBurst =  calc_SectorBurst();
1435                                 }
1436                         } else
1437                                 break;
1438                 } while (++retry_count < MAX_READRETRY);
1439
1440                 if (retry_count == MAX_READRETRY && newbuf == NULL && global.verbose != 0) {
1441                         (*total_unsuccessful_retries)++;
1442                 }
1443
1444                 if (newbuf) {
1445                         offset = newbuf - ((unsigned char *)p->data);
1446                 } else {
1447                         offset = global.overlap * CD_FRAMESIZE_RAW;
1448                 }
1449                 set_offset(p,offset);
1450
1451                 /* how much has been added? */
1452                 added_size = SectorBurst * CD_FRAMESAMPLES - offset/4;
1453
1454                 if (newbuf && *nSamplesToDo != global.iloop) {
1455                         minover = min(global.overlap, minover);
1456                         maxover = max(global.overlap, maxover);
1457
1458
1459                         /* should we reduce the overlap setting ? */
1460                         if (offset > CD_FRAMESIZE_RAW && global.overlap > 1) {
1461 #ifdef DEBUG_DYN_OVERLAP
1462 fprintf(stderr, "decreasing overlap from %u to %u (jitter %d)\n", global.overlap, global.overlap-1, offset - (global.overlap)*CD_FRAMESIZE_RAW);
1463 #endif
1464                                 global.overlap--;
1465                                 SectorBurst =  calc_SectorBurst();
1466                         }
1467                 }
1468         }
1469         if (global.iloop >= added_size) {
1470                 global.iloop -= added_size;
1471         } else {
1472                 global.iloop = 0;
1473         }
1474
1475         lSector += SectorBurst - global.overlap;
1476
1477 #if     defined PERCENTAGE_PER_TRACK && defined HAVE_FORK_AND_SHAREDMEM
1478         {
1479                 int as;
1480                 while ((as = Get_StartSector(current_track+1)) != -1
1481                         && lSector >= as) {
1482                         current_track++;
1483                 }
1484         }
1485 #endif
1486
1487         return offset;
1488 }
1489
1490 static void
1491 print_percentage(unsigned *poper, int c_offset);
1492
1493 static void print_percentage(unsigned *poper, int c_offset)
1494 {
1495         unsigned per;
1496 #ifdef  PERCENTAGE_PER_TRACK
1497         /* Thomas Niederreiter wants percentage per track */
1498         unsigned start_in_track = max(BeginAtSample,
1499                 Get_AudioStartSector(current_track)*CD_FRAMESAMPLES);
1500
1501         per = min(BeginAtSample + (long)*nSamplesToDo,
1502                 Get_StartSector(current_track+1)*CD_FRAMESAMPLES)
1503                 - (long)start_in_track;
1504
1505         per = (BeginAtSample+nSamplesDone
1506                 - start_in_track
1507                 )/(per/100);
1508
1509 #else
1510         per = global.iloop ? (nSamplesDone)/(*nSamplesToDo/100) : 100;
1511 #endif
1512
1513         if (global.overlap > 0) {
1514                 fprintf(stderr, "\r%2d/%2d/%2d/%7d %3d%%",
1515                         minover, maxover, global.overlap,
1516                         c_offset - global.overlap*CD_FRAMESIZE_RAW,
1517                         per);
1518         } else if (*poper != per) {
1519                 fprintf(stderr, "\r%3d%%", per);
1520         }
1521         *poper = per;
1522         fflush(stderr);
1523 }
1524
1525 static unsigned long do_write(myringbuff *p);
1526 static unsigned long do_write(myringbuff *p)
1527 {
1528         int current_offset;
1529         unsigned int InSamples;
1530         static unsigned oper = 200;
1531
1532         current_offset = get_offset(p);
1533
1534         /* how many bytes are available? */
1535         InSamples = global.nsectors*CD_FRAMESAMPLES - current_offset/4;
1536         /* how many samples are wanted? */
1537         InSamples = min((*nSamplesToDo-nSamplesDone),InSamples);
1538
1539         /* when track end is reached, close current file and start a new one */
1540         while ((nSamplesDone < *nSamplesToDo) && (InSamples != 0)) {
1541                 long unsigned int how_much = InSamples;
1542
1543                 long int left_in_track;
1544                 left_in_track  = Get_StartSector(current_track+1)*CD_FRAMESAMPLES
1545                                  - (int)(BeginAtSample+nSamplesDone);
1546
1547                 if (*eorecording != 0 && current_track == cdtracks+1 &&
1548                     (*total_segments_read) == (*total_segments_written)+1) {
1549                         /* limit, if the actual end of the last track is
1550                          * not known from the toc. */
1551                         left_in_track = InSamples;
1552                 }
1553
1554 if (left_in_track < 0) {
1555         fprintf(stderr, "internal error: negative left_in_track:%ld, current_track=%d\n",left_in_track, current_track);
1556 }
1557
1558                 if (bulk) {
1559                         how_much = min(how_much, (unsigned long) left_in_track);
1560                 }
1561
1562 #ifdef MD5_SIGNATURES
1563                 if (global.md5count) {
1564                         MD5Update (&global.context, ((unsigned char *)p->data) +current_offset, min(global.md5count,how_much));
1565                         global.md5count -= min(global.md5count,how_much);
1566                 }
1567 #endif
1568                 if ( SaveBuffer ( p->data + current_offset/4,
1569                          how_much,
1570                          &nSamplesDone) ) {
1571                         if (global.have_forked == 1) {
1572                                 pid_t   ppid;
1573                                 /*
1574                                  * Kill the parent too if we are not orphaned.
1575                                  */
1576                                 ppid = getppid();
1577                                 if (ppid > 1)
1578                                         kill(ppid, SIGINT);
1579                         }
1580                         exit(WRITE_ERROR);
1581                 }
1582
1583                 global.nSamplesDoneInTrack += how_much;
1584                 SamplesToWrite -= how_much;
1585
1586                 /* move residual samples upto buffer start */
1587                 if (how_much < InSamples) {
1588                         memmove(
1589                           (char *)(p->data) + current_offset,
1590                           (char *)(p->data) + current_offset + how_much*4,
1591                           (InSamples - how_much) * 4);
1592                 }
1593
1594                 if ((unsigned long) left_in_track <= InSamples || SamplesToWrite == 0) {
1595                         /* the current portion to be handled is 
1596                            the end of a track */
1597
1598                         if (bulk) {
1599                                 /* finish sample file for this track */
1600                                 CloseAudio(global.channels,
1601                                   global.nSamplesDoneInTrack, global.audio_out);
1602                         } else if (SamplesToWrite == 0) {
1603                                 /* finish sample file for this track */
1604                                 CloseAudio(global.channels,
1605                                   (unsigned int) *nSamplesToDo, global.audio_out);
1606                         }
1607
1608                         if (global.verbose) {
1609 #ifdef  USE_PARANOIA
1610                                 double  f;
1611 #endif
1612                                 print_percentage(&oper, current_offset);
1613                                 fputc(' ', stderr);
1614 #ifndef THOMAS_SCHAU_MAL
1615                                 if ((unsigned long)left_in_track > InSamples) {
1616                                         fputs(" incomplete", stderr);
1617                                 }
1618 #endif
1619                                 if (global.tracktitle[current_track] != NULL) {
1620                                         fprintf( stderr,
1621                                                 " track %2u '%s' recorded", 
1622                                                 current_track,
1623                                                 global.tracktitle[current_track]);
1624                                 } else {
1625                                         fprintf( stderr,
1626                                                 " track %2u recorded",
1627                                                 current_track);
1628                                 }
1629 #ifdef  USE_PARANOIA
1630                                 oper = para_stat->readerrs + para_stat->skips +
1631                                           para_stat->fixup_edges + para_stat->fixup_atoms + 
1632                                           para_stat->fixup_droppeds + para_stat->fixup_dupeds + 
1633                                           para_stat->drifts;
1634                                 f = (100.0 * oper) / (((double)global.nSamplesDoneInTrack)/588.0);
1635
1636                                 if (para_stat->readerrs) {
1637                                         fprintf(stderr, " with audible hard errors");
1638                                 } else if ((para_stat->skips) > 0) {
1639                                         fprintf(stderr, " with %sretry/skip errors",
1640                                                         f < 2.0 ? "":"audible ");
1641                                 } else if (oper > 0) {
1642                                         oper = f;
1643                                         
1644                                         fprintf(stderr, " with ");
1645                                         if (oper < 2)
1646                                                 fprintf(stderr, "minor");
1647                                         else if (oper < 10)
1648                                                 fprintf(stderr, "medium");
1649                                         else if (oper < 67)
1650                                                 fprintf(stderr, "noticable audible");
1651                                         else if (oper < 100)
1652                                                 fprintf(stderr, "major audible");
1653                                         else
1654                                                 fprintf(stderr, "extreme audible");
1655                                         fprintf(stderr, " problems");
1656                                 } else {
1657                                         fprintf(stderr, " successfully");
1658                                 }
1659                                 if (f >= 0.1)
1660                                         fprintf(stderr, " (%.1f%% problem sectors)", f);
1661 #else
1662                                 fprintf(stderr, " successfully");
1663 #endif
1664
1665                                 if (waitforsignal == 1) {
1666                                         fprintf(stderr, ". %d silent samples omitted", global.SkippedSamples);
1667                                 }
1668                                 fputs("\n", stderr);
1669
1670                                 if (global.reads_illleadout && *eorecording == 1) {
1671                                         fprintf(stderr, "Real lead out at: %ld sectors\n", 
1672                                           (*nSamplesToDo+BeginAtSample)/CD_FRAMESAMPLES);
1673                                 }
1674 #ifdef  USE_PARANOIA
1675                                 if (global.paranoia_selected) {
1676                                         oper = 200;     /* force new output */
1677                                         print_percentage(&oper, current_offset);
1678                                         if (para_stat->minoverlap == 0x7FFFFFFF)
1679                                                 para_stat->minoverlap = 0;
1680                                         fprintf(stderr, "  %u rderr, %u skip, %u atom, %u edge, %u drop, %u dup, %u drift\n"
1681                                                 ,para_stat->readerrs
1682                                                 ,para_stat->skips
1683                                                 ,para_stat->fixup_atoms
1684                                                 ,para_stat->fixup_edges
1685                                                 ,para_stat->fixup_droppeds
1686                                                 ,para_stat->fixup_dupeds
1687                                                 ,para_stat->drifts);
1688                                         oper = 200;     /* force new output */
1689                                         print_percentage(&oper, current_offset);
1690                                         fprintf(stderr, "  %u overlap(%.4g .. %.4g)\n",
1691                                                 para_stat->overlaps,
1692                                                 (float)para_stat->minoverlap / (2352.0/2.0),
1693                                                 (float)para_stat->maxoverlap / (2352.0/2.0));
1694                                         paranoia_reset();
1695                                 }
1696 #endif
1697                         }
1698
1699                         global.nSamplesDoneInTrack = 0;
1700                         if ( bulk && SamplesToWrite > 0 ) {
1701                                 if ( !global.no_file ) {
1702                                         char *tmp_fname;
1703
1704                                         /* build next filename */
1705                                         tmp_fname = get_next_name();
1706                                         if (tmp_fname != NULL) {
1707                                                 strncpy(global.fname_base,
1708                                                         tmp_fname,
1709                                                         sizeof global.fname_base);
1710                                                 global.fname_base[
1711                                                         sizeof(global.fname_base)-1] =
1712                                                         '\0';
1713                                         }
1714
1715                                         tmp_fname = cut_extension(global.fname_base);
1716                                         tmp_fname[0] = '\0';
1717
1718                                         if (global.multiname == 0) {
1719                                                 sprintf(fname, "%s_%02u.%s",
1720                                                         global.fname_base,
1721                                                         current_track+1,
1722                                                         audio_type);
1723                                         } else {
1724                                                 sprintf(fname, "%s.%s",
1725                                                         global.fname_base,
1726                                                         audio_type);
1727                                         }
1728
1729                                         OpenAudio( fname, rate, bits, global.channels,
1730                                                 (Get_AudioStartSector(current_track+1) -
1731                                                  Get_AudioStartSector(current_track))
1732                                                         *CD_FRAMESIZE_RAW,
1733                                                 global.audio_out);
1734                                 } /* global.nofile */
1735                         } /* if ( bulk && SamplesToWrite > 0 ) */
1736                         current_track++;
1737
1738                 } /* left_in_track <= InSamples */
1739                 InSamples -= how_much;
1740
1741         }  /* end while */
1742         if (!global.quiet && *nSamplesToDo != nSamplesDone) {
1743                 print_percentage(&oper, current_offset);
1744         }
1745         return nSamplesDone;
1746 }
1747
1748 #define PRINT_OVERLAP_INIT \
1749    if (global.verbose) { \
1750         if (global.overlap > 0) \
1751                 fprintf(stderr, "overlap:min/max/cur, jitter, percent_done:\n  /  /  /          0%%"); \
1752         else \
1753                 fputs("percent_done:\n  0%", stderr); \
1754    }
1755
1756 #if defined HAVE_FORK_AND_SHAREDMEM
1757 static void forked_read(void);
1758
1759 /* This function does all audio cdrom reads
1760  * until there is nothing more to do
1761  */
1762 static void forked_read()
1763 {
1764    unsigned total_unsuccessful_retries = 0;
1765
1766 #if !defined(HAVE_SEMGET) || !defined(USE_SEMAPHORES)
1767    init_child();
1768 #endif
1769
1770    minover = global.nsectors;
1771
1772    PRINT_OVERLAP_INIT
1773    while (global.iloop) { 
1774
1775       do_read(get_next_buffer(), &total_unsuccessful_retries);
1776
1777       define_buffer();
1778
1779    } /* while (global.iloop) */
1780
1781    if (total_unsuccessful_retries) {
1782       fprintf(stderr,"%u unsuccessful matches while reading\n",total_unsuccessful_retries);
1783    }
1784 }
1785
1786 static void forked_write(void);
1787
1788 static void forked_write()
1789 {
1790
1791     /* don't need these anymore.  Good security policy says we get rid
1792        of them ASAP */
1793         priv_off();
1794         neverneedroot();
1795         neverneedgroup();
1796
1797 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
1798 #else
1799     init_parent();
1800 #endif
1801
1802     for (;nSamplesDone < *nSamplesToDo;) {
1803         if (*eorecording == 1 && (*total_segments_read) == (*total_segments_written)) break;
1804
1805         /* get oldest buffers */
1806       
1807         nSamplesDone = do_write(get_oldest_buffer());
1808
1809         drop_buffer();
1810
1811     } /* end for */
1812
1813 }
1814 #endif
1815
1816 /* This function implements the read and write calls in one loop (in case
1817  * there is no fork/thread_create system call).
1818  * This means reads and writes have to wait for each other to complete.
1819  */
1820 static void nonforked_loop(void);
1821
1822 static void nonforked_loop()
1823 {
1824     unsigned total_unsuccessful_retries = 0;
1825
1826     minover = global.nsectors;
1827
1828     PRINT_OVERLAP_INIT
1829     while (global.iloop) { 
1830
1831       do_read(get_next_buffer(), &total_unsuccessful_retries);
1832
1833       do_write(get_oldest_buffer());
1834
1835     }
1836
1837     if (total_unsuccessful_retries) {
1838       fprintf(stderr,"%u unsuccessful matches while reading\n",total_unsuccessful_retries);
1839     }
1840
1841 }
1842
1843 void verbose_usage(void);
1844
1845 void verbose_usage()
1846 {
1847         fputs("\
1848         help            lists all verbose options.\n\
1849         disable         disables verbose mode.\n\
1850         all             enables all verbose options.\n\
1851         toc             display the table of contents.\n\
1852         summary         display a summary of track parameters.\n\
1853         indices         retrieve/display index positions.\n\
1854         catalog         retrieve/display media catalog number.\n\
1855         trackid         retrieve/display international standard recording code.\n\
1856         sectors         display the start sectors of each track.\n\
1857         titles          display any known track titles.\n\
1858 ", stderr);
1859 }
1860
1861 #ifdef  USE_PARANOIA
1862 void paranoia_usage(void);
1863
1864 void paranoia_usage()
1865 {
1866         fputs("\
1867         help            lists all paranoia options.\n\
1868         disable         disables paranoia mode. Paranoia is still being used.\n\
1869         no-verify       switches verify off, and overlap on.\n\
1870         retries=amount  set the number of maximum retries per sector.\n\
1871         overlap=amount  set the number of sectors used for statical paranoia overlap.\n\
1872         minoverlap=amt  set the min. number of sectors used for dynamic paranoia overlap.\n\
1873         maxoverlap=amt  set the max. number of sectors used for dynamic paranoia overlap.\n\
1874 ", stderr);
1875 }
1876 #endif
1877
1878 int
1879 handle_verbose_opts(char *optstr, long *flagp);
1880
1881 int handle_verbose_opts(char *optstr, long *flagp)
1882 {
1883         char    *ep;
1884         char    *np;
1885         int     optlen;
1886
1887         *flagp = 0;
1888         while (*optstr) {
1889                 if ((ep = strchr(optstr, ',')) != NULL) {
1890                         optlen = ep - optstr;
1891                         np = ep + 1;
1892                 } else {
1893                         optlen = strlen(optstr);
1894                         np = optstr + optlen;
1895                 }
1896                 if (strncmp(optstr, "toc", optlen) == 0) {
1897                         *flagp |= SHOW_TOC;
1898                 }
1899                 else if (strncmp(optstr, "summary", optlen) == 0) {
1900                         *flagp |= SHOW_SUMMARY;
1901                 }
1902                 else if (strncmp(optstr, "indices", optlen) == 0) {
1903                         *flagp |= SHOW_INDICES;
1904                 }
1905                 else if (strncmp(optstr, "catalog", optlen) == 0) {
1906                         *flagp |= SHOW_MCN;
1907                 }
1908                 else if (strncmp(optstr, "trackid", optlen) == 0) {
1909                         *flagp |= SHOW_ISRC;
1910                 }
1911                 else if (strncmp(optstr, "sectors", optlen) == 0) {
1912                         *flagp |= SHOW_STARTPOSITIONS;
1913                 }
1914                 else if (strncmp(optstr, "titles", optlen) == 0) {
1915                         *flagp |= SHOW_TITLES;
1916                 }
1917                 else if (strncmp(optstr, "all", optlen) == 0) {
1918                         *flagp |= SHOW_MAX;
1919                 }
1920                 else if (strncmp(optstr, "disable", optlen) == 0) {
1921                         *flagp = 0;
1922                 }
1923                 else if (strncmp(optstr, "help", optlen) == 0) {
1924                         verbose_usage();
1925                         exit(NO_ERROR);
1926                 }
1927                 else {
1928                         char    *endptr;
1929                         unsigned arg = strtoul(optstr, &endptr, 10);
1930                         if (optstr != endptr
1931                                 && arg <= SHOW_MAX) {
1932                                 *flagp |= arg;
1933                                 fprintf(stderr, "Warning: numerical parameters for -v are no more supported in the next releases!\n");
1934                         }
1935                         else {
1936                                 fprintf(stderr, "unknown option %s\n", optstr);
1937                                 verbose_usage();
1938                                 exit(SYNTAX_ERROR);
1939                         }
1940                 }
1941                 optstr = np;
1942         }
1943         return 1;
1944 }
1945
1946
1947 int
1948 handle_paranoia_opts(char *optstr, long *flagp);
1949
1950 int handle_paranoia_opts(char *optstr, long *flagp)
1951 {
1952 #ifdef  USE_PARANOIA
1953         char    *ep;
1954         char    *np;
1955         int     optlen;
1956
1957         while (*optstr) {
1958                 if ((ep = strchr(optstr, ',')) != NULL) {
1959                         optlen = ep - optstr;
1960                         np = ep + 1;
1961                 } else {
1962                         optlen = strlen(optstr);
1963                         np = optstr + optlen;
1964                 }
1965                 if (strncmp(optstr, "retries=", min(8,optlen)) == 0) {
1966                         char *eqp = strchr(optstr, '=');
1967                         int   rets;
1968
1969                         astoi(eqp+1, &rets);
1970                         if (rets >= 0) {
1971                                 global.paranoia_parms.retries = rets;
1972                         }
1973                 }
1974                 else if (strncmp(optstr, "overlap=", min(8, optlen)) == 0) {
1975                         char *eqp = strchr(optstr, '=');
1976                         int   rets;
1977
1978                         astoi(eqp+1, &rets);
1979                         if (rets >= 0) {
1980                                 global.paranoia_parms.overlap = rets;
1981                         }
1982                 }
1983                 else if (strncmp(optstr, "minoverlap=", min(11, optlen)) == 0) {
1984                         char *eqp = strchr(optstr, '=');
1985                         int   rets;
1986
1987                         astoi(eqp+1, &rets);
1988                         if (rets >= 0) {
1989                                 global.paranoia_parms.mindynoverlap = rets;
1990                         }
1991                 }
1992                 else if (strncmp(optstr, "maxoverlap=", min(11, optlen)) == 0) {
1993                         char *eqp = strchr(optstr, '=');
1994                         int   rets;
1995
1996                         astoi(eqp+1, &rets);
1997                         if (rets >= 0) {
1998                                 global.paranoia_parms.maxdynoverlap = rets;
1999                         }
2000                 }
2001                 else if (strncmp(optstr, "no-verify", optlen) == 0) {
2002                         global.paranoia_parms.disable_extra_paranoia = 1;
2003                 }
2004                 else if (strncmp(optstr, "disable", optlen) == 0) {
2005                         global.paranoia_parms.disable_paranoia = 1;
2006                 }
2007                 else if (strncmp(optstr, "help", optlen) == 0) {
2008                         paranoia_usage();
2009                         exit(NO_ERROR);
2010                 }
2011                 else {
2012                         fprintf(stderr, "unknown option %s\n", optstr);
2013                         paranoia_usage();
2014                         exit(SYNTAX_ERROR);
2015                 }
2016                 optstr = np;
2017         }
2018         return 1;
2019 #else
2020         fputs("lib paranoia support is not configured!\n", stderr);
2021         return 0;
2022 #endif
2023 }
2024
2025
2026 /* and finally: the MAIN program */
2027 int main(int argc, char *argv[])
2028 {
2029   long lSector_p1;
2030   long sector_offset = 0;
2031   unsigned long endtrack = 1;
2032   double rectime = DURATION;
2033   int cd_index = -1;
2034   double int_part;
2035   int littleendian = -1;
2036   char *int_name;
2037   static char *user_sound_device = "";
2038   char * env_p;
2039   int tracks_included;
2040         int     moreargs;
2041
2042   int_name = DEF_INTERFACE;
2043   audio_type = AUDIOTYPE;
2044   save_args(argc, argv);
2045
2046   /* init global variables */
2047   init_globals();
2048 {
2049   int am_i_cdda2wav;
2050   /* When being invoked as list_audio_tracks, just dump a list of
2051      audio tracks. */
2052   am_i_cdda2wav = !(strlen(argv[0]) >= sizeof("list_audio_tracks")-1
2053         && !strcmp(argv[0]+strlen(argv[0])+1-sizeof("list_audio_tracks"),"list_audio_tracks"));
2054   if (!am_i_cdda2wav) global.verbose = SHOW_JUSTAUDIOTRACKS;
2055 }
2056   /* Control those set-id privileges... */
2057   initsecurity();
2058
2059   env_p = getenv("CDDA_DEVICE");
2060   if (env_p != NULL) {
2061     global.dev_name = env_p;
2062   }
2063
2064   env_p = getenv("CDDBP_SERVER");
2065   if (env_p != NULL) {
2066     global.cddbp_server = env_p;
2067   }
2068
2069   env_p = getenv("CDDBP_PORT");
2070   if (env_p != NULL) {
2071     global.cddbp_port = env_p;
2072   }
2073
2074 {
2075         int     cac;
2076         char    *const*cav;
2077
2078         BOOL    version = FALSE;
2079         BOOL    help = FALSE;
2080         char    *channels = NULL;
2081         int     irate = -1;
2082         char    *divider = NULL;
2083         char    *trackspec = NULL;
2084         char    *duration = NULL;
2085
2086         char    *oendianess = NULL;
2087         char    *cendianess = NULL;
2088         int     cddbp = -1;
2089         BOOL    stereo = FALSE;
2090         BOOL    mono = FALSE;
2091         BOOL    domax = FALSE;
2092         BOOL    dump_rates = FALSE;
2093         int     userverbose = -1;
2094         long    paraopts = 0;
2095
2096         cac = argc;
2097         cav = argv;
2098         cac--;
2099         cav++;
2100         if (getargs(&cac, &cav, opts
2101                         , &global.paranoia_selected
2102                         , handle_paranoia_opts, &paraopts
2103                         , &version
2104                         , &help, &help
2105
2106                         , &global.no_file, &global.no_file
2107                         , &dump_rates, &dump_rates
2108                         , &bulk, &bulk, &bulk
2109                         , &global.scsi_verbose, &global.scsi_verbose
2110
2111                         , &global.findminmax, &global.findminmax
2112                         , &global.findmono, &global.findmono
2113                         , &global.no_infofile, &global.no_infofile
2114
2115                         , &global.deemphasize, &global.deemphasize
2116                         , &global.just_the_toc, &global.just_the_toc
2117                         , &global.scsi_silent, &global.scsi_silent
2118
2119                         , &global.cddbp_server, &global.cddbp_port
2120                         , &global.scanbus
2121                         , &global.scandevs
2122                         , &global.dev_name, &global.dev_name, &global.dev_name
2123                         , &global.aux_name, &global.aux_name
2124                         , &int_name, &int_name
2125                         , &audio_type, &audio_type
2126
2127                         , &oendianess, &oendianess
2128                         , &cendianess, &cendianess
2129                         , &global.userspeed, &global.userspeed
2130
2131                         , &global.playback_rate, &global.playback_rate
2132                         , &global.md5blocksize, &global.md5blocksize
2133                         , &global.useroverlap, &global.useroverlap
2134                         , &user_sound_device, &user_sound_device
2135
2136                         , &cddbp, &cddbp
2137                         , &channels, &channels
2138                         , &bits, &bits
2139                         , &irate, &irate
2140                         , &global.gui, &global.gui
2141
2142                         , &divider, &divider
2143                         , &trackspec, &trackspec
2144                         , &cd_index, &cd_index
2145                         , &duration, &duration
2146                         , &sector_offset, &sector_offset
2147
2148                         , &global.nsectors, &global.nsectors
2149                         , handle_verbose_opts, &userverbose
2150                         , handle_verbose_opts, &userverbose
2151                         , &global.buffers, &global.buffers
2152
2153                         , &stereo, &stereo
2154                         , &mono, &mono
2155                         , &waitforsignal, &waitforsignal
2156                         , &global.echo, &global.echo
2157                         , &global.quiet, &global.quiet
2158                         , &domax, &domax
2159
2160                         ) < 0) {
2161                 errmsgno(EX_BAD, "Bad Option: %s.\n", cav[0]);
2162                 fputs ("use 'icedax -help' to get more information.\n", stderr);
2163                 exit (SYNTAX_ERROR);
2164         }
2165         if (getfiles(&cac, &cav, opts) == 0)
2166                 /* No more file type arguments */;
2167         moreargs = cav - argv;
2168         if (version) {
2169      fprintf(stderr, "icedax " CDRKIT_VERSION "\n");
2170      exit(EXIT_SUCCESS);
2171   }
2172         if (help) {
2173                 usage();
2174         }
2175         if (!global.scanbus)
2176                 cdr_defaults(&global.dev_name, NULL, NULL, NULL); 
2177         if (dump_rates) {       /* list available rates */
2178                 int ii;
2179
2180                 fputs("\
2181 Available rates are:\n\
2182 Rate   Divider      Rate   Divider      Rate   Divider      Rate   Divider\n\
2183 "                       , stderr );
2184                 for (ii = 1; ii <= 44100 / 880 / 2; ii++) {
2185                         long i2 = ii;
2186                         fprintf(stderr, "%7.1f  %2ld         %7.1f  %2ld.5       ",
2187                                 44100.0/i2, i2, 44100.0/(i2+0.5), i2);
2188                         i2 += 25;
2189                         fprintf(stderr, "%7.1f  %2ld         %7.1f  %2ld.5\n",
2190                                 44100.0/i2, i2, 44100.0/(i2+0.5), i2);
2191                         i2 -= 25;
2192                 }
2193                 exit(NO_ERROR);
2194         }
2195         if (channels) {
2196                 if (*channels == 's') {
2197                         global.channels = 2;
2198                         global.swapchannels = 1;
2199                 } else {
2200                         global.channels = strtol(channels, NULL, 10);
2201                 }
2202         }
2203         if (irate >= 0) {
2204                 rate = irate;
2205         }
2206         if (divider) {
2207                 double divider_d;
2208                 divider_d = strtod(divider , NULL);
2209                 if (divider_d > 0.0) {
2210                         rate = 44100.0 / divider_d;
2211                 } else {
2212                         fputs("E option -divider requires a nonzero, positive argument.\nSee -dump-rates.", stderr);
2213                         exit(SYNTAX_ERROR);
2214                 }
2215         }
2216         if (trackspec) {
2217                 char * endptr;
2218                 char * endptr2;
2219                 track = strtoul(trackspec, &endptr, 10 );
2220                 endtrack = strtoul(endptr, &endptr2, 10 );
2221                 if (endptr2 == endptr) {
2222                         endtrack = track;
2223                 } else if (track == endtrack) {
2224                         bulk = -1;
2225                 }
2226         }
2227         if (duration) {
2228                 char *end_ptr = NULL;
2229                 rectime = strtod(duration, &end_ptr );
2230                 if (*end_ptr == 'f') {
2231                         rectime = rectime / 75.0;
2232                         /* TODO: add an absolute end of recording. */
2233 #if     0
2234                 } else if (*end_ptr == 'F') {
2235                         rectime = rectime / 75.0;
2236 #endif
2237                 } else if (*end_ptr != '\0') {
2238                         rectime = -1.0;
2239                 }
2240         }
2241         if (oendianess) {
2242                 if (strcasecmp(oendianess, "little") == 0) {
2243                         global.outputendianess = LITTLE;
2244                 } else if (strcasecmp(oendianess, "big") == 0) {
2245                         global.outputendianess = BIG;
2246                 } else {
2247                         usage2("wrong parameter '%s' for option -E", oendianess);
2248                 }
2249         }
2250         if (cendianess) {
2251                 if (strcasecmp(cendianess, "little") == 0) {
2252                         littleendian = 1;
2253                 } else if (strcasecmp(cendianess, "big") == 0) {
2254                         littleendian = 0;
2255                 } else if (strcasecmp(cendianess, "guess") == 0) {
2256                         littleendian = -2;
2257                 } else {
2258                         usage2("wrong parameter '%s' for option -C", cendianess);
2259                 }
2260         }
2261         if (cddbp >= 0) {
2262                 global.cddbp = 1 + cddbp;
2263         }
2264         if (stereo) {
2265                 global.channels = 2;
2266         }
2267         if (mono) {
2268                 global.channels = 1;
2269                 global.need_hostorder = 1;
2270         }
2271         if (global.echo) {
2272 #ifdef  ECHO_TO_SOUNDCARD
2273                 if (global.playback_rate != 100) {
2274                         RestrictPlaybackRate( global.playback_rate );
2275                 }
2276                 global.need_hostorder = 1;
2277 #else
2278                 fprintf(stderr, "There is no sound support compiled into %s.\n",argv[0]);
2279                 global.echo = 0;
2280 #endif
2281         }
2282         if (global.quiet) {
2283                 global.verbose = 0;
2284         }
2285         if (domax) {
2286                 global.channels = 2; bits = 16; rate = 44100;
2287         }
2288         if (global.findminmax) {
2289                 global.need_hostorder = 1;
2290         }
2291         if (global.deemphasize) {
2292                 global.need_hostorder = 1;
2293         }
2294         if (global.just_the_toc) {
2295                 global.verbose = SHOW_MAX;
2296                 bulk = 1;
2297         }
2298         if (global.gui) {
2299 #ifdef  Thomas_will_es
2300                 global.no_file = 1;
2301                 global.no_infofile = 1;
2302                 global.verbose = SHOW_MAX;
2303 #endif
2304                 global.no_cddbfile = 1;
2305         }
2306         if (global.no_file) {
2307                 global.no_infofile = 1;
2308                 global.no_cddbfile = 1;
2309         }
2310         if (global.no_infofile) {
2311                 global.no_cddbfile = 1;
2312         }
2313         if (global.md5blocksize) {
2314 #ifdef  MD5_SIGNATURES
2315                 fputs("MD5 signatures are currently broken! Sorry\n", stderr);
2316 #else
2317                 fputs("MD5 signatures are currently broken! Sorry\n", stderr);
2318 #endif
2319         }
2320         if (user_sound_device) {
2321 #ifndef ECHO_TO_SOUNDCARD
2322                 fputs("There is no sound support configured!\n", stderr);
2323 #endif
2324         }
2325         if (global.paranoia_selected) {
2326                 global.useroverlap = 0;
2327         }
2328         if (userverbose >= 0) {
2329                 global.verbose = userverbose;
2330         }
2331 }
2332
2333   /* check all parameters */
2334   if (global.buffers < 1) {
2335     usage2("Incorrect buffer setting: %d", global.buffers);
2336   }
2337
2338   if (global.nsectors < 1) {
2339     usage2("Incorrect nsectors setting: %d", global.nsectors);
2340   }
2341
2342   if (global.verbose < 0 || global.verbose > SHOW_MAX) {
2343     usage2("Incorrect verbose level setting: %d",global.verbose);
2344   }
2345   if (global.verbose == 0) global.quiet = 1;
2346
2347   if ( rectime < 0.0 ) {
2348     usage2("Incorrect recording time setting: %d.%02d",
2349                         (int)rectime, (int)(rectime*100+0.5) % 100);
2350   }
2351
2352   if ( global.channels != 1 && global.channels != 2 ) {
2353     usage2("Incorrect channel setting: %d",global.channels);
2354   }
2355
2356   if ( bits != 8 && bits != 12 && bits != 16 ) {
2357     usage2("Incorrect bits_per_sample setting: %d",bits);
2358   }
2359
2360   if ( rate < 827.0 || rate > 44100.0 ) {
2361     usage2("Incorrect sample rate setting: %d.%02d",
2362         (int)rate, ((int)rate*100) % 100);
2363   }
2364
2365   int_part = (double)(long) (2*44100.0 / rate);
2366   
2367   if (2*44100.0 / rate - int_part >= 0.5 ) {
2368       int_part += 1.0;
2369       fprintf( stderr, "Nearest available sample rate is %d.%02d Hertz\n",
2370               2*44100 / (int)int_part,
2371               (2*4410000 / (int)int_part) % 100);
2372   }
2373   Halved = ((int) int_part) & 1;
2374   rate = 2*44100.0 / int_part;
2375   undersampling = (int) int_part / 2.0;
2376   samples_to_do = undersampling;
2377
2378   if (!strcmp((char *)int_name,"generic_scsi"))
2379       interface = GENERIC_SCSI;
2380   else if (!strcmp((char *)int_name,"cooked_ioctl"))
2381       interface = COOKED_IOCTL;
2382   else  {
2383     usage2("Incorrect interface setting: %s",int_name);
2384   }
2385
2386   /* check * init audio file */
2387   if (!strncmp(audio_type,"wav",3)) {
2388     global.audio_out = &wavsound;
2389   } else if (!strncmp(audio_type, "sun", 3) || !strncmp(audio_type, "au", 2)) {
2390     /* Enhanced compatibility */
2391     audio_type = "au";
2392     global.audio_out = &sunsound;
2393   } else if (!strncmp(audio_type, "cdr", 3) || 
2394              !strncmp(audio_type, "raw", 3)) {
2395     global.audio_out = &rawsound;
2396   } else if (!strncmp(audio_type, "aiff", 4)) {
2397     global.audio_out = &aiffsound;
2398   } else if (!strncmp(audio_type, "aifc", 4)) {
2399     global.audio_out = &aifcsound;
2400 #ifdef USE_LAME
2401   } else if (!strncmp(audio_type, "mp3", 3)) {
2402     global.audio_out = &mp3sound;
2403     if (!global.quiet) {
2404         unsigned char Lame_version[20];
2405
2406         fetch_lame_version(Lame_version);
2407         fprintf(stderr, "Using LAME version %s.\n", Lame_version);
2408     }
2409     if (bits < 9) {
2410         bits = 16;
2411         fprintf(stderr, "Warning: sample size forced to 16 bit for MP3 format.\n");
2412     }
2413 #endif /* USE_LAME */
2414   } else {
2415     usage2("Incorrect audio type setting: %3s", audio_type);
2416   }
2417
2418   if (bulk == -1) bulk = 0;
2419
2420   global.need_big_endian = global.audio_out->need_big_endian;
2421   if (global.outputendianess != NONE)
2422     global.need_big_endian = global.outputendianess == BIG;
2423
2424   if (global.no_file) global.fname_base[0] = '\0';
2425
2426   if (!bulk) {
2427     strcat(global.fname_base, ".");
2428     strcat(global.fname_base, audio_type);
2429   }
2430
2431   /* If we need to calculate with samples or write them to a soundcard,
2432    * we need a conversion to host byte order.
2433    */ 
2434   if (global.channels != 2 
2435       || bits != 16
2436       || rate != 44100)
2437         global.need_hostorder = 1;
2438
2439   /* Bad hack!!
2440    * Remove for release 2.0
2441    * this is a bug compatibility feature.
2442    */
2443   if (global.gui && global.verbose == SHOW_TOC)
2444         global.verbose |= SHOW_STARTPOSITIONS | SHOW_SUMMARY | SHOW_TITLES;
2445
2446   /*
2447    * all options processed.
2448    * Now a file name per track may follow 
2449    */
2450   argc2 = argc3 = argc - moreargs;
2451   argv2 = argv + moreargs;
2452   if ( moreargs < argc ) {
2453     if (!strcmp(argv[moreargs],"-")) {
2454 #ifdef  NEED_O_BINARY
2455       setmode(fileno(stdout), O_BINARY);
2456 #endif
2457       global.audio = dup (fileno(stdout));
2458       strncpy( global.fname_base, "standard_output", sizeof(global.fname_base) );
2459       global.fname_base[sizeof(global.fname_base)-1]=0;
2460     } else if (!is_fifo(argv[moreargs])) {
2461         /* we do have at least one argument */
2462         global.multiname = 1;
2463     }
2464   }
2465
2466 #define SETSIGHAND(PROC, SIG, SIGNAME) if (signal(SIG, PROC) == SIG_ERR) \
2467         { fprintf(stderr, "cannot set signal %s handler\n", SIGNAME); exit(SETSIG_ERROR); }
2468     SETSIGHAND(exit_wrapper, SIGINT, "SIGINT")
2469     SETSIGHAND(exit_wrapper, SIGQUIT, "SIGQUIT")
2470     SETSIGHAND(exit_wrapper, SIGTERM, "SIGTERM")
2471     SETSIGHAND(exit_wrapper, SIGHUP, "SIGHUP")
2472
2473     SETSIGHAND(set_nonforked, SIGPIPE, "SIGPIPE")
2474
2475   /* setup interface and open cdrom device */
2476   /* request sychronization facilities and shared memory */
2477   SetupInterface( );
2478
2479   /* use global.useroverlap to set our overlap */
2480   if (global.useroverlap != -1)
2481         global.overlap = global.useroverlap;
2482
2483   /* check for more valid option combinations */
2484
2485   if (global.nsectors < 1+global.overlap) {
2486         fprintf( stderr, "Warning: Setting #nsectors to minimum of %d, due to jitter correction!\n", global.overlap+1);
2487           global.nsectors = global.overlap+1;
2488   }
2489
2490   if (global.overlap > 0 && global.buffers < 2) {
2491         fprintf( stderr, "Warning: Setting #buffers to minimum of 2, due to jitter correction!\n");
2492           global.buffers = 2;
2493   }
2494
2495     /* Value of 'nsectors' must be defined here */
2496
2497     global.shmsize = 0;
2498 #ifdef  USE_PARANOIA
2499     while (global.shmsize < sizeof (struct paranoia_statistics))
2500                 global.shmsize += global.pagesize;
2501 #endif
2502     global.shmsize += 10*global.pagesize;       /* XXX Der Speicherfehler ist nicht in libparanoia sondern in cdda2wav :-( */
2503     global.shmsize += HEADER_SIZE + ENTRY_SIZE_PAGE_AL * global.buffers;
2504
2505 #if     defined (HAVE_FORK_AND_SHAREDMEM)
2506         /*
2507          * The (void *) cast is to avoid a GCC warning like:
2508          * warning: dereferencing type-punned pointer will break strict-aliasing rules
2509          * which does not apply to this code. (void *) introduces a compatible
2510          * intermediate type in the cast list.
2511          */
2512     he_fill_buffer = request_shm_sem(global.shmsize, (unsigned char **)(void *)&he_fill_buffer);
2513     if (he_fill_buffer == NULL) {
2514         fprintf( stderr, "no shared memory available!\n");
2515         exit(SHMMEM_ERROR);
2516     }
2517 #else /* do not have fork() and shared memory */
2518     he_fill_buffer = malloc(global.shmsize);
2519     if (he_fill_buffer == NULL) {
2520         fprintf( stderr, "no buffer memory available!\n");
2521         exit(NOMEM_ERROR);
2522     }
2523 #endif
2524 #ifdef  USE_PARANOIA
2525     {
2526         int     i = 0;
2527
2528         para_stat = (struct paranoia_statistics *)he_fill_buffer;
2529         while (i < sizeof (struct paranoia_statistics)) {
2530                         i += global.pagesize;
2531                         he_fill_buffer += global.pagesize;
2532                         global.shmsize -= global.pagesize;
2533         }
2534     }
2535 #endif
2536
2537     if (global.verbose != 0)
2538          fprintf(stderr,
2539                  "%u bytes buffer memory requested, %d buffers, %d sectors\n",
2540                  global.shmsize, global.buffers, global.nsectors);
2541
2542     /* initialize pointers into shared memory segment */
2543     last_buffer = he_fill_buffer + 1;
2544     total_segments_read = (unsigned long *) (last_buffer + 1);
2545     total_segments_written = total_segments_read + 1;
2546     child_waits = (int *) (total_segments_written + 1);
2547     parent_waits = child_waits + 1;
2548     in_lendian = parent_waits + 1;
2549     eorecording = in_lendian + 1;
2550     *total_segments_read = *total_segments_written = 0;
2551     nSamplesToDo = (unsigned long *)(eorecording + 1);
2552     *eorecording = 0;
2553     *in_lendian = global.in_lendian;
2554
2555     set_total_buffers(global.buffers, sem_id);
2556
2557
2558 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
2559   atexit ( free_sem );
2560 #endif
2561
2562   /*
2563    * set input endian default
2564    */
2565   if (littleendian != -1)
2566     *in_lendian = littleendian;
2567
2568   /* get table of contents */
2569   cdtracks = ReadToc();
2570   if (cdtracks == 0) {
2571     fprintf(stderr, "No track in table of contents! Aborting...\n");
2572     exit(MEDIA_ERROR);
2573   }
2574
2575   calc_cddb_id();
2576   calc_cdindex_id();
2577
2578 #if     1
2579   Check_Toc();
2580 #endif
2581
2582   if (ReadTocText != NULL && FirstAudioTrack () != -1) {
2583         ReadTocText(get_scsi_p());
2584         handle_cdtext();
2585   }
2586   if ( global.verbose == SHOW_JUSTAUDIOTRACKS ) {
2587     unsigned int z;
2588
2589     for (z = 0; z < cdtracks; z++)
2590         if (Get_Datatrack(z) == 0)
2591           printf("%02d\t%06ld\n", Get_Tracknumber(z), Get_AudioStartSector(z));
2592     exit(NO_ERROR);
2593   }
2594
2595   if ( global.verbose != 0 ) {
2596     fputs( "#icedax version ", stderr );
2597     fputs( VERSION, stderr );
2598 #if defined USE_POSIX_PRIORITY_SCHEDULING || defined HAVE_SYS_PRIOCNTL_H
2599     fputs( ", real time sched.", stderr );
2600 #endif
2601 #if defined ECHO_TO_SOUNDCARD
2602     fputs( ", soundcard", stderr );
2603 #endif
2604 #if defined USE_PARANOIA
2605     fputs( ", libparanoia", stderr );
2606 #endif
2607     fputs( " support\n", stderr );
2608   }
2609
2610   FixupTOC(cdtracks + 1);
2611
2612 #if     0
2613   if (!global.paranoia_selected) {
2614     fprintf(stderr, "NICE\n");
2615     /* try to get some extra kicks */
2616     priv_on();
2617     needroot(0);
2618 #if defined HAVE_SETPRIORITY
2619     setpriority(PRIO_PROCESS, 0, -20);
2620 #else
2621 # if defined(HAVE_NICE) && (HAVE_NICE == 1)
2622     nice(-20);
2623 # endif
2624 #endif
2625     priv_off();
2626     dontneedroot();
2627   }
2628 #endif
2629
2630   /* switch cdrom to audio mode */
2631   EnableCdda (get_scsi_p(), 1, CD_FRAMESIZE_RAW);
2632
2633   atexit ( CloseAll );
2634
2635   DisplayToc();
2636   if ( FirstAudioTrack () == -1 ) {
2637     if (no_disguised_audiotracks()) {
2638       FatalError ( "This disk has no audio tracks\n" );
2639     }
2640   }
2641
2642   Read_MCN_ISRC();
2643
2644   /* check if start track is in range */
2645   if ( track < 1 || track > cdtracks ) {
2646     usage2("Incorrect start track setting: %d",track);
2647   }
2648
2649   /* check if end track is in range */
2650   if ( endtrack < track || endtrack > cdtracks ) {
2651     usage2("Incorrect end track setting: %ld",endtrack);
2652   }
2653
2654   do {
2655     lSector = Get_AudioStartSector ( track );
2656     lSector_p1 = Get_EndSector ( track ) + 1;
2657
2658     if ( lSector < 0 ) {
2659       if ( bulk == 0 ) {
2660         FatalError ( "Track %d not found\n", track );
2661       } else {
2662         fprintf(stderr, "Skipping data track %d...\n", track);
2663         if (endtrack == track) endtrack++;
2664         track++;
2665       }
2666     }
2667   } while (bulk != 0 && track <= cdtracks && lSector < 0);
2668
2669   if ((global.illleadout_cd == 0 || global.reads_illleadout != 0) && cd_index != -1) {
2670     if (global.verbose && !global.quiet) {
2671       global.verbose |= SHOW_INDICES;
2672     }
2673     sector_offset += ScanIndices( track, cd_index, bulk );
2674   } else {
2675     cd_index = 1;
2676     if (global.deemphasize || (global.verbose & SHOW_INDICES)) {
2677       ScanIndices( track, cd_index, bulk );
2678     }
2679   }
2680
2681   lSector += sector_offset;
2682   /* check against end sector of track */
2683   if ( lSector >= lSector_p1 ) {
2684     fprintf(stderr, "W Sector offset %lu exceeds track size (ignored)\n", sector_offset );
2685     lSector -= sector_offset;
2686   }
2687
2688   if ( lSector < 0L ) {
2689     fputs( "Negative start sector! Set to zero.\n", stderr );
2690     lSector = 0L;
2691   }
2692
2693   lSector_p2 = Get_LastSectorOnCd( track );
2694   if (bulk == 1 && track == endtrack && rectime == 0.0)
2695      rectime = 99999.0;
2696   if ( rectime == 0.0 ) {
2697     /* set time to track time */
2698     *nSamplesToDo = (lSector_p1 - lSector) * CD_FRAMESAMPLES;
2699     rectime = (lSector_p1 - lSector) / 75.0;
2700     if (CheckTrackrange( track, endtrack) == 1) {
2701       lSector_p2 = Get_EndSector ( endtrack ) + 1;
2702
2703       if (lSector_p2 >= 0) {
2704         rectime = (lSector_p2 - lSector) / 75.0;
2705         *nSamplesToDo = (long)(rectime*44100.0 + 0.5);
2706       } else {
2707         fputs( "End track is no valid audio track (ignored)\n", stderr );
2708       }
2709     } else {
2710       fputs( "Track range does not consist of audio tracks only (ignored)\n", stderr );
2711     }
2712   } else {
2713     /* Prepare the maximum recording duration.
2714      * It is defined as the biggest amount of
2715      * adjacent audio sectors beginning with the
2716      * specified track/index/offset. */
2717
2718     if ( rectime > (lSector_p2 - lSector) / 75.0 ) {
2719       rectime = (lSector_p2 - lSector) / 75.0;
2720       lSector_p1 = lSector_p2;
2721     }
2722
2723     /* calculate # of samples to read */
2724     *nSamplesToDo = (long)(rectime*44100.0 + 0.5);
2725   }
2726
2727   global.OutSampleSize = (1+bits/12);
2728   if (*nSamplesToDo/undersampling == 0L) {
2729       usage2("Time interval is too short. Choose a duration greater than %d.%02d secs!", 
2730                undersampling/44100, (int)(undersampling/44100) % 100);
2731   }
2732   if ( moreargs < argc ) {
2733     if (!strcmp(argv[moreargs],"-") || is_fifo(argv[moreargs])) {
2734       /*
2735        * pipe mode
2736        */
2737       if (bulk == 1) {
2738         fprintf(stderr, "W Bulk mode is disabled while outputting to a %spipe\n",
2739                 is_fifo(argv[moreargs]) ? "named " : "");
2740         bulk = 0;
2741       }
2742       global.no_cddbfile = 1;
2743     }
2744   }
2745   if (global.no_infofile == 0) {
2746     global.no_infofile = 1;
2747     if (global.channels == 1 || bits != 16 || rate != 44100) {
2748       fprintf(stderr, "W Sample conversions disable generation of info files!\n");
2749     } else if (waitforsignal == 1) {
2750       fprintf(stderr, "W Option -w 'wait for signal' disables generation of info files!\n");
2751     } else if (sector_offset != 0) {
2752       fprintf(stderr, "W Using an start offset (option -o) disables generation of info files!\n");
2753     } else if (!bulk &&
2754       !((lSector == Get_AudioStartSector(track)) &&
2755         ((long)(lSector + rectime*75.0 + 0.5) == Get_EndSector(track) + 1))) {
2756       fprintf(stderr, "W Duration is not set for complete tracks (option -d), this disables generation\n  of info files!\n");
2757     } else {
2758       global.no_infofile = 0;
2759     }
2760   }
2761
2762   SamplesToWrite = *nSamplesToDo*2/(int)int_part;
2763
2764   {
2765         int first = FirstAudioTrack();
2766         tracks_included = Get_Track(
2767               (unsigned) (lSector + *nSamplesToDo/CD_FRAMESAMPLES -1))
2768                                      - max((int)track,first) +1;
2769   }
2770
2771   if (global.multiname != 0 && moreargs + tracks_included > argc) {
2772         global.multiname = 0;
2773   }
2774
2775   if ( !waitforsignal ) {
2776
2777 #ifdef INFOFILES
2778       if (!global.no_infofile) {
2779         int i;
2780
2781         for (i = track; i < (int)track + tracks_included; i++) {
2782                 unsigned minsec, maxsec;
2783                 char *tmp_fname;
2784
2785                 /* build next filename */
2786
2787                 tmp_fname = get_next_name();
2788                 if (tmp_fname != NULL)
2789                   strncpy( global.fname_base, tmp_fname, sizeof(global.fname_base)-8 );
2790                 global.fname_base[sizeof(global.fname_base)-1]=0;
2791                 minsec = max(lSector, Get_AudioStartSector(i));
2792                 maxsec = min(lSector + rectime*75.0 + 0.5, 1+Get_EndSector(i));
2793                 if ((int)minsec == Get_AudioStartSector(i) &&
2794                     (int)maxsec == 1+Get_EndSector(i)) {
2795                         write_info_file(global.fname_base,i,(maxsec-minsec)*CD_FRAMESAMPLES, bulk && global.multiname == 0);
2796                 } else {
2797                         fprintf(stderr,
2798                                  "Partial length copy for track %d, no info file will be generated for this track!\n", i);
2799                 }
2800                 if (!bulk) break;
2801         }
2802         reset_name_iterator();
2803       }
2804 #endif
2805
2806   }
2807
2808   if (global.just_the_toc) exit(NO_ERROR);
2809
2810 #ifdef  ECHO_TO_SOUNDCARD
2811   if (user_sound_device[0] != '\0') {
2812       set_snd_device(user_sound_device);
2813   }
2814   init_soundcard(rate, bits);
2815 #endif /* ECHO_TO_SOUNDCARD */
2816
2817   if (global.userspeed > -1)
2818      global.speed = global.userspeed;
2819
2820   if (global.speed != 0 && SelectSpeed != NULL) {
2821      SelectSpeed(get_scsi_p(), global.speed);
2822   }
2823
2824   current_track = track;
2825
2826   if ( !global.no_file ) {
2827     {
2828       char *myfname;
2829
2830       myfname = get_next_name();
2831
2832       if (myfname != NULL) {
2833         strncpy( global.fname_base, myfname, sizeof(global.fname_base)-8 );
2834         global.fname_base[sizeof(global.fname_base)-1]=0;
2835       }
2836     }
2837
2838     /* strip audio_type extension */
2839     {
2840       char *cp = global.fname_base;
2841
2842       cp = strrchr(cp, '.');
2843       if (cp == NULL) {
2844         cp = global.fname_base + strlen(global.fname_base);
2845       }
2846       *cp = '\0';
2847     }
2848     if (bulk && global.multiname == 0) {
2849       sprintf(fname, "%s_%02u.%s",global.fname_base,current_track,audio_type);
2850     } else {
2851       sprintf(fname, "%s.%s",global.fname_base,audio_type);
2852     }
2853
2854     OpenAudio( fname, rate, bits, global.channels, 
2855               (unsigned)(SamplesToWrite*global.OutSampleSize*global.channels),
2856                 global.audio_out);
2857   }
2858
2859   global.Remainder = (75 % global.nsectors)+1;
2860
2861   global.sh_bits = 16 - bits;           /* shift counter */
2862
2863   global.iloop = *nSamplesToDo;
2864   if (Halved && (global.iloop&1))
2865       global.iloop += 2;
2866
2867   BeginAtSample = lSector * CD_FRAMESAMPLES;
2868
2869 #if     1
2870         if ( (global.verbose & SHOW_SUMMARY) && !global.just_the_toc &&
2871              (global.reads_illleadout == 0 ||
2872               lSector+*nSamplesToDo/CD_FRAMESAMPLES
2873                <= (unsigned) Get_AudioStartSector(cdtracks-1))) {
2874
2875                 fprintf(stderr, "samplefile size will be %lu bytes.\n",
2876                         global.audio_out->GetHdrSize() +
2877                         global.audio_out->InSizeToOutSize(SamplesToWrite*global.OutSampleSize*global.channels)  ); 
2878                 fprintf (stderr, "recording %d.%04d seconds %s with %d bits @ %5d.%01d Hz"
2879                         ,(int)rectime , (int)(rectime * 10000) % 10000,
2880                         global.channels == 1 ? "mono":"stereo", bits, (int)rate, (int)(rate*10)%10);
2881                 if (!global.no_file && *global.fname_base)
2882                         fprintf(stderr, " ->'%s'...", global.fname_base );
2883                 fputs("\n", stderr);
2884         }
2885 #endif
2886
2887 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
2888 #else
2889         init_pipes();
2890 #endif
2891
2892 #ifdef  USE_PARANOIA
2893         if (global.paranoia_selected) {
2894                 long paranoia_mode;
2895
2896                 global.cdp = paranoia_init(get_scsi_p(), global.nsectors);
2897
2898                 if (global.paranoia_parms.overlap >= 0) {
2899                         int     overlap = global.paranoia_parms.overlap;
2900
2901                         if (overlap > global.nsectors - 1) 
2902                                 overlap = global.nsectors - 1;
2903                         paranoia_overlapset(global.cdp, overlap);
2904                 }
2905                 /*
2906                  * Default to a  minimum of dynamic overlapping == 0.5 sectors.
2907                  * If we don't do this, we get the default from libparanoia
2908                  * which is approx. 0.1.
2909                  */
2910                 if (global.paranoia_parms.mindynoverlap < 0)
2911                         paranoia_dynoverlapset(global.cdp, CD_FRAMEWORDS/2, -1);
2912                 paranoia_dynoverlapset(global.cdp,
2913                         global.paranoia_parms.mindynoverlap * CD_FRAMEWORDS,
2914                         global.paranoia_parms.maxdynoverlap * CD_FRAMEWORDS);
2915
2916                 paranoia_mode = PARANOIA_MODE_FULL ^ PARANOIA_MODE_NEVERSKIP;
2917
2918                 if (global.paranoia_parms.disable_paranoia) {
2919                         paranoia_mode = PARANOIA_MODE_DISABLE;
2920                 }
2921                 if (global.paranoia_parms.disable_extra_paranoia) {
2922                         paranoia_mode |= PARANOIA_MODE_OVERLAP;
2923                         paranoia_mode &= ~PARANOIA_MODE_VERIFY;
2924                 }
2925                 /* not yet implemented */
2926                 if (global.paranoia_parms.disable_scratch_detect) {
2927                         paranoia_mode &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);
2928                 }
2929                 /* not yet implemented */
2930                 if (global.paranoia_parms.disable_scratch_repair) {
2931                         paranoia_mode &= ~PARANOIA_MODE_REPAIR;
2932                 }
2933
2934                 paranoia_modeset(global.cdp, paranoia_mode);
2935                 if (global.verbose)
2936                         fprintf(stderr, "using lib paranoia for reading.\n");
2937                 paranoia_seek(global.cdp, lSector, SEEK_SET);
2938                 paranoia_reset();
2939         }
2940 #endif
2941 #if defined(HAVE_FORK_AND_SHAREDMEM)
2942
2943         /* Everything is set up. Now fork and let one process read cdda sectors
2944            and let the other one store them in a wav file */
2945
2946         /* forking */
2947         child_pid = fork();
2948         if (child_pid > 0 && global.gui > 0 && global.verbose > 0)
2949                 fprintf( stderr, "child pid is %d\n", child_pid);
2950
2951         /*********************** fork **************************************/
2952         if (child_pid == 0) {
2953                 /* child WRITER section */
2954
2955 #ifdef  HAVE_AREAS
2956                 /* Under BeOS a fork() with shared memory does not work as
2957                  * it does under System V Rel. 4. The mapping of the child
2958                  * works with copy on write semantics, so changes do not propagate
2959                  * back and forth. The existing mapping has to be deleted
2960                  * and replaced by an clone without copy on write semantics.
2961                  * This is done with clone_area(...,B_CLONE_ADDRESS,...).
2962                  * Thanks to file support.c from the postgreSQL project.
2963                  */
2964                 area_info inf;
2965                 int32 cook = 0;
2966                 /* iterate over all mappings to find our shared memory mapping. */
2967                 while (get_next_area_info(0, &cook, &inf) == B_OK)
2968                 {
2969                         /* check the name of the mapping. */
2970                         if (!strcmp(inf.name, AREA_NAME))
2971                         {
2972                                 void *area_address;
2973                                 area_id area_parent;
2974
2975                                 /* kill the cow mapping. */
2976                                 area_address = inf.address;
2977                                 if (B_OK != delete_area(inf.area))
2978                                 {
2979                                         fprintf(stderr, "delete_area: no valid area.\n");
2980                                         exit(SHMMEM_ERROR);
2981                                 }
2982                                 /* get the parent mapping. */
2983                                 area_parent = find_area(inf.name);
2984                                 if (area_parent == B_NAME_NOT_FOUND)
2985                                 {
2986                                         fprintf(stderr, "find_area: no such area name.\n");
2987                                         exit(SHMMEM_ERROR);
2988                                 }
2989                                 /* clone the parent mapping without cow. */
2990                                 if (B_OK > clone_area("shm_child", &area_address, B_CLONE_ADDRESS,
2991                                         B_READ_AREA | B_WRITE_AREA, area_parent))
2992                                 {
2993                                         fprintf(stderr,"clone_area failed\n");
2994                                         exit(SHMMEM_ERROR);
2995                                 }
2996                         }
2997                 }
2998 #endif
2999 #ifdef  __EMX__
3000                 if (DosGetSharedMem(he_fill_buffer, 3)) {
3001                         comerr("DosGetSharedMem() failed.\n");
3002                 }
3003 #endif
3004                 global.have_forked = 1;
3005                 forked_write();
3006 #ifdef  __EMX__
3007                 DosFreeMem(he_fill_buffer);
3008                 _exit(NO_ERROR);
3009                 /* NOTREACHED */
3010 #endif
3011                 exit_wrapper(NO_ERROR);
3012                 /* NOTREACHED */
3013         } else if (child_pid > 0) {
3014                 /* parent READER section */
3015     
3016                 global.have_forked = 1;
3017                 switch_to_realtime_priority();
3018
3019                 forked_read();
3020 #ifdef  HAVE_AREAS
3021                 {
3022                         area_id aid;
3023                         aid = find_area(AREA_NAME);
3024                         if (aid < B_OK) {
3025                                 comerrno(aid, "find_area() failed.\n");
3026                         }
3027                         delete_area(aid);
3028                 }
3029 #endif
3030 #ifdef  __EMX__
3031                 DosFreeMem(he_fill_buffer);
3032 #endif
3033                 exit_wrapper(NO_ERROR);
3034                 /* NOTREACHED */
3035         } else
3036                 perror("fork error.");
3037
3038 #endif
3039         /* version without fork */
3040         {
3041                 global.have_forked = 0;
3042 #if     0
3043                 if (!global.paranoia_selected) {
3044                         fprintf(stderr, "REAL\n");
3045                         switch_to_realtime_priority();
3046                 }
3047 #endif
3048                 fprintf(stderr, "a nonforking version is running...\n");
3049                 nonforked_loop();
3050                 exit_wrapper(NO_ERROR);
3051                 /* NOTREACHED */
3052         }
3053 #ifdef  USE_PARANOIA
3054         if (global.paranoia_selected)
3055                 paranoia_free(global.cdp);
3056 #endif
3057
3058         return 0;
3059 }