1 /*
2  *   cdda - CD Digital Audio support
3  *
4  *   Copyright (C) 1993-2004  Ti Kan
5  *   E-mail: xmcd@amb.org
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 #ifndef lint
22 static char *_wr_gen_c_ident_ = "@(#)wr_gen.c	7.164 04/03/17";
23 #endif
24 
25 #include "common_d/appenv.h"
26 #include "common_d/version.h"
27 #include "common_d/util.h"
28 #include "libdi_d/libdi.h"
29 #include "cdda_d/cdda.h"
30 #include "cdda_d/common.h"
31 
32 #ifdef CDDA_SUPPORTED
33 
34 #include "cdinfo_d/cdinfo.h"
35 #include "cdda_d/wr_gen.h"
36 #include "cdda_d/au.h"
37 #include "cdda_d/wav.h"
38 #include "cdda_d/aiff.h"
39 #include "cdda_d/if_lame.h"
40 #include "cdda_d/if_vorb.h"
41 #include "cdda_d/if_flac.h"
42 #include "cdda_d/if_faac.h"
43 #include "cdda_d/id3map.h"
44 
45 
46 #ifdef __VMS
47 #include <unixlib.h>
48 /* The C headers exclude fsync for _POSIX_C_SOURCE and _ANSI_C_SOURCE */
49 extern int	fsync(int);
50 /* The unixlib.h header file has these only on the later releases
51  * of Compaq C, but the functions were available earlier.
52  */
53 extern int	decc$set_child_standard_streams(int, int, int);
54 extern int	decc$write_eof_to_mbx(int);
55 #endif
56 
57 
58 /* Defines used by gen_open_pipe() */
59 #define STR_SHPATH	"/bin/sh"		/* Path to shell */
60 #define STR_SHNAME	"sh"			/* Name of shell */
61 #define STR_SHARG	"-c"			/* Shell arg */
62 
63 
64 extern appdata_t	app_data;
65 extern FILE		*errfp;
66 extern cdda_client_t	*cdda_clinfo;
67 
68 #ifdef HAS_LAME
69 extern char		*lamepath;
70 #endif
71 
72 #ifdef HAS_FAAC
73 extern char		*faacpath;
74 #endif
75 
76 
77 STATIC uid_t		ruid,			/* Real user id */
78 			euid;			/* Effective user id */
79 STATIC gid_t		rgid,			/* Real group id */
80 			egid;			/* Effective group id */
81 
82 char			*tagcomment =
83 			"xmcd-" VERSION_MAJ "." VERSION_MIN "." VERSION_TEENY;
84 						/* Tag comment string */
85 
86 /*********************
87  * Private functions *
88  *********************/
89 
90 
91 #ifdef __VMS
92 /*
93  * gen_exec_vms
94  *	Parse a command string, create an argv array from it, and pass it
95  *	to execvp() for execution.
96  *
97  * Args:
98  *	cmd - The command string.
99  *
100  * Return:
101  *	On success, this function does not return.
102  */
103 STATIC void
gen_exec_vms(char * cmd)104 gen_exec_vms(char *cmd)
105 {
106 	char	**largv = NULL,
107 		*cmd_copy;
108 	int	largc = 0,
109 		i,
110 		j,
111 		k,
112 		l,
113 		c,
114 		saverr = 0;
115 	bool_t	white = FALSE,
116 		string = FALSE,
117 		quote = FALSE;
118 
119 	l = strlen(cmd);
120 	if ((cmd_copy = (char *) MEM_ALLOC("cmd_copy", l + 1)) == NULL) {
121 		(void) fprintf(errfp, "gen_exec_vms: Out of memory.\n");
122 		errno = ENOMEM;
123 		return;
124 	}
125 
126 	for (i = j = k = 0; (c = cmd[i]) != '\0'; i++) {
127 		switch (c) {
128 		case '"':
129 			if (quote) {
130 				cmd_copy[k++] = c;
131 				quote = FALSE;
132 			}
133 			else
134 				string = !string;
135 			break;
136 		case '\\':
137 			if (quote) {
138 				cmd_copy[k++] = c;
139 				quote = FALSE;
140 			}
141 			else
142 				quote = TRUE;
143 			break;
144 		case ' ':
145 		case '\t':
146 			if (string || quote) {
147 				cmd_copy[k++] = c;
148 
149 				if (quote)
150 					quote = FALSE;
151 			}
152 			else {
153 				if (white)
154 					continue;
155 
156 				cmd_copy[k++] = 0;
157 
158 				largv = (char **) MEM_REALLOC("largv",
159 					largv, (largc+2) * sizeof(*largv)
160 				);
161 
162 				largv[largc] = &cmd_copy[j];
163 				largc++;
164 				white = TRUE;
165 			}
166 			break;
167 		default:
168 			if (white) {
169 				j = k;
170 				white = FALSE;
171 			}
172 
173 			quote = FALSE;
174 			cmd_copy[k++] = c;
175 			break;
176 		}
177 	}
178 	cmd_copy[k] = '\0';
179 
180 	if (cmd_copy[0] != '\0') {
181 		if (!white) {
182 			largv = (char **) MEM_REALLOC("largv",
183 				largv, (largc + 2) * sizeof(*largv)
184 			);
185 			largv[largc] = &cmd_copy[j];
186 			largc++;
187 		}
188 		largv[largc] = NULL;
189 
190 		if (app_data.debug & DBG_GEN) {
191 			(void) fprintf(errfp, "gen_vms_exec: cmd='%s'\n", cmd);
192 			for (i = 0; largv[i]; i++) {
193 				(void) fprintf(errfp, "    largv[%d]='%s'\n",
194 						i, largv[i]);
195 			}
196 		}
197 
198 		/* Exec the program */
199 		(void) execvp(largv[0], largv);
200 		saverr = errno;
201 	}
202 
203 	MEM_FREE(largv);
204 	MEM_FREE(cmd_copy);
205 	errno = saverr;
206 }
207 #endif	/* __VMS */
208 
209 
210 /*
211  * gen_write_au_hdr
212  *	Writes an au file header to the output file.
213  *
214  * Args:
215  *	gdp - Pointer to the gen_desc_t structure
216  *
217  * Return:
218  *	FALSE - failure
219  *	TRUE  - success
220  */
221 STATIC bool_t
gen_write_au_hdr(gen_desc_t * gdp)222 gen_write_au_hdr(gen_desc_t *gdp)
223 {
224 	au_filehdr_t	hdr;
225 
226 	if (gdp->datalen == 0) {
227 		struct stat	stbuf;
228 
229 		/* Get file information */
230 #ifndef NO_FSYNC
231 		(void) fsync(gdp->fd);
232 #endif
233 		if (fstat(gdp->fd, &stbuf) < 0) {
234 			(void) sprintf(gdp->cdp->i->msgbuf,
235 				"gen_write_au_hdr: fstat failed (errno=%d)",
236 				errno);
237 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
238 			return FALSE;
239 		}
240 
241 		/* Set actual data length */
242 		gdp->datalen = stbuf.st_size - sizeof(hdr) -
243 			       strlen(tagcomment);
244 
245 		/* Rewind to beginning of file */
246 		if (!gen_seek(gdp, (off_t) 0, SEEK_SET))
247 			return FALSE;
248 	}
249 
250 	(void) memset(&hdr, 0, sizeof(hdr));
251 
252 	/* Initialize an au file header. */
253 	hdr.au_magic = util_bswap32(AUDIO_AU_FILE_MAGIC);
254 	hdr.au_offset = util_bswap32(sizeof(hdr) + strlen(tagcomment));
255 	hdr.au_data_size = util_bswap32((word32_t) gdp->datalen);
256 	hdr.au_encoding = util_bswap32(AUDIO_AU_ENCODING_LINEAR_16);
257 	hdr.au_sample_rate = util_bswap32(44100);
258 	hdr.au_channels = util_bswap32(2);
259 
260 	/* Write header */
261 	if (!gen_write_chunk(gdp, (byte_t *) &hdr, sizeof(hdr)))
262 		return FALSE;
263 
264 	/* Write comment */
265 	if (!gen_write_chunk(gdp, (byte_t *) tagcomment, strlen(tagcomment)))
266 		return FALSE;
267 
268 	return TRUE;
269 }
270 
271 
272 /*
273  * gen_write_wav_hdr
274  *	Writes an wav file header to the output file.
275  *
276  * Args:
277  *	gdp - Pointer to the gen_desc_t structure
278  *
279  * Return:
280  *	FALSE - failure
281  *	TRUE  - success
282  */
283 STATIC bool_t
gen_write_wav_hdr(gen_desc_t * gdp)284 gen_write_wav_hdr(gen_desc_t *gdp)
285 {
286 	wav_filehdr_t	hdr;
287 
288 	if (gdp->datalen == 0) {
289 		struct stat	stbuf;
290 
291 		/* Get file information */
292 #ifndef NO_FSYNC
293 		(void) fsync(gdp->fd);
294 #endif
295 		if (fstat(gdp->fd, &stbuf) < 0) {
296 			(void) sprintf(gdp->cdp->i->msgbuf,
297 				"gen_write_wav_hdr: fstat failed (errno=%d)",
298 				errno);
299 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
300 			return FALSE;
301 		}
302 
303 		/* Set actual data length */
304 		gdp->datalen = stbuf.st_size - sizeof(hdr);
305 
306 		/* Rewind to beginning of file */
307 		if (!gen_seek(gdp, (off_t) 0, SEEK_SET))
308 			return FALSE;
309 	}
310 
311 	(void) memset(&hdr, 0, sizeof(hdr));
312 
313 	/* RIFF chunk */
314 	(void) strncpy(hdr.r_riff, "RIFF", 4);
315 	hdr.r_length = util_lswap32((word32_t) gdp->datalen + 36);
316 	(void) strncpy(hdr.r_wave, "WAVE", 4);
317 
318 	/* FORMAT chunk */
319 	(void) strncpy(hdr.f_format, "fmt ", 4);
320 	hdr.f_length = util_lswap32(16);
321 	hdr.f_const = util_lswap16(1);
322 	hdr.f_channels = util_lswap16(2);
323 	hdr.f_sample_rate = util_lswap32(44100);
324 	hdr.f_bytes_per_s = util_lswap32(44100 * 2 * 2);
325 	hdr.f_block_align = util_lswap16(4);
326 	hdr.f_bits_per_sample = util_lswap16(16);
327 
328 	/* DATA chunk */
329 	(void) strncpy(hdr.d_data, "data", 4);
330 	hdr.d_length = util_lswap32((word32_t) gdp->datalen);
331 
332 	/* Write header */
333 	if (!gen_write_chunk(gdp, (byte_t *) &hdr, sizeof(hdr)))
334 		return FALSE;
335 
336 	return TRUE;
337 }
338 
339 
340 /*
341  * gen_write_aiff_hdr
342  *	Writes an aiff file header to the output file.
343  *
344  * Args:
345  *	gdp - Pointer to the gen_desc_t structure
346  *
347  * Return:
348  *	FALSE - failure
349  *	TRUE  - success
350  */
351 STATIC bool_t
gen_write_aiff_hdr(gen_desc_t * gdp)352 gen_write_aiff_hdr(gen_desc_t *gdp)
353 {
354 	word32_t	tmp;
355 	aiff_filehdr_t	hdr;
356 
357 	if (gdp->datalen == 0) {
358 		struct stat	stbuf;
359 
360 		/* Get file information */
361 #ifndef NO_FSYNC
362 		(void) fsync(gdp->fd);
363 #endif
364 		if (fstat(gdp->fd, &stbuf) < 0) {
365 			(void) sprintf(gdp->cdp->i->msgbuf,
366 				"gen_write_aiff_hdr: fstat failed (errno=%d)",
367 				errno);
368 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
369 			return FALSE;
370 		}
371 
372 		/* Set actual data length */
373 		gdp->datalen = stbuf.st_size - AIFF_HDRSZ;
374 
375 		/* Rewind to beginning of file */
376 		if (!gen_seek(gdp, (off_t) 0, SEEK_SET))
377 			return FALSE;
378 	}
379 
380 	(void) memset(&hdr, 0, sizeof(hdr));
381 
382 	/* FORM chunk */
383 	(void) strncpy(hdr.a_form, "FORM", 4);
384 	tmp = (word32_t) gdp->datalen + AIFF_HDRSZ - 8;
385 	hdr.a_length[0] = (tmp & 0xff000000) >> 24;
386 	hdr.a_length[1] = (tmp & 0x00ff0000) >> 16;
387 	hdr.a_length[2] = (tmp & 0x0000ff00) >> 8;
388 	hdr.a_length[3] = (tmp & 0x000000ff);
389 	(void) strncpy(hdr.a_aiff, "AIFF", 4);
390 
391 	/* COMM chunk */
392 	(void) strncpy(hdr.c_comm, "COMM", 4);
393 	tmp = 18;
394 	hdr.c_length[0] = (tmp & 0xff000000) >> 24;
395 	hdr.c_length[1] = (tmp & 0x00ff0000) >> 16;
396 	hdr.c_length[2] = (tmp & 0x0000ff00) >> 8;
397 	hdr.c_length[3] = (tmp & 0x000000ff);
398 	tmp = 2;
399 	hdr.c_channels[0] = (tmp & 0xff00) >> 8;
400 	hdr.c_channels[1] = (tmp & 0x00ff);
401 	tmp = (word32_t) gdp->datalen >> 2;
402 	hdr.c_frames[0] = (tmp & 0xff000000) >> 24;
403 	hdr.c_frames[1] = (tmp & 0x00ff0000) >> 16;
404 	hdr.c_frames[2] = (tmp & 0x0000ff00) >> 8;
405 	hdr.c_frames[3] = (tmp & 0x000000ff);
406 	tmp = 16;
407 	hdr.c_sample_size[0] = (tmp & 0xff00) >> 8;
408 	hdr.c_sample_size[1] = (tmp & 0x00ff);
409 	(void) strncpy(hdr.c_sample_rate, "@\016\254D\0\0\0\0\0\0", 10);
410 				/* 44100 in 80-bit IEEE floating point */
411 
412 	/* SSND chunk */
413 	(void) strncpy(hdr.s_ssnd, "SSND", 4);
414 	tmp = (word32_t) gdp->datalen + 8;
415 	hdr.s_length[0] = (tmp & 0xff000000) >> 24;
416 	hdr.s_length[1] = (tmp & 0x00ff0000) >> 16;
417 	hdr.s_length[2] = (tmp & 0x0000ff00) >> 8;
418 	hdr.s_length[3] = (tmp & 0x000000ff);
419 
420 	/* Write header */
421 	if (!gen_write_chunk(gdp, (byte_t *) &hdr, AIFF_HDRSZ))
422 		return FALSE;
423 
424 	return TRUE;
425 }
426 
427 
428 /*
429  * gen_write_aifc_hdr
430  *	Writes an aifc file header to the output file.
431  *
432  * Args:
433  *	gdp - Pointer to the gen_desc_t structure
434  *
435  * Return:
436  *	FALSE - failure
437  *	TRUE  - success
438  */
439 STATIC bool_t
gen_write_aifc_hdr(gen_desc_t * gdp)440 gen_write_aifc_hdr(gen_desc_t *gdp)
441 {
442 	word32_t	tmp;
443 	aifc_filehdr_t	hdr;
444 
445 	if (gdp->datalen == 0) {
446 		struct stat	stbuf;
447 
448 		/* Get file information */
449 #ifndef NO_FSYNC
450 		(void) fsync(gdp->fd);
451 #endif
452 		if (fstat(gdp->fd, &stbuf) < 0) {
453 			(void) sprintf(gdp->cdp->i->msgbuf,
454 				"gen_write_aifc_hdr: fstat failed (errno=%d)",
455 				errno);
456 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
457 			return FALSE;
458 		}
459 
460 		/* Set actual data length */
461 		gdp->datalen = stbuf.st_size - AIFC_HDRSZ;
462 
463 		/* Rewind to beginning of file */
464 		if (!gen_seek(gdp, (off_t) 0, SEEK_SET))
465 			return FALSE;
466 	}
467 
468 	(void) memset(&hdr, 0, sizeof(hdr));
469 
470 	/* FORM chunk */
471 	(void) strncpy(hdr.a_form, "FORM", 4);
472 	tmp = (word32_t) gdp->datalen + AIFC_HDRSZ - 8;
473 	hdr.a_length[0] = (tmp & 0xff000000) >> 24;
474 	hdr.a_length[1] = (tmp & 0x00ff0000) >> 16;
475 	hdr.a_length[2] = (tmp & 0x0000ff00) >> 8;
476 	hdr.a_length[3] = (tmp & 0x000000ff);
477 	(void) strncpy(hdr.a_aifc, "AIFC", 4);
478 
479 	/* FVER chunk */
480 	(void) strncpy(hdr.f_fver, "FVER", 4);
481 	tmp = 4;
482 	hdr.f_length[0] = (tmp & 0xff000000) >> 24;
483 	hdr.f_length[1] = (tmp & 0x00ff0000) >> 16;
484 	hdr.f_length[2] = (tmp & 0x0000ff00) >> 8;
485 	hdr.f_length[3] = (tmp & 0x000000ff);
486 	tmp = 2726318400UL;
487 	hdr.f_version[0] = (tmp & 0xff000000) >> 24;
488 	hdr.f_version[1] = (tmp & 0x00ff0000) >> 16;
489 	hdr.f_version[2] = (tmp & 0x0000ff00) >> 8;
490 	hdr.f_version[3] = (tmp & 0x000000ff);
491 
492 	/* COMM chunk */
493 	(void) strncpy(hdr.c_comm, "COMM", 4);
494 	tmp = 18;
495 	hdr.c_length[0] = (tmp & 0xff000000) >> 24;
496 	hdr.c_length[1] = (tmp & 0x00ff0000) >> 16;
497 	hdr.c_length[2] = (tmp & 0x0000ff00) >> 8;
498 	hdr.c_length[3] = (tmp & 0x000000ff);
499 	tmp = 2;
500 	hdr.c_channels[0] = (tmp & 0xff00) >> 8;
501 	hdr.c_channels[1] = (tmp & 0x00ff);
502 	tmp = (word32_t) gdp->datalen >> 2;
503 	hdr.c_frames[0] = (tmp & 0xff000000) >> 24;
504 	hdr.c_frames[1] = (tmp & 0x00ff0000) >> 16;
505 	hdr.c_frames[2] = (tmp & 0x0000ff00) >> 8;
506 	hdr.c_frames[3] = (tmp & 0x000000ff);
507 	tmp = 16;
508 	hdr.c_sample_size[0] = (tmp & 0xff00) >> 8;
509 	hdr.c_sample_size[1] = (tmp & 0x00ff);
510 	(void) strncpy(hdr.c_sample_rate, "@\016\254D\0\0\0\0\0\0", 10);
511 				/* 44100 in 80-bit IEEE floating point */
512 	(void) strncpy(hdr.c_comptype, "NONE", 4);
513 	hdr.c_complength = 14;
514 	(void) strncpy(hdr.c_compstr, "not compressed", 14);
515 
516 	/* SSND chunk */
517 	(void) strncpy(hdr.s_ssnd, "SSND", 4);
518 	tmp = (word32_t) gdp->datalen + 8;
519 	hdr.s_length[0] = (tmp & 0xff000000) >> 24;
520 	hdr.s_length[1] = (tmp & 0x00ff0000) >> 16;
521 	hdr.s_length[2] = (tmp & 0x0000ff00) >> 8;
522 	hdr.s_length[3] = (tmp & 0x000000ff);
523 
524 	/* Write header */
525 	if (!gen_write_chunk(gdp, (byte_t *) &hdr, AIFC_HDRSZ))
526 		return FALSE;
527 
528 	return TRUE;
529 }
530 
531 
532 /********************
533  * Public functions *
534  ********************/
535 
536 
537 /*
538  * gen_esc_shellquote
539  *	Handle quote characters in a quoted shell command line string.
540  *
541  * Args:
542  *	gdp - Pointer to the gen_desc_t structure
543  *	str - Input string
544  *
545  * Return:
546  *	Return string.  This is a dynamically allocated string.  The caller
547  *	should deallocate it via MEM_FREE when done.  A NULL is returned
548  *	if the input string is NULL, or if the output string buffer cannot
549  *	be allocated.
550  */
551 char *
gen_esc_shellquote(gen_desc_t * gdp,char * str)552 gen_esc_shellquote(gen_desc_t *gdp, char *str)
553 {
554 	char	*ret,
555 		*cp;
556 
557 	if (str == NULL)
558 		return NULL;
559 
560 #ifdef __VMS
561 	/* For VMS, just dup the string.  All character validity
562 	 * checks has been done prior to getting here.
563 	 */
564 	ret = NULL;
565 	if (!util_newstr(&ret, str)) {
566 		(void) strcpy(gdp->cdp->i->msgbuf,
567 				"gen_esc_shellquote: Out of memory.");
568 		DBGPRN(DBG_GEN)(errfp, "%s\n", gdp->cdp->i->msgbuf);
569 		return NULL;
570 	}
571 #else
572 	if ((ret = (char *) MEM_ALLOC("ret", strlen(str) + 1)) == NULL) {
573 		(void) strcpy(gdp->cdp->i->msgbuf,
574 				"gen_esc_shellquote: Out of memory.");
575 		DBGPRN(DBG_GEN)(errfp, "%s\n", gdp->cdp->i->msgbuf);
576 		return NULL;
577 	}
578 
579 	for (cp = ret; *str != '\0'; cp++, str++) {
580 		if (*str == '\047')
581 			*cp = '`';	/* Change single quote to backquote */
582 		else
583 			*cp = *str;
584 	}
585 	*cp = '\0';
586 #endif
587 
588 	return (ret);
589 }
590 
591 
592 /*
593  * gen_genre_cddb2id3
594  *	Map CDDB2 genre to ID3tag genre.  This function now does a sparse
595  *	mapping because the two genre systems are not one-to-one mappable.
596  *	Moreover this has to work for both classic CDDB and CDDB2.
597  *
598  * Args:
599  *	genreid - CDDB genre ID string
600  *
601  * Return:
602  *	ID3tag genre ID string.
603  */
604 char *
gen_genre_cddb2id3(char * genreid)605 gen_genre_cddb2id3(char	*genreid)
606 {
607 	cdinfo_genre_t	*gp;
608 	char		*id;
609 	int		i;
610 
611 	if ((gp = cdinfo_genre(genreid)) == NULL)
612 		return ("12");	/* "Other" */
613 
614 	if (gp->parent == NULL)
615 		id = gp->id;		/* CDDB Genre */
616 	else
617 		id = gp->parent->id;	/* CDDB Subgenre */
618 
619 	/* Look for mapping in the genre mapping table */
620 	for (i = 0; id3_gmap[i].cddbgenre != NULL; i++) {
621 		if (strcmp(id, id3_gmap[i].cddbgenre) == 0)
622 			return (id3_gmap[i].id3genre);
623 	}
624 
625 	return ("12");	/* Other */
626 }
627 
628 
629 /*
630  * gen_set_eid
631  *	Set effective uid/gid to that of the invoking user.  This is
632  *	called before accessing any device or files for security reasons.
633  *
634  * Args:
635  *	cdp - Pointer to the cd_state_t structure
636  *
637  * Return:
638  *	FALSE - failure
639  *	TRUE  - success
640  */
641 bool_t
gen_set_eid(cd_state_t * cdp)642 gen_set_eid(cd_state_t *cdp)
643 {
644 #ifdef HAS_EUID
645 	if (util_seteuid(ruid) < 0 || geteuid() != ruid) {
646 		(void) strcpy(cdp->i->msgbuf, "gen_set_eid: Cannot set uid");
647 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
648 		return FALSE;
649 	}
650 	if (util_setegid(rgid) < 0 || getegid() != rgid) {
651 		(void) strcpy(cdp->i->msgbuf, "gen_set_eid: Cannot set gid");
652 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
653 		return FALSE;
654 	}
655 #endif
656 	return TRUE;
657 }
658 
659 
660 /*
661  * gen_reset_eid
662  *	Restore saved uid/gid after the use of gen_set_eid()..
663  *
664  * Args:
665  *	cdp - Pointer to the cd_state_t structure
666  *
667  * Return:
668  *	FALSE - failure
669  *	TRUE  - success
670  */
671 bool_t
gen_reset_eid(cd_state_t * cdp)672 gen_reset_eid(cd_state_t *cdp)
673 {
674 #ifdef HAS_EUID
675 	if (util_seteuid(euid) < 0 || geteuid() != euid) {
676 		(void) strcpy(cdp->i->msgbuf, "gen_reset_eid: Cannot set uid");
677 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
678 		return FALSE;
679 	}
680 	if (util_setegid(egid) < 0 || getegid() != egid) {
681 		(void) strcpy(cdp->i->msgbuf, "gen_reset_eid: Cannot set gid");
682 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
683 		return FALSE;
684 	}
685 #endif
686 
687 	return TRUE;
688 }
689 
690 
691 /*
692  * gen_open_file
693  *	Open an output file.
694  *
695  * Args:
696  *	cdp	- Pointer to the cd_state_t structure
697  *	path	- File path name
698  *	oflag	- Open flags
699  *	mode	- Open mode, or 0 if the mode is not to be set
700  *	fmt	- File header format to be written
701  *	datalen	- Audio data length in bytes
702  *
703  * Return:
704  *	Pointer to a gen_desc_t structure associated with this open,
705  *	or NULL on failure.
706  */
707 gen_desc_t *
gen_open_file(cd_state_t * cdp,char * path,int oflag,mode_t mode,int fmt,size_t datalen)708 gen_open_file(
709 	cd_state_t	*cdp,
710 	char		*path,
711 	int		oflag,
712 	mode_t		mode,
713 	int		fmt,
714 	size_t		datalen
715 )
716 {
717 	gen_desc_t	*gdp;
718 	int		fd;
719 	char		*oflag_str;
720 	struct stat	stbuf;
721 
722 	if (!cdda_filefmt_supp(fmt)) {
723 		(void) sprintf(cdp->i->msgbuf,
724 			    "gen_open_file: Support for the selected file "
725 			    "format (%d) is not compiled-in.",
726 			    fmt);
727 		DBGPRN(DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
728 		return NULL;
729 	}
730 
731 	if (!gen_set_eid(cdp))
732 		return NULL;
733 
734 	if ((oflag & 0x03) == O_WRONLY && (oflag & O_CREAT) != 0) {
735 		char	*dpath;
736 		mode_t	dmode;
737 
738 		if ((dpath = util_dirname(path)) == NULL) {
739 			(void) sprintf(cdp->i->msgbuf,
740 				"gen_open_file: Invalid directory path:\n%s",
741 				dpath);
742 			DBGPRN(DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
743 			(void) gen_reset_eid(cdp);
744 			return NULL;
745 		}
746 
747 		if (util_dirstat(dpath, &stbuf, FALSE) < 0 ) {
748 			if (errno == ENOENT) {
749 				/* Set directory perm based on file perm */
750 				dmode = (mode | S_IXUSR);
751 				if (mode & S_IRGRP)
752 					dmode |= (S_IRGRP | S_IXGRP);
753 				if (mode & S_IWGRP)
754 					dmode |= (S_IWGRP | S_IXGRP);
755 				if (mode & S_IROTH)
756 					dmode |= (S_IROTH | S_IXOTH);
757 				if (mode & S_IWOTH)
758 					dmode |= (S_IWOTH | S_IXOTH);
759 
760 				/* Make directory if necessary */
761 				if (!util_mkdir(dpath, dmode)) {
762 					(void) sprintf(cdp->i->msgbuf,
763 						"gen_open_file: "
764 						"Cannot create directory:\n%s",
765 						dpath
766 					);
767 					DBGPRN(DBG_SND)(errfp, "%s\n",
768 							cdp->i->msgbuf);
769 					MEM_FREE(dpath);
770 					(void) gen_reset_eid(cdp);
771 					return NULL;
772 				}
773 			}
774 			else {
775 				(void) sprintf(cdp->i->msgbuf,
776 					"gen_open_file: "
777 					"Cannot stat %s (errno=%d)",
778 					dpath,
779 					errno
780 				);
781 				DBGPRN(DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
782 				MEM_FREE(dpath);
783 				(void) gen_reset_eid(cdp);
784 				return NULL;
785 			}
786 		}
787 		else if (!S_ISDIR(stbuf.st_mode)) {
788 			(void) sprintf(cdp->i->msgbuf,
789 				    "gen_open_file: %s:\nNot a directory.",
790 				    dpath);
791 			DBGPRN(DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
792 			MEM_FREE(dpath);
793 			(void) gen_reset_eid(cdp);
794 			return NULL;
795 		}
796 
797 		MEM_FREE(dpath);
798 	}
799 
800 #if defined(HAS_LAME) || defined(HAS_FAAC)
801 	switch (fmt) {
802 	case FILEFMT_MP3:
803 	case FILEFMT_AAC:
804 	case FILEFMT_MP4:
805 		{
806 			char	*cmd;
807 
808 			/* Use the external encoder program, pipe audio
809 			 * data to it.
810 			 */
811 #ifdef HAS_LAME
812 			if (fmt == FILEFMT_MP3 && lamepath == NULL) {
813 				(void) strcpy(cdp->i->msgbuf,
814 					    "LAME encoder program not found.");
815 				DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
816 				(void) gen_reset_eid(cdp);
817 				return NULL;
818 			}
819 #endif
820 
821 #ifdef HAS_FAAC
822 			if ((fmt == FILEFMT_AAC || fmt == FILEFMT_MP4) &&
823 			    faacpath == NULL) {
824 				(void) strcpy(cdp->i->msgbuf,
825 					    "FAAC encoder program not found.");
826 				DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
827 				(void) gen_reset_eid(cdp);
828 				return NULL;
829 			}
830 #endif
831 
832 			/* Create temporary gen_desc_t structure */
833 			gdp = (gen_desc_t *) MEM_ALLOC(
834 				"gen_desc_t", sizeof(gen_desc_t)
835 			);
836 			if (gdp == NULL) {
837 				(void) strcpy(cdp->i->msgbuf,
838 					    "gen_open_file: Out of memory.");
839 				DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
840 				(void) gen_reset_eid(cdp);
841 				return NULL;
842 			}
843 			(void) memset(gdp, 0, sizeof(gen_desc_t));
844 
845 			gdp->fd = -1;
846 			gdp->mode = mode;
847 			gdp->fmt = fmt;
848 			gdp->cdp = cdp;
849 			gdp->datalen = datalen;
850 			gdp->fp = NULL;
851 
852 			if (!util_newstr(&gdp->path, path)) {
853 				MEM_FREE(gdp);
854 				(void) strcpy(cdp->i->msgbuf,
855 					    "gen_open_file: Out of memory.");
856 				DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
857 				(void) gen_reset_eid(cdp);
858 				return NULL;
859 			}
860 
861 			switch (fmt) {
862 #ifdef HAS_LAME
863 			case FILEFMT_MP3:
864 				cmd = if_lame_gencmd(gdp, lamepath);
865 				break;
866 #endif
867 
868 #ifdef HAS_FAAC
869 			case FILEFMT_AAC:
870 			case FILEFMT_MP4:
871 				cmd = if_faac_gencmd(gdp, faacpath);
872 				break;
873 #endif
874 
875 			default:
876 				cmd = NULL;
877 				break;
878 			}
879 
880 			if (cmd == NULL) {
881 				MEM_FREE(gdp->path);
882 				MEM_FREE(gdp);
883 				(void) gen_reset_eid(cdp);
884 				return NULL;
885 			}
886 
887 			MEM_FREE(gdp->path);
888 			MEM_FREE(gdp);
889 
890 			/* Spawn external encoder and open pipe to it */
891 			gdp = gen_open_pipe(cdp, cmd, NULL, fmt, datalen);
892 
893 			MEM_FREE(cmd);
894 
895 			(void) gen_reset_eid(cdp);
896 			return (gdp);
897 		}
898 		/*NOTREACHED*/
899 
900 	default:
901 		break;
902 	}
903 #endif	/* HAS_LAME HAS_FAAC */
904 
905 	/* Open file */
906 	if ((fd = open(path, oflag, mode)) < 0) {
907 		(void) sprintf(cdp->i->msgbuf,
908 			    "gen_open_file: open of %s failed (errno=%d)",
909 			    path, errno);
910 		DBGPRN(DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
911 		(void) gen_reset_eid(cdp);
912 		return NULL;
913 	}
914 
915 	DBGPRN(DBG_GEN|DBG_SND)(errfp, "\nOpened [%s]\n", path);
916 
917 	gdp = (gen_desc_t *) MEM_ALLOC("gen_desc_t", sizeof(gen_desc_t));
918 	if (gdp == NULL) {
919 		(void) close(fd);
920 		(void) strcpy(cdp->i->msgbuf, "gen_open_file: Out of memory.");
921 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
922 		(void) gen_reset_eid(cdp);
923 		return NULL;
924 	}
925 	(void) memset(gdp, 0, sizeof(gen_desc_t));
926 
927 	switch ((int) (oflag & 0x03)) {
928 	case O_WRONLY:
929 		oflag_str = "w";
930 		if (mode != (mode_t) 0)
931 			(void) chmod(path, mode);
932 		break;
933 	case O_RDWR:
934 		oflag_str = "r+";
935 		if (mode != (mode_t) 0)
936 			(void) chmod(path, mode);
937 		break;
938 	case O_RDONLY:
939 	default:
940 		oflag_str = "r";
941 		break;
942 	}
943 
944 	gdp->fd = fd;
945 	gdp->mode = mode;
946 	gdp->fmt = fmt;
947 	gdp->cdp = cdp;
948 	gdp->datalen = datalen;
949 
950 #ifdef __VMS
951 	gdp->fp = NULL;
952 #else
953 	if (fstat(gdp->fd, &stbuf) == 0 &&
954 	    (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode))) {
955 		gdp->fp = NULL;	/* Use non-stdio on devices special files */
956 	}
957 	else {
958 		if ((gdp->fp = fdopen(gdp->fd, oflag_str)) == NULL) {
959 			DBGPRN(DBG_SND)(errfp,
960 					"%s: fdopen failed.\n"
961 					"Using non-buffered file I/O.\n",
962 					path);
963 		}
964 		else {
965 			gdp->buf = (char *) MEM_ALLOC("gdp_buf", GDESC_BUFSZ);
966 			if (gdp->buf != NULL)
967 				setbuf(gdp->fp, gdp->buf);
968 		}
969 	}
970 #endif
971 
972 	if (!util_newstr(&gdp->path, path)) {
973 		if (gdp->fp != NULL)
974 			(void) fclose(gdp->fp);
975 		else
976 			(void) close(gdp->fd);
977 		MEM_FREE(gdp);
978 		(void) strcpy(cdp->i->msgbuf, "gen_open_file: Out of memory.");
979 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
980 		(void) gen_reset_eid(cdp);
981 		return NULL;
982 	}
983 
984 	/* Update file header */
985 	switch (fmt) {
986 	case FILEFMT_AU:
987 		if (!gen_write_au_hdr(gdp)) {
988 			(void) close(fd);
989 			MEM_FREE(gdp->path);
990 			MEM_FREE(gdp);
991 			(void) gen_reset_eid(cdp);
992 			return NULL;
993 		}
994 		break;
995 
996 	case FILEFMT_WAV:
997 		if (!gen_write_wav_hdr(gdp)) {
998 			(void) close(fd);
999 			MEM_FREE(gdp->path);
1000 			MEM_FREE(gdp);
1001 			(void) gen_reset_eid(cdp);
1002 			return NULL;
1003 		}
1004 		break;
1005 
1006 	case FILEFMT_AIFF:
1007 		if (!gen_write_aiff_hdr(gdp)) {
1008 			(void) close(fd);
1009 			MEM_FREE(gdp->path);
1010 			MEM_FREE(gdp);
1011 			(void) gen_reset_eid(cdp);
1012 			return NULL;
1013 		}
1014 		break;
1015 
1016 	case FILEFMT_AIFC:
1017 		if (!gen_write_aifc_hdr(gdp)) {
1018 			(void) close(fd);
1019 			MEM_FREE(gdp->path);
1020 			MEM_FREE(gdp);
1021 			(void) gen_reset_eid(cdp);
1022 			return NULL;
1023 		}
1024 		break;
1025 
1026 #ifdef HAS_VORBIS
1027 	case FILEFMT_OGG:
1028 		if (!if_vorbis_init(gdp)) {
1029 			(void) close(fd);
1030 			MEM_FREE(gdp->path);
1031 			MEM_FREE(gdp);
1032 			(void) gen_reset_eid(cdp);
1033 			return NULL;
1034 		}
1035 		break;
1036 #endif	/* HAS_VORBIS */
1037 
1038 #ifdef HAS_FLAC
1039 	case FILEFMT_FLAC:
1040 		if (!if_flac_init(gdp)) {
1041 			(void) close(fd);
1042 			MEM_FREE(gdp->path);
1043 			MEM_FREE(gdp);
1044 			(void) gen_reset_eid(cdp);
1045 			return NULL;
1046 		}
1047 		break;
1048 #endif	/* HAS_FLAC */
1049 
1050 	default:
1051 		break;
1052 	}
1053 
1054 	(void) gen_reset_eid(cdp);
1055 	return (gdp);
1056 }
1057 
1058 
1059 /*
1060  * gen_close_file
1061  *	Close a file opened with gen_open_file().
1062  *
1063  * Args:
1064  *	gdp - Pointer to the gen_desc_t structure
1065  *
1066  * Return:
1067  *	FALSE - failure
1068  *	TRUE  - success
1069  */
1070 bool_t
gen_close_file(gen_desc_t * gdp)1071 gen_close_file(gen_desc_t *gdp)
1072 {
1073 	cd_state_t	*cdp = gdp->cdp;
1074 	bool_t		ret;
1075 
1076 	if (!gen_set_eid(cdp))
1077 		return FALSE;
1078 
1079 	gdp->datalen = 0;
1080 	if (gdp->fp != NULL)
1081 		(void) fflush(gdp->fp);
1082 
1083 	switch (gdp->fmt) {
1084 	case FILEFMT_AU:
1085 		(void) gen_write_au_hdr(gdp);
1086 		break;
1087 
1088 	case FILEFMT_WAV:
1089 		(void) gen_write_wav_hdr(gdp);
1090 		break;
1091 
1092 	case FILEFMT_AIFF:
1093 		(void) gen_write_aiff_hdr(gdp);
1094 		break;
1095 
1096 	case FILEFMT_AIFC:
1097 		(void) gen_write_aifc_hdr(gdp);
1098 		break;
1099 
1100 #ifdef HAS_LAME
1101 	case FILEFMT_MP3:
1102 		ret = gen_close_pipe(gdp);
1103 		(void) gen_reset_eid(cdp);
1104 		return (ret);
1105 #endif	/* HAS_LAME */
1106 
1107 #ifdef HAS_VORBIS
1108 	case FILEFMT_OGG:
1109 		if_vorbis_halt(gdp);
1110 		break;
1111 #endif	/* HAS_VORBIS */
1112 
1113 #ifdef HAS_FLAC
1114 	case FILEFMT_FLAC:
1115 		if_flac_halt(gdp);
1116 		break;
1117 #endif	/* HAS_FLAC */
1118 
1119 #ifdef HAS_FAAC
1120 	case FILEFMT_AAC:
1121 	case FILEFMT_MP4:
1122 		ret = gen_close_pipe(gdp);
1123 		(void) gen_reset_eid(cdp);
1124 		return (ret);
1125 #endif	/* HAS_FAAC */
1126 
1127 	default:
1128 		break;
1129 	}
1130 
1131 	/* Close file */
1132 	if (gdp->fp != NULL)
1133 		ret = (fclose(gdp->fp) == 0);
1134 	else
1135 		ret = (close(gdp->fd) == 0);
1136 
1137 	if (ret) {
1138 		DBGPRN(DBG_GEN|DBG_SND)(errfp, "\nClosed [%s]\n", gdp->path);
1139 	}
1140 	else {
1141 		DBGPRN(DBG_GEN|DBG_SND)(errfp,
1142 			"\nClose [%s] failed: errno=%d\n",
1143 			gdp->path, errno);
1144 	}
1145 
1146 	MEM_FREE(gdp->path);
1147 	MEM_FREE(gdp);
1148 
1149 	(void) gen_reset_eid(cdp);
1150 	return (ret);
1151 }
1152 
1153 
1154 /*
1155  * gen_open_pipe
1156  *	Spawn an external program and connect a pipe to its stdin
1157  *
1158  * Args:
1159  *	cdp	 - Pointer to the cd_state_t structure
1160  *	progpath - Command line of program to spawn
1161  *	ret_pid	 - Child process ID return
1162  *	fmt	 - File header format to be written
1163  *	datalen	 - Audio data length in bytes
1164  *
1165  * Return:
1166  *	Pointer to a gen_desc_t structure associated with this open,
1167  *	or NULL on failure.
1168  */
1169 gen_desc_t *
gen_open_pipe(cd_state_t * cdp,char * progpath,pid_t * ret_pid,int fmt,size_t datalen)1170 gen_open_pipe(
1171 	cd_state_t	*cdp,
1172 	char		*progpath,
1173 	pid_t		*ret_pid,
1174 	int		fmt,
1175 	size_t		datalen
1176 )
1177 {
1178 	gen_desc_t	*gdp;
1179 	char		*cmd;
1180 	pid_t		cpid;
1181 	int		i,
1182 			pfd[2];
1183 
1184 	if (!cdda_filefmt_supp(fmt)) {
1185 		(void) sprintf(cdp->i->msgbuf,
1186 			    "gen_open_pipe: Support for the selected file "
1187 			    "format (%d) is not compiled-in.",
1188 			    fmt);
1189 		DBGPRN(DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
1190 		return NULL;
1191 	}
1192 
1193 	if (!gen_set_eid(cdp))
1194 		return NULL;
1195 
1196 	if (PIPE(pfd) < 0) {
1197 		(void) sprintf(cdp->i->msgbuf,
1198 				"gen_open_pipe: output pipe failed (errno=%d)",
1199 				errno);
1200 		DBGPRN(DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
1201 		(void) gen_reset_eid(cdp);
1202 		return NULL;
1203 	}
1204 
1205 	cmd = NULL;
1206 	if (!util_newstr(&cmd, progpath)) {
1207 		(void) strcpy(cdp->i->msgbuf, "gen_open_pipe: Out of memory.");
1208 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
1209 		(void) gen_reset_eid(cdp);
1210 		return NULL;
1211 	}
1212 
1213 #if defined(HAS_LAME) || defined(HAS_FAAC)
1214 	if (ret_pid != NULL) {
1215 		switch (fmt) {
1216 		case FILEFMT_MP3:
1217 		case FILEFMT_AAC:
1218 		case FILEFMT_MP4:
1219 			/* Use the external encoder program, pipe audio
1220 			 * data to it.
1221 			 */
1222 #ifdef HAS_LAME
1223 			if (fmt == FILEFMT_MP3 && lamepath == NULL) {
1224 				(void) strcpy(cdp->i->msgbuf,
1225 					    "LAME encoder program not found.");
1226 				DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
1227 				(void) gen_reset_eid(cdp);
1228 				return NULL;
1229 			}
1230 #endif
1231 #ifdef HAS_FAAC
1232 			if ((fmt == FILEFMT_AAC || fmt == FILEFMT_MP4) &&
1233 			    faacpath == NULL) {
1234 				(void) strcpy(cdp->i->msgbuf,
1235 					    "FAAC encoder program not found.");
1236 				DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
1237 				(void) gen_reset_eid(cdp);
1238 				return NULL;
1239 			}
1240 #endif
1241 
1242 			/* Create temporary gen_desc_t structure */
1243 			gdp = (gen_desc_t *) MEM_ALLOC(
1244 				"gen_desc_t", sizeof(gen_desc_t)
1245 			);
1246 			if (gdp == NULL) {
1247 				(void) strcpy(cdp->i->msgbuf,
1248 					    "gen_open_file: Out of memory.");
1249 				DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
1250 				(void) gen_reset_eid(cdp);
1251 				return NULL;
1252 			}
1253 			(void) memset(gdp, 0, sizeof(gen_desc_t));
1254 
1255 			gdp->fd = -1;
1256 			gdp->fmt = fmt;
1257 			gdp->cdp = cdp;
1258 			gdp->datalen = datalen;
1259 			gdp->fp = NULL;
1260 			gdp->flags |= GDESC_ISPIPE;
1261 
1262 			if (!util_newstr(&gdp->path, progpath)) {
1263 				MEM_FREE(gdp);
1264 				(void) strcpy(cdp->i->msgbuf,
1265 					    "gen_open_pipe: Out of memory.");
1266 				DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
1267 				(void) gen_reset_eid(cdp);
1268 				return NULL;
1269 			}
1270 
1271 			if (cmd != NULL)
1272 				MEM_FREE(cmd);
1273 
1274 			switch (fmt) {
1275 #ifdef HAS_LAME
1276 			case FILEFMT_MP3:
1277 				cmd = if_lame_gencmd(gdp, lamepath);
1278 				break;
1279 #endif
1280 
1281 #ifdef HAS_FAAC
1282 			case FILEFMT_AAC:
1283 			case FILEFMT_MP4:
1284 				cmd = if_faac_gencmd(gdp, faacpath);
1285 				break;
1286 #endif
1287 
1288 			default:
1289 				cmd = NULL;
1290 			}
1291 
1292 			if (cmd == NULL) {
1293 				MEM_FREE(gdp->path);
1294 				MEM_FREE(gdp);
1295 				(void) gen_reset_eid(cdp);
1296 				return NULL;
1297 			}
1298 
1299 			MEM_FREE(gdp->path);
1300 			MEM_FREE(gdp);
1301 			break;
1302 
1303 		default:
1304 			break;
1305 		}
1306 	}
1307 #endif	/* HAS_LAME HAS_FAAC */
1308 
1309 	DBGPRN(DBG_GEN|DBG_SND)(errfp, "\nInvoking [%s]\n", cmd);
1310 
1311 	switch (cpid = FORK()) {
1312 	case -1:
1313 		(void) sprintf(cdp->i->msgbuf,
1314 			    "gen_open_pipe: fork failed (errno=%d)",
1315 			    errno);
1316 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
1317 		(void) gen_reset_eid(cdp);
1318 		return NULL;
1319 
1320 	case 0:
1321 		/* Child */
1322 
1323 		(void) util_signal(SIGTERM, SIG_DFL);
1324 		(void) util_signal(SIGALRM, SIG_DFL);
1325 		(void) util_signal(SIGPIPE, SIG_DFL);
1326 
1327 #ifdef __VMS
1328 		/* Special handling to work with VMS vfork */
1329 
1330 		/* Close on exec for unneeded pipe/file descriptors */
1331 		(void) fcntl(pfd[1], F_SETFD, FD_CLOEXEC);
1332 
1333 		for (i = 3; i < 255; i++) {
1334 			if (i != pfd[0])
1335 				(void) fcntl(i, F_SETFD, FD_CLOEXEC);
1336 		}
1337 
1338 		/* Connect stdin to pipe, leave stdout and stderr as is */
1339 		if (decc$set_child_standard_streams(pfd[0], -1, -1) < 0) {
1340 			(void) fprintf(errfp,
1341 				"gen_open_pipe: "
1342 				"decc$set_child_standard_streams failed "
1343 				"(errno=%d)\n",
1344 				errno
1345 			);
1346 			_exit(1);
1347 		}
1348 
1349 		gen_exec_vms(cmd);
1350 #else
1351 		/* Close unneeded pipe descriptors */
1352 		(void) close(pfd[1]);
1353 
1354 		for (i = 3; i < 255; i++) {
1355 			/* Close unneeded fds */
1356 			if (i != pfd[0])
1357 				(void) close(i);
1358 		}
1359 
1360 		(void) close(0);	/* Close stdin */
1361 
1362 		if (dup(pfd[0]) < 0) {	/* Connect stdin to pipe */
1363 			(void) fprintf(errfp,
1364 				    "gen_open_pipe: dup failed (errno=%d)\n",
1365 				    errno);
1366 			_exit(1);
1367 		}
1368 
1369 		/* Exec the pipe program */
1370 		(void) execl(STR_SHPATH, STR_SHNAME, STR_SHARG, cmd, NULL);
1371 #endif
1372 
1373 		/* An error has occurred */
1374 		_exit(errno);
1375 
1376 		/*NOTREACHED*/
1377 
1378 	default:
1379 		/* Parent */
1380 		if (ret_pid != NULL)
1381 			*ret_pid = cpid;
1382 
1383 		/* Close unneeded pipe descriptor */
1384 		(void) close(pfd[0]);
1385 		break;
1386 	}
1387 
1388 	gdp = (gen_desc_t *) MEM_ALLOC("gen_desc_t", sizeof(gen_desc_t));
1389 	if (gdp == NULL) {
1390 		(void) close(pfd[1]);
1391 		(void) strcpy(cdp->i->msgbuf, "gen_open_pipe: Out of memory.");
1392 		DBGPRN(DBG_GEN)(errfp, "%s\n", cdp->i->msgbuf);
1393 		(void) gen_reset_eid(cdp);
1394 		return NULL;
1395 	}
1396 	(void) memset(gdp, 0, sizeof(gen_desc_t));
1397 
1398 	gdp->fd = pfd[1];
1399 	gdp->fmt = fmt;
1400 	gdp->cdp = cdp;
1401 	gdp->datalen = datalen;
1402 	gdp->flags |= GDESC_ISPIPE;
1403 	gdp->path = cmd;
1404 	gdp->cpid = cpid;
1405 
1406 #ifdef __VMS
1407 	gdp->fp = NULL;
1408 #else
1409 	if ((gdp->fp = fdopen(gdp->fd, "w")) == NULL) {
1410 		DBGPRN(DBG_SND)(errfp,
1411 				"%s: fdopen failed.\n"
1412 				"Using non-buffered file I/O.\n",
1413 				gdp->path);
1414 	}
1415 	else {
1416 		gdp->buf = (char *) MEM_ALLOC("gdp_buf", GDESC_BUFSZ);
1417 		if (gdp->buf != NULL)
1418 			setbuf(gdp->fp, gdp->buf);
1419 	}
1420 #endif
1421 
1422 	switch (fmt) {
1423 	case FILEFMT_AU:
1424 		if (!gen_write_au_hdr(gdp)) {
1425 			(void) close(pfd[1]);
1426 			MEM_FREE(gdp->path);
1427 			MEM_FREE(gdp);
1428 			(void) gen_reset_eid(cdp);
1429 			return NULL;
1430 		}
1431 		break;
1432 
1433 	case FILEFMT_WAV:
1434 		if (!gen_write_wav_hdr(gdp)) {
1435 			(void) close(pfd[1]);
1436 			MEM_FREE(gdp->path);
1437 			MEM_FREE(gdp);
1438 			(void) gen_reset_eid(cdp);
1439 			return NULL;
1440 		}
1441 		break;
1442 
1443 	case FILEFMT_AIFF:
1444 		if (!gen_write_aiff_hdr(gdp)) {
1445 			(void) close(pfd[1]);
1446 			MEM_FREE(gdp->path);
1447 			MEM_FREE(gdp);
1448 			(void) gen_reset_eid(cdp);
1449 			return NULL;
1450 		}
1451 		break;
1452 
1453 	case FILEFMT_AIFC:
1454 		if (!gen_write_aifc_hdr(gdp)) {
1455 			(void) close(pfd[1]);
1456 			MEM_FREE(gdp->path);
1457 			MEM_FREE(gdp);
1458 			(void) gen_reset_eid(cdp);
1459 			return NULL;
1460 		}
1461 		break;
1462 
1463 #ifdef HAS_VORBIS
1464 	case FILEFMT_OGG:
1465 		if (!if_vorbis_init(gdp)) {
1466 			(void) close(pfd[1]);
1467 			MEM_FREE(gdp->path);
1468 			MEM_FREE(gdp);
1469 			(void) gen_reset_eid(cdp);
1470 			return NULL;
1471 		}
1472 		break;
1473 #endif	/* HAS_VORBIS */
1474 
1475 #ifdef HAS_FLAC
1476 	case FILEFMT_FLAC:
1477 		if (!if_flac_init(gdp)) {
1478 			(void) close(pfd[1]);
1479 			MEM_FREE(gdp->path);
1480 			MEM_FREE(gdp);
1481 			(void) gen_reset_eid(cdp);
1482 			return NULL;
1483 		}
1484 		break;
1485 #endif	/* HAS_FLAC */
1486 
1487 	default:
1488 		break;
1489 	}
1490 
1491 	(void) gen_reset_eid(cdp);
1492 	return (gdp);
1493 }
1494 
1495 
1496 /*
1497  * gen_close_pipe
1498  *	Close the program pipe that was opened via gen_open_pipe()
1499  *
1500  * Args:
1501  *	gdp - Pointer to the gen_desc_t structure
1502  *
1503  * Return:
1504  *	FALSE - failure
1505  *	TRUE  - success
1506  */
1507 bool_t
gen_close_pipe(gen_desc_t * gdp)1508 gen_close_pipe(gen_desc_t *gdp)
1509 {
1510 	cd_state_t	*cdp = gdp->cdp;
1511 	char		*cp;
1512 	int		ret,
1513 			wstat;
1514 
1515 	if (!gen_set_eid(cdp))
1516 		return FALSE;
1517 
1518 	switch (gdp->fmt) {
1519 #ifdef HAS_VORBIS
1520 	case FILEFMT_OGG:
1521 		if_vorbis_halt(gdp);
1522 		break;
1523 #endif	/* HAS_VORBIS */
1524 
1525 #ifdef HAS_FLAC
1526 	case FILEFMT_FLAC:
1527 		if_flac_halt(gdp);
1528 		break;
1529 #endif	/* HAS_FLAC */
1530 
1531 	default:
1532 		break;
1533 	}
1534 
1535 	/* Close pipe */
1536 	if (gdp->fp != NULL)
1537 		(void) fclose(gdp->fp);
1538 	else {
1539 #ifdef __VMS
1540 		decc$write_eof_to_mbx(gdp->fd);
1541 #endif
1542 		(void) close(gdp->fd);
1543 	}
1544 
1545 	/* Cut off anything beyond argv[0] */
1546 	if ((cp = strchr(gdp->path, ' ')) != NULL)
1547 		*cp = '\0';
1548 
1549 	/* Wait for pipe program and get exit status */
1550 	ret = util_waitchild(gdp->cpid, app_data.hb_timeout,
1551 			     NULL, 0, TRUE, &wstat);
1552 	if (ret < 0) {
1553 		DBGPRN(DBG_GEN|DBG_SND)(errfp,
1554 			    "%s: waitpid failed (pid=%d errno=%d)\n",
1555 			    gdp->path, (int) gdp->cpid, errno);
1556 		ret = -1;
1557 	}
1558 	else if (WIFEXITED(wstat)) {
1559 		ret = WEXITSTATUS(wstat);
1560 		if (ret == 0) {
1561 			DBGPRN(DBG_GEN|DBG_SND)(errfp,
1562 				"%s: Program exited (pid=%d status=%d)\n",
1563 				gdp->path, (int) gdp->cpid, ret);
1564 		}
1565 		else {
1566 			(void) sprintf(cdp->i->msgbuf,
1567 				"NOTICE: %s\nProgram exited abnormally "
1568 				"(pid=%d status=%d)",
1569 				gdp->path, (int) gdp->cpid, ret
1570 			);
1571 			DBGPRN(DBG_GEN|DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
1572 		}
1573 	}
1574 	else if (WIFSIGNALED(wstat)) {
1575 		ret = WTERMSIG(wstat);
1576 		(void) sprintf(cdp->i->msgbuf,
1577 			"NOTICE: %s\nProgram killed (pid=%d status=%d)",
1578 			gdp->path, (int) gdp->cpid, ret
1579 		);
1580 		DBGPRN(DBG_GEN|DBG_SND)(errfp, "%s\n", cdp->i->msgbuf);
1581 	}
1582 
1583 	MEM_FREE(gdp->path);
1584 	MEM_FREE(gdp);
1585 
1586 	(void) gen_reset_eid(cdp);
1587 	return (ret == 0);
1588 }
1589 
1590 
1591 /*
1592  * gen_read_chunk
1593  *	Reads data from the opened file descriptor, catering for possible
1594  *	interrupts.
1595  *
1596  * Args:
1597  *	gdp	- Pointer to the gen_desc_t structure
1598  *	data	- Data buffer
1599  *	len	- Data length
1600  *
1601  * Return:
1602  *	FALSE - failure
1603  *	TRUE  - success
1604  */
1605 bool_t
gen_read_chunk(gen_desc_t * gdp,byte_t * data,size_t len)1606 gen_read_chunk(gen_desc_t *gdp, byte_t *data, size_t len)
1607 {
1608 	int	offset = 0,
1609 		req,
1610 		n;
1611 
1612 	if (data == NULL || len == 0)
1613 		/* Nothing to do */
1614 		return TRUE;
1615 
1616 	if (!gen_set_eid(gdp->cdp))
1617 		return FALSE;
1618 
1619 	if ((app_data.debug & DBG_SND) != 0) {
1620 		if ((gdp->flags & GDESC_ISPIPE) != 0) {
1621 			char	*cp,
1622 				sav = '\0';
1623 
1624 			if ((cp = strchr(gdp->path, ' ')) != NULL) {
1625 				sav = *cp;
1626 				*cp = '\0';
1627 			}
1628 
1629 			(void) fprintf(errfp,
1630 					"\nReading pipe [%s]: %d bytes\n",
1631 					gdp->path, (int) len);
1632 
1633 			if (cp != NULL)
1634 				*cp = sav;
1635 		}
1636 		else
1637 			(void) fprintf(errfp, "\nReading [%s]: %d bytes\n",
1638 					gdp->path, (int) len);
1639 	}
1640 
1641 	/* Read in */
1642 	do {
1643 		errno = 0;
1644 		req = len - offset;
1645 
1646 		if (gdp->fp != NULL) {
1647 			n = fread(&data[offset], 1, req, gdp->fp);
1648 			if (n < req) {
1649 				if (feof(gdp->fp)) {
1650 					(void) gen_reset_eid(gdp->cdp);
1651 					return TRUE;
1652 				}
1653 				else if (ferror(gdp->fp))
1654 					break;
1655 			}
1656 		}
1657 		else {
1658 			if ((n = read(gdp->fd, &data[offset], req)) < 0)
1659 				break;
1660 		}
1661 
1662 		/* Have we finished? */
1663 		if (n == req || n == 0) {
1664 			(void) gen_reset_eid(gdp->cdp);
1665 			return TRUE;
1666 		}
1667 
1668 		offset += n;
1669 
1670 	} while (offset < len);
1671 
1672 	if (n >= 0) {
1673 		(void) sprintf(gdp->cdp->i->msgbuf,
1674 				"gen_read_chunk: read failed (ret=%d)", n);
1675 	}
1676 	else {
1677 		(void) sprintf(gdp->cdp->i->msgbuf,
1678 				"gen_read_chunk: read failed (errno=%d)",
1679 				errno);
1680 	}
1681 	DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
1682 
1683 	(void) gen_reset_eid(gdp->cdp);
1684 	return FALSE;
1685 }
1686 
1687 
1688 /*
1689  * gen_write_chunk
1690  *	Writes data to the opened file descriptor, catering for possible
1691  *	interrupts.
1692  *
1693  * Args:
1694  *	gdp	- Pointer to the gen_desc_t structure
1695  *	data	- Data buffer
1696  *	len	- Data length
1697  *
1698  * Return:
1699  *	FALSE - failure
1700  *	TRUE  - success
1701  */
1702 bool_t
gen_write_chunk(gen_desc_t * gdp,byte_t * data,size_t len)1703 gen_write_chunk(gen_desc_t *gdp, byte_t *data, size_t len)
1704 {
1705 	int	offset = 0,
1706 		req,
1707 		n;
1708 	bool_t	ret;
1709 
1710 	if (!gen_set_eid(gdp->cdp))
1711 		return FALSE;
1712 
1713 	if (data == NULL && len == 0) {
1714 		/* Flush buffered I/O */
1715 		if (gdp->fp != NULL)
1716 			(void) fflush(gdp->fp);
1717 
1718 		/* Write EOF */
1719 		ret = !(write(gdp->fd, NULL, 0) < 0);
1720 
1721 		(void) gen_reset_eid(gdp->cdp);
1722 		return (ret);
1723 	}
1724 
1725 	if (len == 0) {
1726 		/* Nothing to do */
1727 		(void) gen_reset_eid(gdp->cdp);
1728 		return TRUE;
1729 	}
1730 
1731 	if ((gdp->flags & GDESC_WRITEOUT) == 0) {
1732 		switch (gdp->fmt) {
1733 #ifdef HAS_VORBIS
1734 		case FILEFMT_OGG:
1735 			ret = if_vorbis_encode_chunk(gdp, data, len);
1736 			(void) gen_reset_eid(gdp->cdp);
1737 			return (ret);
1738 #endif	/* HAS_VORBIS */
1739 
1740 #ifdef HAS_FLAC
1741 		case FILEFMT_FLAC:
1742 			ret = if_flac_encode_chunk(gdp, data, len);
1743 			(void) gen_reset_eid(gdp->cdp);
1744 			return (ret);
1745 #endif	/* HAS_FLAC */
1746 
1747 		default:
1748 			break;
1749 		}
1750 	}
1751 
1752 	gdp->flags &= ~GDESC_WRITEOUT;
1753 
1754 	if ((app_data.debug & DBG_SND) != 0) {
1755 		if ((gdp->flags & GDESC_ISPIPE) != 0) {
1756 			char	*cp,
1757 				sav = '\0';
1758 
1759 			if ((cp = strchr(gdp->path, ' ')) != NULL) {
1760 				sav = *cp;
1761 				*cp = '\0';
1762 			}
1763 
1764 			(void) fprintf(errfp,
1765 					"\nWriting pipe [%s]: %d bytes\n",
1766 					gdp->path, (int) len);
1767 
1768 			if (cp != NULL)
1769 				*cp = sav;
1770 		}
1771 		else
1772 			(void) fprintf(errfp, "\nWriting [%s]: %d bytes\n",
1773 					gdp->path, (int) len);
1774 	}
1775 
1776 	/* Write out */
1777 	do {
1778 		req = len - offset;
1779 		errno = 0;
1780 
1781 		if (gdp->fp != NULL) {
1782 			n = fwrite(&data[offset], 1, req, gdp->fp);
1783 			if (n < req && ferror(gdp->fp))
1784 				break;
1785 		}
1786 		else {
1787 			if ((n = write(gdp->fd, &data[offset], req)) <= 0)
1788 				break;
1789 		}
1790 
1791 		/* Have we finished? */
1792 		if (n == req) {
1793 			(void) gen_reset_eid(gdp->cdp);
1794 			return TRUE;
1795 		}
1796 
1797 		offset += n;
1798 
1799 	} while (offset < len);
1800 
1801 	if (n >= 0) {
1802 		(void) sprintf(gdp->cdp->i->msgbuf,
1803 				"gen_write_chunk: write failed (ret=%d)", n);
1804 	}
1805 	else {
1806 		(void) sprintf(gdp->cdp->i->msgbuf,
1807 				"gen_write_chunk: write failed (errno=%d)",
1808 				errno);
1809 	}
1810 	DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
1811 
1812 	(void) gen_reset_eid(gdp->cdp);
1813 	return FALSE;
1814 }
1815 
1816 
1817 /*
1818  * gen_seek
1819  *	Wrapper function for fseek(3) and lseek(2).  It uses the appropriate
1820  *	function based on whether a buffered stdio stream is opened.
1821  *
1822  * Args:
1823  *	gdp    - Pointer to the gen_desc_t structure
1824  *	offset - Seek offset
1825  *	whence - Seek type (SEEK_SET, SEEK_CUR or SEEK_END)
1826  *
1827  * Return:
1828  *	FALSE - failure
1829  *	TRUE  - success
1830  */
1831 bool_t
gen_seek(gen_desc_t * gdp,off_t offset,int whence)1832 gen_seek(gen_desc_t *gdp, off_t offset, int whence)
1833 {
1834 	off_t	ret;
1835 
1836 	if (gdp->fp != NULL) {
1837 		if ((ret = fseek(gdp->fp, (long) offset, whence)) < 0) {
1838 			(void) sprintf(gdp->cdp->i->msgbuf,
1839 				    "gen_seek: %s: fseek failed (errno=%d)",
1840 				    gdp->path, errno);
1841 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
1842 		}
1843 	}
1844 	else {
1845 		if ((ret = lseek(gdp->fd, offset, whence)) < 0) {
1846 			(void) sprintf(gdp->cdp->i->msgbuf,
1847 				    "gen_seek: %s: lseek failed (errno=%d)",
1848 				    gdp->path, errno);
1849 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
1850 		}
1851 	}
1852 
1853 	return ((bool_t) (ret >= 0));
1854 }
1855 
1856 
1857 #ifndef __VMS
1858 /*
1859  * gen_ioctl
1860  *	Wrapper for ioctl(2) function.
1861  *
1862  * Args:
1863  *	gdp - Pointer to the gen_desc_t structure
1864  *	req - ioctl request
1865  *	arg - ioctl argument
1866  *
1867  * Return:
1868  *	FALSE - failure
1869  *	TRUE  - success
1870  */
1871 bool_t
gen_ioctl(gen_desc_t * gdp,int req,void * arg)1872 gen_ioctl(gen_desc_t *gdp, int req, void *arg)
1873 {
1874 	/* Flush buffered I/O first */
1875 	if (gdp->fp != NULL)
1876 		(void) fflush(gdp->fp);
1877 
1878 	/* Do the ioctl */
1879 	return (!(ioctl(gdp->fd, req, arg) < 0));
1880 }
1881 #endif
1882 
1883 
1884 /*
1885  * gen_byteswap
1886  *	Carry out byte swapping.
1887  *
1888  * Args:
1889  *	srcbuf - audio data source buffer
1890  *	tgtbuf - audio data target buffer
1891  *	len    - data length in bytes
1892  *
1893  * Return:
1894  *	Nothing.
1895  */
1896 void
gen_byteswap(byte_t * srcbuf,byte_t * tgtbuf,size_t len)1897 gen_byteswap(byte_t *srcbuf, byte_t *tgtbuf, size_t len)
1898 {
1899 	int	i;
1900 
1901 	/* Run through samples */
1902 	for (i = 0; i < (int) len; i += 2) {
1903 		/* Byte swapping */
1904 		tgtbuf[i] = srcbuf[i+1];
1905 		tgtbuf[i+1] = srcbuf[i];;
1906 	}
1907 }
1908 
1909 
1910 /*
1911  * gen_filefmt_be
1912  *	Determine whether the audio data should be in big endian for the
1913  *	format of file and platform we're running on.
1914  *
1915  * Args:
1916  *	filefmt - File format code
1917  *
1918  * Return:
1919  *	FALSE - should be little endian
1920  *	TRUE  - should be big endian
1921  */
1922 bool_t
gen_filefmt_be(int filefmt)1923 gen_filefmt_be(int filefmt)
1924 {
1925 	switch (filefmt) {
1926 	case FILEFMT_FLAC:
1927 		/* Always native endian */
1928 #if _BYTE_ORDER_ == _B_ENDIAN_
1929 		return TRUE;
1930 #else
1931 		return FALSE;
1932 #endif
1933 
1934 	case FILEFMT_AU:
1935 	case FILEFMT_AIFF:
1936 	case FILEFMT_AIFC:
1937 	case FILEFMT_MP3:
1938 	case FILEFMT_AAC:
1939 	case FILEFMT_MP4:
1940 		/* Always big endian */
1941 		return TRUE;
1942 
1943 	case FILEFMT_WAV:
1944 	case FILEFMT_OGG:
1945 	default:
1946 		/* Always little endian */
1947 		return FALSE;
1948 	}
1949 }
1950 
1951 
1952 /*
1953  * gen_chroute_att
1954  *	Other optional processing may need be carried out on the audio
1955  *	prior to sending it to the audio device, file and/or pipe stream.
1956  *
1957  * Args:
1958  *	chroute - Channel routing value:
1959  *	    CHROUTE_NORMAL	Leave as is
1960  *	    CHROUTE_REVERSE	Swaps left and right
1961  *	    CHROUTE_L_MONO	Feed left to both channels
1962  *	    CHROUTE_R_MONO	Feed right to both channels
1963  *	    CHROUTE_MONO	Feed left and right avrg to both channels
1964  *	att - Attenuation level (0-100)
1965  *	data - Data to transform
1966  *	len  - Data length in bytes
1967  *
1968  * Return:
1969  *	Nothing.
1970  */
1971 void
gen_chroute_att(int chroute,int att,sword16_t * data,size_t len)1972 gen_chroute_att(int chroute, int att, sword16_t *data, size_t len)
1973 {
1974 	int		nsamples,
1975 			i,
1976 			l,
1977 			r;
1978 	sword16_t	temp1,
1979 			temp2,
1980 			temp3;
1981 
1982 	nsamples = (int) (len / (sizeof(sword16_t) << 1));
1983 
1984 	switch (chroute) {
1985 	case CHROUTE_NORMAL:
1986 		if (att >= 100)
1987 			break;
1988 
1989 		for (i = 0; i < nsamples; i++) {
1990 			l = i << 1;
1991 			r = l + 1;
1992 
1993 			/* Set attenuation */
1994 			temp1 = util_lswap16(data[l]);
1995 			temp2 = util_lswap16(data[r]);
1996 			if (att == 0) {
1997 				temp1 = temp2 = 0;
1998 			}
1999 			else {
2000 				temp1 = (sword16_t) ((temp1 * att) / 100);
2001 				temp2 = (sword16_t) ((temp2 * att) / 100);
2002 			}
2003 
2004 			data[l] = util_lswap16(temp1);
2005 			data[r] = util_lswap16(temp2);
2006 		}
2007 		break;
2008 
2009 	case CHROUTE_REVERSE:
2010 		for (i = 0; i < nsamples; i++) {
2011 			l = i << 1;
2012 			r = l + 1;
2013 
2014 			/* Set attenuation */
2015 			temp1 = util_lswap16(data[l]);
2016 			temp2 = util_lswap16(data[r]);
2017 			if (att == 0) {
2018 				temp1 = temp2 = 0;
2019 			}
2020 			else if (att < 100) {
2021 				temp1 = (sword16_t) ((temp1 * att) / 100);
2022 				temp2 = (sword16_t) ((temp2 * att) / 100);
2023 			}
2024 
2025 			/* Swap left and right samples */
2026 			data[l] = util_lswap16(temp2);
2027 			data[r] = util_lswap16(temp1);
2028 		}
2029 		break;
2030 
2031 	case CHROUTE_L_MONO:
2032 		for (i = 0; i < nsamples; i++) {
2033 			l = i << 1;
2034 			r = l + 1;
2035 
2036 			/* Set attenuation */
2037 			temp1 = util_lswap16(data[l]);
2038 			if (att == 0)
2039 				temp1 = 0;
2040 			else if (att < 100)
2041 				temp1 = (sword16_t) ((temp1 * att) / 100);
2042 
2043 			/* Make right same as left */
2044 			data[l] = data[r] = util_lswap16(temp1);
2045 		}
2046 		break;
2047 
2048 	case CHROUTE_R_MONO:
2049 		for (i = 0; i < nsamples; i++) {
2050 			l = i << 1;
2051 			r = l + 1;
2052 
2053 			/* Set attenuation */
2054 			temp2 = util_lswap16(data[r]);
2055 			if (att == 0)
2056 				temp2 = 0;
2057 			else if (att < 100)
2058 				temp2 = (sword16_t) ((temp2 * att) / 100);
2059 
2060 			/* Make left same as right */
2061 			data[l] = data[r] = util_lswap16(temp2);
2062 		}
2063 		break;
2064 
2065 	case CHROUTE_MONO:
2066 		for (i = 0; i < nsamples; i++) {
2067 			l = i << 1;
2068 			r = l + 1;
2069 
2070 			/* Set attenuation */
2071 			temp1 = util_lswap16(data[l]);
2072 			temp2 = util_lswap16(data[r]);
2073 			if (att == 0) {
2074 				temp1 = temp2 = 0;
2075 			}
2076 			else if (att < 100) {
2077 				temp1 = (sword16_t) ((temp1 * att) / 100);
2078 				temp2 = (sword16_t) ((temp2 * att) / 100);
2079 			}
2080 
2081 			/* Average left and right */
2082 			temp3 = util_lswap16((temp1 + temp2) >> 1);
2083 			data[l] = data[r] = temp3;
2084 		}
2085 		break;
2086 
2087 	default:
2088 		break;
2089 	}
2090 }
2091 
2092 
2093 /*
2094  * gen_write_init
2095  *	Generic write services initialization
2096  *
2097  * Args:
2098  *	None.
2099  *
2100  * Return:
2101  *	Nothing.
2102  */
2103 void
gen_write_init(void)2104 gen_write_init(void)
2105 {
2106 	static bool_t	gen_write_initted = FALSE;
2107 
2108 	if (!gen_write_initted) {
2109 		gen_write_initted = TRUE;
2110 
2111 		ruid = util_get_ouid();
2112 		rgid = util_get_ogid();
2113 		euid = geteuid();
2114 		egid = getegid();
2115 	}
2116 }
2117 
2118 #endif	/* CDDA_SUPPORTED */
2119 
2120 
2121