8672 proc_t changes broke genunix dmods and walker
[unleashed.git] / usr / src / cmd / cdrw / bstream.c
bloba9c5639952af94686681804abb7faf3ef5a8c080
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2012 Marcel Telka <marcel@telka.sk>
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>
42 #include "bstream.h"
43 #include "util.h"
44 #include "audio.h"
45 #include "byteorder.h"
46 #include "main.h"
48 int str_errno;
50 char *
51 str_errno_to_string(int serrno)
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"));
81 static int
82 file_stream_size(bstreamhandle h, off_t *size)
84 struct stat st;
86 str_errno = 0;
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);
94 *size = st.st_size;
95 return (1);
98 static int
99 audio_stream_size(bstreamhandle h, off_t *size)
101 str_errno = 0;
102 *size = (off_t)(uintptr_t)(h->bstr_private);
103 return (1);
106 static int
107 file_stream_read(bstreamhandle h, uchar_t *buf, off_t size)
109 str_errno = 0;
110 return (read(h->bstr_fd, buf, size));
113 static int
114 file_stream_write(bstreamhandle h, uchar_t *buf, off_t size)
116 str_errno = 0;
117 return (write(h->bstr_fd, buf, size));
121 * with reverse byteorder
123 static int
124 file_stream_read_wrbo(bstreamhandle h, uchar_t *buf, off_t size)
126 int cnt;
128 str_errno = 0;
129 cnt = read(h->bstr_fd, buf, size);
130 if (cnt > 0) {
131 int i;
132 uchar_t ch;
134 for (i = 0; i < cnt; i += 2) {
135 ch = buf[i];
136 buf[i] = buf[i+1];
137 buf[i+1] = ch;
140 return (cnt);
144 * This will change the byteorder in the buffer but that is fine with us.
146 static int
147 file_stream_write_wrbo(bstreamhandle h, uchar_t *buf, off_t size)
149 int i;
150 uchar_t ch;
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;
160 return (write(h->bstr_fd, buf, size));
163 static int
164 file_stream_close(bstreamhandle h)
166 int fd;
168 str_errno = 0;
169 fd = h->bstr_fd;
170 free(h);
171 return (close(fd));
174 static int
175 stdin_stream_close(bstreamhandle h)
177 str_errno = 0;
178 free(h);
179 return (0);
182 static int
183 wav_write_stream_close(bstreamhandle h)
185 uint32_t sz;
186 Wave_filehdr wav;
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);
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);
201 (void) close(h->bstr_fd);
202 free(h);
203 return (0);
206 static int
207 au_write_stream_close(bstreamhandle h)
209 uint32_t sz;
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);
218 if (write(h->bstr_fd, &sz, 4) < 0)
219 return (1);
221 (void) close(h->bstr_fd);
222 free(h);
223 return (0);
226 /* ARGSUSED */
227 static void
228 stdin_stream_rewind(bstreamhandle h)
232 static void
233 file_stream_rewind(bstreamhandle h)
235 (void) lseek(h->bstr_fd, 0L, SEEK_SET);
238 static void
239 au_stream_rewind(bstreamhandle h)
241 au_filehdr_t au;
243 (void) lseek(h->bstr_fd, 0L, SEEK_SET);
244 if (read(h->bstr_fd, &au, sizeof (au)) != sizeof (au)) {
245 return;
248 if (lseek(h->bstr_fd, (long)(BE32_TO_CPU(au.au_offset)),
249 SEEK_SET) < 0) {
250 return;
254 static void
255 wav_stream_rewind(bstreamhandle h)
257 (void) lseek(h->bstr_fd, (long)(sizeof (Wave_filehdr)), SEEK_SET);
260 bstreamhandle
261 open_file_read_stream(char *file)
263 bstreamhandle h;
264 int fd;
265 struct stat st;
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);
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;
284 return (h);
287 bstreamhandle
288 open_iso_read_stream(char *fname)
290 bstreamhandle h;
291 off_t iso_size = 0;
292 char iso_desc[ISO9660_PRIMARY_DESC_SIZE];
294 h = open_file_read_stream(fname);
296 /* If we don't have a valid handle immediately return NULL */
297 if (h == NULL)
298 return (NULL);
300 if (debug)
301 (void) printf("Checking the ISO file header\n");
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);
313 if (debug)
314 (void) printf("ISO header size is sane.\n");
316 /* Skip over the boot block sector of the ISO. */
317 (void) lseek(h->bstr_fd, ISO9660_BOOT_BLOCK_SIZE, SEEK_SET);
320 * Try to read in the ISO Descriptor and validate this
321 * is in fact an ISO image.
323 if (read(h->bstr_fd, iso_desc, ISO9660_PRIMARY_DESC_SIZE) ==
324 ISO9660_PRIMARY_DESC_SIZE) {
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.
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);
343 } else {
344 h->bstr_close(h);
345 str_errno = STR_ERR_ISO_READ_ERR;
346 return (NULL);
350 * Our ISO image is valid rewind the stream
351 * and return the handle.
353 if (debug)
354 (void) printf("ISO header is sane.\n");
355 h->bstr_rewind(h);
356 return (h);
359 bstreamhandle
360 open_stdin_read_stream(void)
362 bstreamhandle h;
363 int mode;
365 str_errno = 0;
366 if ((mode = fcntl(0, F_GETFD, NULL)) < 0) {
367 str_errno = STR_ERR_NO_READ_STDIN;
368 return (NULL);
370 mode &= 3;
371 if ((mode != O_RDONLY) && (mode != O_RDWR)) {
372 str_errno = STR_ERR_NO_READ_STDIN;
373 return (NULL);
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;
382 return (h);
385 bstreamhandle
386 open_au_read_stream(char *fname)
388 bstreamhandle h;
389 int fd, sav;
390 au_filehdr_t *au;
391 struct stat st;
392 uint32_t data_size;
394 au = NULL;
395 str_errno = 0;
396 fd = open(fname, O_RDONLY);
397 if (fd < 0)
398 return (NULL);
400 if (fstat(fd, &st) < 0) {
401 goto au_open_failed;
403 if ((st.st_mode & S_IFMT) != S_IFREG) {
404 str_errno = STR_ERR_NO_REG_FILE;
405 goto au_open_failed;
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;
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);
419 if (au->au_magic != AUDIO_AU_FILE_MAGIC) {
420 str_errno = STR_ERR_AU_BAD_HEADER;
421 goto au_open_failed;
423 if ((au->au_encoding != AUDIO_AU_ENCODING_LINEAR_16) ||
424 (au->au_sample_rate != 44100) || (au->au_channels != 2)) {
426 str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT;
427 goto au_open_failed;
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;
434 data_size = au->au_data_size;
435 } else {
436 data_size = st.st_size - au->au_offset;
438 if (data_size == 0) {
439 str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT;
440 goto au_open_failed;
442 if (lseek(fd, au->au_offset, SEEK_SET) < 0) {
443 goto au_open_failed;
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;
455 return (h);
457 au_open_failed:
458 sav = errno;
459 (void) close(fd);
460 if (au != NULL)
461 free(au);
462 errno = sav;
463 return (NULL);
466 bstreamhandle
467 open_wav_read_stream(char *fname)
469 bstreamhandle h;
470 int fd, sav;
471 Wave_filehdr *wav;
472 struct stat st;
473 uint32_t data_size;
475 wav = NULL;
476 str_errno = 0;
477 fd = open(fname, O_RDONLY);
478 if (fd < 0)
479 return (NULL);
481 if (fstat(fd, &st) < 0) {
482 goto wav_open_failed;
484 if ((st.st_mode & S_IFMT) != S_IFREG) {
485 str_errno = STR_ERR_NO_REG_FILE;
486 goto wav_open_failed;
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;
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;
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)) {
507 str_errno = STR_ERR_WAV_UNSUPPORTED_FORMAT;
508 goto wav_open_failed;
510 data_size = CPU_TO_LE32(wav->data_size);
511 if (lseek(fd, sizeof (*wav), SEEK_SET) < 0) {
512 goto wav_open_failed;
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;
524 return (h);
526 wav_open_failed:
527 sav = errno;
528 (void) close(fd);
529 if (wav != NULL)
530 free(wav);
531 errno = sav;
532 return (NULL);
535 bstreamhandle
536 open_aur_read_stream(char *fname)
538 bstreamhandle h;
540 h = open_file_read_stream(fname);
541 if (h != NULL) {
542 h->bstr_read = file_stream_read_wrbo;
544 return (h);
547 bstreamhandle
548 open_au_write_stream(char *fname)
550 bstreamhandle h;
551 int esav, fd;
552 uchar_t head[] = PRE_DEF_AU_HDR;
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;
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);
569 open_au_write_stream_failed:
570 esav = errno;
571 if (fd != -1)
572 (void) close(fd);
573 errno = esav;
574 return (NULL);
577 bstreamhandle
578 open_wav_write_stream(char *fname)
580 bstreamhandle h;
581 int esav, fd;
582 uchar_t head[] = PRE_DEF_WAV_HDR;
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;
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);
598 open_wav_write_stream_failed:
599 esav = errno;
600 if (fd != -1)
601 (void) close(fd);
602 errno = esav;
603 return (NULL);
606 bstreamhandle
607 open_aur_write_stream(char *fname)
609 bstreamhandle h;
610 int fd;
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);
623 bstreamhandle
624 open_file_write_stream(char *fname)
626 bstreamhandle h;
627 int fd;
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);
640 bstreamhandle
641 open_temp_file_stream(void)
643 bstreamhandle h;
644 char *t;
645 int fd;
647 str_errno = 0;
649 t = (char *)get_tmp_name();
651 if (strlcat(t, "/cdXXXXXX", PATH_MAX) >= PATH_MAX)
652 return (NULL);
654 fd = mkstemp(t);
656 if (debug)
657 (void) printf("temp is: %s length: %d\n", t, strlen(t));
659 if (fd < 0)
660 return (NULL);
661 (void) unlink(t);
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;
671 return (h);
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
680 check_avail_temp_space(size_t req_size)
682 struct statvfs buf;
683 u_longlong_t free_size = 0;
685 if (statvfs(get_tmp_name(), &buf) < 0) {
686 return (errno);
689 free_size = buf.f_bfree * buf.f_frsize;
691 if (free_size <= req_size)
692 return (ENOMEM);
694 return (0);
698 char *
699 get_tmp_name(void)
701 char *t;
702 char *envptr;
704 t = (char *)my_zalloc(PATH_MAX);
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.
712 if (alt_tmp_dir) {
714 /* copy and leave room for temp filename */
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);
727 * no need to check if path is valid. statvfs will catch
728 * it later and fail with a proper error message.
731 return (t);