1/*
2 * Copyright (c) Ian F. Darwin 1986-1995.
3 * Software written by Ian F. Darwin and others;
4 * maintained 1995-present by Christos Zoulas and others.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice immediately at the beginning of the file, without modification,
11 *    this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28/*
29 * compress routines:
30 *	zmagic() - returns 0 if not recognized, uncompresses and prints
31 *		   information if recognized
32 *	uncompress(method, old, n, newch) - uncompress old into new,
33 *					    using method, return sizeof new
34 */
35#include "file.h"
36
37#ifndef lint
38FILE_RCSID("@(#)$File: compress.c,v 1.124 2019/07/21 11:42:09 christos Exp $")
39#endif
40
41#include "magic.h"
42#include <stdlib.h>
43#ifdef HAVE_UNISTD_H
44#include <unistd.h>
45#endif
46#include <string.h>
47#include <errno.h>
48#include <ctype.h>
49#include <stdarg.h>
50#include <signal.h>
51#ifndef HAVE_SIG_T
52typedef void (*sig_t)(int);
53#endif /* HAVE_SIG_T */
54#if !defined(__MINGW32__) && !defined(WIN32)
55#include <sys/ioctl.h>
56#endif
57#ifdef HAVE_SYS_WAIT_H
58#include <sys/wait.h>
59#endif
60#if defined(HAVE_SYS_TIME_H)
61#include <sys/time.h>
62#endif
63
64#if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT)
65#define BUILTIN_DECOMPRESS
66#include <zlib.h>
67#endif
68
69#if defined(HAVE_BZLIB_H) || defined(BZLIBSUPPORT)
70#define BUILTIN_BZLIB
71#include <bzlib.h>
72#endif
73
74#if defined(HAVE_XZLIB_H) || defined(XZLIBSUPPORT)
75#define BUILTIN_XZLIB
76#include <lzma.h>
77#endif
78
79#ifdef DEBUG
80int tty = -1;
81#define DPRINTF(...)	do { \
82	if (tty == -1) \
83		tty = open("/dev/tty", O_RDWR); \
84	if (tty == -1) \
85		abort(); \
86	dprintf(tty, __VA_ARGS__); \
87} while (/*CONSTCOND*/0)
88#else
89#define DPRINTF(...)
90#endif
91
92#ifdef ZLIBSUPPORT
93/*
94 * The following python code is not really used because ZLIBSUPPORT is only
95 * defined if we have a built-in zlib, and the built-in zlib handles that.
96 * That is not true for android where we have zlib.h and not -lz.
97 */
98static const char zlibcode[] =
99    "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))";
100
101static const char *zlib_args[] = { "python", "-c", zlibcode, NULL };
102
103static int
104zlibcmp(const unsigned char *buf)
105{
106	unsigned short x = 1;
107	unsigned char *s = CAST(unsigned char *, CAST(void *, &x));
108
109	if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0)
110		return 0;
111	if (s[0] != 1)	/* endianness test */
112		x = buf[0] | (buf[1] << 8);
113	else
114		x = buf[1] | (buf[0] << 8);
115	if (x % 31)
116		return 0;
117	return 1;
118}
119#endif
120
121static int
122lzmacmp(const unsigned char *buf)
123{
124	if (buf[0] != 0x5d || buf[1] || buf[2])
125		return 0;
126	if (buf[12] && buf[12] != 0xff)
127		return 0;
128	return 1;
129}
130
131#define gzip_flags "-cd"
132#define lrzip_flags "-do"
133#define lzip_flags gzip_flags
134
135static const char *gzip_args[] = {
136	"gzip", gzip_flags, NULL
137};
138static const char *uncompress_args[] = {
139	"uncompress", "-c", NULL
140};
141static const char *bzip2_args[] = {
142	"bzip2", "-cd", NULL
143};
144static const char *lzip_args[] = {
145	"lzip", lzip_flags, NULL
146};
147static const char *xz_args[] = {
148	"xz", "-cd", NULL
149};
150static const char *lrzip_args[] = {
151	"lrzip", lrzip_flags, NULL
152};
153static const char *lz4_args[] = {
154	"lz4", "-cd", NULL
155};
156static const char *zstd_args[] = {
157	"zstd", "-cd", NULL
158};
159
160#define	do_zlib		NULL
161#define	do_bzlib	NULL
162
163private const struct {
164	const void *magic;
165	int maglen;
166	const char **argv;
167	void *unused;
168} compr[] = {
169#define METH_FROZEN	2
170#define METH_BZIP	7
171#define METH_XZ		9
172#define METH_LZMA	13
173#define METH_ZLIB	14
174	{ "\037\235",	2, gzip_args, NULL },		/* 0, compressed */
175	/* Uncompress can get stuck; so use gzip first if we have it
176	 * Idea from Damien Clark, thanks! */
177	{ "\037\235",	2, uncompress_args, NULL },	/* 1, compressed */
178	{ "\037\213",	2, gzip_args, do_zlib },	/* 2, gzipped */
179	{ "\037\236",	2, gzip_args, NULL },		/* 3, frozen */
180	{ "\037\240",	2, gzip_args, NULL },		/* 4, SCO LZH */
181	/* the standard pack utilities do not accept standard input */
182	{ "\037\036",	2, gzip_args, NULL },		/* 5, packed */
183	{ "PK\3\4",	4, gzip_args, NULL },		/* 6, pkzipped, */
184	/* ...only first file examined */
185	{ "BZh",	3, bzip2_args, do_bzlib },	/* 7, bzip2-ed */
186	{ "LZIP",	4, lzip_args, NULL },		/* 8, lzip-ed */
187 	{ "\3757zXZ\0",	6, xz_args, NULL },		/* 9, XZ Utils */
188 	{ "LRZI",	4, lrzip_args, NULL },	/* 10, LRZIP */
189 	{ "\004\"M\030",4, lz4_args, NULL },		/* 11, LZ4 */
190 	{ "\x28\xB5\x2F\xFD", 4, zstd_args, NULL },	/* 12, zstd */
191	{ RCAST(const void *, lzmacmp),	-13, xz_args, NULL },	/* 13, lzma */
192#ifdef ZLIBSUPPORT
193	{ RCAST(const void *, zlibcmp),	-2, zlib_args, NULL },	/* 14, zlib */
194#endif
195};
196
197#define OKDATA 	0
198#define NODATA	1
199#define ERRDATA	2
200
201private ssize_t swrite(int, const void *, size_t);
202#if HAVE_FORK
203private size_t ncompr = __arraycount(compr);
204private int uncompressbuf(int, size_t, size_t, const unsigned char *,
205    unsigned char **, size_t *);
206#ifdef BUILTIN_DECOMPRESS
207private int uncompresszlib(const unsigned char *, unsigned char **, size_t,
208    size_t *, int);
209private int uncompressgzipped(const unsigned char *, unsigned char **, size_t,
210    size_t *);
211#endif
212#ifdef BUILTIN_BZLIB
213private int uncompressbzlib(const unsigned char *, unsigned char **, size_t,
214    size_t *);
215#endif
216#ifdef BUILTIN_XZLIB
217private int uncompressxzlib(const unsigned char *, unsigned char **, size_t,
218    size_t *);
219#endif
220
221static int makeerror(unsigned char **, size_t *, const char *, ...)
222    __attribute__((__format__(__printf__, 3, 4)));
223private const char *methodname(size_t);
224
225private int
226format_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf)
227{
228	unsigned char *p;
229	int mime = ms->flags & MAGIC_MIME;
230
231	if (!mime)
232		return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf);
233
234	for (p = buf; *p; p++)
235		if (!isalnum(*p))
236			*p = '-';
237
238	return file_printf(ms, "application/x-decompression-error-%s-%s",
239	    methodname(i), buf);
240}
241
242protected int
243file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
244{
245	unsigned char *newbuf = NULL;
246	size_t i, nsz;
247	char *rbuf;
248	file_pushbuf_t *pb;
249	int urv, prv, rv = 0;
250	int mime = ms->flags & MAGIC_MIME;
251	int fd = b->fd;
252	const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
253	size_t nbytes = b->flen;
254	int sa_saved = 0;
255	struct sigaction sig_act;
256
257	if ((ms->flags & MAGIC_COMPRESS) == 0)
258		return 0;
259
260	for (i = 0; i < ncompr; i++) {
261		int zm;
262		if (nbytes < CAST(size_t, abs(compr[i].maglen)))
263			continue;
264		if (compr[i].maglen < 0) {
265			zm = (RCAST(int (*)(const unsigned char *),
266			    CCAST(void *, compr[i].magic)))(buf);
267		} else {
268			zm = memcmp(buf, compr[i].magic,
269			    CAST(size_t, compr[i].maglen)) == 0;
270		}
271
272		if (!zm)
273			continue;
274
275		/* Prevent SIGPIPE death if child dies unexpectedly */
276		if (!sa_saved) {
277			//We can use sig_act for both new and old, but
278			struct sigaction new_act;
279			memset(&new_act, 0, sizeof(new_act));
280			new_act.sa_handler = SIG_IGN;
281			sa_saved = sigaction(SIGPIPE, &new_act, &sig_act) != -1;
282		}
283
284		nsz = nbytes;
285		urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
286		DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv,
287		    (char *)newbuf, nsz);
288		switch (urv) {
289		case OKDATA:
290		case ERRDATA:
291			ms->flags &= ~MAGIC_COMPRESS;
292			if (urv == ERRDATA)
293				prv = format_decompression_error(ms, i, newbuf);
294			else
295				prv = file_buffer(ms, -1, NULL, name, newbuf, nsz);
296			if (prv == -1)
297				goto error;
298			rv = 1;
299			if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
300				goto out;
301			if (mime != MAGIC_MIME && mime != 0)
302				goto out;
303			if ((file_printf(ms,
304			    mime ? " compressed-encoding=" : " (")) == -1)
305				goto error;
306			if ((pb = file_push_buffer(ms)) == NULL)
307				goto error;
308			/*
309			 * XXX: If file_buffer fails here, we overwrite
310			 * the compressed text. FIXME.
311			 */
312			if (file_buffer(ms, -1, NULL, NULL, buf, nbytes) == -1) {
313				if (file_pop_buffer(ms, pb) != NULL)
314					abort();
315				goto error;
316			}
317			if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
318				if (file_printf(ms, "%s", rbuf) == -1) {
319					free(rbuf);
320					goto error;
321				}
322				free(rbuf);
323			}
324			if (!mime && file_printf(ms, ")") == -1)
325				goto error;
326			/*FALLTHROUGH*/
327		case NODATA:
328			break;
329		default:
330			abort();
331			/*NOTREACHED*/
332		error:
333			rv = -1;
334			break;
335		}
336	}
337out:
338	DPRINTF("rv = %d\n", rv);
339
340	if (sa_saved && sig_act.sa_handler != SIG_IGN)
341		(void)sigaction(SIGPIPE, &sig_act, NULL);
342
343	free(newbuf);
344	ms->flags |= MAGIC_COMPRESS;
345	DPRINTF("Zmagic returns %d\n", rv);
346	return rv;
347}
348#endif
349/*
350 * `safe' write for sockets and pipes.
351 */
352private ssize_t
353swrite(int fd, const void *buf, size_t n)
354{
355	ssize_t rv;
356	size_t rn = n;
357
358	do
359		switch (rv = write(fd, buf, n)) {
360		case -1:
361			if (errno == EINTR)
362				continue;
363			return -1;
364		default:
365			n -= rv;
366			buf = CAST(const char *, buf) + rv;
367			break;
368		}
369	while (n > 0);
370	return rn;
371}
372
373
374/*
375 * `safe' read for sockets and pipes.
376 */
377protected ssize_t
378sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__)))
379{
380	ssize_t rv;
381#ifdef FIONREAD
382	int t = 0;
383#endif
384	size_t rn = n;
385
386	if (fd == STDIN_FILENO)
387		goto nocheck;
388
389#ifdef FIONREAD
390	if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) {
391#ifdef FD_ZERO
392		ssize_t cnt;
393		for (cnt = 0;; cnt++) {
394			fd_set check;
395			struct timeval tout = {0, 100 * 1000};
396			int selrv;
397
398			FD_ZERO(&check);
399			FD_SET(fd, &check);
400
401			/*
402			 * Avoid soft deadlock: do not read if there
403			 * is nothing to read from sockets and pipes.
404			 */
405			selrv = select(fd + 1, &check, NULL, NULL, &tout);
406			if (selrv == -1) {
407				if (errno == EINTR || errno == EAGAIN)
408					continue;
409			} else if (selrv == 0 && cnt >= 5) {
410				return 0;
411			} else
412				break;
413		}
414#endif
415		(void)ioctl(fd, FIONREAD, &t);
416	}
417
418	if (t > 0 && CAST(size_t, t) < n) {
419		n = t;
420		rn = n;
421	}
422#endif
423
424nocheck:
425	do
426		switch ((rv = read(fd, buf, n))) {
427		case -1:
428			if (errno == EINTR)
429				continue;
430			return -1;
431		case 0:
432			return rn - n;
433		default:
434			n -= rv;
435			buf = CAST(char *, CCAST(void *, buf)) + rv;
436			break;
437		}
438	while (n > 0);
439	return rn;
440}
441
442protected int
443file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
444    size_t nbytes)
445{
446	char buf[4096];
447	ssize_t r;
448	int tfd;
449
450	(void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
451#ifndef HAVE_MKSTEMP
452	{
453		char *ptr = mktemp(buf);
454		tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
455		r = errno;
456		(void)unlink(ptr);
457		errno = r;
458	}
459#else
460	{
461		int te;
462		mode_t ou = umask(0);
463		tfd = mkstemp(buf);
464		(void)umask(ou);
465		te = errno;
466		(void)unlink(buf);
467		errno = te;
468	}
469#endif
470	if (tfd == -1) {
471		file_error(ms, errno,
472		    "cannot create temporary file for pipe copy");
473		return -1;
474	}
475
476	if (swrite(tfd, startbuf, nbytes) != CAST(ssize_t, nbytes))
477		r = 1;
478	else {
479		while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
480			if (swrite(tfd, buf, CAST(size_t, r)) != r)
481				break;
482	}
483
484	switch (r) {
485	case -1:
486		file_error(ms, errno, "error copying from pipe to temp file");
487		return -1;
488	case 0:
489		break;
490	default:
491		file_error(ms, errno, "error while writing to temp file");
492		return -1;
493	}
494
495	/*
496	 * We duplicate the file descriptor, because fclose on a
497	 * tmpfile will delete the file, but any open descriptors
498	 * can still access the phantom inode.
499	 */
500	if ((fd = dup2(tfd, fd)) == -1) {
501		file_error(ms, errno, "could not dup descriptor for temp file");
502		return -1;
503	}
504	(void)close(tfd);
505	if (lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) {
506		file_badseek(ms);
507		return -1;
508	}
509	return fd;
510}
511#if HAVE_FORK
512#ifdef BUILTIN_DECOMPRESS
513
514#define FHCRC		(1 << 1)
515#define FEXTRA		(1 << 2)
516#define FNAME		(1 << 3)
517#define FCOMMENT	(1 << 4)
518
519
520private int
521uncompressgzipped(const unsigned char *old, unsigned char **newch,
522    size_t bytes_max, size_t *n)
523{
524	unsigned char flg = old[3];
525	size_t data_start = 10;
526
527	if (flg & FEXTRA) {
528		if (data_start + 1 >= *n)
529			goto err;
530		data_start += 2 + old[data_start] + old[data_start + 1] * 256;
531	}
532	if (flg & FNAME) {
533		while(data_start < *n && old[data_start])
534			data_start++;
535		data_start++;
536	}
537	if (flg & FCOMMENT) {
538		while(data_start < *n && old[data_start])
539			data_start++;
540		data_start++;
541	}
542	if (flg & FHCRC)
543		data_start += 2;
544
545	if (data_start >= *n)
546		goto err;
547
548	*n -= data_start;
549	old += data_start;
550	return uncompresszlib(old, newch, bytes_max, n, 0);
551err:
552	return makeerror(newch, n, "File too short");
553}
554
555private int
556uncompresszlib(const unsigned char *old, unsigned char **newch,
557    size_t bytes_max, size_t *n, int zlib)
558{
559	int rc;
560	z_stream z;
561
562	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
563		return makeerror(newch, n, "No buffer, %s", strerror(errno));
564
565	z.next_in = CCAST(Bytef *, old);
566	z.avail_in = CAST(uint32_t, *n);
567	z.next_out = *newch;
568	z.avail_out = CAST(unsigned int, bytes_max);
569	z.zalloc = Z_NULL;
570	z.zfree = Z_NULL;
571	z.opaque = Z_NULL;
572
573	/* LINTED bug in header macro */
574	rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
575	if (rc != Z_OK)
576		goto err;
577
578	rc = inflate(&z, Z_SYNC_FLUSH);
579	if (rc != Z_OK && rc != Z_STREAM_END)
580		goto err;
581
582	*n = CAST(size_t, z.total_out);
583	rc = inflateEnd(&z);
584	if (rc != Z_OK)
585		goto err;
586
587	/* let's keep the nul-terminate tradition */
588	(*newch)[*n] = '\0';
589
590	return OKDATA;
591err:
592	strlcpy(RCAST(char *, *newch), z.msg ? z.msg : zError(rc), bytes_max);
593	*n = strlen(RCAST(char *, *newch));
594	return ERRDATA;
595}
596#endif
597
598#ifdef BUILTIN_BZLIB
599private int
600uncompressbzlib(const unsigned char *old, unsigned char **newch,
601    size_t bytes_max, size_t *n)
602{
603	int rc;
604	bz_stream bz;
605
606	memset(&bz, 0, sizeof(bz));
607	rc = BZ2_bzDecompressInit(&bz, 0, 0);
608	if (rc != BZ_OK)
609		goto err;
610
611	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
612		return makeerror(newch, n, "No buffer, %s", strerror(errno));
613
614	bz.next_in = CCAST(char *, RCAST(const char *, old));
615	bz.avail_in = CAST(uint32_t, *n);
616	bz.next_out = RCAST(char *, *newch);
617	bz.avail_out = CAST(unsigned int, bytes_max);
618
619	rc = BZ2_bzDecompress(&bz);
620	if (rc != BZ_OK && rc != BZ_STREAM_END)
621		goto err;
622
623	/* Assume byte_max is within 32bit */
624	/* assert(bz.total_out_hi32 == 0); */
625	*n = CAST(size_t, bz.total_out_lo32);
626	rc = BZ2_bzDecompressEnd(&bz);
627	if (rc != BZ_OK)
628		goto err;
629
630	/* let's keep the nul-terminate tradition */
631	(*newch)[*n] = '\0';
632
633	return OKDATA;
634err:
635	snprintf(RCAST(char *, *newch), bytes_max, "bunzip error %d", rc);
636	*n = strlen(RCAST(char *, *newch));
637	return ERRDATA;
638}
639#endif
640
641#ifdef BUILTIN_XZLIB
642private int
643uncompressxzlib(const unsigned char *old, unsigned char **newch,
644    size_t bytes_max, size_t *n)
645{
646	int rc;
647	lzma_stream xz;
648
649	memset(&xz, 0, sizeof(xz));
650	rc = lzma_auto_decoder(&xz, UINT64_MAX, 0);
651	if (rc != LZMA_OK)
652		goto err;
653
654	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
655		return makeerror(newch, n, "No buffer, %s", strerror(errno));
656
657	xz.next_in = CCAST(const uint8_t *, old);
658	xz.avail_in = CAST(uint32_t, *n);
659	xz.next_out = RCAST(uint8_t *, *newch);
660	xz.avail_out = CAST(unsigned int, bytes_max);
661
662	rc = lzma_code(&xz, LZMA_RUN);
663	if (rc != LZMA_OK && rc != LZMA_STREAM_END)
664		goto err;
665
666	*n = CAST(size_t, xz.total_out);
667
668	lzma_end(&xz);
669
670	/* let's keep the nul-terminate tradition */
671	(*newch)[*n] = '\0';
672
673	return OKDATA;
674err:
675	snprintf(RCAST(char *, *newch), bytes_max, "unxz error %d", rc);
676	*n = strlen(RCAST(char *, *newch));
677	return ERRDATA;
678}
679#endif
680
681
682static int
683makeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
684{
685	char *msg;
686	va_list ap;
687	int rv;
688
689	va_start(ap, fmt);
690	rv = vasprintf(&msg, fmt, ap);
691	va_end(ap);
692	if (rv < 0) {
693		*buf = NULL;
694		*len = 0;
695		return NODATA;
696	}
697	*buf = RCAST(unsigned char *, msg);
698	*len = strlen(msg);
699	return ERRDATA;
700}
701
702static void
703closefd(int *fd, size_t i)
704{
705	if (fd[i] == -1)
706		return;
707	(void) close(fd[i]);
708	fd[i] = -1;
709}
710
711static void
712closep(int *fd)
713{
714	size_t i;
715	for (i = 0; i < 2; i++)
716		closefd(fd, i);
717}
718
719static int
720copydesc(int i, int fd)
721{
722	if (fd == i)
723		return 0; /* "no dup was necessary" */
724	if (dup2(fd, i) == -1) {
725		DPRINTF("dup(%d, %d) failed (%s)\n", fd, i, strerror(errno));
726		exit(1);
727	}
728	return 1;
729}
730
731static pid_t
732writechild(int fd, const void *old, size_t n)
733{
734	pid_t pid;
735
736	/*
737	 * fork again, to avoid blocking because both
738	 * pipes filled
739	 */
740	pid = fork();
741	if (pid == -1) {
742		DPRINTF("Fork failed (%s)\n", strerror(errno));
743		exit(1);
744	}
745	if (pid == 0) {
746		/* child */
747		if (swrite(fd, old, n) != CAST(ssize_t, n)) {
748			DPRINTF("Write failed (%s)\n", strerror(errno));
749			exit(1);
750		}
751		exit(0);
752	}
753	/* parent */
754	return pid;
755}
756
757static ssize_t
758filter_error(unsigned char *ubuf, ssize_t n)
759{
760	char *p;
761	char *buf;
762
763	ubuf[n] = '\0';
764	buf = RCAST(char *, ubuf);
765	while (isspace(CAST(unsigned char, *buf)))
766		buf++;
767	DPRINTF("Filter error[[[%s]]]\n", buf);
768	if ((p = strchr(CAST(char *, buf), '\n')) != NULL)
769		*p = '\0';
770	if ((p = strchr(CAST(char *, buf), ';')) != NULL)
771		*p = '\0';
772	if ((p = strrchr(CAST(char *, buf), ':')) != NULL) {
773		++p;
774		while (isspace(CAST(unsigned char, *p)))
775			p++;
776		n = strlen(p);
777		memmove(ubuf, p, CAST(size_t, n + 1));
778	}
779	DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
780	if (islower(*ubuf))
781		*ubuf = toupper(*ubuf);
782	return n;
783}
784
785private const char *
786methodname(size_t method)
787{
788	switch (method) {
789#ifdef BUILTIN_DECOMPRESS
790	case METH_FROZEN:
791	case METH_ZLIB:
792		return "zlib";
793#endif
794#ifdef BUILTIN_BZLIB
795	case METH_BZIP:
796		return "bzlib";
797#endif
798#ifdef BUILTIN_XZLIB
799	case METH_XZ:
800	case METH_LZMA:
801		return "xzlib";
802#endif
803	default:
804		return compr[method].argv[0];
805	}
806}
807
808private int
809uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
810    unsigned char **newch, size_t* n)
811{
812	int fdp[3][2];
813	int status, rv, w;
814	pid_t pid;
815	pid_t writepid = -1;
816	size_t i;
817	ssize_t r;
818
819	switch (method) {
820#ifdef BUILTIN_DECOMPRESS
821	case METH_FROZEN:
822		return uncompressgzipped(old, newch, bytes_max, n);
823	case METH_ZLIB:
824		return uncompresszlib(old, newch, bytes_max, n, 1);
825#endif
826#ifdef BUILTIN_BZLIB
827	case METH_BZIP:
828		return uncompressbzlib(old, newch, bytes_max, n);
829#endif
830#ifdef BUILTIN_XZLIB
831	case METH_XZ:
832	case METH_LZMA:
833		return uncompressxzlib(old, newch, bytes_max, n);
834#endif
835	default:
836		break;
837	}
838
839	(void)fflush(stdout);
840	(void)fflush(stderr);
841
842	for (i = 0; i < __arraycount(fdp); i++)
843		fdp[i][0] = fdp[i][1] = -1;
844
845	if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
846	    pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
847		closep(fdp[STDIN_FILENO]);
848		closep(fdp[STDOUT_FILENO]);
849		return makeerror(newch, n, "Cannot create pipe, %s",
850		    strerror(errno));
851	}
852
853	/* For processes with large mapped virtual sizes, vfork
854	 * may be _much_ faster (10-100 times) than fork.
855	 */
856	pid = vfork();
857	if (pid == -1) {
858		return makeerror(newch, n, "Cannot vfork, %s",
859		    strerror(errno));
860	}
861	if (pid == 0) {
862		/* child */
863		/* Note: we are after vfork, do not modify memory
864		 * in a way which confuses parent. In particular,
865		 * do not modify fdp[i][j].
866		 */
867		if (fd != -1) {
868			(void) lseek(fd, CAST(off_t, 0), SEEK_SET);
869			if (copydesc(STDIN_FILENO, fd))
870				(void) close(fd);
871		} else {
872			if (copydesc(STDIN_FILENO, fdp[STDIN_FILENO][0]))
873				(void) close(fdp[STDIN_FILENO][0]);
874			if (fdp[STDIN_FILENO][1] > 2)
875				(void) close(fdp[STDIN_FILENO][1]);
876		}
877///FIXME: if one of the fdp[i][j] is 0 or 1, this can bomb spectacularly
878		if (copydesc(STDOUT_FILENO, fdp[STDOUT_FILENO][1]))
879			(void) close(fdp[STDOUT_FILENO][1]);
880		if (fdp[STDOUT_FILENO][0] > 2)
881			(void) close(fdp[STDOUT_FILENO][0]);
882
883		if (copydesc(STDERR_FILENO, fdp[STDERR_FILENO][1]))
884			(void) close(fdp[STDERR_FILENO][1]);
885		if (fdp[STDERR_FILENO][0] > 2)
886			(void) close(fdp[STDERR_FILENO][0]);
887
888		(void)execvp(compr[method].argv[0],
889		    RCAST(char *const *, RCAST(intptr_t, compr[method].argv)));
890		dprintf(STDERR_FILENO, "exec `%s' failed, %s",
891		    compr[method].argv[0], strerror(errno));
892		_exit(1); /* _exit(), not exit(), because of vfork */
893	}
894	/* parent */
895	/* Close write sides of child stdout/err pipes */
896	for (i = 1; i < __arraycount(fdp); i++)
897		closefd(fdp[i], 1);
898	/* Write the buffer data to child stdin, if we don't have fd */
899	if (fd == -1) {
900		closefd(fdp[STDIN_FILENO], 0);
901		writepid = writechild(fdp[STDIN_FILENO][1], old, *n);
902		closefd(fdp[STDIN_FILENO], 1);
903	}
904
905	*newch = CAST(unsigned char *, malloc(bytes_max + 1));
906	if (*newch == NULL) {
907		rv = makeerror(newch, n, "No buffer, %s",
908		    strerror(errno));
909		goto err;
910	}
911	rv = OKDATA;
912	r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0);
913	if (r <= 0) {
914		DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
915		    r != -1 ? strerror(errno) : "no data");
916
917		rv = ERRDATA;
918		if (r == 0 &&
919		    (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
920		{
921			r = filter_error(*newch, r);
922			goto ok;
923		}
924		free(*newch);
925		if  (r == 0)
926			rv = makeerror(newch, n, "Read failed, %s",
927			    strerror(errno));
928		else
929			rv = makeerror(newch, n, "No data");
930		goto err;
931	}
932ok:
933	*n = r;
934	/* NUL terminate, as every buffer is handled here. */
935	(*newch)[*n] = '\0';
936err:
937	closefd(fdp[STDIN_FILENO], 1);
938	closefd(fdp[STDOUT_FILENO], 0);
939	closefd(fdp[STDERR_FILENO], 0);
940
941	w = waitpid(pid, &status, 0);
942wait_err:
943	if (w == -1) {
944		free(*newch);
945		rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
946		DPRINTF("Child wait return %#x\n", status);
947	} else if (!WIFEXITED(status)) {
948		DPRINTF("Child not exited (%#x)\n", status);
949	} else if (WEXITSTATUS(status) != 0) {
950		DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status));
951	}
952	if (writepid > 0) {
953		/* _After_ we know decompressor has exited, our input writer
954		 * definitely will exit now (at worst, writing fails in it,
955		 * since output fd is closed now on the reading size).
956		 */
957		w = waitpid(writepid, &status, 0);
958		writepid = -1;
959		goto wait_err;
960	}
961
962	closefd(fdp[STDIN_FILENO], 0); //why? it is already closed here!
963	DPRINTF("Returning %p n=%" SIZE_T_FORMAT "u rv=%d\n", *newch, *n, rv);
964
965	return rv;
966}
967#endif
968