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