xref: /netbsd-src/external/bsd/file/dist/src/compress.c (revision c9496f6b604074a9451a67df576a5b423068e71e)
1 /*	$NetBSD: compress.c,v 1.14 2017/09/08 13:40:25 christos Exp $	*/
2 
3 /*
4  * Copyright (c) Ian F. Darwin 1986-1995.
5  * Software written by Ian F. Darwin and others;
6  * maintained 1995-present by Christos Zoulas and others.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice immediately at the beginning of the file, without modification,
13  *    this list of conditions, and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 /*
31  * compress routines:
32  *	zmagic() - returns 0 if not recognized, uncompresses and prints
33  *		   information if recognized
34  *	uncompress(method, old, n, newch) - uncompress old into new,
35  *					    using method, return sizeof new
36  */
37 #include "file.h"
38 
39 #ifndef lint
40 #if 0
41 FILE_RCSID("@(#)$File: compress.c,v 1.105 2017/05/25 00:13:03 christos Exp $")
42 #else
43 __RCSID("$NetBSD: compress.c,v 1.14 2017/09/08 13:40:25 christos Exp $");
44 #endif
45 #endif
46 
47 #include "magic.h"
48 #include <stdlib.h>
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include <string.h>
53 #include <errno.h>
54 #include <ctype.h>
55 #include <stdarg.h>
56 #ifdef HAVE_SIGNAL_H
57 #include <signal.h>
58 # ifndef HAVE_SIG_T
59 typedef void (*sig_t)(int);
60 # endif /* HAVE_SIG_T */
61 #endif
62 #if !defined(__MINGW32__) && !defined(WIN32)
63 #include <sys/ioctl.h>
64 #endif
65 #ifdef HAVE_SYS_WAIT_H
66 #include <sys/wait.h>
67 #endif
68 #if defined(HAVE_SYS_TIME_H)
69 #include <sys/time.h>
70 #endif
71 #if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT)
72 #define BUILTIN_DECOMPRESS
73 #include <zlib.h>
74 #endif
75 #ifdef DEBUG
76 int tty = -1;
77 #define DPRINTF(...)	do { \
78 	if (tty == -1) \
79 		tty = open("/dev/tty", O_RDWR); \
80 	if (tty == -1) \
81 		abort(); \
82 	dprintf(tty, __VA_ARGS__); \
83 } while (/*CONSTCOND*/0)
84 #else
85 #define DPRINTF(...)
86 #endif
87 
88 #ifdef ZLIBSUPPORT
89 /*
90  * The following python code is not really used because ZLIBSUPPORT is only
91  * defined if we have a built-in zlib, and the built-in zlib handles that.
92  * That is not true for android where we have zlib.h and not -lz.
93  */
94 static const char zlibcode[] =
95     "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))";
96 
97 static const char *zlib_args[] = { "python", "-c", zlibcode, NULL };
98 
99 static int
100 zlibcmp(const unsigned char *buf)
101 {
102 	unsigned short x = 1;
103 	unsigned char *s = CAST(unsigned char *, CAST(void *, &x));
104 
105 	if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0)
106 		return 0;
107 	if (s[0] != 1)	/* endianness test */
108 		x = buf[0] | (buf[1] << 8);
109 	else
110 		x = buf[1] | (buf[0] << 8);
111 	if (x % 31)
112 		return 0;
113 	return 1;
114 }
115 #endif
116 
117 #define gzip_flags "-cd"
118 #define lrzip_flags "-do"
119 #define lzip_flags gzip_flags
120 
121 static const char *gzip_args[] = {
122 	"gzip", gzip_flags, NULL
123 };
124 static const char *uncompress_args[] = {
125 	"uncompress", "-c", NULL
126 };
127 static const char *bzip2_args[] = {
128 	"bzip2", "-cd", NULL
129 };
130 static const char *lzip_args[] = {
131 	"lzip", lzip_flags, NULL
132 };
133 static const char *xz_args[] = {
134 	"xz", "-cd", NULL
135 };
136 static const char *lrzip_args[] = {
137 	"lrzip", lrzip_flags, NULL
138 };
139 static const char *lz4_args[] = {
140 	"lz4", "-cd", NULL
141 };
142 static const char *zstd_args[] = {
143 	"zstd", "-cd", NULL
144 };
145 
146 private const struct {
147 	const void *magic;
148 	size_t maglen;
149 	const char **argv;
150 } compr[] = {
151 	{ "\037\235",	2, gzip_args },		/* compressed */
152 	/* Uncompress can get stuck; so use gzip first if we have it
153 	 * Idea from Damien Clark, thanks! */
154 	{ "\037\235",	2, uncompress_args },	/* compressed */
155 	{ "\037\213",	2, gzip_args },		/* gzipped */
156 	{ "\037\236",	2, gzip_args },		/* frozen */
157 	{ "\037\240",	2, gzip_args },		/* SCO LZH */
158 	/* the standard pack utilities do not accept standard input */
159 	{ "\037\036",	2, gzip_args },		/* packed */
160 	{ "PK\3\4",	4, gzip_args },		/* pkzipped, */
161 	/* ...only first file examined */
162 	{ "BZh",	3, bzip2_args },	/* bzip2-ed */
163 	{ "LZIP",	4, lzip_args },		/* lzip-ed */
164  	{ "\3757zXZ\0",	6, xz_args },		/* XZ Utils */
165  	{ "LRZI",	4, lrzip_args },	/* LRZIP */
166  	{ "\004\"M\030",4, lz4_args },		/* LZ4 */
167  	{ "\x28\xB5\x2F\xFD", 4, zstd_args },	/* zstd */
168 #ifdef ZLIBSUPPORT
169 	{ RCAST(const void *, zlibcmp),	0, zlib_args },		/* zlib */
170 #endif
171 };
172 
173 #define OKDATA 	0
174 #define NODATA	1
175 #define ERRDATA	2
176 
177 private ssize_t swrite(int, const void *, size_t);
178 #if HAVE_FORK
179 private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
180 private int uncompressbuf(int, size_t, size_t, const unsigned char *,
181     unsigned char **, size_t *);
182 #ifdef BUILTIN_DECOMPRESS
183 private int uncompresszlib(const unsigned char *, unsigned char **, size_t,
184     size_t *, int);
185 private int uncompressgzipped(const unsigned char *, unsigned char **, size_t,
186     size_t *);
187 #endif
188 static int makeerror(unsigned char **, size_t *, const char *, ...)
189     __attribute__((__format__(__printf__, 3, 4)));
190 private const char *methodname(size_t);
191 
192 protected int
193 file_zmagic(struct magic_set *ms, int fd, const char *name,
194     const unsigned char *buf, size_t nbytes)
195 {
196 	unsigned char *newbuf = NULL;
197 	size_t i, nsz;
198 	char *rbuf;
199 	file_pushbuf_t *pb;
200 	int urv, prv, rv = 0;
201 	int mime = ms->flags & MAGIC_MIME;
202 #ifdef HAVE_SIGNAL_H
203 	sig_t osigpipe;
204 #endif
205 
206 	if ((ms->flags & MAGIC_COMPRESS) == 0)
207 		return 0;
208 
209 #ifdef HAVE_SIGNAL_H
210 	osigpipe = signal(SIGPIPE, SIG_IGN);
211 #endif
212 	for (i = 0; i < ncompr; i++) {
213 		int zm;
214 		if (nbytes < compr[i].maglen)
215 			continue;
216 #ifdef ZLIBSUPPORT
217 		if (compr[i].maglen == 0)
218 			zm = (RCAST(int (*)(const unsigned char *),
219 			    CCAST(void *, compr[i].magic)))(buf);
220 		else
221 #endif
222 			zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0;
223 
224 		if (!zm)
225 			continue;
226 		nsz = nbytes;
227 		urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
228 		DPRINTF("uncompressbuf = %d, %s, %zu\n", urv, (char *)newbuf,
229 		    nsz);
230 		switch (urv) {
231 		case OKDATA:
232 		case ERRDATA:
233 
234 			ms->flags &= ~MAGIC_COMPRESS;
235 			if (urv == ERRDATA)
236 				prv = file_printf(ms, "%s ERROR: %s",
237 				    methodname(i), newbuf);
238 			else
239 				prv = file_buffer(ms, -1, name, newbuf, nsz);
240 			if (prv == -1)
241 				goto error;
242 			rv = 1;
243 			if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
244 				goto out;
245 			if (mime != MAGIC_MIME && mime != 0)
246 				goto out;
247 			if ((file_printf(ms,
248 			    mime ? " compressed-encoding=" : " (")) == -1)
249 				goto error;
250 			if ((pb = file_push_buffer(ms)) == NULL)
251 				goto error;
252 			/*
253 			 * XXX: If file_buffer fails here, we overwrite
254 			 * the compressed text. FIXME.
255 			 */
256 			if (file_buffer(ms, -1, NULL, buf, nbytes) == -1)
257 				goto error;
258 			if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
259 				if (file_printf(ms, "%s", rbuf) == -1) {
260 					free(rbuf);
261 					goto error;
262 				}
263 				free(rbuf);
264 			}
265 			if (!mime && file_printf(ms, ")") == -1)
266 				goto error;
267 			/*FALLTHROUGH*/
268 		case NODATA:
269 			break;
270 		default:
271 			abort();
272 			/*NOTREACHED*/
273 		error:
274 			rv = -1;
275 			break;
276 		}
277 	}
278 out:
279 	DPRINTF("rv = %d\n", rv);
280 
281 #ifdef HAVE_SIGNAL_H
282 	(void)signal(SIGPIPE, osigpipe);
283 #endif
284 	free(newbuf);
285 	ms->flags |= MAGIC_COMPRESS;
286 	DPRINTF("Zmagic returns %d\n", rv);
287 	return rv;
288 }
289 #endif
290 /*
291  * `safe' write for sockets and pipes.
292  */
293 private ssize_t
294 swrite(int fd, const void *buf, size_t n)
295 {
296 	ssize_t rv;
297 	size_t rn = n;
298 
299 	do
300 		switch (rv = write(fd, buf, n)) {
301 		case -1:
302 			if (errno == EINTR)
303 				continue;
304 			return -1;
305 		default:
306 			n -= rv;
307 			buf = CAST(const char *, buf) + rv;
308 			break;
309 		}
310 	while (n > 0);
311 	return rn;
312 }
313 
314 
315 /*
316  * `safe' read for sockets and pipes.
317  */
318 protected ssize_t
319 sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__)))
320 {
321 	ssize_t rv;
322 #ifdef FIONREAD
323 	int t = 0;
324 #endif
325 	size_t rn = n;
326 
327 	if (fd == STDIN_FILENO)
328 		goto nocheck;
329 
330 #ifdef FIONREAD
331 	if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) {
332 #ifdef FD_ZERO
333 		ssize_t cnt;
334 		for (cnt = 0;; cnt++) {
335 			fd_set check;
336 			struct timeval tout = {0, 100 * 1000};
337 			int selrv;
338 
339 			FD_ZERO(&check);
340 			FD_SET(fd, &check);
341 
342 			/*
343 			 * Avoid soft deadlock: do not read if there
344 			 * is nothing to read from sockets and pipes.
345 			 */
346 			selrv = select(fd + 1, &check, NULL, NULL, &tout);
347 			if (selrv == -1) {
348 				if (errno == EINTR || errno == EAGAIN)
349 					continue;
350 			} else if (selrv == 0 && cnt >= 5) {
351 				return 0;
352 			} else
353 				break;
354 		}
355 #endif
356 		(void)ioctl(fd, FIONREAD, &t);
357 	}
358 
359 	if (t > 0 && (size_t)t < n) {
360 		n = t;
361 		rn = n;
362 	}
363 #endif
364 
365 nocheck:
366 	do
367 		switch ((rv = read(fd, buf, n))) {
368 		case -1:
369 			if (errno == EINTR)
370 				continue;
371 			return -1;
372 		case 0:
373 			return rn - n;
374 		default:
375 			n -= rv;
376 			buf = CAST(char *, CCAST(void *, buf)) + rv;
377 			break;
378 		}
379 	while (n > 0);
380 	return rn;
381 }
382 
383 protected int
384 file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
385     size_t nbytes)
386 {
387 	char buf[4096];
388 	ssize_t r;
389 	int tfd;
390 
391 	(void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
392 #ifndef HAVE_MKSTEMP
393 	{
394 		char *ptr = mktemp(buf);
395 		tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
396 		r = errno;
397 		(void)unlink(ptr);
398 		errno = r;
399 	}
400 #else
401 	{
402 		int te;
403 		tfd = mkstemp(buf);
404 		te = errno;
405 		(void)unlink(buf);
406 		errno = te;
407 	}
408 #endif
409 	if (tfd == -1) {
410 		file_error(ms, errno,
411 		    "cannot create temporary file for pipe copy");
412 		return -1;
413 	}
414 
415 	if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
416 		r = 1;
417 	else {
418 		while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
419 			if (swrite(tfd, buf, (size_t)r) != r)
420 				break;
421 	}
422 
423 	switch (r) {
424 	case -1:
425 		file_error(ms, errno, "error copying from pipe to temp file");
426 		return -1;
427 	case 0:
428 		break;
429 	default:
430 		file_error(ms, errno, "error while writing to temp file");
431 		return -1;
432 	}
433 
434 	/*
435 	 * We duplicate the file descriptor, because fclose on a
436 	 * tmpfile will delete the file, but any open descriptors
437 	 * can still access the phantom inode.
438 	 */
439 	if ((fd = dup2(tfd, fd)) == -1) {
440 		file_error(ms, errno, "could not dup descriptor for temp file");
441 		return -1;
442 	}
443 	(void)close(tfd);
444 	if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
445 		file_badseek(ms);
446 		return -1;
447 	}
448 	return fd;
449 }
450 #if HAVE_FORK
451 #ifdef BUILTIN_DECOMPRESS
452 
453 #define FHCRC		(1 << 1)
454 #define FEXTRA		(1 << 2)
455 #define FNAME		(1 << 3)
456 #define FCOMMENT	(1 << 4)
457 
458 
459 private int
460 uncompressgzipped(const unsigned char *old, unsigned char **newch,
461     size_t bytes_max, size_t *n)
462 {
463 	unsigned char flg = old[3];
464 	size_t data_start = 10;
465 
466 	if (flg & FEXTRA) {
467 		if (data_start + 1 >= *n)
468 			goto err;
469 		data_start += 2 + old[data_start] + old[data_start + 1] * 256;
470 	}
471 	if (flg & FNAME) {
472 		while(data_start < *n && old[data_start])
473 			data_start++;
474 		data_start++;
475 	}
476 	if (flg & FCOMMENT) {
477 		while(data_start < *n && old[data_start])
478 			data_start++;
479 		data_start++;
480 	}
481 	if (flg & FHCRC)
482 		data_start += 2;
483 
484 	if (data_start >= *n)
485 		goto err;
486 
487 	*n -= data_start;
488 	old += data_start;
489 	return uncompresszlib(old, newch, bytes_max, n, 0);
490 err:
491 	return makeerror(newch, n, "File too short");
492 }
493 
494 private int
495 uncompresszlib(const unsigned char *old, unsigned char **newch,
496     size_t bytes_max, size_t *n, int zlib)
497 {
498 	int rc;
499 	z_stream z;
500 
501 	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
502 		return makeerror(newch, n, "No buffer, %s", strerror(errno));
503 
504 	z.next_in = CCAST(Bytef *, old);
505 	z.avail_in = CAST(uint32_t, *n);
506 	z.next_out = *newch;
507 	z.avail_out = CAST(unsigned int, bytes_max);
508 	z.zalloc = Z_NULL;
509 	z.zfree = Z_NULL;
510 	z.opaque = Z_NULL;
511 
512 	/* LINTED bug in header macro */
513 	rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
514 	if (rc != Z_OK)
515 		goto err;
516 
517 	rc = inflate(&z, Z_SYNC_FLUSH);
518 	if (rc != Z_OK && rc != Z_STREAM_END)
519 		goto err;
520 
521 	*n = (size_t)z.total_out;
522 	rc = inflateEnd(&z);
523 	if (rc != Z_OK)
524 		goto err;
525 
526 	/* let's keep the nul-terminate tradition */
527 	(*newch)[*n] = '\0';
528 
529 	return OKDATA;
530 err:
531 	strlcpy((char *)*newch, z.msg ? z.msg : zError(rc), bytes_max);
532 	*n = strlen((char *)*newch);
533 	return ERRDATA;
534 }
535 #endif
536 
537 static int
538 makeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
539 {
540 	char *msg;
541 	va_list ap;
542 	int rv;
543 
544 	va_start(ap, fmt);
545 	rv = vasprintf(&msg, fmt, ap);
546 	va_end(ap);
547 	if (rv < 0) {
548 		*buf = NULL;
549 		*len = 0;
550 		return NODATA;
551 	}
552 	*buf = (unsigned char *)msg;
553 	*len = strlen(msg);
554 	return ERRDATA;
555 }
556 
557 static void
558 closefd(int *fd, size_t i)
559 {
560 	if (fd[i] == -1)
561 		return;
562 	(void) close(fd[i]);
563 	fd[i] = -1;
564 }
565 
566 static void
567 closep(int *fd)
568 {
569 	size_t i;
570 	for (i = 0; i < 2; i++)
571 		closefd(fd, i);
572 }
573 
574 static void
575 copydesc(int i, int *fd)
576 {
577 	int j = fd[i == STDIN_FILENO ? 0 : 1];
578 	if (j == i)
579 		return;
580 	if (dup2(j, i) == -1) {
581 		DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno));
582 		exit(1);
583 	}
584 	closep(fd);
585 }
586 
587 static void
588 writechild(int fdp[3][2], const void *old, size_t n)
589 {
590 	int status;
591 
592 	closefd(fdp[STDIN_FILENO], 0);
593 	/*
594 	 * fork again, to avoid blocking because both
595 	 * pipes filled
596 	 */
597 	switch (fork()) {
598 	case 0: /* child */
599 		closefd(fdp[STDOUT_FILENO], 0);
600 		if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) {
601 			DPRINTF("Write failed (%s)\n", strerror(errno));
602 			exit(1);
603 		}
604 		exit(0);
605 		/*NOTREACHED*/
606 
607 	case -1:
608 		DPRINTF("Fork failed (%s)\n", strerror(errno));
609 		exit(1);
610 		/*NOTREACHED*/
611 
612 	default:  /* parent */
613 		if (wait(&status) == -1) {
614 			DPRINTF("Wait failed (%s)\n", strerror(errno));
615 			exit(1);
616 		}
617 		DPRINTF("Grandchild wait return %#x\n", status);
618 	}
619 	closefd(fdp[STDIN_FILENO], 1);
620 }
621 
622 static ssize_t
623 filter_error(unsigned char *ubuf, ssize_t n)
624 {
625 	char *p;
626 	char *buf;
627 
628 	ubuf[n] = '\0';
629 	buf = (char *)ubuf;
630 	while (isspace((unsigned char)*buf))
631 		buf++;
632 	DPRINTF("Filter error[[[%s]]]\n", buf);
633 	if ((p = strchr((char *)buf, '\n')) != NULL)
634 		*p = '\0';
635 	if ((p = strchr((char *)buf, ';')) != NULL)
636 		*p = '\0';
637 	if ((p = strrchr((char *)buf, ':')) != NULL) {
638 		++p;
639 		while (isspace((unsigned char)*p))
640 			p++;
641 		n = strlen(p);
642 		memmove(ubuf, p, CAST(size_t, n + 1));
643 	}
644 	DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
645 	if (islower(*ubuf))
646 		*ubuf = toupper(*ubuf);
647 	return n;
648 }
649 
650 private const char *
651 methodname(size_t method)
652 {
653 #ifdef BUILTIN_DECOMPRESS
654         /* FIXME: This doesn't cope with bzip2 */
655 	if (method == 2 || compr[method].maglen == 0)
656 	    return "zlib";
657 #endif
658 	return compr[method].argv[0];
659 }
660 
661 private int
662 uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
663     unsigned char **newch, size_t* n)
664 {
665 	int fdp[3][2];
666 	int status, rv;
667 	size_t i;
668 	ssize_t r;
669 
670 #ifdef BUILTIN_DECOMPRESS
671         /* FIXME: This doesn't cope with bzip2 */
672 	if (method == 2)
673 		return uncompressgzipped(old, newch, bytes_max, n);
674 	if (compr[method].maglen == 0)
675 		return uncompresszlib(old, newch, bytes_max, n, 1);
676 #endif
677 	(void)fflush(stdout);
678 	(void)fflush(stderr);
679 
680 	for (i = 0; i < __arraycount(fdp); i++)
681 		fdp[i][0] = fdp[i][1] = -1;
682 
683 	if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
684 	    pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
685 		closep(fdp[STDIN_FILENO]);
686 		closep(fdp[STDOUT_FILENO]);
687 		return makeerror(newch, n, "Cannot create pipe, %s",
688 		    strerror(errno));
689 	}
690 	switch (fork()) {
691 	case 0:	/* child */
692 		if (fd != -1) {
693 			fdp[STDIN_FILENO][0] = fd;
694 			(void) lseek(fd, (off_t)0, SEEK_SET);
695 		}
696 
697 		for (i = 0; i < __arraycount(fdp); i++)
698 			copydesc(CAST(int, i), fdp[i]);
699 
700 		(void)execvp(compr[method].argv[0],
701 		    (char *const *)(intptr_t)compr[method].argv);
702 		dprintf(STDERR_FILENO, "exec `%s' failed, %s",
703 		    compr[method].argv[0], strerror(errno));
704 		exit(1);
705 		/*NOTREACHED*/
706 	case -1:
707 		return makeerror(newch, n, "Cannot fork, %s",
708 		    strerror(errno));
709 
710 	default: /* parent */
711 		for (i = 1; i < __arraycount(fdp); i++)
712 			closefd(fdp[i], 1);
713 
714 		/* Write the buffer data to the child, if we don't have fd */
715 		if (fd == -1)
716 			writechild(fdp, old, *n);
717 
718 		*newch = CAST(unsigned char *, malloc(bytes_max + 1));
719 		if (*newch == NULL) {
720 			rv = makeerror(newch, n, "No buffer, %s",
721 			    strerror(errno));
722 			goto err;
723 		}
724 		rv = OKDATA;
725 		if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0)
726 			break;
727 		DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
728 		    r != -1 ? strerror(errno) : "no data");
729 
730 		rv = ERRDATA;
731 		if (r == 0 &&
732 		    (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
733 		{
734 			r = filter_error(*newch, r);
735 			break;
736 		}
737 		free(*newch);
738 		if  (r == 0)
739 			rv = makeerror(newch, n, "Read failed, %s",
740 			    strerror(errno));
741 		else
742 			rv = makeerror(newch, n, "No data");
743 		goto err;
744 	}
745 
746 	*n = r;
747 	/* NUL terminate, as every buffer is handled here. */
748 	(*newch)[*n] = '\0';
749 err:
750 	closefd(fdp[STDIN_FILENO], 1);
751 	closefd(fdp[STDOUT_FILENO], 0);
752 	closefd(fdp[STDERR_FILENO], 0);
753 	if (wait(&status) == -1) {
754 		free(*newch);
755 		rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
756 		DPRINTF("Child wait return %#x\n", status);
757 	} else if (!WIFEXITED(status)) {
758 		DPRINTF("Child not exited (%#x)\n", status);
759 	} else if (WEXITSTATUS(status) != 0) {
760 		DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status));
761 	}
762 
763 	closefd(fdp[STDIN_FILENO], 0);
764 	DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv);
765 
766 	return rv;
767 }
768 #endif
769