xref: /illumos-gate/usr/src/cmd/cdrw/bstream.c (revision eab441e2)
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