1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <fcntl.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <sys/statvfs.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <libintl.h>
38 #include <limits.h>
39 #include <audio/au.h>
40
41 #include "bstream.h"
42 #include "util.h"
43 #include "audio.h"
44 #include "byteorder.h"
45 #include "main.h"
46
47 int str_errno;
48
49 char *
str_errno_to_string(int serrno)50 str_errno_to_string(int serrno)
51 {
52 switch (serrno) {
53 case STR_ERR_NO_ERR:
54 return (gettext("No error"));
55 case STR_ERR_NO_REG_FILE:
56 return (gettext("Not a regular file"));
57 case STR_ERR_NO_READ_STDIN:
58 return (gettext("Stdin not open for reading"));
59 case STR_ERR_AU_READ_ERR:
60 return (gettext("Unable to read au header"));
61 case STR_ERR_AU_UNSUPPORTED_FORMAT:
62 return (gettext("Unsupported au format"));
63 case STR_ERR_AU_BAD_HEADER:
64 return (gettext("Bad au header"));
65 case STR_ERR_WAV_READ_ERR:
66 return (gettext("Unable to read wav header"));
67 case STR_ERR_WAV_UNSUPPORTED_FORMAT:
68 return (gettext("Unsupported wav format"));
69 case STR_ERR_WAV_BAD_HEADER:
70 return (gettext("Bad wav header"));
71 case STR_ERR_ISO_READ_ERR:
72 return (gettext("Unable to read ISO header"));
73 case STR_ERR_ISO_BAD_HEADER:
74 return (gettext("Invalid ISO header or not an ISO"));
75 default:
76 return (gettext("unknown error"));
77 }
78 }
79
80 static int
file_stream_size(bstreamhandle h,off_t * size)81 file_stream_size(bstreamhandle h, off_t *size)
82 {
83 struct stat st;
84
85 str_errno = 0;
86
87 if (fstat(h->bstr_fd, &st) < 0)
88 return (0);
89 if ((st.st_mode & S_IFMT) != S_IFREG) {
90 str_errno = STR_ERR_NO_REG_FILE;
91 return (0);
92 }
93 *size = st.st_size;
94 return (1);
95 }
96
97 static int
audio_stream_size(bstreamhandle h,off_t * size)98 audio_stream_size(bstreamhandle h, off_t *size)
99 {
100 str_errno = 0;
101 *size = (off_t)(uintptr_t)(h->bstr_private);
102 return (1);
103 }
104
105 static int
file_stream_read(bstreamhandle h,uchar_t * buf,off_t size)106 file_stream_read(bstreamhandle h, uchar_t *buf, off_t size)
107 {
108 str_errno = 0;
109 return (read(h->bstr_fd, buf, size));
110 }
111
112 static int
file_stream_write(bstreamhandle h,uchar_t * buf,off_t size)113 file_stream_write(bstreamhandle h, uchar_t *buf, off_t size)
114 {
115 str_errno = 0;
116 return (write(h->bstr_fd, buf, size));
117 }
118
119 /*
120 * with reverse byteorder
121 */
122 static int
file_stream_read_wrbo(bstreamhandle h,uchar_t * buf,off_t size)123 file_stream_read_wrbo(bstreamhandle h, uchar_t *buf, off_t size)
124 {
125 int cnt;
126
127 str_errno = 0;
128 cnt = read(h->bstr_fd, buf, size);
129 if (cnt > 0) {
130 int i;
131 uchar_t ch;
132
133 for (i = 0; i < cnt; i += 2) {
134 ch = buf[i];
135 buf[i] = buf[i+1];
136 buf[i+1] = ch;
137 }
138 }
139 return (cnt);
140 }
141
142 /*
143 * This will change the byteorder in the buffer but that is fine with us.
144 */
145 static int
file_stream_write_wrbo(bstreamhandle h,uchar_t * buf,off_t size)146 file_stream_write_wrbo(bstreamhandle h, uchar_t *buf, off_t size)
147 {
148 int i;
149 uchar_t ch;
150
151 str_errno = 0;
152 if (size > 0) {
153 for (i = 0; i < size; i += 2) {
154 ch = buf[i];
155 buf[i] = buf[i+1];
156 buf[i+1] = ch;
157 }
158 }
159 return (write(h->bstr_fd, buf, size));
160 }
161
162 static int
file_stream_close(bstreamhandle h)163 file_stream_close(bstreamhandle h)
164 {
165 int fd;
166
167 str_errno = 0;
168 fd = h->bstr_fd;
169 free(h);
170 return (close(fd));
171 }
172
173 static int
stdin_stream_close(bstreamhandle h)174 stdin_stream_close(bstreamhandle h)
175 {
176 str_errno = 0;
177 free(h);
178 return (0);
179 }
180
181 static int
wav_write_stream_close(bstreamhandle h)182 wav_write_stream_close(bstreamhandle h)
183 {
184 uint32_t sz;
185 Wave_filehdr wav;
186
187 str_errno = 0;
188 (void) memset(&wav, 0, sizeof (wav));
189 sz = lseek(h->bstr_fd, 0L, SEEK_END);
190 (void) lseek(h->bstr_fd, 0L, SEEK_SET);
191 if (read(h->bstr_fd, &wav, sizeof (wav)) != sizeof (wav)) {
192 return (1);
193 }
194 wav.total_chunk_size = CPU_TO_LE32(sz - 8);
195 wav.data_size = CPU_TO_LE32(sz - 44);
196 (void) lseek(h->bstr_fd, 0L, SEEK_SET);
197 if (write(h->bstr_fd, &wav, sizeof (wav)) != sizeof (wav)) {
198 return (1);
199 }
200 (void) close(h->bstr_fd);
201 free(h);
202 return (0);
203 }
204
205 static int
au_write_stream_close(bstreamhandle h)206 au_write_stream_close(bstreamhandle h)
207 {
208 uint32_t sz;
209
210 str_errno = 0;
211 sz = lseek(h->bstr_fd, 0L, SEEK_END);
212 sz -= PRE_DEF_AU_HDR_LEN;
213 sz = CPU_TO_BE32(sz);
214 if (lseek(h->bstr_fd, 8L, SEEK_SET) < 0)
215 return (1);
216
217 if (write(h->bstr_fd, &sz, 4) < 0)
218 return (1);
219
220 (void) close(h->bstr_fd);
221 free(h);
222 return (0);
223 }
224
225 /* ARGSUSED */
226 static void
stdin_stream_rewind(bstreamhandle h)227 stdin_stream_rewind(bstreamhandle h)
228 {
229 }
230
231 static void
file_stream_rewind(bstreamhandle h)232 file_stream_rewind(bstreamhandle h)
233 {
234 (void) lseek(h->bstr_fd, 0L, SEEK_SET);
235 }
236
237 static void
au_stream_rewind(bstreamhandle h)238 au_stream_rewind(bstreamhandle h)
239 {
240 au_filehdr_t au;
241
242 (void) lseek(h->bstr_fd, 0L, SEEK_SET);
243 if (read(h->bstr_fd, &au, sizeof (au)) != sizeof (au)) {
244 return;
245 }
246
247 if (lseek(h->bstr_fd, (long)(BE32_TO_CPU(au.au_offset)),
248 SEEK_SET) < 0) {
249 return;
250 }
251 }
252
253 static void
wav_stream_rewind(bstreamhandle h)254 wav_stream_rewind(bstreamhandle h)
255 {
256 (void) lseek(h->bstr_fd, (long)(sizeof (Wave_filehdr)), SEEK_SET);
257 }
258
259 bstreamhandle
open_file_read_stream(char * file)260 open_file_read_stream(char *file)
261 {
262 bstreamhandle h;
263 int fd;
264 struct stat st;
265
266 str_errno = 0;
267 if (stat(file, &st) < 0)
268 return (NULL);
269 if ((st.st_mode & S_IFMT) == S_IFDIR) {
270 str_errno = STR_ERR_NO_REG_FILE;
271 return (NULL);
272 }
273 fd = open(file, O_RDONLY);
274 if (fd < 0)
275 return (NULL);
276 h = (bstreamhandle)my_zalloc(sizeof (*h));
277 h->bstr_fd = fd;
278 h->bstr_read = file_stream_read;
279 h->bstr_close = file_stream_close;
280 h->bstr_size = file_stream_size;
281 h->bstr_rewind = file_stream_rewind;
282
283 return (h);
284 }
285
286 bstreamhandle
open_iso_read_stream(char * fname)287 open_iso_read_stream(char *fname)
288 {
289 bstreamhandle h;
290 off_t iso_size = 0;
291 char iso_desc[ISO9660_PRIMARY_DESC_SIZE];
292
293 h = open_file_read_stream(fname);
294
295 /* If we don't have a valid handle immediately return NULL */
296 if (h == NULL)
297 return (NULL);
298
299 if (debug)
300 (void) printf("Checking the ISO 9660 file header\n");
301
302 /* Check to see if we have a valid sized ISO image */
303 h->bstr_size(h, &iso_size);
304 if (iso_size < ISO9660_HEADER_SIZE) {
305 if (debug)
306 (void) printf("ISO 9660 header size not sane.\n");
307 h->bstr_close(h);
308 str_errno = STR_ERR_ISO_BAD_HEADER;
309 return (NULL);
310 }
311
312 if (debug)
313 (void) printf("ISO 9660 header size is sane.\n");
314
315 /* Skip over the boot block sector of the ISO. */
316 (void) lseek(h->bstr_fd, ISO9660_BOOT_BLOCK_SIZE, SEEK_SET);
317
318 /*
319 * Try to read in the ISO Descriptor and validate this
320 * is in fact an ISO 9660 image.
321 */
322 if (read(h->bstr_fd, iso_desc, ISO9660_PRIMARY_DESC_SIZE) ==
323 ISO9660_PRIMARY_DESC_SIZE) {
324 /*
325 * Bytes one through five of a valid ISO 9660 cd image
326 * should contain the string CD001. High Sierra format,
327 * the ISO 9660 predecessor, fills this field with the
328 * string CDROM. If neither is the case then we should
329 * close the stream, set str_errno, and return NULL.
330 */
331 if (strncmp(iso_desc + ISO9660_STD_IDENT_OFFSET, "CD001",
332 5) != 0 && strncmp(iso_desc + ISO9660_STD_IDENT_OFFSET,
333 "CDROM", 5) != 0) {
334 if (debug)
335 (void) printf("Invalid ISO 9660 identifier.\n");
336 h->bstr_close(h);
337 str_errno = STR_ERR_ISO_BAD_HEADER;
338 return (NULL);
339 }
340 } else {
341 h->bstr_close(h);
342 str_errno = STR_ERR_ISO_READ_ERR;
343 return (NULL);
344 }
345
346 /*
347 * Our ISO image is valid rewind the stream
348 * and return the handle.
349 */
350 if (debug)
351 (void) printf("ISO 9660 header is sane.\n");
352 h->bstr_rewind(h);
353 return (h);
354 }
355
356 bstreamhandle
open_stdin_read_stream(void)357 open_stdin_read_stream(void)
358 {
359 bstreamhandle h;
360 int mode;
361
362 str_errno = 0;
363 if ((mode = fcntl(0, F_GETFD, NULL)) < 0) {
364 str_errno = STR_ERR_NO_READ_STDIN;
365 return (NULL);
366 }
367 mode &= 3;
368 if ((mode != O_RDONLY) && (mode != O_RDWR)) {
369 str_errno = STR_ERR_NO_READ_STDIN;
370 return (NULL);
371 }
372 h = (bstreamhandle)my_zalloc(sizeof (*h));
373 h->bstr_fd = 0;
374 h->bstr_read = file_stream_read;
375 h->bstr_close = stdin_stream_close;
376 h->bstr_size = file_stream_size;
377 h->bstr_rewind = stdin_stream_rewind;
378
379 return (h);
380 }
381
382 bstreamhandle
open_au_read_stream(char * fname)383 open_au_read_stream(char *fname)
384 {
385 bstreamhandle h;
386 int fd, sav;
387 au_filehdr_t *au;
388 struct stat st;
389 uint32_t data_size;
390
391 au = NULL;
392 str_errno = 0;
393 fd = open(fname, O_RDONLY);
394 if (fd < 0)
395 return (NULL);
396
397 if (fstat(fd, &st) < 0) {
398 goto au_open_failed;
399 }
400 if ((st.st_mode & S_IFMT) != S_IFREG) {
401 str_errno = STR_ERR_NO_REG_FILE;
402 goto au_open_failed;
403 }
404 au = (au_filehdr_t *)my_zalloc(sizeof (*au));
405 if (read(fd, au, sizeof (*au)) != sizeof (*au)) {
406 str_errno = STR_ERR_AU_READ_ERR;
407 goto au_open_failed;
408 }
409 au->au_magic = BE32_TO_CPU(au->au_magic);
410 au->au_offset = BE32_TO_CPU(au->au_offset);
411 au->au_data_size = BE32_TO_CPU(au->au_data_size);
412 au->au_encoding = BE32_TO_CPU(au->au_encoding);
413 au->au_sample_rate = BE32_TO_CPU(au->au_sample_rate);
414 au->au_channels = BE32_TO_CPU(au->au_channels);
415
416 if (au->au_magic != AUDIO_AU_FILE_MAGIC) {
417 str_errno = STR_ERR_AU_BAD_HEADER;
418 goto au_open_failed;
419 }
420 if ((au->au_encoding != AUDIO_AU_ENCODING_LINEAR_16) ||
421 (au->au_sample_rate != 44100) || (au->au_channels != 2)) {
422
423 str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT;
424 goto au_open_failed;
425 }
426 if (au->au_data_size != AUDIO_AU_UNKNOWN_SIZE) {
427 if ((au->au_offset + au->au_data_size) != st.st_size) {
428 str_errno = STR_ERR_AU_BAD_HEADER;
429 goto au_open_failed;
430 }
431 data_size = au->au_data_size;
432 } else {
433 data_size = st.st_size - au->au_offset;
434 }
435 if (data_size == 0) {
436 str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT;
437 goto au_open_failed;
438 }
439 if (lseek(fd, au->au_offset, SEEK_SET) < 0) {
440 goto au_open_failed;
441 }
442
443 free(au);
444 h = (bstreamhandle)my_zalloc(sizeof (*h));
445 h->bstr_fd = fd;
446 h->bstr_read = file_stream_read_wrbo;
447 h->bstr_close = file_stream_close;
448 h->bstr_size = audio_stream_size;
449 h->bstr_rewind = au_stream_rewind;
450 h->bstr_private = (void *)data_size;
451
452 return (h);
453
454 au_open_failed:
455 sav = errno;
456 (void) close(fd);
457 if (au != NULL)
458 free(au);
459 errno = sav;
460 return (NULL);
461 }
462
463 bstreamhandle
open_wav_read_stream(char * fname)464 open_wav_read_stream(char *fname)
465 {
466 bstreamhandle h;
467 int fd, sav;
468 Wave_filehdr *wav;
469 struct stat st;
470 uint32_t data_size;
471
472 wav = NULL;
473 str_errno = 0;
474 fd = open(fname, O_RDONLY);
475 if (fd < 0)
476 return (NULL);
477
478 if (fstat(fd, &st) < 0) {
479 goto wav_open_failed;
480 }
481 if ((st.st_mode & S_IFMT) != S_IFREG) {
482 str_errno = STR_ERR_NO_REG_FILE;
483 goto wav_open_failed;
484 }
485 wav = (Wave_filehdr *)my_zalloc(sizeof (*wav));
486 if (read(fd, wav, sizeof (*wav)) != sizeof (*wav)) {
487 str_errno = STR_ERR_WAV_READ_ERR;
488 goto wav_open_failed;
489 }
490 if ((strncmp(wav->riff, "RIFF", 4) != 0) ||
491 (strncmp(wav->wave, "WAVE", 4) != 0)) {
492 str_errno = STR_ERR_WAV_BAD_HEADER;
493 goto wav_open_failed;
494 }
495 if (((CPU_TO_LE32(wav->total_chunk_size) + 8) != st.st_size) ||
496 (strncmp(wav->fmt, "fmt ", 4) != 0) ||
497 (CPU_TO_LE16(wav->fmt_tag) != 1) ||
498 (CPU_TO_LE16(wav->n_channels) != 2) ||
499 (CPU_TO_LE32(wav->sample_rate) != 44100) ||
500 (CPU_TO_LE16(wav->bits_per_sample) != 16) ||
501 (strncmp(wav->data, "data", 4) != 0) ||
502 ((CPU_TO_LE32(wav->data_size) + 44) != st.st_size)) {
503
504 str_errno = STR_ERR_WAV_UNSUPPORTED_FORMAT;
505 goto wav_open_failed;
506 }
507 data_size = CPU_TO_LE32(wav->data_size);
508 if (lseek(fd, sizeof (*wav), SEEK_SET) < 0) {
509 goto wav_open_failed;
510 }
511
512 free(wav);
513 h = (bstreamhandle)my_zalloc(sizeof (*h));
514 h->bstr_fd = fd;
515 h->bstr_read = file_stream_read;
516 h->bstr_close = file_stream_close;
517 h->bstr_size = audio_stream_size;
518 h->bstr_rewind = wav_stream_rewind;
519 h->bstr_private = (void *)data_size;
520
521 return (h);
522
523 wav_open_failed:
524 sav = errno;
525 (void) close(fd);
526 if (wav != NULL)
527 free(wav);
528 errno = sav;
529 return (NULL);
530 }
531
532 bstreamhandle
open_aur_read_stream(char * fname)533 open_aur_read_stream(char *fname)
534 {
535 bstreamhandle h;
536
537 h = open_file_read_stream(fname);
538 if (h != NULL) {
539 h->bstr_read = file_stream_read_wrbo;
540 }
541 return (h);
542 }
543
544 bstreamhandle
open_au_write_stream(char * fname)545 open_au_write_stream(char *fname)
546 {
547 bstreamhandle h;
548 int esav, fd;
549 uchar_t head[] = PRE_DEF_AU_HDR;
550
551 str_errno = 0;
552 fd = -1;
553 /* O_RDWR because we need to read while closing */
554 fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
555 if (fd < 0)
556 goto open_au_write_stream_failed;
557 if (write(fd, head, PRE_DEF_AU_HDR_LEN) != PRE_DEF_AU_HDR_LEN) {
558 goto open_au_write_stream_failed;
559 }
560 h = (bstreamhandle)my_zalloc(sizeof (*h));
561 h->bstr_fd = fd;
562 h->bstr_write = file_stream_write_wrbo;
563 h->bstr_close = au_write_stream_close;
564 return (h);
565
566 open_au_write_stream_failed:
567 esav = errno;
568 if (fd != -1)
569 (void) close(fd);
570 errno = esav;
571 return (NULL);
572 }
573
574 bstreamhandle
open_wav_write_stream(char * fname)575 open_wav_write_stream(char *fname)
576 {
577 bstreamhandle h;
578 int esav, fd;
579 uchar_t head[] = PRE_DEF_WAV_HDR;
580
581 str_errno = 0;
582 fd = -1;
583 fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
584 if (fd < 0)
585 goto open_wav_write_stream_failed;
586 if (write(fd, head, PRE_DEF_WAV_HDR_LEN) != PRE_DEF_WAV_HDR_LEN) {
587 goto open_wav_write_stream_failed;
588 }
589 h = (bstreamhandle)my_zalloc(sizeof (*h));
590 h->bstr_fd = fd;
591 h->bstr_write = file_stream_write;
592 h->bstr_close = wav_write_stream_close;
593 return (h);
594
595 open_wav_write_stream_failed:
596 esav = errno;
597 if (fd != -1)
598 (void) close(fd);
599 errno = esav;
600 return (NULL);
601 }
602
603 bstreamhandle
open_aur_write_stream(char * fname)604 open_aur_write_stream(char *fname)
605 {
606 bstreamhandle h;
607 int fd;
608
609 str_errno = 0;
610 fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
611 if (fd < 0)
612 return (NULL);
613 h = (bstreamhandle)my_zalloc(sizeof (*h));
614 h->bstr_fd = fd;
615 h->bstr_write = file_stream_write_wrbo;
616 h->bstr_close = file_stream_close;
617 return (h);
618 }
619
620 bstreamhandle
open_file_write_stream(char * fname)621 open_file_write_stream(char *fname)
622 {
623 bstreamhandle h;
624 int fd;
625
626 str_errno = 0;
627 fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
628 if (fd < 0)
629 return (NULL);
630 h = (bstreamhandle)my_zalloc(sizeof (*h));
631 h->bstr_fd = fd;
632 h->bstr_write = file_stream_write;
633 h->bstr_close = file_stream_close;
634 return (h);
635 }
636
637 bstreamhandle
open_temp_file_stream(void)638 open_temp_file_stream(void)
639 {
640 bstreamhandle h;
641 char *t;
642 int fd;
643
644 str_errno = 0;
645
646 t = (char *)get_tmp_name();
647
648 if (strlcat(t, "/cdXXXXXX", PATH_MAX) >= PATH_MAX)
649 return (NULL);
650
651 fd = mkstemp(t);
652
653 if (debug)
654 (void) printf("temp is: %s length: %d\n", t, strlen(t));
655
656 if (fd < 0)
657 return (NULL);
658 (void) unlink(t);
659
660 h = (bstreamhandle)my_zalloc(sizeof (*h));
661 h->bstr_fd = fd;
662 h->bstr_read = file_stream_read;
663 h->bstr_write = file_stream_write;
664 h->bstr_close = file_stream_close;
665 h->bstr_size = file_stream_size;
666 h->bstr_rewind = file_stream_rewind;
667
668 return (h);
669 }
670
671 /*
672 * check_avail_temp_space returns 0 if there is adequate space
673 * in the temporary directory, or a non-zero error code if
674 * something goes wrong
675 */
676 int
check_avail_temp_space(size_t req_size)677 check_avail_temp_space(size_t req_size)
678 {
679 struct statvfs buf;
680 u_longlong_t free_size = 0;
681
682 if (statvfs(get_tmp_name(), &buf) < 0) {
683 return (errno);
684 }
685
686 free_size = buf.f_bfree * buf.f_frsize;
687
688 if (free_size <= req_size)
689 return (ENOMEM);
690
691 return (0);
692 }
693
694
695 char *
get_tmp_name(void)696 get_tmp_name(void)
697 {
698 char *t;
699 char *envptr;
700
701 t = (char *)my_zalloc(PATH_MAX);
702
703 /*
704 * generate temp directory path based on this order:
705 * user specified (-m option), temp env variable,
706 * and finally /tmp if nothing is found.
707 */
708
709 if (alt_tmp_dir) {
710
711 /* copy and leave room for temp filename */
712
713 (void) strlcpy(t, alt_tmp_dir, PATH_MAX - 10);
714 } else {
715 envptr = getenv("TMPDIR");
716 if (envptr != NULL) {
717 (void) strlcpy(t, envptr, PATH_MAX - 10);
718 } else {
719 (void) strlcpy(t, "/tmp", 5);
720 }
721 }
722
723 /*
724 * no need to check if path is valid. statvfs will catch
725 * it later and fail with a proper error message.
726 */
727
728 return (t);
729 }
730