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 *)&param))
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 			&divider, &divider,
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