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.127 2020/05/31 00:11:06 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) && !defined(__MINGW64__)
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	union {
165		const char *magic;
166		int (*func)(const unsigned char *);
167	} u;
168	int maglen;
169	const char **argv;
170	void *unused;
171} compr[] = {
172#define METH_FROZEN	2
173#define METH_BZIP	7
174#define METH_XZ		9
175#define METH_LZMA	13
176#define METH_ZLIB	14
177    { { .magic = "\037\235" },	2, gzip_args, NULL },	/* 0, compressed */
178    /* Uncompress can get stuck; so use gzip first if we have it
179     * Idea from Damien Clark, thanks! */
180    { { .magic = "\037\235" },	2, uncompress_args, NULL },/* 1, compressed */
181    { { .magic = "\037\213" },	2, gzip_args, do_zlib },/* 2, gzipped */
182    { { .magic = "\037\236" },	2, gzip_args, NULL },	/* 3, frozen */
183    { { .magic = "\037\240" },	2, gzip_args, NULL },	/* 4, SCO LZH */
184    /* the standard pack utilities do not accept standard input */
185    { { .magic = "\037\036" },	2, gzip_args, NULL },	/* 5, packed */
186    { { .magic = "PK\3\4" },	4, gzip_args, NULL },	/* 6, pkziped */
187    /* ...only first file examined */
188    { { .magic = "BZh" },	3, bzip2_args, do_bzlib },/* 7, bzip2-ed */
189    { { .magic = "LZIP" },	4, lzip_args, NULL },	/* 8, lzip-ed */
190    { { .magic = "\3757zXZ\0" },6, xz_args, NULL },	/* 9, XZ Util */
191    { { .magic = "LRZI" },	4, lrzip_args, NULL },	/* 10, LRZIP */
192    { { .magic = "\004\"M\030" },4, lz4_args, NULL },	/* 11, LZ4 */
193    { { .magic = "\x28\xB5\x2F\xFD" }, 4, zstd_args, NULL },/* 12, zstd */
194    { { .func = lzmacmp },	-13, xz_args, NULL },	/* 13, lzma */
195#ifdef ZLIBSUPPORT
196    { { .func = zlibcmp },	-2, zlib_args, NULL },	/* 14, zlib */
197#endif
198};
199
200#define OKDATA 	0
201#define NODATA	1
202#define ERRDATA	2
203
204private ssize_t swrite(int, const void *, size_t);
205#if HAVE_FORK
206private size_t ncompr = __arraycount(compr);
207private int uncompressbuf(int, size_t, size_t, const unsigned char *,
208    unsigned char **, size_t *);
209#ifdef BUILTIN_DECOMPRESS
210private int uncompresszlib(const unsigned char *, unsigned char **, size_t,
211    size_t *, int);
212private int uncompressgzipped(const unsigned char *, unsigned char **, size_t,
213    size_t *);
214#endif
215#ifdef BUILTIN_BZLIB
216private int uncompressbzlib(const unsigned char *, unsigned char **, size_t,
217    size_t *);
218#endif
219#ifdef BUILTIN_XZLIB
220private int uncompressxzlib(const unsigned char *, unsigned char **, size_t,
221    size_t *);
222#endif
223
224static int makeerror(unsigned char **, size_t *, const char *, ...)
225    __attribute__((__format__(__printf__, 3, 4)));
226private const char *methodname(size_t);
227
228private int
229format_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf)
230{
231	unsigned char *p;
232	int mime = ms->flags & MAGIC_MIME;
233
234	if (!mime)
235		return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf);
236
237	for (p = buf; *p; p++)
238		if (!isalnum(*p))
239			*p = '-';
240
241	return file_printf(ms, "application/x-decompression-error-%s-%s",
242	    methodname(i), buf);
243}
244
245protected int
246file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
247{
248	unsigned char *newbuf = NULL;
249	size_t i, nsz;
250	char *rbuf;
251	file_pushbuf_t *pb;
252	int urv, prv, rv = 0;
253	int mime = ms->flags & MAGIC_MIME;
254	int fd = b->fd;
255	const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
256	size_t nbytes = b->flen;
257	int sa_saved = 0;
258	struct sigaction sig_act;
259
260	if ((ms->flags & MAGIC_COMPRESS) == 0)
261		return 0;
262
263	for (i = 0; i < ncompr; i++) {
264		int zm;
265		if (nbytes < CAST(size_t, abs(compr[i].maglen)))
266			continue;
267		if (compr[i].maglen < 0) {
268			zm = (*compr[i].u.func)(buf);
269		} else {
270			zm = memcmp(buf, compr[i].u.magic,
271			    CAST(size_t, compr[i].maglen)) == 0;
272		}
273
274		if (!zm)
275			continue;
276
277		/* Prevent SIGPIPE death if child dies unexpectedly */
278		if (!sa_saved) {
279			//We can use sig_act for both new and old, but
280			struct sigaction new_act;
281			memset(&new_act, 0, sizeof(new_act));
282			new_act.sa_handler = SIG_IGN;
283			sa_saved = sigaction(SIGPIPE, &new_act, &sig_act) != -1;
284		}
285
286		nsz = nbytes;
287		urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
288		DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv,
289		    (char *)newbuf, nsz);
290		switch (urv) {
291		case OKDATA:
292		case ERRDATA:
293			ms->flags &= ~MAGIC_COMPRESS;
294			if (urv == ERRDATA)
295				prv = format_decompression_error(ms, i, newbuf);
296			else
297				prv = file_buffer(ms, -1, NULL, name, newbuf, nsz);
298			if (prv == -1)
299				goto error;
300			rv = 1;
301			if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
302				goto out;
303			if (mime != MAGIC_MIME && mime != 0)
304				goto out;
305			if ((file_printf(ms,
306			    mime ? " compressed-encoding=" : " (")) == -1)
307				goto error;
308			if ((pb = file_push_buffer(ms)) == NULL)
309				goto error;
310			/*
311			 * XXX: If file_buffer fails here, we overwrite
312			 * the compressed text. FIXME.
313			 */
314			if (file_buffer(ms, -1, NULL, NULL, buf, nbytes) == -1) {
315				if (file_pop_buffer(ms, pb) != NULL)
316					abort();
317				goto error;
318			}
319			if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
320				if (file_printf(ms, "%s", rbuf) == -1) {
321					free(rbuf);
322					goto error;
323				}
324				free(rbuf);
325			}
326			if (!mime && file_printf(ms, ")") == -1)
327				goto error;
328			/*FALLTHROUGH*/
329		case NODATA:
330			break;
331		default:
332			abort();
333			/*NOTREACHED*/
334		error:
335			rv = -1;
336			break;
337		}
338	}
339out:
340	DPRINTF("rv = %d\n", rv);
341
342	if (sa_saved && sig_act.sa_handler != SIG_IGN)
343		(void)sigaction(SIGPIPE, &sig_act, NULL);
344
345	free(newbuf);
346	ms->flags |= MAGIC_COMPRESS;
347	DPRINTF("Zmagic returns %d\n", rv);
348	return rv;
349}
350#endif
351/*
352 * `safe' write for sockets and pipes.
353 */
354private ssize_t
355swrite(int fd, const void *buf, size_t n)
356{
357	ssize_t rv;
358	size_t rn = n;
359
360	do
361		switch (rv = write(fd, buf, n)) {
362		case -1:
363			if (errno == EINTR)
364				continue;
365			return -1;
366		default:
367			n -= rv;
368			buf = CAST(const char *, buf) + rv;
369			break;
370		}
371	while (n > 0);
372	return rn;
373}
374
375
376/*
377 * `safe' read for sockets and pipes.
378 */
379protected ssize_t
380sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__)))
381{
382	ssize_t rv;
383#ifdef FIONREAD
384	int t = 0;
385#endif
386	size_t rn = n;
387
388	if (fd == STDIN_FILENO)
389		goto nocheck;
390
391#ifdef FIONREAD
392	if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) {
393#ifdef FD_ZERO
394		ssize_t cnt;
395		for (cnt = 0;; cnt++) {
396			fd_set check;
397			struct timeval tout = {0, 100 * 1000};
398			int selrv;
399
400			FD_ZERO(&check);
401			FD_SET(fd, &check);
402
403			/*
404			 * Avoid soft deadlock: do not read if there
405			 * is nothing to read from sockets and pipes.
406			 */
407			selrv = select(fd + 1, &check, NULL, NULL, &tout);
408			if (selrv == -1) {
409				if (errno == EINTR || errno == EAGAIN)
410					continue;
411			} else if (selrv == 0 && cnt >= 5) {
412				return 0;
413			} else
414				break;
415		}
416#endif
417		(void)ioctl(fd, FIONREAD, &t);
418	}
419
420	if (t > 0 && CAST(size_t, t) < n) {
421		n = t;
422		rn = n;
423	}
424#endif
425
426nocheck:
427	do
428		switch ((rv = read(fd, buf, n))) {
429		case -1:
430			if (errno == EINTR)
431				continue;
432			return -1;
433		case 0:
434			return rn - n;
435		default:
436			n -= rv;
437			buf = CAST(char *, CCAST(void *, buf)) + rv;
438			break;
439		}
440	while (n > 0);
441	return rn;
442}
443
444protected int
445file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
446    size_t nbytes)
447{
448	char buf[4096];
449	ssize_t r;
450	int tfd;
451
452	(void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
453#ifndef HAVE_MKSTEMP
454	{
455		char *ptr = mktemp(buf);
456		tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
457		r = errno;
458		(void)unlink(ptr);
459		errno = r;
460	}
461#else
462	{
463		int te;
464		mode_t ou = umask(0);
465		tfd = mkstemp(buf);
466		(void)umask(ou);
467		te = errno;
468		(void)unlink(buf);
469		errno = te;
470	}
471#endif
472	if (tfd == -1) {
473		file_error(ms, errno,
474		    "cannot create temporary file for pipe copy");
475		return -1;
476	}
477
478	if (swrite(tfd, startbuf, nbytes) != CAST(ssize_t, nbytes))
479		r = 1;
480	else {
481		while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
482			if (swrite(tfd, buf, CAST(size_t, r)) != r)
483				break;
484	}
485
486	switch (r) {
487	case -1:
488		file_error(ms, errno, "error copying from pipe to temp file");
489		return -1;
490	case 0:
491		break;
492	default:
493		file_error(ms, errno, "error while writing to temp file");
494		return -1;
495	}
496
497	/*
498	 * We duplicate the file descriptor, because fclose on a
499	 * tmpfile will delete the file, but any open descriptors
500	 * can still access the phantom inode.
501	 */
502	if ((fd = dup2(tfd, fd)) == -1) {
503		file_error(ms, errno, "could not dup descriptor for temp file");
504		return -1;
505	}
506	(void)close(tfd);
507	if (lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) {
508		file_badseek(ms);
509		return -1;
510	}
511	return fd;
512}
513#if HAVE_FORK
514#ifdef BUILTIN_DECOMPRESS
515
516#define FHCRC		(1 << 1)
517#define FEXTRA		(1 << 2)
518#define FNAME		(1 << 3)
519#define FCOMMENT	(1 << 4)
520
521
522private int
523uncompressgzipped(const unsigned char *old, unsigned char **newch,
524    size_t bytes_max, size_t *n)
525{
526	unsigned char flg = old[3];
527	size_t data_start = 10;
528
529	if (flg & FEXTRA) {
530		if (data_start + 1 >= *n)
531			goto err;
532		data_start += 2 + old[data_start] + old[data_start + 1] * 256;
533	}
534	if (flg & FNAME) {
535		while(data_start < *n && old[data_start])
536			data_start++;
537		data_start++;
538	}
539	if (flg & FCOMMENT) {
540		while(data_start < *n && old[data_start])
541			data_start++;
542		data_start++;
543	}
544	if (flg & FHCRC)
545		data_start += 2;
546
547	if (data_start >= *n)
548		goto err;
549
550	*n -= data_start;
551	old += data_start;
552	return uncompresszlib(old, newch, bytes_max, n, 0);
553err:
554	return makeerror(newch, n, "File too short");
555}
556
557private int
558uncompresszlib(const unsigned char *old, unsigned char **newch,
559    size_t bytes_max, size_t *n, int zlib)
560{
561	int rc;
562	z_stream z;
563
564	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
565		return makeerror(newch, n, "No buffer, %s", strerror(errno));
566
567	z.next_in = CCAST(Bytef *, old);
568	z.avail_in = CAST(uint32_t, *n);
569	z.next_out = *newch;
570	z.avail_out = CAST(unsigned int, bytes_max);
571	z.zalloc = Z_NULL;
572	z.zfree = Z_NULL;
573	z.opaque = Z_NULL;
574
575	/* LINTED bug in header macro */
576	rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
577	if (rc != Z_OK)
578		goto err;
579
580	rc = inflate(&z, Z_SYNC_FLUSH);
581	if (rc != Z_OK && rc != Z_STREAM_END)
582		goto err;
583
584	*n = CAST(size_t, z.total_out);
585	rc = inflateEnd(&z);
586	if (rc != Z_OK)
587		goto err;
588
589	/* let's keep the nul-terminate tradition */
590	(*newch)[*n] = '\0';
591
592	return OKDATA;
593err:
594	strlcpy(RCAST(char *, *newch), z.msg ? z.msg : zError(rc), bytes_max);
595	*n = strlen(RCAST(char *, *newch));
596	return ERRDATA;
597}
598#endif
599
600#ifdef BUILTIN_BZLIB
601private int
602uncompressbzlib(const unsigned char *old, unsigned char **newch,
603    size_t bytes_max, size_t *n)
604{
605	int rc;
606	bz_stream bz;
607
608	memset(&bz, 0, sizeof(bz));
609	rc = BZ2_bzDecompressInit(&bz, 0, 0);
610	if (rc != BZ_OK)
611		goto err;
612
613	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
614		return makeerror(newch, n, "No buffer, %s", strerror(errno));
615
616	bz.next_in = CCAST(char *, RCAST(const char *, old));
617	bz.avail_in = CAST(uint32_t, *n);
618	bz.next_out = RCAST(char *, *newch);
619	bz.avail_out = CAST(unsigned int, bytes_max);
620
621	rc = BZ2_bzDecompress(&bz);
622	if (rc != BZ_OK && rc != BZ_STREAM_END)
623		goto err;
624
625	/* Assume byte_max is within 32bit */
626	/* assert(bz.total_out_hi32 == 0); */
627	*n = CAST(size_t, bz.total_out_lo32);
628	rc = BZ2_bzDecompressEnd(&bz);
629	if (rc != BZ_OK)
630		goto err;
631
632	/* let's keep the nul-terminate tradition */
633	(*newch)[*n] = '\0';
634
635	return OKDATA;
636err:
637	snprintf(RCAST(char *, *newch), bytes_max, "bunzip error %d", rc);
638	*n = strlen(RCAST(char *, *newch));
639	return ERRDATA;
640}
641#endif
642
643#ifdef BUILTIN_XZLIB
644private int
645uncompressxzlib(const unsigned char *old, unsigned char **newch,
646    size_t bytes_max, size_t *n)
647{
648	int rc;
649	lzma_stream xz;
650
651	memset(&xz, 0, sizeof(xz));
652	rc = lzma_auto_decoder(&xz, UINT64_MAX, 0);
653	if (rc != LZMA_OK)
654		goto err;
655
656	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
657		return makeerror(newch, n, "No buffer, %s", strerror(errno));
658
659	xz.next_in = CCAST(const uint8_t *, old);
660	xz.avail_in = CAST(uint32_t, *n);
661	xz.next_out = RCAST(uint8_t *, *newch);
662	xz.avail_out = CAST(unsigned int, bytes_max);
663
664	rc = lzma_code(&xz, LZMA_RUN);
665	if (rc != LZMA_OK && rc != LZMA_STREAM_END)
666		goto err;
667
668	*n = CAST(size_t, xz.total_out);
669
670	lzma_end(&xz);
671
672	/* let's keep the nul-terminate tradition */
673	(*newch)[*n] = '\0';
674
675	return OKDATA;
676err:
677	snprintf(RCAST(char *, *newch), bytes_max, "unxz error %d", rc);
678	*n = strlen(RCAST(char *, *newch));
679	return ERRDATA;
680}
681#endif
682
683
684static int
685makeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
686{
687	char *msg;
688	va_list ap;
689	int rv;
690
691	va_start(ap, fmt);
692	rv = vasprintf(&msg, fmt, ap);
693	va_end(ap);
694	if (rv < 0) {
695		*buf = NULL;
696		*len = 0;
697		return NODATA;
698	}
699	*buf = RCAST(unsigned char *, msg);
700	*len = strlen(msg);
701	return ERRDATA;
702}
703
704static void
705closefd(int *fd, size_t i)
706{
707	if (fd[i] == -1)
708		return;
709	(void) close(fd[i]);
710	fd[i] = -1;
711}
712
713static void
714closep(int *fd)
715{
716	size_t i;
717	for (i = 0; i < 2; i++)
718		closefd(fd, i);
719}
720
721static int
722copydesc(int i, int fd)
723{
724	if (fd == i)
725		return 0; /* "no dup was necessary" */
726	if (dup2(fd, i) == -1) {
727		DPRINTF("dup(%d, %d) failed (%s)\n", fd, i, strerror(errno));
728		exit(1);
729	}
730	return 1;
731}
732
733static pid_t
734writechild(int fd, const void *old, size_t n)
735{
736	pid_t pid;
737
738	/*
739	 * fork again, to avoid blocking because both
740	 * pipes filled
741	 */
742	pid = fork();
743	if (pid == -1) {
744		DPRINTF("Fork failed (%s)\n", strerror(errno));
745		exit(1);
746	}
747	if (pid == 0) {
748		/* child */
749		if (swrite(fd, old, n) != CAST(ssize_t, n)) {
750			DPRINTF("Write failed (%s)\n", strerror(errno));
751			exit(1);
752		}
753		exit(0);
754	}
755	/* parent */
756	return pid;
757}
758
759static ssize_t
760filter_error(unsigned char *ubuf, ssize_t n)
761{
762	char *p;
763	char *buf;
764
765	ubuf[n] = '\0';
766	buf = RCAST(char *, ubuf);
767	while (isspace(CAST(unsigned char, *buf)))
768		buf++;
769	DPRINTF("Filter error[[[%s]]]\n", buf);
770	if ((p = strchr(CAST(char *, buf), '\n')) != NULL)
771		*p = '\0';
772	if ((p = strchr(CAST(char *, buf), ';')) != NULL)
773		*p = '\0';
774	if ((p = strrchr(CAST(char *, buf), ':')) != NULL) {
775		++p;
776		while (isspace(CAST(unsigned char, *p)))
777			p++;
778		n = strlen(p);
779		memmove(ubuf, p, CAST(size_t, n + 1));
780	}
781	DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
782	if (islower(*ubuf))
783		*ubuf = toupper(*ubuf);
784	return n;
785}
786
787private const char *
788methodname(size_t method)
789{
790	switch (method) {
791#ifdef BUILTIN_DECOMPRESS
792	case METH_FROZEN:
793	case METH_ZLIB:
794		return "zlib";
795#endif
796#ifdef BUILTIN_BZLIB
797	case METH_BZIP:
798		return "bzlib";
799#endif
800#ifdef BUILTIN_XZLIB
801	case METH_XZ:
802	case METH_LZMA:
803		return "xzlib";
804#endif
805	default:
806		return compr[method].argv[0];
807	}
808}
809
810private int
811uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
812    unsigned char **newch, size_t* n)
813{
814	int fdp[3][2];
815	int status, rv, w;
816	pid_t pid;
817	pid_t writepid = -1;
818	size_t i;
819	ssize_t r;
820
821	switch (method) {
822#ifdef BUILTIN_DECOMPRESS
823	case METH_FROZEN:
824		return uncompressgzipped(old, newch, bytes_max, n);
825	case METH_ZLIB:
826		return uncompresszlib(old, newch, bytes_max, n, 1);
827#endif
828#ifdef BUILTIN_BZLIB
829	case METH_BZIP:
830		return uncompressbzlib(old, newch, bytes_max, n);
831#endif
832#ifdef BUILTIN_XZLIB
833	case METH_XZ:
834	case METH_LZMA:
835		return uncompressxzlib(old, newch, bytes_max, n);
836#endif
837	default:
838		break;
839	}
840
841	(void)fflush(stdout);
842	(void)fflush(stderr);
843
844	for (i = 0; i < __arraycount(fdp); i++)
845		fdp[i][0] = fdp[i][1] = -1;
846
847	if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
848	    pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
849		closep(fdp[STDIN_FILENO]);
850		closep(fdp[STDOUT_FILENO]);
851		return makeerror(newch, n, "Cannot create pipe, %s",
852		    strerror(errno));
853	}
854
855	/* For processes with large mapped virtual sizes, vfork
856	 * may be _much_ faster (10-100 times) than fork.
857	 */
858	pid = vfork();
859	if (pid == -1) {
860		return makeerror(newch, n, "Cannot vfork, %s",
861		    strerror(errno));
862	}
863	if (pid == 0) {
864		/* child */
865		/* Note: we are after vfork, do not modify memory
866		 * in a way which confuses parent. In particular,
867		 * do not modify fdp[i][j].
868		 */
869		if (fd != -1) {
870			(void) lseek(fd, CAST(off_t, 0), SEEK_SET);
871			if (copydesc(STDIN_FILENO, fd))
872				(void) close(fd);
873		} else {
874			if (copydesc(STDIN_FILENO, fdp[STDIN_FILENO][0]))
875				(void) close(fdp[STDIN_FILENO][0]);
876			if (fdp[STDIN_FILENO][1] > 2)
877				(void) close(fdp[STDIN_FILENO][1]);
878		}
879///FIXME: if one of the fdp[i][j] is 0 or 1, this can bomb spectacularly
880		if (copydesc(STDOUT_FILENO, fdp[STDOUT_FILENO][1]))
881			(void) close(fdp[STDOUT_FILENO][1]);
882		if (fdp[STDOUT_FILENO][0] > 2)
883			(void) close(fdp[STDOUT_FILENO][0]);
884
885		if (copydesc(STDERR_FILENO, fdp[STDERR_FILENO][1]))
886			(void) close(fdp[STDERR_FILENO][1]);
887		if (fdp[STDERR_FILENO][0] > 2)
888			(void) close(fdp[STDERR_FILENO][0]);
889
890		(void)execvp(compr[method].argv[0],
891		    RCAST(char *const *, RCAST(intptr_t, compr[method].argv)));
892		dprintf(STDERR_FILENO, "exec `%s' failed, %s",
893		    compr[method].argv[0], strerror(errno));
894		_exit(1); /* _exit(), not exit(), because of vfork */
895	}
896	/* parent */
897	/* Close write sides of child stdout/err pipes */
898	for (i = 1; i < __arraycount(fdp); i++)
899		closefd(fdp[i], 1);
900	/* Write the buffer data to child stdin, if we don't have fd */
901	if (fd == -1) {
902		closefd(fdp[STDIN_FILENO], 0);
903		writepid = writechild(fdp[STDIN_FILENO][1], old, *n);
904		closefd(fdp[STDIN_FILENO], 1);
905	}
906
907	*newch = CAST(unsigned char *, malloc(bytes_max + 1));
908	if (*newch == NULL) {
909		rv = makeerror(newch, n, "No buffer, %s",
910		    strerror(errno));
911		goto err;
912	}
913	rv = OKDATA;
914	r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0);
915	if (r <= 0) {
916		DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
917		    r != -1 ? strerror(errno) : "no data");
918
919		rv = ERRDATA;
920		if (r == 0 &&
921		    (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
922		{
923			r = filter_error(*newch, r);
924			goto ok;
925		}
926		free(*newch);
927		if  (r == 0)
928			rv = makeerror(newch, n, "Read failed, %s",
929			    strerror(errno));
930		else
931			rv = makeerror(newch, n, "No data");
932		goto err;
933	}
934ok:
935	*n = r;
936	/* NUL terminate, as every buffer is handled here. */
937	(*newch)[*n] = '\0';
938err:
939	closefd(fdp[STDIN_FILENO], 1);
940	closefd(fdp[STDOUT_FILENO], 0);
941	closefd(fdp[STDERR_FILENO], 0);
942
943	w = waitpid(pid, &status, 0);
944wait_err:
945	if (w == -1) {
946		free(*newch);
947		rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
948		DPRINTF("Child wait return %#x\n", status);
949	} else if (!WIFEXITED(status)) {
950		DPRINTF("Child not exited (%#x)\n", status);
951	} else if (WEXITSTATUS(status) != 0) {
952		DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status));
953	}
954	if (writepid > 0) {
955		/* _After_ we know decompressor has exited, our input writer
956		 * definitely will exit now (at worst, writing fails in it,
957		 * since output fd is closed now on the reading size).
958		 */
959		w = waitpid(writepid, &status, 0);
960		writepid = -1;
961		goto wait_err;
962	}
963
964	closefd(fdp[STDIN_FILENO], 0); //why? it is already closed here!
965	DPRINTF("Returning %p n=%" SIZE_T_FORMAT "u rv=%d\n", *newch, *n, rv);
966
967	return rv;
968}
969#endif
970