1 /* @(#)cdda2wav.c 1.174 20/02/26 Copyright 1993-2004,2015,2017 Heiko Eissfeldt, Copyright 2004-2020 J. Schilling */
2 #include "config.h"
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)cdda2wav.c 1.174 20/02/26 Copyright 1993-2004,2015,2017 Heiko Eissfeldt, Copyright 2004-2020 J. Schilling";
6
7 #endif
8 #undef DEBUG_BUFFER_ADDRESSES
9 #undef GPROF
10 #undef DEBUG_FORKED
11 #undef DEBUG_CLEANUP
12 #undef DEBUG_DYN_OVERLAP
13 #undef DEBUG_READS
14
15 #define DEBUG_ILLLEADOUT 0 /* 0 disables, 1 enables */
16 /*
17 * The contents of this file are subject to the terms of the
18 * Common Development and Distribution License, Version 1.0 only
19 * (the "License"). You may not use this file except in compliance
20 * with the License.
21 *
22 * See the file CDDL.Schily.txt in this distribution for details.
23 * A copy of the CDDL is also available via the Internet at
24 * http://www.opensource.org/licenses/cddl1.txt
25 *
26 * When distributing Covered Code, include this CDDL HEADER in each
27 * file and include the License file CDDL.Schily.txt from this distribution.
28 */
29 /*
30 * Copright 1993-2004,2015,2017 (C) Heiko Eissfeldt
31 * Copright 2004-2020 (C) J. Schilling
32 *
33 * last changes:
34 * 18.12.93 - first version, OK
35 * 01.01.94 - generalized & clean up HE
36 * 10.06.94 - first linux version HE
37 * 12.06.94 - wav header alignment problem fixed HE
38 * 12.08.94 - open the cdrom device O_RDONLY makes more sense :-)
39 * no more floating point math
40 * change to sector size 2352 which is more common
41 * sub-q-channel information per kernel ioctl requested
42 * doesn't work as well as before
43 * some new options (-max -i)
44 * 01.02.95 - async i/o via semaphores and shared memory
45 * 03.02.95 - overlapped reading on sectors
46 * 03.02.95 - generalized sample rates. all integral divisors are legal
47 * 04.02.95 - sun format added
48 * more divisors: all integral halves >= 1 allowed
49 * floating point math needed again
50 * 06.02.95 - bugfix for last track and not d0
51 * tested with photo-cd with audio tracks
52 * tested with xa disk
53 * 29.01.96 - new options for bulk transfer
54 * 01.06.96 - tested with enhanced cd
55 * 01.06.96 - tested with cd-plus
56 * 02.06.96 - support pipes
57 * 02.06.96 - support raw format
58 * 04.02.96 - security hole fixed
59 * 22.04.97 - large parts rewritten
60 * 28.04.97 - make file names DOS compatible
61 * 01.09.97 - add speed control
62 * 20.10.97 - add find mono option
63 * Jan/Feb 98 - conversion to use Joerg Schillings SCSI library
64 * see ChangeLog
65 */
66
67 #include "config.h"
68
69 #include <schily/unistd.h>
70 #include <schily/stdio.h>
71 #include <schily/standard.h>
72 #include <schily/stdlib.h>
73 #include <schily/string.h>
74 #include <schily/nlsdefs.h>
75 #include <schily/signal.h>
76 #include <schily/math.h>
77 #include <schily/fcntl.h>
78 #include <schily/time.h>
79 #include <schily/limits.h>
80 #include <schily/ioctl.h>
81 #include <schily/errno.h>
82 #include <schily/stat.h>
83 #include <schily/wait.h>
84 #include <schily/resource.h>
85 #include <schily/varargs.h>
86 #include <schily/maxpath.h>
87 #include <schily/btorder.h>
88 #include <schily/io.h> /* for setmode() prototype */
89 #include <schily/priv.h> /* To get PRIV_PFEXEC definition */
90 #include <schily/schily.h>
91
92 #include <scg/scsitransp.h>
93
94 #ifdef HAVE_AREAS
95 #ifdef HAVE_OS_H
96 #include <OS.h>
97 #else
98 #include <be/kernel/OS.h>
99 #endif
100 #endif
101
102 #include "mytype.h"
103 #include "sndconfig.h"
104
105 #include "semshm.h" /* semaphore functions */
106 #include "sndfile.h"
107 #include "wav.h" /* wav file header structures */
108 #include "sun.h" /* sun audio file header structures */
109 #include "raw.h" /* raw file handling */
110 #include "aiff.h" /* aiff file handling */
111 #include "aifc.h" /* aifc file handling */
112 #ifdef USE_LAME
113 #include "mp3.h" /* mp3 file handling */
114 #endif
115 #include "interface.h" /* low level cdrom interfacing */
116 #include "cdda2wav.h"
117 #include "cdrecord.h" /* Only for getnum() */
118 #include "resample.h"
119 #include "toc.h"
120 #include "setuid.h"
121 #include "ringbuff.h"
122 #include "global.h"
123 #include "exitcodes.h"
124 #ifdef USE_PARANOIA
125 #include "cdda_paranoia.h"
126 #endif
127 #include "parse.h"
128 #include "cdrdeflt.h"
129 #include "version.h"
130
131 #ifdef VMS
132 #include <vms_init.h>
133 #define open(n, p, m) (open)((n), (p), (m), \
134 "ctx=bin", "rfm=fix", "mrs=512", \
135 "acc", acc_cb, &open_id)
136 #endif
137
138 EXPORT int main __PR((int argc, char **argv));
139 #ifdef ECHO_TO_SOUNDCARD
140 LOCAL void RestrictPlaybackRate __PR((long newrate));
141 #endif
142 LOCAL void output_indices __PR((FILE *fp, index_list *p,
143 unsigned trackstart));
144 LOCAL FILE *info_file_open __PR((char *fname_baseval,
145 unsigned int track,
146 BOOL doappend,
147 BOOL numbered));
148 LOCAL FILE *cue_file_open __PR((char *fname_baseval));
149 LOCAL void get_datetime __PR((char *datetime, int size));
150 LOCAL int write_info_file __PR((char *fname_baseval,
151 unsigned int track,
152 unsigned long SamplesDone,
153 int numbered));
154 LOCAL int write_md5_info __PR((char *fname_baseval,
155 unsigned int track,
156 BOOL numbered));
157 LOCAL void write_cue_global __PR((FILE *cuef, char *fname_baseval));
158 LOCAL char *index_str __PR((long sector));
159 LOCAL void write_cue_track __PR((FILE *cuef, char *fname_baseval,
160 unsigned int track));
161 LOCAL void CloseAudio __PR((int channels_val,
162 unsigned long nSamples,
163 struct soundfile *audio_out));
164 LOCAL void CloseAll __PR((void));
165 LOCAL void OpenAudio __PR((char *fname, double rate,
166 long nBitsPerSample,
167 long channels_val,
168 unsigned long expected_bytes,
169 struct soundfile *audio_out));
170 LOCAL void set_offset __PR((myringbuff *p, int offset));
171 LOCAL int get_offset __PR((myringbuff *p));
172 LOCAL void usage __PR((void));
173 LOCAL void prdefaults __PR((FILE *f));
174 LOCAL void init_globals __PR((void));
175 LOCAL int is_fifo __PR((char * filename));
176 LOCAL const char *get_audiotype __PR((void));
177 LOCAL void priv_warn __PR((const char *what, const char *msg));
178 LOCAL void gargs __PR((int argc, char *argv[]));
179
180
181 /*
182 * Rules:
183 * unique parameterless options first,
184 * unique parametrized option names next,
185 * ambigious parameterless option names next,
186 * ambigious string parametrized option names last
187 */
188 /* BEGIN CSTYLED */
189 LOCAL const char *opts = "paranoia,paraopts&,version,help,h,\
190 no-write,N,dump-rates,R,bulk,B,alltracks,verbose-scsi+,V+,\
191 find-extremes,F,find-mono,G,no-infofile,H,no-textdefaults,\
192 no-textfile,cuefile,no-hidden-track,\
193 deemphasize,T,info-only,J,silent-scsi,Q,\
194 cddbp-server*,cddbp-port*,\
195 scanbus,device*,dev*,D*,scgopts*,debug#,debug-scsi#,kdebug#,kd#,kdebug-scsi#,ts&,\
196 auxdevice*,A*,interface*,I*,output-format*,O*,\
197 output-endianess*,E*,cdrom-endianess*,C*,speed#,S#,\
198 playback-realtime#L,p#L,md5,M,set-overlap#,P#,sound-device*,K*,\
199 cddb#,L#,channels*,c*,bits-per-sample#,b#,rate#,r#,gui,g,\
200 divider*,a*,track*,t*,index#,i#,duration*,d*,offset#L,o#L,start-sector#L,\
201 sectors-per-request#,n#,verbose-level&,v&,buffers-in-ring#,l#,\
202 stereo,s,mono,m,wait,w,echo,e,quiet,q,max,x,out-fd#,audio-fd#,no-fork,interactive\
203 ";
204 /* END CSTYLED */
205
206
207 /*
208 * Global variables
209 */
210 EXPORT global_t global;
211
212 /*
213 * Local variables
214 */
215 LOCAL unsigned long nSamplesDone = 0;
216 LOCAL unsigned long *nSamplesToDo;
217 LOCAL unsigned int current_track_reading;
218 LOCAL unsigned int current_track_writing;
219 LOCAL int bulk = 0;
220
221 unsigned int get_current_track_writing __PR((void));
222
223 unsigned int
get_current_track_writing()224 get_current_track_writing()
225 {
226 return (current_track_writing);
227 }
228
229 #ifdef ECHO_TO_SOUNDCARD
230 LOCAL void
RestrictPlaybackRate(newrate)231 RestrictPlaybackRate(newrate)
232 long newrate;
233 {
234 global.playback_rate = newrate;
235
236 /*
237 * filter out insane values
238 */
239 if (global.playback_rate < 25)
240 global.playback_rate = 25;
241 if (global.playback_rate > 250)
242 global.playback_rate = 250;
243
244 if (global.playback_rate < 100)
245 global.nsectors = (global.nsectors*global.playback_rate)/100;
246 }
247 #endif
248
249 long
SamplesNeeded(amount,undersampling_val)250 SamplesNeeded(amount, undersampling_val)
251 long amount;
252 long undersampling_val;
253 {
254 long retval = ((undersampling_val * 2 + Halved) * amount) / 2;
255
256 if (Halved && (*nSamplesToDo & 1))
257 retval += 2;
258 return (retval);
259 }
260
261 LOCAL int argc2;
262 LOCAL int argc3;
263 LOCAL char **argv2;
264
265 LOCAL void reset_name_iterator __PR((void));
266 LOCAL void
reset_name_iterator()267 reset_name_iterator()
268 {
269 argv2 -= argc3 - argc2;
270 argc2 = argc3;
271 }
272
273 LOCAL char *get_next_name __PR((void));
274 LOCAL char
get_next_name()275 *get_next_name()
276 {
277 if (argc2 > 0) {
278 argc2--;
279 return (*argv2++);
280 } else {
281 return (NULL);
282 }
283 }
284
285 LOCAL char *cut_extension __PR((char * fname));
286
287 LOCAL char
cut_extension(fname)288 *cut_extension(fname)
289 char *fname;
290 {
291 char *pp;
292
293 pp = strrchr(fname, '.');
294
295 if (pp == NULL) {
296 pp = fname + strlen(fname);
297 }
298 *pp = '\0';
299
300 return (pp);
301 }
302
303 #ifdef INFOFILES
304 LOCAL void
output_indices(fp,p,trackstart)305 output_indices(fp, p, trackstart)
306 FILE *fp;
307 index_list *p;
308 unsigned trackstart;
309 {
310 int ci;
311
312 fprintf(fp, "Index=\t\t");
313
314 if (p == NULL) {
315 fprintf(fp, "0\n");
316 return;
317 }
318
319 for (ci = 1; p != NULL; ci++, p = p->next) {
320 int frameoff = p->frameoffset;
321
322 if (p->next == NULL)
323 fputs("\nIndex0=\t\t", fp);
324 #if 0
325 else if (ci > 8 && (ci % 8) == 1)
326 fputs("\nIndex =\t\t", fp);
327 #endif
328 if (frameoff != -1)
329 fprintf(fp, "%d ", frameoff - trackstart);
330 else
331 fprintf(fp, "-1 ");
332 }
333 fputs("\n", fp);
334 }
335
336 LOCAL FILE *
info_file_open(fname_baseval,track,doappend,numbered)337 info_file_open(fname_baseval, track, doappend, numbered)
338 char *fname_baseval;
339 unsigned int track;
340 BOOL doappend;
341 BOOL numbered;
342 {
343 char fname[PATH_MAX+1];
344
345 /*
346 * write info file
347 */
348 if (strcmp(fname_baseval, "-") == 0)
349 return ((FILE *)0);
350
351 strncpy(fname, fname_baseval, sizeof (fname) -1);
352 fname[sizeof (fname) -1] = 0;
353 if (numbered)
354 sprintf(cut_extension(fname), "_%02u.inf", track);
355 else
356 strcpy(cut_extension(fname), ".inf");
357
358 return (fopen(fname, doappend ? "a" : "w"));
359 }
360
361 LOCAL FILE *
cue_file_open(fname_baseval)362 cue_file_open(fname_baseval)
363 char *fname_baseval;
364 {
365 char fname[PATH_MAX+1];
366
367 /*
368 * write info file
369 */
370 if (strcmp(fname_baseval, "-") == 0)
371 return ((FILE *)0);
372
373 strncpy(fname, fname_baseval, sizeof (fname) -1);
374 fname[sizeof (fname) -1] = 0;
375 strcpy(cut_extension(fname), ".cue");
376
377 return (fopen(fname, "w"));
378 }
379
380 LOCAL void
get_datetime(datetime,size)381 get_datetime(datetime, size)
382 char *datetime;
383 int size;
384 {
385 time_t utc_time;
386 struct tm *tmptr;
387
388 utc_time = time(NULL);
389 tmptr = localtime(&utc_time);
390 if (tmptr) {
391 strftime(datetime, size, "%x %X", tmptr);
392 } else {
393 strlcpy(datetime, "unknown", size);
394 }
395 }
396
397 /*
398 * write information before the start of the sampling process
399 *
400 *
401 * uglyfied for Joerg Schillings ultra dumb line parser
402 */
403 LOCAL int
write_info_file(fname_baseval,track,SamplesDone,numbered)404 write_info_file(fname_baseval, track, SamplesDone, numbered)
405 char *fname_baseval;
406 unsigned int track;
407 unsigned long SamplesDone;
408 int numbered;
409 {
410 FILE *info_fp;
411 char datetime[30];
412 time_t utc_time;
413 struct tm *tmptr;
414
415 /*
416 * write info file
417 */
418 if (strcmp(fname_baseval, "-") == 0)
419 return (0);
420
421 info_fp = info_file_open(fname_baseval, track, FALSE, numbered);
422 if (!info_fp)
423 return (-1);
424
425 utc_time = time(NULL);
426 tmptr = localtime(&utc_time);
427 if (tmptr) {
428 strftime(datetime, sizeof (datetime), "%x %X", tmptr);
429 } else {
430 strncpy(datetime, "unknown", sizeof (datetime));
431 }
432 fprintf(info_fp, "#created by cdda2wav %s %s%s %s\n#\n",
433 VERSION_DATE,
434 VERSION,
435 VERSION_OS,
436 datetime);
437 fprintf(info_fp, "CDINDEX_DISCID=\t'%s'\n", global.cdindex_id);
438 /* BEGIN CSTYLED */
439 fprintf(info_fp,
440 "CDDB_DISCID=\t0x%08lx\n\
441 MCN=\t\t%s\n\
442 ISRC=\t\t%15.15s\n\
443 #\n",
444 (unsigned long) global.cddb_id,
445 Get_MCN(),
446 Get_ISRC(track));
447 /* END CSTYLED */
448
449 fprintf(info_fp, "Albumperformer=\t'%s'\n",
450 global.performer != NULL ?
451 global.performer : (const unsigned char *)"");
452 fprintf(info_fp, "Performer=\t'%s'\n",
453 global.trackperformer[track] != NULL ?
454 global.trackperformer[track] :
455 (global.no_textdefaults == 0 && global.performer != NULL ?
456 global.performer : (const unsigned char *)""));
457
458 fprintf(info_fp, "Albumsongwriter='%s'\n",
459 global.songwriter != NULL ?
460 global.songwriter : (const unsigned char *)"");
461 fprintf(info_fp, "Songwriter=\t'%s'\n",
462 global.tracksongwriter[track] != NULL ?
463 global.tracksongwriter[track] :
464 (global.no_textdefaults == 0 && global.songwriter != NULL ?
465 global.songwriter : (const unsigned char *)""));
466
467 fprintf(info_fp, "Albumcomposer=\t'%s'\n",
468 global.composer != NULL ?
469 global.composer : (const unsigned char *)"");
470 fprintf(info_fp, "Composer=\t'%s'\n",
471 global.trackcomposer[track] != NULL ?
472 global.trackcomposer[track] :
473 (global.no_textdefaults == 0 && global.composer != NULL ?
474 global.composer : (const unsigned char *)""));
475
476 fprintf(info_fp, "Albumarranger=\t'%s'\n",
477 global.arranger != NULL ?
478 global.arranger : (const unsigned char *)"");
479 fprintf(info_fp, "Arranger=\t'%s'\n",
480 global.trackarranger[track] != NULL ?
481 global.trackarranger[track] :
482 (global.no_textdefaults == 0 && global.arranger != NULL ?
483 global.arranger : (const unsigned char *)""));
484
485 fprintf(info_fp, "Albummessage=\t'%s'\n",
486 global.message != NULL ?
487 global.message : (const unsigned char *)"");
488 fprintf(info_fp, "Message=\t'%s'\n",
489 global.trackmessage[track] != NULL ?
490 global.trackmessage[track] :
491 (global.no_textdefaults == 0 && global.message != NULL ?
492 global.message : (const unsigned char *)""));
493
494 fprintf(info_fp, "Albumclosed_info='%s'\n",
495 global.closed_info != NULL ?
496 global.closed_info : (const unsigned char *)"");
497 fprintf(info_fp, "Closed_info=\t'%s'\n",
498 global.trackclosed_info[track] != NULL ?
499 global.trackclosed_info[track] :
500 (global.no_textdefaults == 0 && global.closed_info != NULL ?
501 global.closed_info : (const unsigned char *)""));
502
503 fprintf(info_fp, "Albumtitle=\t'%s'\n",
504 global.disctitle != NULL ?
505 global.disctitle : (const unsigned char *)"");
506 fprintf(info_fp, "Tracktitle=\t'%s'\n",
507 global.tracktitle[track] ?
508 global.tracktitle[track] : (const unsigned char *)"");
509
510 fprintf(info_fp, "Track=\t\t%u\n", track);
511 fprintf(info_fp, "Tracknumber=\t%u\n", Get_Tracknumber(track));
512 fprintf(info_fp, "Trackstart=\t%ld\n", Get_AudioStartSector(track));
513 fprintf(info_fp,
514 "# track length in sectors (1/75 seconds each), rest samples\nTracklength=\t%ld, %d\n",
515 SamplesDone/588L, (int)(SamplesDone%588));
516 fprintf(info_fp, "Pre-emphasis=\t%s\n",
517 Get_Preemphasis(track) && (global.deemphasize == 0) ?
518 "yes" : "no");
519 fprintf(info_fp, "Channels=\t%d\n",
520 Get_Channels(track) ? 4 : global.channels == 2 ? 2 : 1);
521
522 { int cr = Get_Copyright(track);
523
524 fputs("Copy_permitted=\t", info_fp);
525 switch (cr) {
526 case 0:
527 fputs("once (copyright protected)\n", info_fp);
528 break;
529 case 1:
530 fputs("no (SCMS first copy, not made by copyright holder)\n", info_fp);
531 break;
532 case 2:
533 fputs("yes (not copyright protected)\n",
534 info_fp);
535 break;
536 default:
537 fputs("unknown\n", info_fp);
538 }
539 }
540 fprintf(info_fp, "Endianess=\t%s\n",
541 global.need_big_endian ? "big" : "little");
542 fprintf(info_fp, "# index list\n");
543 output_indices(info_fp, global.trackindexlist[track],
544 Get_AudioStartSector(track));
545
546 fclose(info_fp);
547 return (0);
548 }
549
550 LOCAL int
write_md5_info(fname_baseval,track,numbered)551 write_md5_info(fname_baseval, track, numbered)
552 char *fname_baseval;
553 unsigned int track;
554 BOOL numbered;
555 {
556 #ifdef MD5_SIGNATURES
557 FILE *info_fp;
558
559 /*
560 * write info file
561 */
562 if (strcmp(fname_baseval, "-") == 0)
563 return (0);
564
565 info_fp = info_file_open(fname_baseval, track, TRUE, numbered);
566 if (!info_fp)
567 return (-1);
568
569 if (global.md5blocksize)
570 MD5Final(global.MD5_result, global.context);
571
572 fprintf(info_fp,
573 "# md5 sum\nMD5-offset=\t%d\n", global.md5offset);
574 if (global.md5blocksize) {
575 fprintf(info_fp,
576 "MD5-size=\t%d\n", global.md5size);
577 fprintf(info_fp,
578 "MD5-sum=\t%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
579 global.MD5_result[0],
580 global.MD5_result[1],
581 global.MD5_result[2],
582 global.MD5_result[3],
583 global.MD5_result[4],
584 global.MD5_result[5],
585 global.MD5_result[6],
586 global.MD5_result[7],
587 global.MD5_result[8],
588 global.MD5_result[9],
589 global.MD5_result[10],
590 global.MD5_result[11],
591 global.MD5_result[12],
592 global.MD5_result[13],
593 global.MD5_result[14],
594 global.MD5_result[15]);
595 }
596 fclose(info_fp);
597 #endif
598 return (0);
599 }
600 #endif /* INFOFILES */
601
602 LOCAL void
write_cue_global(cuef,fname_baseval)603 write_cue_global(cuef, fname_baseval)
604 FILE *cuef;
605 char *fname_baseval;
606 {
607 char datetime[30];
608 char fname[200];
609
610 if (cuef == NULL)
611 return;
612
613 get_datetime(datetime, sizeof (datetime));
614
615 fprintf(cuef, "REM created by cdda2wav %s %s%s %s\n",
616 VERSION_DATE,
617 VERSION,
618 VERSION_OS,
619 datetime);
620 fprintf(cuef, "REM CDRTOOLS\n");
621 fprintf(cuef, "REM\n");
622
623 if (Get_MCN()[0] != '\0')
624 fprintf(cuef, "CATALOG %s\n", Get_MCN());
625 if (global.did_textfile) {
626 char *pp;
627
628 strncpy(fname, fname_baseval, sizeof (fname) -1);
629 fname[sizeof (fname) -1] = 0;
630 pp = strrchr(fname, '.');
631 if (pp == NULL)
632 pp = fname + strlen(fname);
633 strncpy(pp, ".cdtext", sizeof (fname) - 1 - (pp - fname));
634 fprintf(cuef, "CDTEXTFILE \"%s\"\n", fname);
635 }
636 if (global.performer)
637 fprintf(cuef, "PERFORMER \"%s\"\n", global.performer);
638 if (global.songwriter)
639 fprintf(cuef, "SONGWRITER \"%s\"\n", global.songwriter);
640 if (global.disctitle)
641 fprintf(cuef, "TITLE \"%s\"\n", global.disctitle);
642
643 /*
644 * If we allow to wite cue files with -B, we need to remove the FILE
645 * entry here.
646 */
647 snprintf(fname, sizeof (fname),
648 "%s.%s",
649 global.fname_base,
650 get_audiotype());
651 fprintf(cuef, "FILE \"%s\" %s\n", fname, global.audio_out->auf_cuename);
652 }
653
654 LOCAL char *
index_str(sector)655 index_str(sector)
656 long sector;
657 {
658 static char strbuf[10];
659 long val;
660
661 val = sector / (60 * 75);
662 if (val > 99)
663 return ("err");
664 strbuf[0] = (val / 10) + '0';
665 strbuf[1] = (val % 10) + '0';
666 strbuf[2] = ':';
667
668 sector = sector % (60 * 75);
669 val = sector / 75;
670 strbuf[3] = (val / 10) + '0';
671 strbuf[4] = (val % 10) + '0';
672 strbuf[5] = ':';
673
674 val = sector % 75;
675 strbuf[6] = (val / 10) + '0';
676 strbuf[7] = (val % 10) + '0';
677 strbuf[8] = '\0';
678
679 return (strbuf);
680 }
681
682 LOCAL void
write_cue_track(cuef,fname_baseval,track)683 write_cue_track(cuef, fname_baseval, track)
684 FILE *cuef;
685 char *fname_baseval;
686 unsigned int track;
687 {
688 long off_01;
689 int i;
690 index_list *ip;
691
692 if (cuef == NULL)
693 return;
694 if (track == 0)
695 return;
696
697 /*
698 * If we allow to write cue files with -B, we need to add the FILE
699 * entry here.
700 */
701
702 fprintf(cuef, " TRACK %2.2d AUDIO\n", Get_Tracknumber(track));
703 if (global.tracktitle[track])
704 fprintf(cuef, " TITLE \"%s\"\n", global.tracktitle[track]);
705 if (global.trackperformer[track] ||
706 (global.no_textdefaults == 0 && global.performer != NULL)) {
707 fprintf(cuef, " PERFORMER \"%s\"\n",
708 global.trackperformer[track] != NULL ?
709 global.trackperformer[track] :
710 global.performer);
711 }
712 if (global.tracksongwriter[track] ||
713 (global.no_textdefaults == 0 && global.songwriter != NULL)) {
714 fprintf(cuef, " SONGWRITER \"%s\"\n",
715 global.tracksongwriter[track] != NULL ?
716 global.tracksongwriter[track] :
717 global.songwriter);
718 }
719 if (Get_ISRC(track)[0]) {
720 char *p = (char *)Get_ISRC(track);
721 fprintf(cuef, " ISRC ");
722 while (*p) {
723 if (*p == '-')
724 p++;
725 putc(*p++, cuef);
726 }
727 fprintf(cuef, "\n");
728 }
729 if ((Get_Preemphasis(track) && (global.deemphasize == 0)) ||
730 Get_Copyright(track) != 0 ||
731 Get_Channels(track)) {
732 fprintf(cuef, " FLAGS");
733 switch (Get_Copyright(track)) {
734
735 case 1: fprintf(cuef, " SCMS"); break;
736 case 2: fprintf(cuef, " DCP"); break;
737 }
738 if (Get_Channels(track))
739 fprintf(cuef, " 4CH");
740 if (Get_Preemphasis(track) && (global.deemphasize == 0))
741 fprintf(cuef, " PRE");
742 fprintf(cuef, "\n");
743 }
744 for (ip = global.trackindexlist[track]; ip; ip = ip->next) {
745 if (ip->next == NULL)
746 break;
747 }
748 if (useHiddenTrack())
749 off_01 = 0L;
750 else
751 off_01 = Get_AudioStartSector(FirstAudioTrack());
752 if (global.trackindexlist[track] == NULL) {
753 if (track == 1) {
754 if (useHiddenTrack())
755 fprintf(cuef, " INDEX 00 %s\n", "00:00:00");
756 else
757 fprintf(cuef, " PREGAP %s\n", index_str(off_01));
758 }
759 fprintf(cuef, " INDEX 01 %s\n",
760 index_str(Get_AudioStartSector(track) - off_01));
761 } else if (track == 1 &&
762 global.trackindexlist[track] &&
763 global.trackindexlist[track]->frameoffset != 0) {
764 if (useHiddenTrack())
765 fprintf(cuef, " INDEX 00 %s\n", "00:00:00");
766 else
767 fprintf(cuef, " PREGAP %s\n", index_str(off_01));
768 } else if (track > 1) {
769 for (ip = global.trackindexlist[track-1]; ip; ip = ip->next) {
770 if (ip->next == NULL)
771 break;
772 }
773 if (ip && ip->frameoffset != -1)
774 fprintf(cuef, " INDEX 00 %s\n",
775 index_str((long)ip->frameoffset - off_01));
776 }
777 for (i = 1, ip = global.trackindexlist[track]; ip; i++, ip = ip->next) {
778 if (ip->next == NULL)
779 break;
780 if (ip->frameoffset == -1)
781 continue;
782 fprintf(cuef, " INDEX %2.2d %s\n", i,
783 index_str((long)ip->frameoffset - off_01));
784 }
785 }
786
787 LOCAL void
CloseAudio(channels_val,nSamples,audio_out)788 CloseAudio(channels_val, nSamples, audio_out)
789 int channels_val;
790 unsigned long nSamples;
791 struct soundfile *audio_out;
792 {
793 /*
794 * define length
795 */
796 audio_out->ExitSound(global.audio,
797 (nSamples-global.SkippedSamples) *
798 global.OutSampleSize*channels_val);
799
800 close(global.audio);
801 global.audio = -1;
802 }
803
804 LOCAL unsigned int track = (unsigned int)-1;
805
806 /*
807 * On terminating:
808 * define size-related entries in audio file header, update and close file
809 */
810 LOCAL void
CloseAll()811 CloseAll()
812 {
813 int amiparent;
814
815 /*
816 * terminate child process first
817 */
818 amiparent = global.child_pid > 0;
819
820 if (global.iloop > 0) {
821 /* set to zero */
822 global.iloop = 0;
823 }
824
825 #if defined HAVE_FORK_AND_SHAREDMEM
826 #ifdef DEBUG_CLEANUP
827 fprintf(stderr, _("%s terminating, \n"), amiparent ?
828 _("Parent (READER)") : _("Child (WRITER)"));
829 #endif
830 #else
831 #ifdef DEBUG_CLEANUP
832 fprintf(stderr, _("Cdda2wav single process terminating, \n"));
833 #endif
834 #endif
835
836 if (amiparent || global.child_pid < 0) {
837 /* switch to original mode and close device */
838 EnableCdda(get_scsi_p(), 0, 0);
839 }
840
841 if (!amiparent) {
842 /* do general clean up */
843
844 if (global.audio >= 0) {
845 if (bulk) {
846 /* finish sample file for this track */
847 CloseAudio(global.channels,
848 global.nSamplesDoneInTrack,
849 global.audio_out);
850 } else {
851 /* finish sample file for this track */
852 CloseAudio(global.channels,
853 (unsigned int) *nSamplesToDo,
854 global.audio_out);
855 }
856 }
857
858 /* tell minimum and maximum amplitudes, if required */
859 if (global.findminmax) {
860 fprintf(outfp,
861 _("Right channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767\n"),
862 global.minamp[0], global.maxamp[0]);
863 fprintf(outfp,
864 _("Left channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767\n"),
865 global.minamp[1], global.maxamp[1]);
866 }
867
868 /* tell mono or stereo recording, if required */
869 if (global.findmono) {
870 fprintf(outfp,
871 _("Audio samples are originally %s.\n"),
872 global.ismono ? _("mono") : _("stereo"));
873 }
874
875 return; /* end of child or single process */
876 }
877
878
879 if (global.have_forked == 1) {
880 #ifdef HAVE_FORK
881 WAIT_T chld_return_status;
882 #endif
883 #ifdef DEBUG_CLEANUP
884 fprintf(stderr, _("Parent wait for child death, \n"));
885 #endif
886 semdestroy();
887
888 #ifdef HAVE_FORK
889 /*
890 * If we don't have fork don't wait() either,
891 * else wait for child to terminate.
892 */
893 if (0 > wait(&chld_return_status)) {
894 errmsg(_("Error waiting for child.\n"));
895 } else {
896 if (WIFEXITED(chld_return_status)) {
897 if (WEXITSTATUS(chld_return_status)) {
898 fprintf(stderr,
899 _("\nW Child exited with %d\n"),
900 WEXITSTATUS(chld_return_status));
901 }
902 }
903 if (WIFSIGNALED(chld_return_status)) {
904 fprintf(stderr,
905 _("\nW Child exited due to signal %d\n"),
906 WTERMSIG(chld_return_status));
907 }
908 if (WIFSTOPPED(chld_return_status)) {
909 fprintf(stderr,
910 _("\nW Child is stopped due to signal %d\n"),
911 WSTOPSIG(chld_return_status));
912 }
913 }
914
915 #ifdef DEBUG_CLEANUP
916 fprintf(stderr,
917 _("\nW Parent child death, state:%d\n"),
918 chld_return_status);
919 #endif
920 #endif
921 }
922
923 #ifdef GPROF
924 rename("gmon.out", "gmon.child");
925 #endif
926 }
927
928
929 /*
930 * report a usage error and exit
931 */
932 #ifdef PROTOTYPES
933 LOCAL void
usage2(const char * szMessage,...)934 usage2(const char *szMessage, ...)
935 #else
936 LOCAL void
937 usage2(szMessage, va_alist)
938 const char *szMessage;
939 va_dcl
940 #endif
941 {
942 va_list marker;
943
944 #ifdef PROTOTYPES
945 va_start(marker, szMessage);
946 #else
947 va_start(marker);
948 #endif
949
950 errmsgno(EX_BAD, "%r", szMessage, marker);
951
952 va_end(marker);
953 fprintf(stderr,
954 _("Please use -help or consult the man page for help.\n"));
955
956 exit(1);
957 }
958
959
960 /*
961 * report a fatal error, clean up and exit
962 */
963 #ifdef PROTOTYPES
964 void
FatalError(int err,const char * szMessage,...)965 FatalError(int err, const char *szMessage, ...)
966 #else
967 void
968 FatalError(err, szMessage, va_alist)
969 int err;
970 const char *szMessage;
971 va_dcl
972 #endif
973 {
974 va_list marker;
975
976 #ifdef PROTOTYPES
977 va_start(marker, szMessage);
978 #else
979 va_start(marker);
980 #endif
981
982 errmsgno(err, "%r", szMessage, marker);
983
984 va_end(marker);
985
986 #ifdef HAVE_KILL
987 if (global.child_pid >= 0) {
988 if (global.child_pid == 0) {
989 pid_t ppid;
990 /*
991 * Kill the parent too if we are not orphaned.
992 */
993 ppid = getppid();
994 if (ppid > 1)
995 kill(ppid, SIGINT);
996 } else {
997 kill(global.child_pid, SIGINT);
998 }
999 }
1000 #endif
1001 exit(1);
1002 }
1003
1004
1005 /*
1006 * open the audio output file and prepare the header.
1007 * the header will be defined on terminating (when the size
1008 * is known). So hitting the interrupt key leaves an intact
1009 * file.
1010 */
1011 LOCAL void
OpenAudio(fname,rate,nBitsPerSample,channels_val,expected_bytes,audio_out)1012 OpenAudio(fname, rate, nBitsPerSample, channels_val, expected_bytes, audio_out)
1013 char *fname;
1014 double rate;
1015 long nBitsPerSample;
1016 long channels_val;
1017 unsigned long expected_bytes;
1018 struct soundfile * audio_out;
1019 {
1020 if (global.audio == -1) {
1021 #ifdef VMS
1022 static int open_id = 3;
1023 #endif
1024 global.audio = open(fname,
1025 #ifdef SYNCHRONOUS_WRITE
1026 O_SYNC |
1027 #endif
1028 O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
1029 (mode_t)0666);
1030 if (global.audio == -1) {
1031 if (errno == EAGAIN && is_fifo(fname)) {
1032 FatalError(errno,
1033 _("Could not open fifo %s. Probably no fifo reader present.\n"),
1034 fname);
1035 }
1036 FatalError(errno,
1037 _("Could not open audio sample file %s.\n"),
1038 fname);
1039 }
1040 }
1041 global.SkippedSamples = 0;
1042 any_signal = 0;
1043 audio_out->InitSound(global.audio, channels_val, (unsigned long)rate,
1044 nBitsPerSample, expected_bytes);
1045
1046 #ifdef MD5_SIGNATURES
1047 global.md5size = 0;
1048 if (global.md5blocksize)
1049 MD5Init(global.context);
1050 global.md5count = global.md5blocksize;
1051 #endif
1052 }
1053
1054 #include "scsi_cmds.h"
1055
1056 LOCAL int RealEnd __PR((SCSI *scgp, UINT4 *buff));
1057
1058 LOCAL int
RealEnd(scgp,buff)1059 RealEnd(scgp, buff)
1060 SCSI *scgp;
1061 UINT4 *buff;
1062 {
1063 if (scg_cmd_err(scgp) != 0) {
1064 int c, k, q;
1065
1066 k = scg_sense_key(scgp);
1067 c = scg_sense_code(scgp);
1068 q = scg_sense_qual(scgp);
1069 if ((k == 0x05 /* ILLEGAL_REQUEST */ &&
1070 c == 0x21 /* lba out of range */ &&
1071 q == 0x00) ||
1072 (k == 0x05 /* ILLEGAL_REQUEST */ &&
1073 c == 0x63 /* end of user area encount. on this tr. */ &&
1074 q == 0x00) ||
1075 (k == 0x08 /* BLANK_CHECK */ &&
1076 c == 0x64 /* illegal mode for this track */ &&
1077 q == 0x00)) {
1078 return (1);
1079 }
1080 }
1081
1082 if (scg_getresid(scgp) > 16)
1083 return (1);
1084
1085 {
1086 unsigned char *p;
1087
1088 /* Look into the subchannel data */
1089 buff += CD_FRAMESAMPLES;
1090 p = (unsigned char *)buff;
1091 if (p[0] == 0x21 && p[1] == 0xaa) {
1092 return (1);
1093 }
1094 }
1095 return (0);
1096 }
1097
1098 LOCAL void
set_offset(p,offset)1099 set_offset(p, offset)
1100 myringbuff *p;
1101 int offset;
1102 {
1103 #ifdef DEBUG_SHM
1104 fprintf(stderr, _("Write offset %d at %p\n"), offset, &p->offset);
1105 #endif
1106 p->offset = offset;
1107 }
1108
1109
1110 LOCAL int
get_offset(p)1111 get_offset(p)
1112 myringbuff *p;
1113 {
1114 #ifdef DEBUG_SHM
1115 fprintf(stderr, _("Read offset %d from %p\n"), p->offset, &p->offset);
1116 #endif
1117 return (p->offset);
1118 }
1119
1120
1121 LOCAL void
usage()1122 usage()
1123 {
1124 /* BEGIN CSTYLED */
1125 fputs(_("Usage: cdda2wav [OPTIONS ...] [trackfilenames ...]\n\
1126 OPTIONS:\n\
1127 [-c chans] [-s] [-m] [-b bits] [-r rate] [-a divider] [-S speed] [-x]\n\
1128 [-t track[+endtrack]] [-i index] [-o offset] [-d duration] [-F] [-G]\n\
1129 [-q] [-w] [-v vopts] [-R] [-P overlap] [-B] [-T] [-C input-endianess]\n\
1130 [-e] [-n sectors] [-N] [-J] [-L cddbp-mode] [-H] [-g] [-l buffers] [-D cd-device]\n\
1131 [-I interface] [-K sound-device] [-O audiotype] [-E output-endianess]\n\
1132 [-A auxdevice] [-paranoia] [-cddbp-server=name] [-cddbp-port=port] [-version]\n"),
1133 stderr);
1134 /* END CSTYLED */
1135
1136 /* BEGIN CSTYLED */
1137 fputs(_("\
1138 (-D) dev=device set the cdrom or scsi device (as Bus,Id,Lun).\n\
1139 scgopts=spec SCSI options for libscg\n\
1140 ts=# set maximum transfer size for a single SCSI command\n\
1141 (-A) auxdevice=device set the aux device (typically /dev/cdrom).\n\
1142 (-K) sound-device=device set the sound device to use for -e (typically /dev/dsp).\n\
1143 out-fd=descriptor set the file descriptor for general output to descriptor.\n\
1144 audio-fd=descriptor set the file descriptor for '-' audio output.\n\
1145 (-I) interface=interface specify the interface for cdrom access.\n\
1146 (generic_scsi or cooked_ioctl).\n\
1147 (-c) channels=channels set 1 for mono, 2 or s for stereo (s: channels swapped).\n\
1148 (-s) -stereo select stereo recording.\n\
1149 (-m) -mono select mono recording.\n\
1150 (-x) -max select maximum quality (stereo/16-bit/44.1 kHz).\n\
1151 (-b) bits=bits set bits per sample per channel (8, 12 or 16 bits).\n\
1152 (-r) rate=rate set rate in samples per second. -R gives all rates\n\
1153 (-a) divider=divider set rate to 44100Hz / divider. -R gives all rates\n\
1154 (-R) -dump-rates dump a table with all available sample rates\n\
1155 (-S) speed=speedfactor set the cdrom drive to a given speed during reading\n\
1156 (-P) set-overlap=sectors set amount of overlap sampling (default is 0)\n\
1157 (-n) sectors-per-request=secs read 'sectors' sectors per request.\n\
1158 (-l) buffers-in-ring=buffers use a ring buffer with 'buffers' elements.\n\
1159 (-t) track=track[+end track] select start track (option. end track).\n\
1160 (-i) index=index select start index.\n\
1161 (-o) offset=offset start at 'offset' sectors behind start track/index.\n\
1162 one sector equivalents 1/75 second.\n\
1163 start-sector=sector set absolute start sector.\n\
1164 (-O) output-format=audiotype set to wav, au (sun), cdr (raw), aiff or aifc format.\n\
1165 (-C) cdrom-endianess=endian set little, big or guess input sample endianess.\n\
1166 (-E) output-endianess=endian set little or big output sample endianess.\n\
1167 (-d) duration=seconds set recording time in seconds or 0 for whole track.\n\
1168 (-w) -wait wait for audio signal, then start recording.\n\
1169 (-F) -find-extremes find extrem amplitudes in samples.\n\
1170 (-G) -find-mono find if input samples are mono.\n\
1171 (-T) -deemphasize undo pre-emphasis in input samples.\n\
1172 (-e) -echo echo audio data to sound device (see -K) SOUND_DEV.\n\
1173 (-v) verbose-level=optlist controls verbosity (for a list use -vhelp).\n\
1174 (-N) -no-write do not create audio sample files.\n\
1175 (-J) -info-only give disc information only.\n\
1176 (-L) cddb=cddbpmode do cddbp title lookups.\n\
1177 resolve multiple entries according to cddbpmode: 0=interactive, 1=first entry\n\
1178 -cuefile create a CDRWIN CUE file instead of info files.\n\
1179 (-H) -no-infofile no info file generation.\n\
1180 -no-textdefaults do not fill missing track CD-Text from album CD-Text.\n\
1181 -no-textfile no binary cdtext file generation.\n\
1182 -no-hidden-track do not scan for hidden audio track (before track #1).\n\
1183 -no-fork do not fork for better buffering.\n\
1184 (-g) -gui generate special output suitable for gui frontends.\n\
1185 (-Q) -silent-scsi do not print status of erreneous scsi-commands.\n\
1186 -scanbus scan the SCSI bus and exit.\n\
1187 (-M) -md5 calculate MD-5 checksum for audio data.\n\
1188 (-q) -quiet quiet operation, no screen output.\n\
1189 (-p) playback-realtime=perc play (echo) audio pitched at perc percent (50%-200%).\n\
1190 (-V) -verbose-scsi each option increases verbosity for SCSI commands.\n\
1191 (-h) -help show this help screen.\n\
1192 (-B) -alltracks, -bulk record each track into a separate file.\n\
1193 -paranoia use the lib paranoia for reading.\n\
1194 -paraopts=opts set options for lib paranoia (see -paraopts=help).\n\
1195 -cddbp-server=servername set the cddbp server to use for title lookups.\n\
1196 -cddbp-port=portnumber set the cddbp port to use for title lookups.\n\
1197 -interactive select interactive mode (used by gstreamer plugin).\n\
1198 -version print version information.\n\
1199 \n\
1200 Please note: some short options will be phased out soon (disappear)!\n\
1201 \n\
1202 parameters: (optional) one or more file names or - for standard output.\n\
1203 "),
1204 stderr);
1205 /* END CSTYLED */
1206
1207 fputs(_("Version "), stderr);
1208 fputs(VERSION_DATE, outfp);
1209 fputs(" ", outfp);
1210 fputs(VERSION, stderr);
1211 fputs(VERSION_OS, stderr);
1212 prdefaults(stderr);
1213 exit(SYNTAX_ERROR);
1214 }
1215
1216 LOCAL void
prdefaults(f)1217 prdefaults(f)
1218 FILE *f;
1219 {
1220 /* BEGIN CSTYLED */
1221 fprintf(f, _("\n\
1222 Defaults: %s, %d bit, %d.%02d Hz, track 1, no offset, one track,\n"),
1223 (CHANNELS-1) ? _("stereo") : _("mono"), BITS_P_S,
1224 44100 / UNDERSAMPLING,
1225 (4410000 / UNDERSAMPLING) % 100);
1226
1227 fprintf(f, _("\
1228 type: %s filename: '%s', don't wait for signal, not quiet,\n"),
1229 AUDIOTYPE, FILENAME);
1230 fprintf(f, _("\
1231 use: '%s', device: '%s', aux: '%s'\n"),
1232 DEF_INTERFACE, CD_DEVICE, AUX_DEVICE);
1233 /* END CSTYLED */
1234 }
1235
1236 LOCAL void
init_globals()1237 init_globals()
1238 {
1239 #ifdef HISTORICAL_JUNK
1240 global.dev_name = CD_DEVICE; /* device name */
1241 #endif
1242 global.dev_opts = NULL; /* scg device options */
1243 global.aux_name = AUX_DEVICE; /* auxiliary cdrom device name */
1244 global.out_fp = stderr; /* -out-fd FILE * for messages */
1245 strncpy(global.fname_base, FILENAME,
1246 sizeof (global.fname_base)); /* current file name base */
1247 global.have_forked = 0; /* state variable for clean up */
1248 global.child_pid = -2; /* state variable for clean up */
1249 global.parent_died = 0; /* state variable for clean up */
1250 global.audio = -1; /* audio-out file desc */
1251 global.cooked_fd = -1; /* cdrom-in file desc */
1252 global.no_file = 0; /* -N option */
1253 global.no_infofile = 0; /* -no-infofile option */
1254 global.no_textfile = 0; /* -no-textfile option */
1255 global.did_textfile = 0; /* flag: did create textfile */
1256 global.no_textdefaults = 0; /* -no-textdefaults option */
1257 global.no_cddbfile = 0; /* flag: do not create cddbfile */
1258 global.cuefile = 0; /* -cuefile option */
1259 global.no_hidden_track = 0; /* -no-hidden-track option */
1260 global.no_fork = 0; /* -no-fork option */
1261 global.interactive = 0; /* -interactive option */
1262 global.quiet = 0; /* -quiet option */
1263 global.verbose = SHOW_TOC + SHOW_SUMMARY +
1264 SHOW_STARTPOSITIONS +
1265 SHOW_TITLES; /* -v verbose level */
1266 global.scsi_silent = 0; /* SCSI silent flag */
1267 global.scsi_verbose = 0; /* SCSI verbose level */
1268 global.scsi_debug = 0; /* SCSI debug level */
1269 global.scsi_kdebug = 0; /* SCSI kernel debug level */
1270 global.scanbus = 0; /* -scanbus option */
1271
1272 global.uid = 0;
1273 global.euid = 0;
1274 global.issetuid = FALSE;
1275
1276 global.sector_offset = 0;
1277 global.start_sector = -1;
1278 global.endtrack = (unsigned int)-1;
1279 global.alltracks = FALSE;
1280 global.maxtrack = FALSE;
1281 global.cd_index = -1;
1282 global.littleendian = -1;
1283 global.rectime = DURATION;
1284 global.int_part = 0;
1285 global.user_sound_device = "";
1286 global.moreargs = 0;
1287
1288 global.multiname = 0; /* multiple file names given */
1289 global.sh_bits = 0; /* sh_bits: sample bit shift */
1290 global.Remainder = 0; /* remainder */
1291 global.iloop = 0; /* todo counter (frames) */
1292 global.SkippedSamples = 0; /* skipped samples */
1293 global.OutSampleSize = 0; /* output sample size */
1294 global.channels = CHANNELS; /* output sound channels */
1295 global.nSamplesDoneInTrack = 0; /* written samples in current track */
1296 global.buffers = 4; /* buffers to use */
1297 global.bufsize = -1L; /* The SCSI buffer size */
1298 global.nsectors = NSECTORS; /* sectors to read in one request */
1299 global.overlap = 1; /* amount of overlapping sectors */
1300 global.useroverlap = -1; /* amt of overl. sect. user override */
1301 global.need_hostorder = 0; /* processing needs samples in host endianess */
1302 global.in_lendian = -1; /* input endianess from SetupSCSI() */
1303 global.outputendianess = NONE; /* user specified output endianess */
1304 global.findminmax = 0; /* flag find extrem amplitudes */
1305 #ifdef HAVE_LIMITS_H
1306 global.maxamp[0] = INT_MIN; /* maximum amplitude */
1307 global.maxamp[1] = INT_MIN; /* maximum amplitude */
1308 global.minamp[0] = INT_MAX; /* minimum amplitude */
1309 global.minamp[1] = INT_MAX; /* minimum amplitude */
1310 #else
1311 global.maxamp[0] = -32768; /* maximum amplitude */
1312 global.maxamp[1] = -32768; /* maximum amplitude */
1313 global.minamp[0] = 32767; /* minimum amplitude */
1314 global.minamp[1] = 32767; /* minimum amplitude */
1315 #endif
1316 global.speed = DEFAULT_SPEED; /* use default */
1317 global.userspeed = -1; /* speed user override */
1318 global.findmono = 0; /* flag find if samples are mono */
1319 global.ismono = 1; /* flag if samples are mono */
1320 global.swapchannels = 0; /* flag if channels shall be swapped */
1321 global.deemphasize = 0; /* flag undo pre-emphasis in samples */
1322 global.playback_rate = 100; /* new fancy selectable sound output rate */
1323 global.gui = 0; /* flag plain formatting for guis */
1324 global.cddb_id = 0; /* disc identifying id for CDDB database */
1325 global.cddb_revision = 0; /* entry revision for CDDB database */
1326 global.cddb_year = 0; /* disc identifying year for CDDB database */
1327 global.cddb_genre[0] = '\0'; /* disc identifying genre for CDDB database */
1328 global.cddbp = 0; /* flag if titles shall be looked up from CDDBP */
1329 global.cddbp_server = 0; /* user supplied CDDBP server */
1330 global.cddbp_port = 0; /* user supplied CDDBP port */
1331 global.illleadout_cd = 0; /* flag if illegal leadout is present */
1332 global.reads_illleadout = 0; /* flag if cdrom drive reads cds with illegal leadouts */
1333 global.copyright_message = NULL;
1334 global.disctitle = NULL;
1335 global.performer = NULL;
1336 global.songwriter = NULL;
1337 global.composer = NULL;
1338 global.arranger = NULL;
1339 global.message = NULL;
1340 global.closed_info = NULL;
1341 memset(global.tracktitle, 0, sizeof (global.tracktitle));
1342 memset(global.trackperformer, 0, sizeof (global.trackperformer));
1343 memset(global.tracksongwriter, 0, sizeof (global.tracksongwriter));
1344 memset(global.trackcomposer, 0, sizeof (global.trackcomposer));
1345 memset(global.trackarranger, 0, sizeof (global.trackarranger));
1346 memset(global.trackmessage, 0, sizeof (global.trackmessage));
1347 memset(global.trackclosed_info, 0, sizeof (global.trackclosed_info));
1348 memset(global.trackindexlist, 0, sizeof (global.trackindexlist));
1349
1350 global.just_the_toc = 0;
1351 global.paranoia_selected = 0;
1352 global.paranoia_flags = 0;
1353 global.paranoia_mode = 0;
1354 #ifdef USE_PARANOIA
1355 global.paranoia_parms.disable_paranoia =
1356 global.paranoia_parms.disable_extra_paranoia =
1357 global.paranoia_parms.disable_scratch_detect =
1358 global.paranoia_parms.disable_scratch_repair =
1359 global.paranoia_parms.enable_c2_check = 0;
1360 global.paranoia_parms.retries = 20;
1361 global.paranoia_parms.readahead = -1;
1362 global.paranoia_parms.overlap = -1;
1363 global.paranoia_parms.mindynoverlap = -1;
1364 global.paranoia_parms.maxdynoverlap = -1;
1365 #endif
1366 global.md5offset = 0;
1367 global.md5blocksize = 0;
1368 #ifdef MD5_SIGNATURES
1369 global.md5count = 0;
1370 global.md5size = 0;
1371 #endif
1372 }
1373
1374 #if !defined(HAVE_STRCASECMP) || (HAVE_STRCASECMP != 1)
1375 #include <schily/ctype.h>
1376 LOCAL int strcasecmp __PR((const char *s1, const char *s2));
1377 LOCAL int
strcasecmp(s1,s2)1378 strcasecmp(s1, s2)
1379 const char *s1;
1380 const char *s2;
1381 {
1382 if (s1 && s2) {
1383 while (*s1 && *s2 && (tolower(*s1) - tolower(*s2) == 0)) {
1384 s1++;
1385 s2++;
1386 }
1387 if (*s1 == '\0' && *s2 == '\0')
1388 return (0);
1389 if (*s1 == '\0')
1390 return (-1);
1391 if (*s2 == '\0')
1392 return (+1);
1393 return (tolower(*s1) - tolower(*s2));
1394 }
1395 return (-1);
1396 }
1397 #endif
1398
1399 LOCAL int
is_fifo(filename)1400 is_fifo(filename)
1401 char *filename;
1402 {
1403 #if defined S_ISFIFO
1404 struct stat statstruct;
1405
1406 if (stat(filename, &statstruct)) {
1407 /*
1408 * maybe the output file does not exist.
1409 */
1410 if (errno == ENOENT)
1411 return (0);
1412 else
1413 comerr(_("Error during stat for output file\n"));
1414 } else {
1415 if (S_ISFIFO(statstruct.st_mode)) {
1416 return (1);
1417 }
1418 }
1419 return (0);
1420 #else
1421 return (0);
1422 #endif
1423 }
1424
1425
1426 #if !defined(HAVE_STRTOUL) || (HAVE_STRTOUL != 1)
1427 LOCAL unsigned int strtoul __PR((const char *s1, char **s2, int base));
1428 LOCAL unsigned int
strtoul(s1,s2,base)1429 strtoul(s1, s2, base)
1430 const char *s1;
1431 char **s2;
1432 int base;
1433 {
1434 long retval;
1435
1436 if (base == 10) {
1437 /* strip zeros in front */
1438 while (*s1 == '0')
1439 s1++;
1440 }
1441 if (s2 != NULL) {
1442 *s2 = astol(s1, &retval);
1443 } else {
1444 (void) astol(s1, &retval);
1445 }
1446
1447 return ((unsigned long) retval);
1448 }
1449 #endif
1450
1451 LOCAL unsigned long SectorBurst;
1452 #if (SENTINEL > CD_FRAMESIZE_RAW)
1453 error block size for overlap check has to be < sector size
1454 #endif
1455
1456
1457 LOCAL void
1458 switch_to_realtime_priority __PR((void));
1459
1460 #ifdef HAVE_SYS_PRIOCNTL_H
1461
1462 #include <sys/priocntl.h>
1463 #include <sys/rtpriocntl.h>
1464 LOCAL void
switch_to_realtime_priority()1465 switch_to_realtime_priority()
1466 {
1467 pcinfo_t info;
1468 pcparms_t param;
1469 rtinfo_t rtinfo;
1470 rtparms_t rtparam;
1471 int pid;
1472
1473 pid = getpid();
1474
1475 /*
1476 * get info
1477 */
1478 strcpy(info.pc_clname, "RT");
1479 if (-1 == priocntl(P_PID, pid, PC_GETCID, (void *)&info)) {
1480 errmsg(_("Cannot get priority class id priocntl(PC_GETCID)\n"));
1481 goto prio_done;
1482 }
1483
1484 memmove(&rtinfo, info.pc_clinfo, sizeof (rtinfo_t));
1485
1486 /*
1487 * set priority not to the max
1488 */
1489 rtparam.rt_pri = rtinfo.rt_maxpri - 2;
1490 rtparam.rt_tqsecs = 0;
1491 rtparam.rt_tqnsecs = RT_TQDEF;
1492 param.pc_cid = info.pc_cid;
1493 memmove(param.pc_clparms, &rtparam, sizeof (rtparms_t));
1494 if (global.issetuid || global.uid != 0)
1495 priv_on();
1496 needroot(0);
1497 if (-1 == priocntl(P_PID, pid, PC_SETPARMS, (void *)¶m))
1498 errmsg(
1499 _("Cannot set priority class parameters priocntl(PC_SETPARMS)\n"));
1500 prio_done:
1501 if (global.issetuid || global.uid != 0)
1502 priv_off();
1503 dontneedroot();
1504 }
1505 #else
1506 #if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING -0 >= 0 && \
1507 defined(HAVE_SCHED_SETSCHEDULER)
1508 #define USE_POSIX_PRIORITY_SCHEDULING
1509 #endif
1510
1511 #ifdef USE_POSIX_PRIORITY_SCHEDULING
1512 #include <sched.h>
1513
1514 LOCAL void
switch_to_realtime_priority()1515 switch_to_realtime_priority()
1516 {
1517 #ifdef _SC_PRIORITY_SCHEDULING
1518 if (sysconf(_SC_PRIORITY_SCHEDULING) == -1) {
1519 errmsg(_("WARNING: RR-scheduler not available, disabling.\n"));
1520 } else
1521 #endif
1522 {
1523 int sched_fifo_min, sched_fifo_max;
1524 struct sched_param sched_parms;
1525
1526 sched_fifo_min = sched_get_priority_min(SCHED_FIFO);
1527 sched_fifo_max = sched_get_priority_max(SCHED_FIFO);
1528 sched_parms.sched_priority = sched_fifo_max - 1;
1529 if (global.issetuid || global.uid != 0)
1530 priv_on();
1531 needroot(0);
1532 if (-1 == sched_setscheduler(getpid(), SCHED_FIFO, &sched_parms) &&
1533 global.quiet != 1)
1534 errmsg(_("Cannot set posix realtime scheduling policy.\n"));
1535 if (global.issetuid || global.uid != 0)
1536 priv_off();
1537 dontneedroot();
1538 }
1539 }
1540 #else
1541 #if defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(_MSC_VER)
1542
1543 /*
1544 * NOTE: Base.h from Cygwin-B20 has a second typedef for BOOL.
1545 * We define BOOL to make all local code use BOOL
1546 * from Windows.h and use the hidden __SBOOL for
1547 * our global interfaces.
1548 *
1549 * NOTE: windows.h from Cygwin-1.x includes a structure field named sample,
1550 * so me may not define our own 'sample' or need to #undef it now.
1551 * With a few nasty exceptions, Microsoft assumes that any global
1552 * defines or identifiers will begin with an Uppercase letter, so
1553 * there may be more of these problems in the future.
1554 *
1555 * NOTE: windows.h defines interface as an alias for struct, this
1556 * is used by COM/OLE2, I guess it is class on C++
1557 * We man need to #undef 'interface'
1558 *
1559 * These workarounds are now applied in schily/windows.h
1560 */
1561 #include <schily/windows.h>
1562 #undef interface
1563
1564 LOCAL void
switch_to_realtime_priority()1565 switch_to_realtime_priority()
1566 {
1567 /*
1568 * set priority class
1569 */
1570 if (FALSE == SetPriorityClass(GetCurrentProcess(),
1571 REALTIME_PRIORITY_CLASS)) {
1572 /*
1573 * XXX No errno?
1574 */
1575 errmsgno(EX_BAD, _("No realtime priority possible.\n"));
1576 return;
1577 }
1578
1579 /*
1580 * set thread priority
1581 */
1582 if (FALSE == SetThreadPriority(GetCurrentThread(),
1583 THREAD_PRIORITY_HIGHEST)) {
1584 /*
1585 * XXX No errno?
1586 */
1587 errmsgno(EX_BAD, _("Could not set realtime priority.\n"));
1588 }
1589 }
1590 #else
1591 LOCAL void
switch_to_realtime_priority()1592 switch_to_realtime_priority()
1593 {
1594 }
1595 #endif
1596 #endif
1597 #endif
1598
1599 /* SCSI cleanup */
1600 int on_exitscsi __PR((void *status));
1601
1602 int
on_exitscsi(status)1603 on_exitscsi(status)
1604 void *status;
1605 {
1606 /*
1607 * The double cast is only needed for GCC in LP64 mode.
1608 */
1609 exit((int)(Intptr_t)status);
1610 return (0);
1611 }
1612
1613 /* wrapper for signal handler exit needed for Mac-OS-X */
1614 LOCAL void exit_wrapper __PR((int status));
1615
1616 LOCAL void
exit_wrapper(status)1617 exit_wrapper(status)
1618 int status;
1619 {
1620 #if defined DEBUG_CLEANUP
1621 fprintf(stderr, _("Exit(%d) for %s\n"),
1622 status, global.child_pid == 0 ? _("Child") : _("Parent"));
1623 fflush(stderr);
1624 #endif
1625
1626 if (global.child_pid != 0) {
1627 SCSI *scgp = get_scsi_p();
1628
1629 /*
1630 * The double cast is only needed for GCC in LP64 mode.
1631 */
1632 if (scgp != NULL && scgp->running) {
1633 scgp->cb_fun = on_exitscsi;
1634 scgp->cb_arg = (void *)(Intptr_t)status;
1635 } else {
1636 on_exitscsi((void *)(Intptr_t)status);
1637 }
1638 } else {
1639 exit(status);
1640 }
1641 }
1642
1643 /* signal handler for process communication */
1644 LOCAL void set_nonforked __PR((int status));
1645
1646 /* ARGSUSED */
1647 LOCAL void
set_nonforked(status)1648 set_nonforked(status)
1649 int status;
1650 {
1651 global.parent_died = 1;
1652 #if defined DEBUG_CLEANUP
1653 fprintf(stderr, _("SIGPIPE received from %s.\n"),
1654 global.child_pid == 0 ? _("Child") : _("Parent"));
1655 #endif
1656 #ifdef HAVE_KILL
1657 if (global.child_pid == 0) {
1658 pid_t ppid;
1659 /*
1660 * Kill the parent too if we are not orphaned.
1661 */
1662 ppid = getppid();
1663 if (ppid > 1)
1664 kill(ppid, SIGINT);
1665 } else {
1666 kill(global.child_pid, SIGINT);
1667 }
1668 #endif
1669 exit(SIGPIPE_ERROR);
1670 }
1671
1672
1673
1674 #ifdef USE_PARANOIA
1675 LOCAL struct paranoia_statistics
1676 {
1677 long c_sector;
1678 long v_sector;
1679 int last_heartbeatstate;
1680 long lasttime;
1681 char heartbeat;
1682 int minoverlap;
1683 int curoverlap;
1684 int maxoverlap;
1685 int slevel;
1686 int slastlevel;
1687 int stimeout;
1688 int rip_smile_level;
1689 unsigned verifies;
1690 unsigned reads;
1691 unsigned sectors;
1692 unsigned fixup_edges;
1693 unsigned fixup_atoms;
1694 unsigned readerrs;
1695 unsigned c2errs;
1696 unsigned c2bytes;
1697 unsigned c2secs;
1698 unsigned c2maxerrs;
1699 unsigned c2badsecs;
1700 unsigned skips;
1701 unsigned overlaps;
1702 unsigned scratchs;
1703 unsigned drifts;
1704 unsigned fixup_droppeds;
1705 unsigned fixup_dupeds;
1706 } *para_stat;
1707
1708
1709 LOCAL void paranoia_statreset __PR((void));
1710 LOCAL void
paranoia_statreset()1711 paranoia_statreset()
1712 {
1713 para_stat->c_sector = 0;
1714 para_stat->v_sector = 0;
1715 para_stat->last_heartbeatstate = 0;
1716 para_stat->lasttime = 0;
1717 para_stat->heartbeat = ' ';
1718 para_stat->minoverlap = 0x7FFFFFFF;
1719 para_stat->curoverlap = 0;
1720 para_stat->maxoverlap = 0;
1721 para_stat->slevel = 0;
1722 para_stat->slastlevel = 0;
1723 para_stat->stimeout = 0;
1724 para_stat->rip_smile_level = 0;
1725 para_stat->verifies = 0;
1726 para_stat->reads = 0;
1727 para_stat->sectors = 0;
1728 para_stat->readerrs = 0;
1729 para_stat->c2errs = 0;
1730 para_stat->c2bytes = 0;
1731 para_stat->c2secs = 0;
1732 para_stat->c2maxerrs = 0;
1733 para_stat->c2badsecs = 0;
1734 para_stat->fixup_edges = 0;
1735 para_stat->fixup_atoms = 0;
1736 para_stat->fixup_droppeds = 0;
1737 para_stat->fixup_dupeds = 0;
1738 para_stat->drifts = 0;
1739 para_stat->scratchs = 0;
1740 para_stat->overlaps = 0;
1741 para_stat->skips = 0;
1742 }
1743
1744 LOCAL void paranoia_callback __PR((long inpos, int function));
1745
1746 LOCAL void
paranoia_callback(inpos,function)1747 paranoia_callback(inpos, function)
1748 long inpos;
1749 int function;
1750 {
1751 struct timeval thistime;
1752 long test;
1753
1754 switch (function) {
1755 case -2:
1756 para_stat->v_sector = inpos / CD_FRAMEWORDS;
1757 return;
1758
1759 case -1:
1760 para_stat->last_heartbeatstate = 8;
1761 para_stat->heartbeat = '*';
1762 para_stat->slevel = 0;
1763 para_stat->v_sector = inpos / CD_FRAMEWORDS;
1764 break;
1765
1766 case PARANOIA_CB_VERIFY:
1767 if (para_stat->stimeout >= 30) {
1768 if (para_stat->curoverlap > CD_FRAMEWORDS) {
1769 para_stat->slevel = 2;
1770 } else {
1771 para_stat->slevel = 1;
1772 }
1773 }
1774 para_stat->verifies++;
1775 break;
1776
1777 case PARANOIA_CB_READ:
1778 if (inpos / CD_FRAMEWORDS > para_stat->c_sector) {
1779 para_stat->c_sector = inpos / CD_FRAMEWORDS;
1780 }
1781 para_stat->reads++;
1782 break;
1783
1784 case PARANOIA_CB_SECS:
1785 para_stat->sectors += inpos;
1786 break;
1787
1788 case PARANOIA_CB_FIXUP_EDGE:
1789 if (para_stat->stimeout >= 5) {
1790 if (para_stat->curoverlap > CD_FRAMEWORDS) {
1791 para_stat->slevel = 2;
1792 } else {
1793 para_stat->slevel = 1;
1794 }
1795 }
1796 para_stat->fixup_edges++;
1797 break;
1798
1799 case PARANOIA_CB_FIXUP_ATOM:
1800 if (para_stat->slevel < 3 || para_stat->stimeout > 5) {
1801 para_stat->slevel = 3;
1802 }
1803 para_stat->fixup_atoms++;
1804 break;
1805
1806 case PARANOIA_CB_READERR:
1807 para_stat->slevel = 6;
1808 para_stat->readerrs++;
1809 break;
1810
1811 case PARANOIA_CB_C2ERR:
1812 para_stat->slevel = 3;
1813 para_stat->c2errs++;
1814 break;
1815
1816 case PARANOIA_CB_C2BYTES:
1817 para_stat->c2bytes += inpos;
1818 break;
1819
1820 case PARANOIA_CB_C2SECS:
1821 para_stat->c2secs += inpos;
1822 break;
1823
1824 case PARANOIA_CB_C2MAXERRS:
1825 if (inpos > para_stat->c2maxerrs)
1826 para_stat->c2maxerrs = inpos;
1827 if (inpos > 100)
1828 para_stat->c2badsecs++;
1829 break;
1830
1831 case PARANOIA_CB_SKIP:
1832 para_stat->slevel = 8;
1833 para_stat->skips++;
1834 break;
1835
1836 case PARANOIA_CB_OVERLAP:
1837 para_stat->curoverlap = inpos;
1838 if (inpos > para_stat->maxoverlap)
1839 para_stat->maxoverlap = inpos;
1840 if (inpos < para_stat->minoverlap)
1841 para_stat->minoverlap = inpos;
1842 para_stat->overlaps++;
1843 break;
1844
1845 case PARANOIA_CB_SCRATCH:
1846 para_stat->slevel = 7;
1847 para_stat->scratchs++;
1848 break;
1849
1850 case PARANOIA_CB_DRIFT:
1851 if (para_stat->slevel < 4 || para_stat->stimeout > 5) {
1852 para_stat->slevel = 4;
1853 }
1854 para_stat->drifts++;
1855 break;
1856
1857 case PARANOIA_CB_FIXUP_DROPPED:
1858 para_stat->slevel = 5;
1859 para_stat->fixup_droppeds++;
1860 break;
1861
1862 case PARANOIA_CB_FIXUP_DUPED:
1863 para_stat->slevel = 5;
1864 para_stat->fixup_dupeds++;
1865 break;
1866 }
1867
1868 gettimeofday(&thistime, NULL);
1869 /* now in tenth of seconds. */
1870 test = thistime.tv_sec * 10 + thistime.tv_usec / 100000;
1871
1872 if (para_stat->lasttime != test ||
1873 function == -1 ||
1874 para_stat->slastlevel != para_stat->slevel) {
1875
1876 if (function == -1 ||
1877 para_stat->slastlevel != para_stat->slevel) {
1878
1879 static const char hstates[] = " .o0O0o.";
1880
1881 para_stat->lasttime = test;
1882 para_stat->stimeout++;
1883
1884 para_stat->last_heartbeatstate++;
1885 if (para_stat->last_heartbeatstate > 7) {
1886 para_stat->last_heartbeatstate = 0;
1887 }
1888 para_stat->heartbeat =
1889 hstates[para_stat->last_heartbeatstate];
1890
1891 if (function == -1) {
1892 para_stat->heartbeat = '*';
1893 }
1894 }
1895
1896 if (para_stat->slastlevel != para_stat->slevel) {
1897 para_stat->stimeout = 0;
1898 }
1899 para_stat->slastlevel = para_stat->slevel;
1900 }
1901
1902 if (para_stat->slevel < 8) {
1903 para_stat->rip_smile_level = para_stat->slevel;
1904 } else {
1905 para_stat->rip_smile_level = 0;
1906 }
1907 }
1908 #endif
1909
1910 LOCAL long lSector; /* Current sector # */
1911 LOCAL long lSector_p2; /* Last sector to read */
1912 LOCAL double rate = 44100.0 / UNDERSAMPLING;
1913 LOCAL int bits = BITS_P_S;
1914 LOCAL char fname[200];
1915 LOCAL const char *audio_type;
1916 LOCAL long BeginAtSample;
1917 LOCAL unsigned long SamplesToWrite;
1918 LOCAL unsigned minover;
1919 LOCAL unsigned maxover;
1920
1921 LOCAL unsigned long calc_SectorBurst __PR((void));
1922 LOCAL void set_newstart __PR((long newstart));
1923
1924 LOCAL const char *
get_audiotype()1925 get_audiotype()
1926 {
1927 return (audio_type);
1928 }
1929
1930 LOCAL unsigned long
calc_SectorBurst()1931 calc_SectorBurst()
1932 {
1933 unsigned long SectorBurstVal;
1934
1935 SectorBurstVal = min(global.nsectors,
1936 (global.iloop + CD_FRAMESAMPLES-1) / CD_FRAMESAMPLES);
1937 if (lSector+(int)SectorBurst-1 >= lSector_p2)
1938 SectorBurstVal = lSector_p2 - lSector;
1939 return (SectorBurstVal);
1940 }
1941
1942 LOCAL void
set_newstart(newstart)1943 set_newstart(newstart)
1944 long newstart;
1945 {
1946 lSector = newstart;
1947 global.iloop = (lSector_p2 - lSector) * CD_FRAMESAMPLES;
1948 *nSamplesToDo = global.iloop;
1949 nSamplesDone = 0;
1950 if (global.paranoia_selected)
1951 paranoia_seek(global.cdp, lSector, SEEK_SET);
1952
1953 #ifdef DEBUG_INTERACTIVE
1954 error("iloop %lu (%lu sects == %lu s) lSector %ld -> %ld\n",
1955 global.iloop, global.iloop/588, global.iloop/588/75,
1956 lSector, lSector_p2);
1957 error("*nSamplesToDo %ld nSamplesDone %ld\n",
1958 *nSamplesToDo, nSamplesDone);
1959 #endif
1960 }
1961
1962 /*
1963 * if PERCENTAGE_PER_TRACK is defined, the percentage message will reach
1964 * 100% every time a track end is reached or the time limit is reached.
1965 *
1966 * Otherwise if PERCENTAGE_PER_TRACK is not defined, the percentage message
1967 * will reach 100% once at the very end of the last track.
1968 */
1969 #define PERCENTAGE_PER_TRACK
1970
1971 LOCAL int do_read __PR((myringbuff *p, unsigned *total_unsuccessful_retries));
1972 LOCAL int
do_read(p,total_unsuccessful_retries)1973 do_read(p, total_unsuccessful_retries)
1974 myringbuff *p;
1975 unsigned *total_unsuccessful_retries;
1976 {
1977 unsigned char *newbuf;
1978 int offset;
1979 unsigned int added_size;
1980
1981 /* how many sectors should be read */
1982 SectorBurst = calc_SectorBurst();
1983
1984 #ifdef USE_PARANOIA
1985 if (global.paranoia_selected) {
1986 int i;
1987
1988 for (i = 0; i < SectorBurst; i++) {
1989 void *dp;
1990
1991 dp = paranoia_read_limited(global.cdp,
1992 paranoia_callback,
1993 global.paranoia_parms.retries);
1994 #ifdef nonono
1995 {
1996 char *err;
1997 char *msg;
1998 err = cdda_errors(global.cdp);
1999 msg = cdda_messages(global.cdp);
2000 if (err) {
2001 fputs(err, stderr);
2002 free(err);
2003 }
2004 if (msg) {
2005 fputs(msg, stderr);
2006 free(msg);
2007 }
2008 }
2009 #endif /* nonono */
2010 if (dp != NULL) {
2011 memcpy(p->data + i*CD_FRAMESAMPLES, dp,
2012 CD_FRAMESIZE_RAW);
2013 } else {
2014 errmsgno(EX_BAD,
2015 _("E unrecoverable error!\n"));
2016 exit(READ_ERROR);
2017 }
2018 }
2019 newbuf = (unsigned char *)p->data;
2020 offset = 0;
2021 set_offset(p, offset);
2022 added_size = SectorBurst * CD_FRAMESAMPLES;
2023 global.overlap = 0;
2024 handle_inputendianess(p->data, added_size);
2025 } else
2026 #endif
2027 {
2028 unsigned int retry_count;
2029 #define MAX_READRETRY 12
2030
2031 retry_count = 0;
2032 do {
2033 SCSI *scgp = get_scsi_p();
2034 #ifdef DEBUG_READS
2035 fprintf(stderr,
2036 "reading from %lu to %lu, overlap %u\n",
2037 lSector, lSector + SectorBurst -1,
2038 global.overlap);
2039 #endif
2040
2041 #ifdef DEBUG_BUFFER_ADDRESSES
2042 fprintf(stderr, "%p %l\n", p->data, global.pagesize);
2043 if (((unsigned)p->data) & (global.pagesize -1) != 0) {
2044 fprintf(stderr,
2045 "Address %p is NOT page aligned!!\n",
2046 p->data);
2047 }
2048 #endif
2049
2050 if (global.reads_illleadout != 0 &&
2051 lSector > Get_StartSector(LastTrack())) {
2052 int singles = 0;
2053 UINT4 bufferSub[CD_FRAMESAMPLES + 24];
2054
2055 /*
2056 * we switch to single sector reads,
2057 * in order to handle the remaining sectors.
2058 */
2059 scgp->silent++;
2060 do {
2061 ReadCdRomSub(scgp, bufferSub,
2062 lSector+singles, 1);
2063 *eorecording = RealEnd(scgp,
2064 bufferSub);
2065 if (*eorecording) {
2066 break;
2067 }
2068 memcpy(p->data+singles*CD_FRAMESAMPLES,
2069 bufferSub, CD_FRAMESIZE_RAW);
2070 singles++;
2071 } while (singles < SectorBurst);
2072 scgp->silent--;
2073
2074 if (*eorecording) {
2075 patch_real_end(lSector+singles);
2076 SectorBurst = singles;
2077 #if DEBUG_ILLLEADOUT
2078 fprintf(stderr,
2079 "iloop=%11lu, nSamplesToDo=%11lu, end=%lu -->\n",
2080 global.iloop,
2081 *nSamplesToDo,
2082 lSector+singles);
2083 #endif
2084
2085 *nSamplesToDo -= global.iloop -
2086 SectorBurst *
2087 CD_FRAMESAMPLES;
2088 global.iloop = SectorBurst *
2089 CD_FRAMESAMPLES;
2090 #if DEBUG_ILLLEADOUT
2091 fprintf(stderr,
2092 "iloop=%11lu, nSamplesToDo=%11lu\n\n",
2093 global.iloop, *nSamplesToDo);
2094 #endif
2095
2096 }
2097 } else {
2098 ReadCdRom(scgp, p->data, lSector, SectorBurst);
2099 }
2100 handle_inputendianess(p->data,
2101 SectorBurst * CD_FRAMESAMPLES);
2102 if (NULL ==
2103 (newbuf = synchronize(p->data,
2104 SectorBurst*CD_FRAMESAMPLES,
2105 *nSamplesToDo-global.iloop))) {
2106 /*
2107 * could not synchronize!
2108 * Try to invalidate the cdrom cache.
2109 * Increase overlap setting, if possible.
2110 */
2111 #ifdef nonono
2112 trash_cache(p->data, lSector, SectorBurst);
2113 #endif
2114 if (global.overlap < global.nsectors - 1) {
2115 global.overlap++;
2116 lSector--;
2117 SectorBurst = calc_SectorBurst();
2118 #ifdef DEBUG_DYN_OVERLAP
2119 fprintf(stderr,
2120 "using increased overlap of %u\n",
2121 global.overlap);
2122 #endif
2123 } else {
2124 lSector += global.overlap - 1;
2125 global.overlap = 1;
2126 SectorBurst = calc_SectorBurst();
2127 }
2128 } else
2129 break;
2130 } while (++retry_count < MAX_READRETRY);
2131
2132 if (retry_count == MAX_READRETRY && newbuf == NULL &&
2133 global.verbose != 0) {
2134 (*total_unsuccessful_retries)++;
2135 }
2136
2137 if (newbuf) {
2138 offset = newbuf - ((unsigned char *)p->data);
2139 } else {
2140 offset = global.overlap * CD_FRAMESIZE_RAW;
2141 }
2142 set_offset(p, offset);
2143
2144 /* how much has been added? */
2145 added_size = SectorBurst * CD_FRAMESAMPLES - offset/4;
2146
2147 if (newbuf && *nSamplesToDo != global.iloop) {
2148 minover = min(global.overlap, minover);
2149 maxover = max(global.overlap, maxover);
2150
2151
2152 /* should we reduce the overlap setting ? */
2153 if (offset > CD_FRAMESIZE_RAW && global.overlap > 1) {
2154 #ifdef DEBUG_DYN_OVERLAP
2155 fprintf(stderr,
2156 "decreasing overlap from %u to %u (jitter %d)\n",
2157 global.overlap, global.overlap-1,
2158 offset - (global.overlap)*CD_FRAMESIZE_RAW);
2159 #endif
2160 global.overlap--;
2161 SectorBurst = calc_SectorBurst();
2162 }
2163 }
2164 }
2165 if (global.iloop >= added_size) {
2166 global.iloop -= added_size;
2167 } else {
2168 global.iloop = 0;
2169 }
2170
2171 lSector += SectorBurst - global.overlap;
2172
2173 #if defined PERCENTAGE_PER_TRACK && defined HAVE_FORK_AND_SHAREDMEM
2174 if (global.iloop > 0) {
2175 int as;
2176 while ((as = Get_StartSector(current_track_reading+1)) != -1 &&
2177 lSector >= as) {
2178 current_track_reading++;
2179 }
2180 }
2181 #endif
2182
2183 return (offset);
2184 }
2185
2186 LOCAL void
2187 print_percentage __PR((unsigned *poper, int c_offset));
2188
2189 LOCAL void
print_percentage(poper,c_offset)2190 print_percentage(poper, c_offset)
2191 unsigned *poper;
2192 int c_offset;
2193 {
2194 unsigned per;
2195 #ifdef PERCENTAGE_PER_TRACK
2196 /* Thomas Niederreiter wants percentage per track */
2197 unsigned start_in_track = max(BeginAtSample,
2198 Get_AudioStartSector(current_track_writing)*CD_FRAMESAMPLES);
2199
2200 per = min(BeginAtSample + (long)*nSamplesToDo,
2201 Get_StartSector(current_track_writing+1)*CD_FRAMESAMPLES)
2202 - (long)start_in_track;
2203
2204 if (per > 0)
2205 per = (BeginAtSample+nSamplesDone - start_in_track)/(per/100);
2206 else
2207 per = 0;
2208
2209 #else
2210 per = global.iloop ? (nSamplesDone)/(*nSamplesToDo/100) : 100;
2211 #endif
2212
2213 if (global.overlap > 0) {
2214 fprintf(outfp, "\r%2u/%2u/%2u/%7d %3u%%",
2215 minover, maxover, global.overlap,
2216 c_offset - global.overlap*CD_FRAMESIZE_RAW,
2217 per);
2218 } else if (*poper != per) {
2219 fprintf(outfp, "\r%3u%%", per);
2220 }
2221 *poper = per;
2222 fflush(outfp);
2223 }
2224
2225 LOCAL unsigned long do_write __PR((myringbuff *p));
2226 LOCAL unsigned long
do_write(p)2227 do_write(p)
2228 myringbuff *p;
2229 {
2230 int current_offset;
2231 unsigned int InSamples;
2232 static unsigned oper = 200;
2233
2234 current_offset = get_offset(p);
2235
2236 /* how many bytes are available? */
2237 InSamples = global.nsectors*CD_FRAMESAMPLES - current_offset/4;
2238 /* how many samples are wanted? */
2239 InSamples = min((*nSamplesToDo-nSamplesDone), InSamples);
2240
2241 while ((nSamplesDone < *nSamplesToDo) && (InSamples != 0)) {
2242 long unsigned int how_much = InSamples;
2243
2244 long int left_in_track;
2245 left_in_track = Get_StartSector(current_track_writing+1) *
2246 CD_FRAMESAMPLES
2247 - (int)(BeginAtSample+nSamplesDone);
2248
2249 if (*eorecording != 0 && current_track_writing == cdtracks+1 &&
2250 (*total_segments_read) == (*total_segments_written)+1) {
2251 /*
2252 * limit, if the actual end of the last track is
2253 * not known from the toc.
2254 */
2255 left_in_track = InSamples;
2256 }
2257
2258 if (left_in_track < 0) {
2259 errmsgno(EX_BAD,
2260 _("internal error: negative left_in_track:%ld, current_track_writing=%d\n"),
2261 left_in_track, current_track_writing);
2262 }
2263
2264 if (bulk) {
2265 how_much = min(how_much,
2266 (unsigned long) left_in_track);
2267 }
2268
2269 if (SaveBuffer(p->data + current_offset/4,
2270 how_much,
2271 &nSamplesDone)) {
2272 #ifdef HAVE_KILL
2273 if (global.have_forked == 1) {
2274 pid_t ppid;
2275 /*
2276 * Kill the parent too if we are not orphaned.
2277 */
2278 ppid = getppid();
2279 if (ppid > 1)
2280 kill(ppid, SIGINT);
2281 }
2282 #endif
2283 exit(WRITE_ERROR);
2284 }
2285
2286 global.nSamplesDoneInTrack += how_much;
2287 SamplesToWrite -= how_much;
2288
2289 /* move residual samples upto buffer start */
2290 if (how_much < InSamples) {
2291 memmove(
2292 (char *)(p->data) + current_offset,
2293 (char *)(p->data) + current_offset +
2294 how_much * 4,
2295 (InSamples - how_much) * 4);
2296 }
2297
2298 /* when track end is reached, close current file and start a new one */
2299 if ((unsigned long) left_in_track <= InSamples ||
2300 SamplesToWrite == 0) {
2301 /*
2302 * the current portion to be handled is
2303 * the end of a track
2304 */
2305
2306 if (bulk) {
2307 /* finish sample file for this track */
2308 CloseAudio(global.channels,
2309 global.nSamplesDoneInTrack,
2310 global.audio_out);
2311 } else if (SamplesToWrite == 0) {
2312 /* finish sample file for this track */
2313 CloseAudio(global.channels,
2314 (unsigned int) *nSamplesToDo,
2315 global.audio_out);
2316 }
2317 #ifdef INFOFILES
2318 if (global.no_infofile == 0) {
2319 write_md5_info(global.fname_base,
2320 current_track_writing,
2321 bulk && global.multiname == 0);
2322 }
2323 #endif
2324 if (global.verbose) {
2325 #ifdef USE_PARANOIA
2326 double f;
2327 double fc2 = 0.0;
2328
2329 if (global.paranoia_mode & PARANOIA_MODE_C2CHECK)
2330 fc2 = para_stat->c2secs * 100.0 /
2331 (para_stat->sectors * 1.0);
2332 #endif
2333 print_percentage(&oper, current_offset);
2334 fputc(' ', outfp);
2335
2336 #ifndef THOMAS_SCHAU_MAL
2337 if ((unsigned long)left_in_track > InSamples) {
2338 fputs(_(" incomplete"), outfp);
2339 }
2340 #endif
2341 if (global.tracktitle[current_track_writing] != NULL) {
2342 fprintf(outfp,
2343 _(" track %2u '%s' recorded"),
2344 current_track_writing,
2345 global.tracktitle[current_track_writing]);
2346 } else {
2347 fprintf(outfp,
2348 _(" track %2u recorded"),
2349 current_track_writing);
2350 }
2351 #ifdef USE_PARANOIA
2352 oper = para_stat->readerrs + para_stat->skips +
2353 para_stat->fixup_edges +
2354 para_stat->fixup_atoms +
2355 para_stat->fixup_droppeds +
2356 para_stat->fixup_dupeds +
2357 para_stat->drifts;
2358 f = (100.0 * oper) /
2359 (para_stat->sectors * 1.0);
2360
2361 if (para_stat->readerrs || para_stat->c2badsecs) {
2362 fprintf(outfp,
2363 _(" with audible hard errors"));
2364 fprintf(outfp,
2365 _(" %u c2badsecs"), para_stat->c2badsecs);
2366 } else if ((para_stat->skips) > 0) {
2367 fprintf(outfp,
2368 _(" with %sretry/skip errors"),
2369 f < 2.0 ? "":_("audible "));
2370 } else if (oper > 0) {
2371 oper = f;
2372
2373 fprintf(outfp, _(" with "));
2374 if (oper < 4)
2375 fprintf(outfp, _("minor"));
2376 else if (oper < 16)
2377 fprintf(outfp, _("medium"));
2378 else if (oper < 67)
2379 fprintf(outfp,
2380 _("noticeable audible"));
2381 else if (oper < 100)
2382 fprintf(outfp,
2383 _("major audible"));
2384 else
2385 fprintf(outfp,
2386 _("extreme audible"));
2387 fprintf(outfp, _(" problems"));
2388 } else {
2389 fprintf(outfp, _(" successfully"));
2390 }
2391 if (f >= 0.1 || fc2 > 0.1) {
2392 fprintf(outfp, " (");
2393 }
2394 if (f >= 0.1) {
2395 fprintf(outfp,
2396 _("%.1f%% problem sectors"), f);
2397 }
2398 if (fc2 >= 0.1) {
2399 if (f >= 0.1)
2400 fprintf(outfp, ", ");
2401 fprintf(outfp,
2402 _("%.2f%% c2 sectors"), fc2);
2403 }
2404 if (f >= 0.1 || fc2 > 0.1) {
2405 fprintf(outfp, ")");
2406 }
2407 #else
2408 fprintf(outfp, _(" successfully"));
2409 #endif
2410
2411 if (waitforsignal == 1) {
2412 fprintf(outfp,
2413 _(". %d silent samples omitted"),
2414 global.SkippedSamples);
2415 }
2416 fputs("\n", outfp);
2417
2418 if (global.reads_illleadout &&
2419 *eorecording == 1) {
2420 fprintf(outfp,
2421 _("Real lead out at: %ld sectors\n"),
2422 (*nSamplesToDo+BeginAtSample)/CD_FRAMESAMPLES);
2423 }
2424 #ifdef USE_PARANOIA
2425 if (global.paranoia_selected) {
2426 oper = 200; /* force new output */
2427 print_percentage(&oper, current_offset);
2428 if (para_stat->minoverlap == 0x7FFFFFFF)
2429 para_stat->minoverlap = 0;
2430 fprintf(outfp,
2431 _(" %u rderr, %u skip, %u atom, %u edge, %u drop, %u dup, %u drift"),
2432 para_stat->readerrs,
2433 para_stat->skips,
2434 para_stat->fixup_atoms,
2435 para_stat->fixup_edges,
2436 para_stat->fixup_droppeds,
2437 para_stat->fixup_dupeds,
2438 para_stat->drifts);
2439 if (global.paranoia_mode & PARANOIA_MODE_C2CHECK) {
2440 fprintf(outfp,
2441 _(", %u %u c2\n"), para_stat->c2errs, para_stat->c2secs);
2442 #ifdef PARANOIA_DEBUG
2443 fprintf(outfp,
2444 ", %u c2b", para_stat->c2bytes);
2445 fprintf(outfp,
2446 ", %u c2s", para_stat->c2secs);
2447 fprintf(outfp,
2448 ", %u c2m", para_stat->c2maxerrs);
2449 fprintf(outfp,
2450 ", %u c2B\n", para_stat->c2badsecs);
2451 #endif
2452 } else {
2453 fprintf(outfp, "\n");
2454 }
2455 oper = 200; /* force new output */
2456 print_percentage(&oper, current_offset);
2457 fprintf(outfp,
2458 _(" %u reads(%.1f%%) %u overlap(%.4g .. %.4g)\n"),
2459 para_stat->reads,
2460 para_stat->sectors*1.0 /
2461 (global.nSamplesDoneInTrack/588.0/100.0),
2462 para_stat->overlaps,
2463 (float)para_stat->minoverlap /
2464 (2352.0/2.0),
2465 (float)para_stat->maxoverlap /
2466 (2352.0/2.0));
2467 paranoia_statreset();
2468 }
2469 #endif
2470 }
2471
2472 global.nSamplesDoneInTrack = 0;
2473 if (bulk && SamplesToWrite > 0) {
2474 if (!global.no_file) {
2475 char *tmp_fname;
2476
2477 /* build next filename */
2478 tmp_fname = get_next_name();
2479 if (tmp_fname != NULL) {
2480 strncpy(global.fname_base,
2481 tmp_fname,
2482 sizeof (global.fname_base));
2483 global.fname_base[
2484 sizeof (global.fname_base)-1] =
2485 '\0';
2486 }
2487
2488 cut_extension(global.fname_base);
2489
2490 if (global.multiname == 0) {
2491 snprintf(fname, sizeof (fname),
2492 "%s_%02u.%s",
2493 global.fname_base,
2494 current_track_writing+1,
2495 audio_type);
2496 } else {
2497 snprintf(fname, sizeof (fname),
2498 "%s.%s",
2499 global.fname_base,
2500 audio_type);
2501 }
2502
2503 OpenAudio(fname, rate, bits,
2504 global.channels,
2505 (Get_AudioStartSector(current_track_writing+1) -
2506 Get_AudioStartSector(current_track_writing))
2507 *CD_FRAMESIZE_RAW,
2508 global.audio_out);
2509 } /* global.nofile */
2510 } /* if (bulk && SamplesToWrite > 0) */
2511 current_track_writing++;
2512
2513 } /* left_in_track <= InSamples */
2514 InSamples -= how_much;
2515
2516 } /* end while */
2517 if (!global.quiet && *nSamplesToDo != nSamplesDone) {
2518 print_percentage(&oper, current_offset);
2519 }
2520 return (nSamplesDone);
2521 }
2522
2523 #define PRINT_OVERLAP_INIT \
2524 if (global.verbose) { \
2525 if (global.overlap > 0) \
2526 fprintf(outfp, _("overlap:min/max/cur, jitter, percent_done:\n / / / 0%%")); \
2527 else \
2528 fputs(_("percent_done:\n 0%"), outfp); \
2529 }
2530
2531 #if defined HAVE_FORK_AND_SHAREDMEM
2532 LOCAL void forked_read __PR((void));
2533
2534 /*
2535 * This function does all audio cdrom reads
2536 * until there is nothing more to do
2537 */
2538 LOCAL void
forked_read()2539 forked_read()
2540 {
2541 unsigned total_unsuccessful_retries = 0;
2542
2543 #if !defined(HAVE_SEMGET) || !defined(USE_SEMAPHORES)
2544 init_child();
2545 #endif
2546
2547 minover = global.nsectors;
2548
2549 if (global.interactive) {
2550 int r;
2551
2552 #ifdef DEBUG_INTERACTIVE
2553 error("iloop %lu (%lu sects == %lu s) lSector %ld -> %ld\n",
2554 global.iloop, global.iloop/588, global.iloop/588/75,
2555 lSector, lSector_p2);
2556 error("*nSamplesToDo %ld nSamplesDone %ld\n",
2557 *nSamplesToDo, nSamplesDone);
2558 #endif
2559 lSector = Get_StartSector(FirstAudioTrack());
2560 lSector_p2 = Get_LastSectorOnCd(cdtracks);
2561 set_newstart(lSector);
2562
2563 r = parse(&lSector);
2564 if (r < 0) {
2565 set_nonforked(-1);
2566 /* NOTREACHED */
2567 }
2568 set_newstart(lSector);
2569 }
2570
2571 PRINT_OVERLAP_INIT
2572 while (global.iloop) {
2573 /* while (global.interactive || global.iloop) {*/
2574 /*
2575 * So blockiert es mit get_next_buffer() + get_oldest_buffer()
2576 * mit -interactive nach Ablauf des Auslesens des aktuellen Auftrags.
2577 */
2578
2579 if (global.interactive && poll_in() > 0) {
2580 int r = parse(&lSector);
2581 if (r < 0) {
2582 set_nonforked(-1);
2583 /* NOTREACHED */
2584 }
2585 set_newstart(lSector);
2586 }
2587
2588 do_read(get_next_buffer(), &total_unsuccessful_retries);
2589
2590 define_buffer();
2591 }
2592
2593 if (total_unsuccessful_retries) {
2594 fprintf(stderr,
2595 _("%u unsuccessful matches while reading\n"),
2596 total_unsuccessful_retries);
2597 }
2598 }
2599
2600 LOCAL void forked_write __PR((void));
2601
2602 LOCAL void
forked_write()2603 forked_write()
2604 {
2605
2606 /*
2607 * don't need these anymore. Good security policy says we get rid
2608 * of them ASAP
2609 */
2610 if (global.issetuid || global.uid != 0)
2611 priv_off();
2612 neverneedroot();
2613 neverneedgroup();
2614
2615 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
2616 #else
2617 init_parent();
2618 #endif
2619
2620 for (; global.interactive || nSamplesDone < *nSamplesToDo; ) {
2621 myringbuff *oldest_buffer;
2622
2623 if (*eorecording == 1 &&
2624 (*total_segments_read) == (*total_segments_written))
2625 break;
2626
2627 /*
2628 * get oldest buffers
2629 */
2630 oldest_buffer = get_oldest_buffer();
2631 if (oldest_buffer == NULL)
2632 break;
2633 nSamplesDone = do_write(oldest_buffer);
2634
2635 drop_buffer();
2636 }
2637 }
2638 #endif
2639
2640 /*
2641 * This function implements the read and write calls in one loop (in case
2642 * there is no fork/thread_create system call).
2643 * This means reads and writes have to wait for each other to complete.
2644 */
2645 LOCAL void nonforked_loop __PR((void));
2646
2647 LOCAL void
nonforked_loop()2648 nonforked_loop()
2649 {
2650 unsigned total_unsuccessful_retries = 0;
2651
2652 minover = global.nsectors;
2653
2654 if (global.interactive) {
2655 int r;
2656
2657 lSector = Get_StartSector(FirstAudioTrack());
2658 lSector_p2 = Get_LastSectorOnCd(cdtracks);
2659 set_newstart(lSector);
2660
2661 r = parse(&lSector);
2662 if (r < 0) {
2663 return;
2664 }
2665 set_newstart(lSector);
2666 }
2667
2668 PRINT_OVERLAP_INIT
2669 while (global.iloop) {
2670 myringbuff *oldest_buffer;
2671
2672 if (global.interactive && poll_in() > 0) {
2673 int r = parse(&lSector);
2674 if (r < 0) {
2675 break;
2676 }
2677 set_newstart(lSector);
2678 }
2679
2680 do_read(get_next_buffer(), &total_unsuccessful_retries);
2681
2682 oldest_buffer = get_oldest_buffer();
2683 if (oldest_buffer == NULL)
2684 break;
2685 do_write(oldest_buffer);
2686 }
2687
2688 if (total_unsuccessful_retries) {
2689 fprintf(stderr, _("%u unsuccessful matches while reading\n"), total_unsuccessful_retries);
2690 }
2691 }
2692
2693 LOCAL void verbose_usage __PR((void));
2694
2695 LOCAL void
verbose_usage()2696 verbose_usage()
2697 {
2698 fputs(_("\
2699 help lists all verbose options.\n\
2700 disable disables verbose mode.\n\
2701 all enables all verbose options.\n\
2702 toc display the table of contents.\n\
2703 summary display a summary of track parameters.\n\
2704 indices retrieve/display index positions.\n\
2705 catalog retrieve/display media catalog number.\n\
2706 mcn retrieve/display media catalog number.\n\
2707 trackid retrieve/display international standard recording code.\n\
2708 isrc retrieve/display international standard recording code.\n\
2709 sectors display the start sectors of each track.\n\
2710 titles display any known track titles.\n\
2711 audio-tracks list the audio tracks and their start sectors.\n\
2712 "), stderr);
2713 }
2714
2715 #ifdef USE_PARANOIA
2716 LOCAL void paranoia_usage __PR((void));
2717
2718 LOCAL void
paranoia_usage()2719 paranoia_usage()
2720 {
2721 /* BEGIN CSTYLED */
2722 fputs(_("\
2723 help lists all paranoia options.\n\
2724 disable disables paranoia mode. Paranoia is still being used.\n\
2725 no-verify switches verify off, and overlap on.\n\
2726 retries=amount set the number of maximum retries per sector.\n\
2727 readahead=amount set the number of sectors to use for the read ahead buffer.\n\
2728 overlap=amount set the number of sectors used for statical overlap.\n\
2729 minoverlap=amt set the min. number of sectors used for dynamic overlap.\n\
2730 maxoverlap=amt set the max. number of sectors used for dynamic overlap.\n\
2731 c2check check C2 pointers from drive to rate quality.\n\
2732 proof alias: minoverlap=20,retries=200,readahead=600,c2check.\n\
2733 "),
2734 stderr);
2735 /* END CSTYLED */
2736 }
2737 #endif
2738
2739 LOCAL int
2740 handle_verbose_opts __PR((char *optstr, long *flagp));
2741
2742 LOCAL int
handle_verbose_opts(optstr,flagp)2743 handle_verbose_opts(optstr, flagp)
2744 char *optstr;
2745 long *flagp;
2746 {
2747 char *ep;
2748 char *np;
2749 int optlen;
2750 BOOL not = FALSE;
2751
2752 *flagp = 0;
2753 while (*optstr) {
2754 if ((ep = strchr(optstr, ',')) != NULL) {
2755 optlen = ep - optstr;
2756 np = ep + 1;
2757 } else {
2758 optlen = strlen(optstr);
2759 np = optstr + optlen;
2760 }
2761 if (optstr[0] == '!') {
2762 optstr++;
2763 optlen--;
2764 not = TRUE;
2765 }
2766 if (strncmp(optstr, "not", optlen) == 0 ||
2767 strncmp(optstr, "!", optlen) == 0) {
2768 not = TRUE;
2769 } else if (strncmp(optstr, "toc", optlen) == 0) {
2770 *flagp |= SHOW_TOC;
2771 } else if (strncmp(optstr, "summary", optlen) == 0) {
2772 *flagp |= SHOW_SUMMARY;
2773 } else if (strncmp(optstr, "indices", optlen) == 0) {
2774 *flagp |= SHOW_INDICES;
2775 } else if (strncmp(optstr, "catalog", optlen) == 0) {
2776 *flagp |= SHOW_MCN;
2777 } else if (strncmp(optstr, "MCN", optlen) == 0) {
2778 *flagp |= SHOW_MCN;
2779 } else if (strncmp(optstr, "mcn", optlen) == 0) {
2780 *flagp |= SHOW_MCN;
2781 } else if (strncmp(optstr, "trackid", optlen) == 0) {
2782 *flagp |= SHOW_ISRC;
2783 } else if (strncmp(optstr, "ISRC", optlen) == 0) {
2784 *flagp |= SHOW_ISRC;
2785 } else if (strncmp(optstr, "isrc", optlen) == 0) {
2786 *flagp |= SHOW_ISRC;
2787 } else if (strncmp(optstr, "sectors", optlen) == 0) {
2788 *flagp |= SHOW_STARTPOSITIONS;
2789 } else if (strncmp(optstr, "titles", optlen) == 0) {
2790 *flagp |= SHOW_TITLES;
2791 } else if (strncmp(optstr, "audio-tracks", optlen) == 0) {
2792 *flagp |= SHOW_JUSTAUDIOTRACKS;
2793 } else if (strncmp(optstr, "all", optlen) == 0) {
2794 *flagp |= SHOW_MAX;
2795 } else if (strncmp(optstr, "disable", optlen) == 0) {
2796 *flagp = 0;
2797 } else if (strncmp(optstr, "help", optlen) == 0) {
2798 verbose_usage();
2799 exit(NO_ERROR);
2800 } else {
2801 char *endptr;
2802 unsigned arg = strtoul(optstr, &endptr, 10);
2803 if (optstr != endptr &&
2804 arg <= SHOW_MAX) {
2805 *flagp |= arg;
2806 errmsgno(EX_BAD,
2807 _("Warning: numerical parameters for -v are no more supported in the next releases!\n"));
2808 } else {
2809 errmsgno(EX_BAD,
2810 _("Unknown option '%s'.\n"), optstr);
2811 verbose_usage();
2812 exit(SYNTAX_ERROR);
2813 }
2814 }
2815 optstr = np;
2816 }
2817 if (not)
2818 *flagp = (~ *flagp) & SHOW_MAX;
2819 return (1);
2820 }
2821
2822
2823 LOCAL int
2824 handle_paranoia_opts __PR((char *optstr, long *flagp));
2825
2826 LOCAL int
handle_paranoia_opts(optstr,flagp)2827 handle_paranoia_opts(optstr, flagp)
2828 char *optstr;
2829 long *flagp;
2830 {
2831 #ifdef USE_PARANOIA
2832 char *ep;
2833 char *np;
2834 int optlen;
2835
2836 while (*optstr) {
2837 if ((ep = strchr(optstr, ',')) != NULL) {
2838 optlen = ep - optstr;
2839 np = ep + 1;
2840 } else {
2841 optlen = strlen(optstr);
2842 np = optstr + optlen;
2843 }
2844 if (strncmp(optstr, "retries=", min(8, optlen)) == 0) {
2845 char *eqp = strchr(optstr, '=');
2846 int rets;
2847
2848 astoi(eqp+1, &rets);
2849 if (rets >= 0) {
2850 global.paranoia_parms.retries = rets;
2851 }
2852 } else if (strncmp(optstr, "readahead=", min(10, optlen)) == 0) {
2853 char *eqp = strchr(optstr, '=');
2854 int readahead;
2855
2856 astoi(eqp+1, &readahead);
2857 if (readahead >= 0) {
2858 global.paranoia_parms.readahead = readahead;
2859 }
2860 } else if (strncmp(optstr, "overlap=", min(8, optlen)) == 0) {
2861 char *eqp = strchr(optstr, '=');
2862 int rets;
2863
2864 astoi(eqp+1, &rets);
2865 if (rets >= 0) {
2866 global.paranoia_parms.overlap = rets;
2867 }
2868 } else if (strncmp(optstr, "minoverlap=",
2869 min(11, optlen)) == 0) {
2870 char *eqp = strchr(optstr, '=');
2871 int rets;
2872
2873 astoi(eqp+1, &rets);
2874 if (rets >= 0) {
2875 global.paranoia_parms.mindynoverlap = rets;
2876 }
2877 } else if (strncmp(optstr, "maxoverlap=",
2878 min(11, optlen)) == 0) {
2879 char *eqp = strchr(optstr, '=');
2880 int rets;
2881
2882 astoi(eqp+1, &rets);
2883 if (rets >= 0) {
2884 global.paranoia_parms.maxdynoverlap = rets;
2885 }
2886 } else if (strncmp(optstr, "no-verify", optlen) == 0) {
2887 global.paranoia_parms.disable_extra_paranoia = 1;
2888 } else if (strncmp(optstr, "disable", optlen) == 0) {
2889 global.paranoia_parms.disable_paranoia = 1;
2890 } else if (strncmp(optstr, "c2check", optlen) == 0) {
2891 global.paranoia_parms.enable_c2_check = 1;
2892 } else if (strncmp(optstr, "help", optlen) == 0) {
2893 paranoia_usage();
2894 exit(NO_ERROR);
2895 } else if (strncmp(optstr, "proof", optlen) == 0) {
2896 *flagp = 1;
2897 global.paranoia_parms.mindynoverlap = -1;
2898 global.paranoia_parms.retries = 200;
2899 global.paranoia_parms.readahead = 600;
2900 #define __should_we__
2901 #ifdef __should_we__
2902 /*
2903 * c2check may cause some drives to become unable
2904 * to read hidden tracks.
2905 */
2906 global.paranoia_parms.enable_c2_check = 1;
2907 #endif
2908 } else {
2909 errmsgno(EX_BAD, _("Unknown option '%s'.\n"), optstr);
2910 paranoia_usage();
2911 exit(SYNTAX_ERROR);
2912 }
2913 optstr = np;
2914 }
2915 global.paranoia_selected = TRUE;
2916 return (1);
2917 #else
2918 errmsgno(EX_BAD, _("lib paranoia support is not configured!\n"));
2919 return (0);
2920 #endif
2921 }
2922
2923
2924 /*
2925 * and finally: the MAIN program
2926 */
2927 EXPORT int
main(argc,argv)2928 main(argc, argv)
2929 int argc;
2930 char *argv[];
2931 {
2932 long lSector_p1;
2933 char *env_p;
2934 #if defined(USE_NLS)
2935 char *dir;
2936 #endif
2937 int tracks_included;
2938
2939 audio_type = AUDIOTYPE;
2940
2941 #ifdef HAVE_SOLARIS_PPRIV
2942 /*
2943 * Try to gain additional privs on Solaris
2944 */
2945 do_pfexec(argc, argv,
2946 PRIV_FILE_DAC_READ,
2947 PRIV_SYS_DEVICES,
2948 PRIV_PROC_PRIOCNTL,
2949 PRIV_NET_PRIVADDR,
2950 NULL);
2951 #endif
2952 save_args(argc, argv);
2953
2954 #if defined(USE_NLS)
2955 (void) setlocale(LC_ALL, "");
2956 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
2957 #define TEXT_DOMAIN "cdda2wav" /* Use this only if it weren't */
2958 #endif
2959 dir = searchfileinpath("share/locale", F_OK,
2960 SIP_ANY_FILE|SIP_NO_PATH, NULL);
2961 if (dir)
2962 (void) bindtextdomain(TEXT_DOMAIN, dir);
2963 else
2964 #if defined(PROTOTYPES) && defined(INS_BASE)
2965 (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
2966 #else
2967 (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
2968 #endif
2969 (void) textdomain(TEXT_DOMAIN);
2970 #endif
2971
2972 /*
2973 * init global variables
2974 */
2975 init_globals();
2976 {
2977 int am_i_cdda2wav;
2978
2979 /*
2980 * When being invoked as list_audio_tracks, just dump a list of
2981 * audio tracks.
2982 */
2983 am_i_cdda2wav = !(strlen(argv[0]) >= sizeof ("list_audio_tracks")-1 &&
2984 strcmp(argv[0]+strlen(argv[0])+1-sizeof ("list_audio_tracks"), "list_audio_tracks") == 0);
2985 if (!am_i_cdda2wav)
2986 global.verbose = SHOW_JUSTAUDIOTRACKS;
2987 }
2988
2989 /*
2990 * Control those set-id and privileges...
2991 *
2992 * At this point, we should have the needed privileges, either because:
2993 *
2994 * 1) We have been called by a privileged user (eg. root)
2995 * 2) This is a suid-root process
2996 * 3) This is a process that did call pfexec to gain privs
2997 * 4) This is a process that has been called via pfexec
2998 * 5) This is a process that gained privs via fcaps
2999 *
3000 * Case (1) is the only case where whe should not give up privileges
3001 * because people would not expect it and because there will be no
3002 * privilege escalation in this process.
3003 */
3004 global.uid = getuid();
3005 global.euid = geteuid();
3006 #ifdef HAVE_ISSETUGID
3007 global.issetuid = issetugid();
3008 #else
3009 global.issetuid = global.uid != global.euid;
3010 #endif
3011 if (global.issetuid || global.uid != 0) {
3012 /*
3013 * If this is a suid-root process or if the real uid of
3014 * this process is not root, we may have gained privileges
3015 * from suid-root or pfexec and need to manage privileges in
3016 * order to prevent privilege escalations for the user.
3017 */
3018 priv_init();
3019 }
3020 initsecurity();
3021
3022 env_p = getenv("CDDA_DEVICE");
3023 if (env_p != NULL) {
3024 global.dev_name = env_p;
3025 }
3026
3027 env_p = getenv("CDDBP_SERVER");
3028 if (env_p != NULL) {
3029 global.cddbp_server = env_p;
3030 }
3031
3032 env_p = getenv("CDDBP_PORT");
3033 if (env_p != NULL) {
3034 global.cddbp_port = env_p;
3035 }
3036
3037 gargs(argc, argv);
3038
3039 /*
3040 * The check has been introduced as some Linux distributions miss the
3041 * skills to perceive the necessity for the needed privileges. So we
3042 * warn which features are impaired by actually missing privileges.
3043 */
3044 if (global.issetuid || global.uid != 0)
3045 priv_on();
3046 needroot(0);
3047 if (!priv_eff_priv(SCHILY_PRIV_FILE_DAC_READ))
3048 priv_warn("file read", "You will not be able to open all needed devices.");
3049 #ifndef __SUNOS5
3050 /*
3051 * Due to a design bug in the Solaris USCSI ioctl, we don't need
3052 * PRIV_FILE_DAC_WRITE to send SCSI commands and most installations
3053 * probably don't grant PRIV_FILE_DAC_WRITE. Once we need /dev/scg*,
3054 * we would need to test for PRIV_FILE_DAC_WRITE also.
3055 */
3056 if (!priv_eff_priv(SCHILY_PRIV_FILE_DAC_WRITE))
3057 priv_warn("file write", "You will not be able to open all needed devices.");
3058 #endif
3059 if (!priv_eff_priv(SCHILY_PRIV_SYS_DEVICES))
3060 priv_warn("device",
3061 "You may not be able to send all needed SCSI commands, this my cause various unexplainable problems.");
3062 if (!priv_eff_priv(SCHILY_PRIV_PROC_PRIOCNTL))
3063 priv_warn("priocntl", "You may get jitter.");
3064 if (!priv_eff_priv(SCHILY_PRIV_NET_PRIVADDR))
3065 priv_warn("network", "You will not be able to do remote SCSI.");
3066 if (global.issetuid || global.uid != 0)
3067 priv_off();
3068 dontneedroot();
3069
3070 #define SETSIGHAND(PROC, SIG, SIGNAME) if (signal(SIG, PROC) == SIG_ERR) \
3071 { errmsg(_("Cannot set signal %s handler.\n"), SIGNAME); exit(SETSIG_ERROR); }
3072 #ifdef SIGINT
3073 SETSIGHAND(exit_wrapper, SIGINT, "SIGINT")
3074 #endif
3075 #ifdef SIGQUIT
3076 SETSIGHAND(exit_wrapper, SIGQUIT, "SIGQUIT")
3077 #endif
3078 #ifdef SIGTERM
3079 SETSIGHAND(exit_wrapper, SIGTERM, "SIGTERM")
3080 #endif
3081 #ifdef SIGHUP
3082 SETSIGHAND(exit_wrapper, SIGHUP, "SIGHUP")
3083 #endif
3084 #ifdef SIGPIPE
3085 SETSIGHAND(set_nonforked, SIGPIPE, "SIGPIPE")
3086 #endif
3087
3088 /* setup interface and open cdrom device */
3089 /*
3090 * request sychronization facilities and shared memory
3091 */
3092 SetupInterface();
3093
3094 /*
3095 * use global.useroverlap to set our overlap
3096 */
3097 if (global.useroverlap != -1)
3098 global.overlap = global.useroverlap;
3099
3100 /*
3101 * check for more valid option combinations
3102 */
3103 if (global.nsectors < 1+global.overlap) {
3104 errmsgno(EX_BAD,
3105 _("Warning: Setting #nsectors to minimum of %d, due to jitter correction!\n"),
3106 global.overlap+1);
3107 global.nsectors = global.overlap+1;
3108 }
3109
3110 if (global.overlap > 0 && global.buffers < 2) {
3111 errmsgno(EX_BAD,
3112 _("Warning: Setting #buffers to minimum of 2, due to jitter correction!\n"));
3113 global.buffers = 2;
3114 }
3115
3116 /*
3117 * Value of 'nsectors' must be defined here
3118 */
3119 global.shmsize = 0;
3120 #ifdef USE_PARANOIA
3121 while (global.shmsize < sizeof (struct paranoia_statistics))
3122 global.shmsize += global.pagesize;
3123 #endif
3124 #ifdef MD5_SIGNATURES
3125 { int i = 0;
3126 while (i < sizeof (MD5_CTX))
3127 i += global.pagesize;
3128 global.shmsize += i;
3129 }
3130 #endif
3131 global.shmsize += 10*global.pagesize; /* XXX Der Speicherfehler ist nicht in libparanoia sondern in cdda2wav :-( */
3132 global.shmsize += HEADER_SIZE + ENTRY_SIZE_PAGE_AL * global.buffers;
3133
3134 #if defined(HAVE_FORK_AND_SHAREDMEM)
3135 /*
3136 * The (void *) cast is to avoid a GCC warning like:
3137 * warning: dereferencing type-punned pointer will break
3138 * strict-aliasing rules
3139 * which does not apply to this code. (void *) introduces a compatible
3140 * intermediate type in the cast list.
3141 */
3142 he_fill_buffer = request_shm_sem(global.shmsize,
3143 (unsigned char **)(void *)&he_fill_buffer);
3144 if (he_fill_buffer == NULL) {
3145 errmsgno(EX_BAD, _("No shared memory available!\n"));
3146 exit(SHMMEM_ERROR);
3147 }
3148 #else /* do not have fork() and shared memory */
3149 he_fill_buffer = malloc(global.shmsize);
3150 if (he_fill_buffer == NULL) {
3151 errmsg(_("No buffer memory available!\n"));
3152 exit(NOMEM_ERROR);
3153 }
3154 #endif
3155 #ifdef USE_PARANOIA
3156 {
3157 int i = 0;
3158 char *ptr = (char *)he_fill_buffer;
3159
3160 para_stat = (struct paranoia_statistics *)he_fill_buffer;
3161 while (i < sizeof (struct paranoia_statistics)) {
3162 i += global.pagesize;
3163 ptr += global.pagesize;
3164 global.shmsize -= global.pagesize;
3165 }
3166 he_fill_buffer = (myringbuff **)ptr;
3167 }
3168 #endif
3169 #ifdef MD5_SIGNATURES
3170 {
3171 int i = 0;
3172 char *ptr = (char *)he_fill_buffer;
3173
3174 global.context = (MD5_CTX*)he_fill_buffer;
3175 while (i < sizeof (MD5_CTX))
3176 i += global.pagesize;
3177 ptr += i;
3178 global.shmsize -= i;
3179
3180 he_fill_buffer = (myringbuff **)ptr;
3181 }
3182 #endif
3183
3184 if (global.verbose != 0) {
3185 fprintf(outfp,
3186 _("%u bytes buffer memory requested, transfer size %ld bytes, %u buffers, %u sectors\n"),
3187 global.shmsize, global.bufsize, global.buffers, global.nsectors);
3188 }
3189
3190 /*
3191 * initialize pointers into shared memory segment
3192 */
3193 last_buffer = he_fill_buffer + 1;
3194 total_segments_read = (unsigned long *) (last_buffer + 1);
3195 total_segments_written = total_segments_read + 1;
3196 child_waits = (int *) (total_segments_written + 1);
3197 parent_waits = child_waits + 1;
3198 in_lendian = parent_waits + 1;
3199 eorecording = in_lendian + 1;
3200 *total_segments_read = *total_segments_written = 0;
3201 nSamplesToDo = (unsigned long *)(eorecording + 1);
3202 *eorecording = 0;
3203 *in_lendian = global.in_lendian;
3204
3205 set_total_buffers(global.buffers, sem_id);
3206
3207
3208 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
3209 atexit(free_sem);
3210 #endif
3211
3212 /*
3213 * set input endian default
3214 */
3215 if (global.littleendian != -1)
3216 *in_lendian = global.littleendian;
3217
3218 /*
3219 * get table of contents
3220 */
3221 cdtracks = ReadToc();
3222 if (cdtracks == 0) {
3223 errmsgno(EX_BAD,
3224 _("No track in table of contents! Aborting...\n"));
3225 exit(MEDIA_ERROR);
3226 } else if (global.maxtrack) {
3227 global.endtrack = cdtracks;
3228 }
3229
3230 calc_cddb_id();
3231 calc_cdindex_id();
3232
3233 #if 1
3234 Check_Toc();
3235 #endif
3236
3237 if (ReadTocText != NULL && FirstAudioTrack() != -1) {
3238 ReadTocText(get_scsi_p());
3239 handle_cdtext();
3240 /*
3241 * Starting from here, we cannot issue any SCSI command that
3242 * overwrites the buffer used to read on the CD-Text data until
3243 * FixupTOC() has been called.
3244 */
3245 }
3246 if (global.verbose == SHOW_JUSTAUDIOTRACKS) {
3247 unsigned int z;
3248
3249 /*
3250 * XXX We did not check for hidden Track here
3251 */
3252 for (z = 0; z <= cdtracks; z++) {
3253 if (Get_Datatrack(z) == 0) {
3254 printf("%02d\t%06ld\n",
3255 Get_Tracknumber(z),
3256 Get_AudioStartSector(z));
3257 }
3258 }
3259 exit(NO_ERROR);
3260 }
3261
3262 if (global.verbose != 0) {
3263 fputs(_("#Cdda2wav version "), outfp);
3264 fputs(VERSION_DATE, outfp);
3265 fputs(" ", outfp);
3266 fputs(VERSION, outfp);
3267 fputs(VERSION_OS, outfp);
3268 #if defined USE_POSIX_PRIORITY_SCHEDULING || defined HAVE_SYS_PRIOCNTL_H
3269 fputs(_(", real time sched."), outfp);
3270 #endif
3271 #if defined ECHO_TO_SOUNDCARD
3272 fputs(_(", soundcard"), outfp);
3273 #endif
3274 #if defined USE_PARANOIA
3275 fputs(_(", libparanoia"), outfp);
3276 #endif
3277 fputs(_(" support\n"), outfp);
3278 }
3279
3280 /*
3281 * Also handles the CD-Text or CD-Extra information that has been read
3282 * avove with ReadTocText().
3283 */
3284 FixupTOC(cdtracks + 1);
3285
3286 if (track == (unsigned int)-1) {
3287 if (useHiddenTrack() && (bulk || global.alltracks))
3288 global.endtrack = track = 0;
3289 else
3290 global.endtrack = track = 1;
3291 if (bulk || global.alltracks)
3292 global.endtrack = cdtracks;
3293 }
3294
3295 #if 0
3296 if (!global.paranoia_selected) {
3297 error("NICE\n");
3298 /*
3299 * try to get some extra kicks
3300 */
3301 if (global.issetuid || global.uid != 0)
3302 priv_on();
3303 needroot(0);
3304 #if defined HAVE_SETPRIORITY
3305 setpriority(PRIO_PROCESS, 0, -20);
3306 #else
3307 #if defined(HAVE_NICE) && (HAVE_NICE == 1)
3308 nice(-NZERO);
3309 #endif
3310 #endif
3311 if (global.issetuid || global.uid != 0)
3312 priv_off();
3313 dontneedroot();
3314 }
3315 #endif
3316
3317 /*
3318 * switch cdrom to audio mode
3319 */
3320 EnableCdda(get_scsi_p(), 1, CD_FRAMESIZE_RAW);
3321
3322 atexit(CloseAll);
3323
3324 DisplayToc();
3325 if (FirstAudioTrack() == -1) {
3326 if (no_disguised_audiotracks()) {
3327 FatalError(EX_BAD,
3328 _("This disk has no audio tracks.\n"));
3329 }
3330 }
3331
3332 /*
3333 * check if start track is in range
3334 */
3335 if (track < 1 || track > cdtracks) {
3336 if (!(track == 0 && useHiddenTrack()))
3337 usage2(_("Incorrect start track setting: %d\n"), track);
3338 }
3339
3340 /*
3341 * check if end track is in range
3342 */
3343 if (global.endtrack < track || global.endtrack > cdtracks) {
3344 usage2(_("Incorrect end track setting: %ld\n"), global.endtrack);
3345 }
3346
3347 /*
3348 * Find track that is related to the absolute sector offset.
3349 */
3350 if (global.start_sector != -1) {
3351 int t;
3352
3353 for (t = 1; t <= cdtracks; t++) {
3354 lSector = Get_AudioStartSector(t);
3355 lSector_p1 = Get_EndSector(t) + 1;
3356 if (lSector < 0)
3357 continue;
3358 if (global.start_sector >= lSector &&
3359 global.start_sector < lSector_p1) {
3360 track = t;
3361 global.sector_offset = global.start_sector - lSector;
3362 } else if (t == 1 && useHiddenTrack() &&
3363 global.start_sector >= 0 &&
3364 global.start_sector < lSector) {
3365 lSector = global.start_sector;
3366 track = 0;
3367 }
3368 if (bulk || global.alltracks)
3369 global.endtrack = t;
3370 }
3371 }
3372
3373 do {
3374 if (track == 0) {
3375 lSector = 0;
3376 lSector_p1 = Get_AudioStartSector(1);
3377 } else {
3378 lSector = Get_AudioStartSector(track);
3379 lSector_p1 = Get_EndSector(track) + 1;
3380 }
3381 if (lSector < 0) {
3382 if (bulk == 0 && !global.alltracks) {
3383 FatalError(EX_BAD,
3384 _("Track %u not found.\n"), track);
3385 } else {
3386 fprintf(outfp,
3387 _("Skipping data track %u...\n"), track);
3388 if (global.endtrack == track)
3389 global.endtrack++;
3390 track++;
3391 }
3392 }
3393 } while ((bulk != 0 || global.alltracks) && track <= cdtracks && lSector < 0);
3394
3395 Read_MCN_ISRC(track, global.endtrack);
3396
3397 if ((global.illleadout_cd == 0 || global.reads_illleadout != 0) &&
3398 global.cd_index != -1) {
3399 if (global.verbose && !global.quiet) {
3400 global.verbose |= SHOW_INDICES;
3401 }
3402 global.sector_offset += ScanIndices(track, global.cd_index, bulk || global.alltracks);
3403 } else {
3404 global.cd_index = 1;
3405 if (global.deemphasize || (global.verbose & SHOW_INDICES)) {
3406 ScanIndices(track, global.cd_index, bulk || global.alltracks);
3407 }
3408 }
3409
3410 lSector += global.sector_offset;
3411 /*
3412 * check against end sector of track
3413 */
3414 if (lSector >= lSector_p1) {
3415 fprintf(stderr,
3416 _("W Sector offset %ld exceeds track size (ignored)\n"),
3417 global.sector_offset);
3418 lSector -= global.sector_offset;
3419 }
3420
3421 if (lSector < 0L) {
3422 fputs(_("Negative start sector! Set to zero.\n"), stderr);
3423 lSector = 0L;
3424 }
3425
3426 lSector_p2 = Get_LastSectorOnCd(track);
3427 if ((bulk == 1 || global.alltracks) && track == global.endtrack && global.rectime == 0.0)
3428 global.rectime = 99999.0;
3429 if (global.rectime == 0.0) {
3430 /*
3431 * set time to track time
3432 */
3433 *nSamplesToDo = (lSector_p1 - lSector) * CD_FRAMESAMPLES;
3434 global.rectime = (lSector_p1 - lSector) / 75.0;
3435 if (CheckTrackrange(track, global.endtrack) == 1) {
3436 lSector_p2 = Get_EndSector(global.endtrack) + 1;
3437
3438 if (lSector_p2 >= 0) {
3439 global.rectime = (lSector_p2 - lSector) / 75.0;
3440 *nSamplesToDo = (long)(global.rectime*44100.0 + 0.5);
3441 } else {
3442 fputs(
3443 _("End track is no valid audio track (ignored)\n"),
3444 stderr);
3445 }
3446 } else {
3447 fputs(
3448 _("Track range does not consist of audio tracks only (ignored)\n"),
3449 stderr);
3450 }
3451 } else {
3452 /*
3453 * Prepare the maximum recording duration.
3454 * It is defined as the biggest amount of
3455 * adjacent audio sectors beginning with the
3456 * specified track/index/offset.
3457 */
3458 if (global.rectime > (lSector_p2 - lSector) / 75.0) {
3459 global.rectime = (lSector_p2 - lSector) / 75.0;
3460 lSector_p1 = lSector_p2;
3461 }
3462
3463 /* calculate # of samples to read */
3464 *nSamplesToDo = (long)(global.rectime*44100.0 + 0.5);
3465 }
3466
3467 global.OutSampleSize = (1+bits/12);
3468 if (*nSamplesToDo/undersampling == 0L) {
3469 usage2(_("Time interval is too short. Choose a duration greater than %d.%02d secs!\n"),
3470 undersampling/44100, (int)(undersampling/44100) % 100);
3471 }
3472 if (global.moreargs < argc) {
3473 if (strcmp(argv[global.moreargs], "-") == 0 ||
3474 is_fifo(argv[global.moreargs])) {
3475 /*
3476 * pipe mode
3477 */
3478 if (bulk == 1) {
3479 fprintf(stderr,
3480 _("W Bulk mode is disabled while outputting to a %spipe\n"),
3481 is_fifo(argv[global.moreargs]) ?
3482 "named " : "");
3483 bulk = 0;
3484 }
3485 global.no_cddbfile = 1;
3486 }
3487 }
3488 if (global.no_infofile == 0) {
3489 global.no_infofile = 1;
3490 if (global.channels == 1 || bits != 16 || rate != 44100) {
3491 fprintf(stderr,
3492 _("W Sample conversions disable generation of info files!\n"));
3493 } else if (waitforsignal == 1) {
3494 fprintf(stderr,
3495 _("W Option -w 'wait for signal' disables generation of info files!\n"));
3496 } else if (global.alltracks) {
3497 fprintf(stderr,
3498 _("W Option -tall 'all tracks into one file' disables generation of info files!\n"));
3499 } else if (global.sector_offset != 0) {
3500 fprintf(stderr,
3501 _("W Using an start offset (option -o) disables generation of info files!\n"));
3502 } else if (!bulk && !global.alltracks &&
3503 !((lSector == Get_AudioStartSector(track)) &&
3504 ((long)(lSector + global.rectime*75.0 + 0.5) ==
3505 Get_EndSector(global.endtrack) + 1))) {
3506 fprintf(stderr,
3507 _("W Duration is not set for complete tracks (option -d), this disables generation\n of info files!\n"));
3508 } else {
3509 global.no_infofile = 0;
3510 }
3511 }
3512 if (global.cuefile) {
3513 if (global.outputendianess != NONE) {
3514 fprintf(stderr,
3515 _("W Option -E 'outout endianess' disables generation of cue file!\n"));
3516 global.cuefile = 0;
3517 } else if (!global.alltracks) {
3518 fprintf(stderr,
3519 _("W Not selecting all tracks disables generation of cue file!\n"));
3520 global.cuefile = 0;
3521 }
3522 }
3523
3524 SamplesToWrite = *nSamplesToDo*2/(int)global.int_part;
3525
3526 {
3527 int first = FirstAudioTrack();
3528
3529 tracks_included = Get_Track(
3530 (unsigned) (lSector +
3531 *nSamplesToDo/CD_FRAMESAMPLES -1))
3532 - max((int)track, first) +1;
3533 }
3534
3535 if (global.multiname != 0 && global.moreargs + tracks_included > argc) {
3536 global.multiname = 0;
3537 }
3538
3539 if (!waitforsignal) {
3540
3541 #ifdef INFOFILES
3542 if (!global.no_infofile) {
3543 int i;
3544
3545 for (i = track; i < (int)track + tracks_included; i++) {
3546 unsigned minsec, maxsec;
3547 char *tmp_fname;
3548
3549 /*
3550 * build next filename
3551 */
3552 tmp_fname = get_next_name();
3553 if (tmp_fname != NULL)
3554 strncpy(global.fname_base, tmp_fname,
3555 sizeof (global.fname_base)-8);
3556 global.fname_base[sizeof (global.fname_base)-1] = 0;
3557 minsec = max(lSector, Get_AudioStartSector(i));
3558 maxsec = min(lSector + global.rectime*75.0 + 0.5,
3559 1+Get_EndSector(i));
3560 if ((int)minsec == Get_AudioStartSector(i) &&
3561 (int)maxsec == 1+Get_EndSector(i)) {
3562 write_info_file(global.fname_base, i,
3563 (maxsec-minsec)*CD_FRAMESAMPLES,
3564 bulk && global.multiname == 0);
3565 } else {
3566 fprintf(stderr,
3567 _("Partial length copy for track %d, no info file will be generated for this track!\n"), i);
3568 }
3569 if (!bulk)
3570 break;
3571 }
3572 reset_name_iterator();
3573 }
3574 #endif
3575 if (global.cuefile) {
3576 int i;
3577 char *tmp_fname;
3578 FILE *cuef;
3579
3580 /*
3581 * build next filename
3582 */
3583 tmp_fname = get_next_name();
3584 if (tmp_fname != NULL)
3585 strncpy(global.fname_base, tmp_fname,
3586 sizeof (global.fname_base)-8);
3587 global.fname_base[sizeof (global.fname_base)-1] = 0;
3588 cut_extension(global.fname_base);
3589
3590 cuef = cue_file_open(global.fname_base);
3591 write_cue_global(cuef, global.fname_base);
3592
3593 for (i = track; i < (int)track + tracks_included; i++) {
3594 unsigned minsec, maxsec;
3595
3596 minsec = max(lSector, Get_AudioStartSector(i));
3597 maxsec = min(lSector + global.rectime*75.0 + 0.5,
3598 1+Get_EndSector(i));
3599 if ((int)minsec == Get_AudioStartSector(i) &&
3600 (int)maxsec == 1+Get_EndSector(i)) {
3601 write_cue_track(cuef, global.fname_base, i);
3602 }
3603
3604 /*
3605 * build next filename
3606 */
3607 tmp_fname = get_next_name();
3608 if (tmp_fname != NULL)
3609 strncpy(global.fname_base, tmp_fname,
3610 sizeof (global.fname_base)-8);
3611 global.fname_base[sizeof (global.fname_base)-1] = 0;
3612 cut_extension(global.fname_base);
3613 }
3614 reset_name_iterator();
3615 if (cuef)
3616 fclose(cuef);
3617 }
3618 }
3619
3620 if (global.just_the_toc)
3621 exit(NO_ERROR);
3622
3623 #ifdef ECHO_TO_SOUNDCARD
3624 if (global.user_sound_device[0] != '\0') {
3625 set_snd_device(global.user_sound_device);
3626 }
3627 if (global.no_fork)
3628 init_soundcard(rate, bits);
3629 #endif /* ECHO_TO_SOUNDCARD */
3630
3631 if (global.userspeed > -1)
3632 global.speed = global.userspeed;
3633
3634 if (global.speed != 0 && SelectSpeed != NULL) {
3635 SelectSpeed(get_scsi_p(), global.speed);
3636 }
3637
3638 current_track_reading = current_track_writing = track;
3639
3640 if (!global.no_file) {
3641 {
3642 char *myfname;
3643
3644 myfname = get_next_name();
3645
3646 if (myfname != NULL) {
3647 strncpy(global.fname_base, myfname,
3648 sizeof (global.fname_base)-8);
3649 global.fname_base[sizeof (global.fname_base)-1] = 0;
3650 }
3651 }
3652
3653 /* strip audio_type extension */
3654 cut_extension(global.fname_base);
3655 if (bulk && global.multiname == 0) {
3656 sprintf(fname, "%s_%02u.%s",
3657 global.fname_base, current_track_writing, audio_type);
3658 } else {
3659 sprintf(fname, "%s.%s", global.fname_base, audio_type);
3660 }
3661
3662 OpenAudio(fname, rate, bits, global.channels,
3663 (unsigned)(SamplesToWrite*global.OutSampleSize*global.channels),
3664 global.audio_out);
3665 }
3666
3667 global.Remainder = (75 % global.nsectors)+1;
3668
3669 global.sh_bits = 16 - bits; /* shift counter */
3670
3671 global.iloop = *nSamplesToDo;
3672 if (Halved && (global.iloop&1))
3673 global.iloop += 2;
3674
3675 BeginAtSample = lSector * CD_FRAMESAMPLES;
3676
3677 #if 1
3678 if ((global.verbose & SHOW_SUMMARY) && !global.just_the_toc &&
3679 (global.reads_illleadout == 0 ||
3680 lSector+*nSamplesToDo/CD_FRAMESAMPLES
3681 <= (unsigned) Get_AudioStartSector(cdtracks-1))) {
3682
3683 fprintf(outfp, _("samplefile size will be %lu bytes.\n"),
3684 global.audio_out->GetHdrSize() +
3685 global.audio_out->InSizeToOutSize(SamplesToWrite*global.OutSampleSize*global.channels));
3686 fprintf(outfp,
3687 _("recording %d.%04d seconds %s with %d bits @ %5d.%01d Hz"),
3688 (int)global.rectime, (int)(global.rectime * 10000) % 10000,
3689 global.channels == 1 ? _("mono"):_("stereo"),
3690 bits, (int)rate, (int)(rate*10)%10);
3691 if (!global.no_file && *global.fname_base)
3692 fprintf(outfp, " ->'%s'...", global.fname_base);
3693 fputs("\n", outfp);
3694 }
3695 #endif
3696
3697 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
3698 #else
3699 init_pipes();
3700 #endif
3701
3702 #ifdef USE_PARANOIA
3703 if (global.paranoia_selected) {
3704 long paranoia_mode;
3705
3706 paranoia_mode = PARANOIA_MODE_FULL ^ PARANOIA_MODE_NEVERSKIP;
3707
3708 if (global.paranoia_parms.disable_paranoia) {
3709 paranoia_mode = PARANOIA_MODE_DISABLE;
3710 }
3711 if (global.paranoia_parms.disable_extra_paranoia) {
3712 paranoia_mode |= PARANOIA_MODE_OVERLAP;
3713 paranoia_mode &= ~PARANOIA_MODE_VERIFY;
3714 }
3715 /* not yet implemented */
3716 if (global.paranoia_parms.disable_scratch_detect) {
3717 paranoia_mode &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);
3718 }
3719 /* not yet implemented */
3720 if (global.paranoia_parms.disable_scratch_repair) {
3721 paranoia_mode &= ~PARANOIA_MODE_REPAIR;
3722 }
3723 if (global.paranoia_parms.enable_c2_check) {
3724 /* test if we can read C2 with ReadCdRom_C2() */
3725 char buffer[3000];
3726 cdda_read_c2(get_scsi_p(), buffer, Get_StartSector(1), 1);
3727 if (ReadCdRom_C2 == NULL) {
3728 if (global.verbose)
3729 fprintf(outfp, _("c2check not supported by drive.\n"));
3730 } else {
3731 if (global.verbose)
3732 fprintf(outfp, _("using c2check to verify reads.\n"));
3733 paranoia_mode |= PARANOIA_MODE_C2CHECK;
3734 }
3735 }
3736
3737 global.cdp = paranoia_init(get_scsi_p(), global.nsectors,
3738 (paranoia_mode & PARANOIA_MODE_C2CHECK) ?
3739 cdda_read_c2 : cdda_read,
3740 cdda_disc_firstsector, cdda_disc_lastsector,
3741 cdda_tracks,
3742 cdda_track_firstsector, cdda_track_lastsector,
3743 cdda_sector_gettrack, cdda_track_audiop);
3744
3745 if (global.paranoia_parms.overlap >= 0) {
3746 int overlap = global.paranoia_parms.overlap;
3747
3748 if (overlap > global.nsectors - 1)
3749 overlap = global.nsectors - 1;
3750 paranoia_overlapset(global.cdp, overlap);
3751 }
3752 /*
3753 * Implement the shortcut "paraopts=proof"
3754 */
3755 if ((global.paranoia_flags & 1) &&
3756 global.paranoia_parms.mindynoverlap < 0) {
3757 if (global.nsectors > 20)
3758 global.paranoia_parms.mindynoverlap = 20;
3759 else
3760 global.paranoia_parms.mindynoverlap = global.nsectors - 1;
3761 }
3762 /*
3763 * Default to a minimum of dynamic overlapping == 0.5 sectors.
3764 * If we don't do this, we get the default from libparanoia
3765 * which is approx. 0.1.
3766 */
3767 if (global.paranoia_parms.mindynoverlap < 0)
3768 paranoia_dynoverlapset(global.cdp, CD_FRAMEWORDS/2, -1);
3769 paranoia_dynoverlapset(global.cdp,
3770 global.paranoia_parms.mindynoverlap * CD_FRAMEWORDS,
3771 global.paranoia_parms.maxdynoverlap * CD_FRAMEWORDS);
3772
3773 paranoia_modeset(global.cdp, paranoia_mode);
3774 global.paranoia_mode = paranoia_mode;
3775
3776 if (global.paranoia_parms.readahead < 0) {
3777 global.paranoia_parms.readahead = paranoia_get_readahead(global.cdp);
3778 if (global.paranoia_parms.readahead < 400) {
3779 global.paranoia_parms.readahead = 400;
3780 paranoia_set_readahead(global.cdp, 400);
3781 }
3782 } else {
3783 paranoia_set_readahead(global.cdp, global.paranoia_parms.readahead);
3784 }
3785 if (global.verbose)
3786 fprintf(outfp, _("using lib paranoia for reading.\n"));
3787 paranoia_seek(global.cdp, lSector, SEEK_SET);
3788 paranoia_statreset();
3789 }
3790 #endif
3791 #if defined(HAVE_FORK_AND_SHAREDMEM)
3792
3793 /*
3794 * Linux comes with a broken libc that makes "stderr" buffered even
3795 * though POSIX requires "stderr" to be never "fully buffered".
3796 * As a result, we would get garbled output once our fork()d child
3797 * calls exit(). We work around the Linux bug by calling fflush()
3798 * before fork()ing.
3799 */
3800 fflush(outfp);
3801
3802 /*
3803 * Everything is set up. Now fork and let one process read cdda sectors
3804 * and let the other one store them in a wav file
3805 */
3806
3807 /* forking */
3808 if (!global.no_fork)
3809 global.child_pid = fork();
3810
3811 if (global.child_pid > 0 && global.gui > 0 && global.verbose > 0)
3812 fprintf(stderr, _("child pid is %lld\n"), (Llong)global.child_pid);
3813
3814 /* ********************** fork ************************************* */
3815 if (global.child_pid == 0) {
3816 /* child WRITER section */
3817
3818 #ifdef ECHO_TO_SOUNDCARD
3819 init_soundcard(rate, bits);
3820 #endif /* ECHO_TO_SOUNDCARD */
3821 #ifdef HAVE_AREAS
3822 /*
3823 * Under BeOS a fork() with shared memory does not work as
3824 * it does under System V Rel. 4. The mapping of the child
3825 * works with copy on write semantics, so changes do not
3826 * propagate back and forth. The existing mapping has to be
3827 * deleted and replaced by an clone without copy on write
3828 * semantics.
3829 * This is done with clone_area(..., B_ANY_ADDRESS,...).
3830 * Thanks to file support.c from the postgreSQL project.
3831 */
3832 area_info inf;
3833 int32 cook = 0;
3834 /*
3835 * iterate over all mappings to find our shared memory mapping.
3836 */
3837 while (get_next_area_info(0, &cook, &inf) == B_OK) {
3838 /* check the name of the mapping. */
3839 if (strcmp(inf.name, AREA_NAME) == 0) {
3840 void *area_address;
3841 area_id area_parent;
3842
3843 /* kill the cow mapping. */
3844 area_address = inf.address;
3845 if (B_OK != delete_area(inf.area)) {
3846 errmsgno(EX_BAD,
3847 _("delete_area: no valid area.\n"));
3848 exit(SHMMEM_ERROR);
3849 }
3850 /* get the parent mapping. */
3851 area_parent = find_area(inf.name);
3852 if (area_parent == B_NAME_NOT_FOUND) {
3853 errmsgno(EX_BAD,
3854 _("find_area: no such area name.\n"));
3855 exit(SHMMEM_ERROR);
3856 }
3857 /*
3858 * clone the parent mapping without cow.
3859 * The original implementaion used
3860 * B_ANY_ADDRESS, but newer Haiku versions
3861 * implement address randomization that
3862 * prevents us from using the pointer in the
3863 * child. So we now use B_EXACT_ADDRESS.
3864 */
3865 if (B_OK > clone_area("shm_child",
3866 &area_address, B_EXACT_ADDRESS,
3867 B_READ_AREA | B_WRITE_AREA, area_parent)) {
3868 errmsgno(EX_BAD,
3869 _("clone_area failed\n"));
3870 exit(SHMMEM_ERROR);
3871 }
3872 }
3873 }
3874 #endif
3875 #ifdef __EMX__
3876 if (DosGetSharedMem(he_fill_buffer, 3)) {
3877 comerr(_("DosGetSharedMem() failed.\n"));
3878 }
3879 #endif
3880 global.have_forked = 1;
3881 forked_write();
3882 #ifdef __EMX__
3883 DosFreeMem(he_fill_buffer);
3884 _exit(NO_ERROR);
3885 /* NOTREACHED */
3886 #endif
3887 exit_wrapper(NO_ERROR);
3888 /* NOTREACHED */
3889 } else if (global.child_pid > 0) {
3890 /* parent READER section */
3891
3892 global.have_forked = 1;
3893 switch_to_realtime_priority();
3894
3895 forked_read();
3896 #ifdef HAVE_AREAS
3897 {
3898 area_id aid;
3899 aid = find_area(AREA_NAME);
3900 if (aid < B_OK) {
3901 comerrno(aid, _("find_area() failed.\n"));
3902 }
3903 delete_area(aid);
3904 }
3905 #endif
3906 #ifdef __EMX__
3907 DosFreeMem(he_fill_buffer);
3908 #endif
3909 exit_wrapper(NO_ERROR);
3910 /* NOTREACHED */
3911 } else {
3912 if (global.child_pid != -2)
3913 errmsg(_("Cannot fork.\n"));
3914 }
3915
3916 #endif /* defined(HAVE_FORK_AND_SHAREDMEM) */
3917
3918 /* version without fork */
3919 {
3920 global.have_forked = 0;
3921 #if 0
3922 if (!global.paranoia_selected) {
3923 error("REAL\n");
3924 switch_to_realtime_priority();
3925 }
3926 #endif
3927 if (!global.quiet)
3928 fprintf(stderr, _("a nonforking version is running...\n"));
3929 nonforked_loop();
3930 exit_wrapper(NO_ERROR);
3931 /* NOTREACHED */
3932 }
3933 #ifdef USE_PARANOIA
3934 if (global.paranoia_selected)
3935 paranoia_free(global.cdp);
3936 #endif
3937
3938 return (0);
3939 }
3940
3941 LOCAL void
priv_warn(what,msg)3942 priv_warn(what, msg)
3943 const char *what;
3944 const char *msg;
3945 {
3946 errmsgno(EX_BAD, "Insufficient '%s' privileges. %s\n", what, msg);
3947 }
3948
3949 LOCAL void
gargs(argc,argv)3950 gargs(argc, argv)
3951 int argc;
3952 char *argv[];
3953 {
3954 int cac;
3955 char *const*cav;
3956
3957 BOOL version = FALSE;
3958 BOOL help = FALSE;
3959 char *channels = NULL;
3960 int irate = -1;
3961 char *divider = NULL;
3962 char *trackspec = NULL;
3963 char *duration = NULL;
3964 char *int_name = DEF_INTERFACE;
3965
3966 char *oendianess = NULL;
3967 char *cendianess = NULL;
3968 int cddbp = -1;
3969 BOOL stereo = FALSE;
3970 BOOL mono = FALSE;
3971 BOOL domax = FALSE;
3972 BOOL dump_rates = FALSE;
3973 BOOL md5blocksize = FALSE;
3974 long userverbose = -1;
3975 int outfd = -1;
3976 int audiofd = -1;
3977
3978 cac = argc;
3979 cav = argv;
3980 cac--;
3981 cav++;
3982 if (getargs(&cac, &cav, opts,
3983 &global.paranoia_selected,
3984 handle_paranoia_opts, &global.paranoia_flags,
3985 &version,
3986 &help, &help,
3987
3988 &global.no_file, &global.no_file,
3989
3990 &dump_rates, &dump_rates,
3991 &bulk, &bulk, &bulk,
3992 &global.scsi_verbose, &global.scsi_verbose,
3993
3994 &global.findminmax, &global.findminmax,
3995 &global.findmono, &global.findmono,
3996 &global.no_infofile, &global.no_infofile,
3997 &global.no_textdefaults,
3998 &global.no_textfile,
3999 &global.cuefile,
4000 &global.no_hidden_track,
4001
4002 &global.deemphasize, &global.deemphasize,
4003 &global.just_the_toc, &global.just_the_toc,
4004 &global.scsi_silent, &global.scsi_silent,
4005
4006 &global.cddbp_server, &global.cddbp_port,
4007 &global.scanbus,
4008 &global.dev_name, &global.dev_name, &global.dev_name,
4009 &global.dev_opts,
4010 &global.scsi_debug, &global.scsi_debug,
4011 &global.scsi_kdebug, &global.scsi_kdebug, &global.scsi_kdebug,
4012 getnum, &global.bufsize,
4013 &global.aux_name, &global.aux_name,
4014 &int_name, &int_name,
4015 &audio_type, &audio_type,
4016
4017 &oendianess, &oendianess,
4018 &cendianess, &cendianess,
4019 &global.userspeed, &global.userspeed,
4020
4021 &global.playback_rate, &global.playback_rate,
4022 &md5blocksize, &md5blocksize,
4023 &global.useroverlap, &global.useroverlap,
4024 &global.user_sound_device, &global.user_sound_device,
4025
4026 &cddbp, &cddbp,
4027 &channels, &channels,
4028 &bits, &bits,
4029 &irate, &irate,
4030 &global.gui, &global.gui,
4031
4032 ÷r, ÷r,
4033 &trackspec, &trackspec,
4034 &global.cd_index, &global.cd_index,
4035 &duration, &duration,
4036 &global.sector_offset, &global.sector_offset,
4037 &global.start_sector,
4038
4039 &global.nsectors, &global.nsectors,
4040 handle_verbose_opts, &userverbose,
4041 handle_verbose_opts, &userverbose,
4042 &global.buffers, &global.buffers,
4043
4044 &stereo, &stereo,
4045 &mono, &mono,
4046 &waitforsignal, &waitforsignal,
4047 &global.echo, &global.echo,
4048 &global.quiet, &global.quiet,
4049 &domax, &domax, &outfd, &audiofd,
4050 &global.no_fork, &global.interactive) < 0) {
4051 errmsgno(EX_BAD, _("Bad Option: %s.\n"), cav[0]);
4052 fputs(_("Use 'cdda2wav -help' to get more information.\n"),
4053 stderr);
4054 exit(SYNTAX_ERROR);
4055 }
4056 if (getfiles(&cac, &cav, opts) == 0)
4057 /* No more file type arguments */;
4058 global.moreargs = cav - argv;
4059 if (version) {
4060 #ifdef OLD_VERSION_PRINT
4061 fputs(_("cdda2wav version "), outfp);
4062 fputs(VERSION_DATE, outfp);
4063 fputs(" ", outfp);
4064 fputs(VERSION, outfp);
4065 fputs(VERSION_OS, outfp);
4066 fputs("\n", outfp);
4067 #else
4068 /*
4069 * Make the version string similar for all cdrtools programs.
4070 */
4071 printf(_("cdda2wav %s %s (%s-%s-%s) Copyright (C) 1993-2004,2015,2017,2019 %s (C) 2004-2020 %s\n"),
4072 VERSION,
4073 VERSION_DATE,
4074 HOST_CPU, HOST_VENDOR, HOST_OS,
4075 _("Heiko Eissfeldt"),
4076 _("Joerg Schilling"));
4077 prdefaults(stdout);
4078 #endif
4079 exit(NO_ERROR);
4080 }
4081 if (help) {
4082 usage();
4083 }
4084 if (outfd >= 0) {
4085 #ifdef F_GETFD
4086 if (fcntl(outfd, F_GETFD, 0) < 0)
4087 comerr(_("Cannot redirect output to fd %d.\n"), outfd);
4088 #endif
4089 global.out_fp = fdopen(outfd, "wa");
4090 if (global.out_fp == NULL)
4091 comerr(_("Cannot open output fd %d.\n"), outfd);
4092 #ifdef HAVE_SETVBUF
4093 setvbuf(global.out_fp, NULL, _IONBF, 0);
4094 #else
4095 #ifdef HAVE_SETVBUF
4096 setbuf(global.out_fp, NULL);
4097 #endif
4098 #endif
4099 }
4100 if (!global.scanbus)
4101 cdr_defaults(&global.dev_name, NULL, NULL, &global.bufsize, NULL);
4102 if (global.bufsize < 0L)
4103 global.bufsize = DEF_BUFSIZE; /* The SCSI buffer size */
4104
4105 if (dump_rates) { /* list available rates */
4106 int ii;
4107
4108 /* BEGIN CSTYLED */
4109 fputs(_("\
4110 Available rates are:\n\
4111 Rate Divider Rate Divider Rate Divider Rate Divider\n\
4112 "),
4113 outfp);
4114 /* END CSTYLED */
4115 for (ii = 1; ii <= 44100 / 880 / 2; ii++) {
4116 long i2 = ii;
4117 fprintf(outfp, "%7.1f %2ld %7.1f %2ld.5 ",
4118 44100.0/i2, i2, 44100.0/(i2+0.5), i2);
4119 i2 += 25;
4120 fprintf(outfp, "%7.1f %2ld %7.1f %2ld.5\n",
4121 44100.0/i2, i2, 44100.0/(i2+0.5), i2);
4122 i2 -= 25;
4123 }
4124 exit(NO_ERROR);
4125 }
4126 if (channels) {
4127 if (*channels == 's') {
4128 global.channels = 2;
4129 global.swapchannels = 1;
4130 } else {
4131 global.channels = strtol(channels, NULL, 10);
4132 }
4133 }
4134 if (irate >= 0) {
4135 rate = irate;
4136 }
4137 if (divider) {
4138 double divider_d;
4139 divider_d = strtod(divider, NULL);
4140 if (divider_d > 0.0) {
4141 rate = 44100.0 / divider_d;
4142 } else {
4143 errmsgno(EX_BAD,
4144 _("E option -divider requires a nonzero, positive argument.\nSee -dump-rates.\n"));
4145 exit(SYNTAX_ERROR);
4146 }
4147 }
4148 if (global.sector_offset != 0 && global.start_sector != -1) {
4149 errmsgno(EX_BAD, _("-offset and -start-sector are mutual exclusive.\n"));
4150 exit(SYNTAX_ERROR);
4151 }
4152 if (trackspec) {
4153 char * endptr;
4154 char * endptr2;
4155
4156 if (streql(trackspec, "all")) {
4157 global.alltracks = TRUE;
4158 } else {
4159 track = strtoul(trackspec, &endptr, 10);
4160 if (trackspec == endptr)
4161 comerrno(EX_BAD,
4162 _("Invalid track specification '%s'.\n"),
4163 trackspec);
4164 if (streql(endptr, "+max")) {
4165 if (track <= 1) {
4166 global.alltracks = TRUE;
4167 /*
4168 * Hack for write_cue_track() to
4169 * use correct INDEX offsets.
4170 */
4171 if (track == 1)
4172 global.no_hidden_track = TRUE;
4173 }
4174 global.maxtrack = TRUE;
4175 endptr2 = endptr;
4176 } else {
4177 global.endtrack = strtoul(endptr, &endptr2, 10);
4178 }
4179 if (endptr2 == endptr) { /* endtrack empty */
4180 global.endtrack = track;
4181 } else if (track == global.endtrack) { /* manually -tn+n */
4182 bulk = -1;
4183 }
4184 }
4185 if (global.start_sector != -1 && !global.alltracks) {
4186 errmsgno(EX_BAD, _("-t and -start-sector are mutual exclusive.\n"));
4187 exit(SYNTAX_ERROR);
4188 }
4189 }
4190 if (duration) {
4191 char *end_ptr = NULL;
4192 global.rectime = strtod(duration, &end_ptr);
4193 if (*end_ptr == 'f') {
4194 global.rectime = global.rectime / 75.0;
4195 /* TODO: add an absolute end of recording. */
4196 #if 0
4197 } else if (*end_ptr == 'F') {
4198 global.rectime = global.rectime / 75.0;
4199 #endif
4200 } else if (*end_ptr != '\0') {
4201 global.rectime = -1.0;
4202 }
4203 }
4204 if (oendianess) {
4205 if (strcasecmp(oendianess, "little") == 0) {
4206 global.outputendianess = LITTLE;
4207 } else if (strcasecmp(oendianess, "big") == 0) {
4208 global.outputendianess = BIG;
4209 } else if (strcasecmp(oendianess, "machine") == 0 ||
4210 strcasecmp(oendianess, "host") == 0) {
4211 #ifdef WORDS_BIGENDIAN
4212 global.outputendianess = BIG;
4213 #else
4214 global.outputendianess = LITTLE;
4215 #endif
4216 } else {
4217 usage2(_("Wrong parameter '%s' for option -E\n"), oendianess);
4218 }
4219 }
4220 if (cendianess) {
4221 if (strcasecmp(cendianess, "little") == 0) {
4222 global.littleendian = 1;
4223 } else if (strcasecmp(cendianess, "big") == 0) {
4224 global.littleendian = 0;
4225 } else if (strcasecmp(cendianess, "machine") == 0 ||
4226 strcasecmp(cendianess, "host") == 0) {
4227 #ifdef WORDS_BIGENDIAN
4228 global.littleendian = 0;
4229 #else
4230 global.littleendian = 1;
4231 #endif
4232 } else if (strcasecmp(cendianess, "guess") == 0) {
4233 global.littleendian = -2;
4234 } else {
4235 usage2(_("Wrong parameter '%s' for option -C\n"), cendianess);
4236 }
4237 }
4238 if (cddbp >= 0) {
4239 global.cddbp = 1 + cddbp;
4240 }
4241 if (stereo) {
4242 global.channels = 2;
4243 }
4244 if (mono) {
4245 global.channels = 1;
4246 global.need_hostorder = 1;
4247 }
4248 if (global.echo) {
4249 #ifdef ECHO_TO_SOUNDCARD
4250 if (global.playback_rate != 100) {
4251 RestrictPlaybackRate(global.playback_rate);
4252 }
4253 global.need_hostorder = 1;
4254 #else
4255 errmsgno(EX_BAD,
4256 _("There is no sound support compiled into %s.\n"),
4257 argv[0]);
4258 global.echo = 0;
4259 #endif
4260 }
4261 if (global.quiet) {
4262 global.verbose = 0;
4263 }
4264 if (domax) {
4265 global.channels = 2; bits = 16; rate = 44100;
4266 }
4267 if (global.findminmax) {
4268 global.need_hostorder = 1;
4269 }
4270 if (global.deemphasize) {
4271 global.need_hostorder = 1;
4272 }
4273 if (global.just_the_toc) {
4274 global.verbose = SHOW_MAX;
4275 bulk = 1;
4276 }
4277 if (global.gui) {
4278 #ifdef Thomas_will_es
4279 global.no_file = 1;
4280 global.no_infofile = 1;
4281 global.verbose = SHOW_MAX;
4282 #endif
4283 global.no_cddbfile = 1;
4284 }
4285 if (global.no_file) {
4286 global.no_infofile = 1;
4287 global.no_cddbfile = 1;
4288 global.no_textfile = 1;
4289 global.cuefile = 0;
4290 }
4291 if (global.no_infofile) {
4292 global.no_cddbfile = 1;
4293 global.no_textfile = 1;
4294 global.cuefile = 0;
4295 }
4296 if (global.cuefile) {
4297 global.no_infofile = 1;
4298 }
4299 if (md5blocksize)
4300 global.md5blocksize = -1;
4301 if (global.md5blocksize) {
4302 #ifndef MD5_SIGNATURES
4303 errmsgno(EX_BAD,
4304 _("The option MD5 signatures is not configured!\n"));
4305 #endif
4306 }
4307 if (global.user_sound_device[0] != '\0') {
4308 #ifndef ECHO_TO_SOUNDCARD
4309 errmsgno(EX_BAD, _("There is no sound support configured!\n"));
4310 #else
4311 global.echo = TRUE;
4312 #endif
4313 }
4314 if (global.paranoia_selected) {
4315 global.useroverlap = 0;
4316 }
4317 if (userverbose >= 0) {
4318 global.verbose = userverbose;
4319 }
4320 /*
4321 * check all parameters
4322 */
4323 if (global.bufsize < CD_FRAMESIZE_RAW) {
4324 usage2(_("Incorrect transfer size setting: %d\n"), global.bufsize);
4325 }
4326
4327 if (global.buffers < 1) {
4328 usage2(_("Incorrect buffer setting: %d\n"), global.buffers);
4329 }
4330
4331 if (global.nsectors < 1) {
4332 usage2(_("Incorrect nsectors setting: %d\n"), global.nsectors);
4333 }
4334
4335 if (global.verbose < 0 || global.verbose > SHOW_MAX) {
4336 usage2(_("Incorrect verbose level setting: %d\n"), global.verbose);
4337 }
4338 if (global.verbose == 0)
4339 global.quiet = 1;
4340
4341 if (global.rectime < 0.0) {
4342 usage2(_("Incorrect recording time setting: %d.%02d\n"),
4343 (int)global.rectime, (int)(global.rectime*100+0.5) % 100);
4344 }
4345
4346 if (global.channels != 1 && global.channels != 2) {
4347 usage2(_("Incorrect channel setting: %d\n"), global.channels);
4348 }
4349
4350 if (bits != 8 && bits != 12 && bits != 16) {
4351 usage2(_("Incorrect bits_per_sample setting: %d\n"), bits);
4352 }
4353
4354 if (rate < 827.0 || rate > 44100.0) {
4355 usage2(_("Incorrect sample rate setting: %d.%02d\n"),
4356 (int)rate, ((int)rate*100) % 100);
4357 }
4358
4359 global.int_part = (double)(long) (2*44100.0 / rate);
4360
4361 if (2*44100.0 / rate - global.int_part >= 0.5) {
4362 global.int_part += 1.0;
4363 fprintf(outfp,
4364 _("Nearest available sample rate is %d.%02d Hertz\n"),
4365 2*44100 / (int)global.int_part,
4366 (2*4410000 / (int)global.int_part) % 100);
4367 }
4368 Halved = ((int) global.int_part) & 1;
4369 rate = 2*44100.0 / global.int_part;
4370 undersampling = (int) global.int_part / 2.0;
4371 samples_to_do = undersampling;
4372
4373 if (strcmp((char *)int_name, "generic_scsi") == 0) {
4374 interface = GENERIC_SCSI;
4375 } else if (strcmp((char *)int_name, "cooked_ioctl") == 0) {
4376 interface = COOKED_IOCTL;
4377 } else {
4378 usage2(_("Incorrect interface setting: %s\n"), int_name);
4379 }
4380
4381 /*
4382 * check * init audio file
4383 */
4384 if (strncmp(audio_type, "wav", 3) == 0) {
4385 global.audio_out = &wavsound;
4386 } else if (strncmp(audio_type, "sun", 3) == 0 ||
4387 strncmp(audio_type, "au", 2) == 0) {
4388 /*
4389 * Enhanced compatibility
4390 */
4391 audio_type = "au";
4392 global.audio_out = &sunsound;
4393 } else if (strncmp(audio_type, "cdr", 3) == 0||
4394 strncmp(audio_type, "raw", 3) == 0) {
4395 global.audio_out = &rawsound;
4396 } else if (strncmp(audio_type, "aiff", 4) == 0) {
4397 global.audio_out = &aiffsound;
4398 } else if (strncmp(audio_type, "aifc", 4) == 0) {
4399 global.audio_out = &aifcsound;
4400 #ifdef USE_LAME
4401 } else if (strncmp(audio_type, "mp3", 3) == 0) {
4402 global.audio_out = &mp3sound;
4403 if (!global.quiet) {
4404 unsigned char Lame_version[20];
4405
4406 fetch_lame_version(Lame_version);
4407 fprintf(outfp,
4408 _("Using LAME version %s.\n"), Lame_version);
4409 }
4410 if (bits < 9) {
4411 bits = 16;
4412 fprintf(outfp,
4413 _("Warning: sample size forced to 16 bit for MP3 format.\n"));
4414 }
4415 #endif /* USE_LAME */
4416 } else {
4417 usage2(_("Incorrect audio type setting: %3s\n"), audio_type);
4418 }
4419
4420 if (bulk == -1)
4421 bulk = 0;
4422
4423 global.need_big_endian = global.audio_out->need_big_endian;
4424 if (global.outputendianess != NONE)
4425 global.need_big_endian = global.outputendianess == BIG;
4426
4427 if (global.no_file)
4428 global.fname_base[0] = '\0';
4429
4430 if (!bulk) {
4431 strlcat(global.fname_base, ".", sizeof (global.fname_base));
4432 strlcat(global.fname_base, audio_type, sizeof (global.fname_base));
4433 }
4434
4435 /*
4436 * If we need to calculate with samples or write them to a soundcard,
4437 * we need a conversion to host byte order.
4438 */
4439 if (global.channels != 2 ||
4440 bits != 16 ||
4441 rate != 44100) {
4442 global.need_hostorder = 1;
4443 }
4444
4445 /*
4446 * Bad hack!!
4447 * Remove for release 2.0
4448 * this is a bug compatibility feature.
4449 */
4450 if (global.gui && global.verbose == SHOW_TOC)
4451 global.verbose |= SHOW_STARTPOSITIONS | SHOW_SUMMARY |
4452 SHOW_TITLES;
4453
4454 /*
4455 * all options processed.
4456 * Now a file name per track may follow
4457 */
4458 argc2 = argc3 = argc - global.moreargs;
4459 argv2 = argv + global.moreargs;
4460 if (global.moreargs < argc) {
4461 if (strcmp(argv[global.moreargs], "-") == 0) {
4462 if (audiofd >= 0) {
4463 #ifdef F_GETFD
4464 if (fcntl(audiofd, F_GETFD, 0) < 0) {
4465 comerr(
4466 _("Cannot redirect audio data to fd %d.\n"),
4467 audiofd);
4468 }
4469 #endif
4470 global.audio = audiofd;
4471 } else {
4472 global.audio = dup(fileno(stdout));
4473 }
4474 setmode(global.audio, O_BINARY);
4475 strncpy(global.fname_base, "standard_output",
4476 sizeof (global.fname_base));
4477 global.fname_base[sizeof (global.fname_base)-1] = 0;
4478 } else if (!is_fifo(argv[global.moreargs])) {
4479 /*
4480 * we do have at least one argument
4481 */
4482 global.multiname = 1;
4483 strlcpy(global.fname_base,
4484 argv[global.moreargs],
4485 sizeof (global.fname_base));
4486 }
4487 }
4488 }
4489