168349Sobrien/*
2133359Sobrien * Copyright (c) Ian F. Darwin 1986-1995.
3133359Sobrien * Software written by Ian F. Darwin and others;
4133359Sobrien * maintained 1995-present by Christos Zoulas and others.
5354939Sdelphij *
6133359Sobrien * Redistribution and use in source and binary forms, with or without
7133359Sobrien * modification, are permitted provided that the following conditions
8133359Sobrien * are met:
9133359Sobrien * 1. Redistributions of source code must retain the above copyright
10133359Sobrien *    notice immediately at the beginning of the file, without modification,
11133359Sobrien *    this list of conditions, and the following disclaimer.
12133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright
13133359Sobrien *    notice, this list of conditions and the following disclaimer in the
14133359Sobrien *    documentation and/or other materials provided with the distribution.
15354939Sdelphij *
16133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26133359Sobrien * SUCH DAMAGE.
27133359Sobrien */
28133359Sobrien/*
2968349Sobrien * compress routines:
3068349Sobrien *	zmagic() - returns 0 if not recognized, uncompresses and prints
3168349Sobrien *		   information if recognized
32354939Sdelphij *	uncompress(method, old, n, newch) - uncompress old into new,
3368349Sobrien *					    using method, return sizeof new
3468349Sobrien */
3568349Sobrien#include "file.h"
36191736Sobrien
37191736Sobrien#ifndef lint
38362844SdelphijFILE_RCSID("@(#)$File: compress.c,v 1.127 2020/05/31 00:11:06 christos Exp $")
39191736Sobrien#endif
40191736Sobrien
41133359Sobrien#include "magic.h"
4268349Sobrien#include <stdlib.h>
4368349Sobrien#ifdef HAVE_UNISTD_H
4468349Sobrien#include <unistd.h>
4568349Sobrien#endif
4668349Sobrien#include <string.h>
47133359Sobrien#include <errno.h>
48298192Sdelphij#include <ctype.h>
49298192Sdelphij#include <stdarg.h>
50276577Sdelphij#include <signal.h>
51354939Sdelphij#ifndef HAVE_SIG_T
52284237Sdelphijtypedef void (*sig_t)(int);
53354939Sdelphij#endif /* HAVE_SIG_T */
54362844Sdelphij#if !defined(__MINGW32__) && !defined(WIN32) && !defined(__MINGW64__)
55169942Sobrien#include <sys/ioctl.h>
56226048Sobrien#endif
5768349Sobrien#ifdef HAVE_SYS_WAIT_H
5868349Sobrien#include <sys/wait.h>
5968349Sobrien#endif
60169962Sobrien#if defined(HAVE_SYS_TIME_H)
61169962Sobrien#include <sys/time.h>
62169962Sobrien#endif
63354939Sdelphij
64328874Seadler#if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT)
65175296Sobrien#define BUILTIN_DECOMPRESS
66103373Sobrien#include <zlib.h>
67103373Sobrien#endif
68354939Sdelphij
69362844Sdelphij#if defined(HAVE_BZLIB_H) && defined(BZLIBSUPPORT)
70354939Sdelphij#define BUILTIN_BZLIB
71354939Sdelphij#include <bzlib.h>
72354939Sdelphij#endif
73354939Sdelphij
74362844Sdelphij#if defined(HAVE_XZLIB_H) && defined(XZLIBSUPPORT)
75360521Sdelphij#define BUILTIN_XZLIB
76360521Sdelphij#include <lzma.h>
77360521Sdelphij#endif
78360521Sdelphij
79298192Sdelphij#ifdef DEBUG
80298192Sdelphijint tty = -1;
81298192Sdelphij#define DPRINTF(...)	do { \
82298192Sdelphij	if (tty == -1) \
83298192Sdelphij		tty = open("/dev/tty", O_RDWR); \
84298192Sdelphij	if (tty == -1) \
85298192Sdelphij		abort(); \
86298192Sdelphij	dprintf(tty, __VA_ARGS__); \
87298192Sdelphij} while (/*CONSTCOND*/0)
88298192Sdelphij#else
89298192Sdelphij#define DPRINTF(...)
90298192Sdelphij#endif
91103373Sobrien
92298192Sdelphij#ifdef ZLIBSUPPORT
93298192Sdelphij/*
94298192Sdelphij * The following python code is not really used because ZLIBSUPPORT is only
95298192Sdelphij * defined if we have a built-in zlib, and the built-in zlib handles that.
96328874Seadler * That is not true for android where we have zlib.h and not -lz.
97298192Sdelphij */
98298192Sdelphijstatic const char zlibcode[] =
99298192Sdelphij    "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))";
100298192Sdelphij
101298192Sdelphijstatic const char *zlib_args[] = { "python", "-c", zlibcode, NULL };
102298192Sdelphij
103298192Sdelphijstatic int
104298192Sdelphijzlibcmp(const unsigned char *buf)
105298192Sdelphij{
106298192Sdelphij	unsigned short x = 1;
107328874Seadler	unsigned char *s = CAST(unsigned char *, CAST(void *, &x));
108298192Sdelphij
109298192Sdelphij	if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0)
110298192Sdelphij		return 0;
111298192Sdelphij	if (s[0] != 1)	/* endianness test */
112298192Sdelphij		x = buf[0] | (buf[1] << 8);
113298192Sdelphij	else
114298192Sdelphij		x = buf[1] | (buf[0] << 8);
115298192Sdelphij	if (x % 31)
116298192Sdelphij		return 0;
117298192Sdelphij	return 1;
118298192Sdelphij}
119298192Sdelphij#endif
120298192Sdelphij
121360521Sdelphijstatic int
122360521Sdelphijlzmacmp(const unsigned char *buf)
123360521Sdelphij{
124360521Sdelphij	if (buf[0] != 0x5d || buf[1] || buf[2])
125360521Sdelphij		return 0;
126360521Sdelphij	if (buf[12] && buf[12] != 0xff)
127360521Sdelphij		return 0;
128360521Sdelphij	return 1;
129360521Sdelphij}
130360521Sdelphij
131298192Sdelphij#define gzip_flags "-cd"
132298192Sdelphij#define lrzip_flags "-do"
133298192Sdelphij#define lzip_flags gzip_flags
134298192Sdelphij
135298192Sdelphijstatic const char *gzip_args[] = {
136298192Sdelphij	"gzip", gzip_flags, NULL
137298192Sdelphij};
138298192Sdelphijstatic const char *uncompress_args[] = {
139298192Sdelphij	"uncompress", "-c", NULL
140298192Sdelphij};
141298192Sdelphijstatic const char *bzip2_args[] = {
142298192Sdelphij	"bzip2", "-cd", NULL
143298192Sdelphij};
144298192Sdelphijstatic const char *lzip_args[] = {
145298192Sdelphij	"lzip", lzip_flags, NULL
146298192Sdelphij};
147298192Sdelphijstatic const char *xz_args[] = {
148298192Sdelphij	"xz", "-cd", NULL
149298192Sdelphij};
150298192Sdelphijstatic const char *lrzip_args[] = {
151298192Sdelphij	"lrzip", lrzip_flags, NULL
152298192Sdelphij};
153298192Sdelphijstatic const char *lz4_args[] = {
154298192Sdelphij	"lz4", "-cd", NULL
155298192Sdelphij};
156309847Sdelphijstatic const char *zstd_args[] = {
157309847Sdelphij	"zstd", "-cd", NULL
158309847Sdelphij};
159298192Sdelphij
160354939Sdelphij#define	do_zlib		NULL
161354939Sdelphij#define	do_bzlib	NULL
162354939Sdelphij
163186690Sobrienprivate const struct {
164362844Sdelphij	union {
165362844Sdelphij		const char *magic;
166362844Sdelphij		int (*func)(const unsigned char *);
167362844Sdelphij	} u;
168360521Sdelphij	int maglen;
169298192Sdelphij	const char **argv;
170354939Sdelphij	void *unused;
17168349Sobrien} compr[] = {
172360521Sdelphij#define METH_FROZEN	2
173360521Sdelphij#define METH_BZIP	7
174360521Sdelphij#define METH_XZ		9
175360521Sdelphij#define METH_LZMA	13
176360521Sdelphij#define METH_ZLIB	14
177362844Sdelphij    { { .magic = "\037\235" },	2, gzip_args, NULL },	/* 0, compressed */
178362844Sdelphij    /* Uncompress can get stuck; so use gzip first if we have it
179362844Sdelphij     * Idea from Damien Clark, thanks! */
180362844Sdelphij    { { .magic = "\037\235" },	2, uncompress_args, NULL },/* 1, compressed */
181362844Sdelphij    { { .magic = "\037\213" },	2, gzip_args, do_zlib },/* 2, gzipped */
182362844Sdelphij    { { .magic = "\037\236" },	2, gzip_args, NULL },	/* 3, frozen */
183362844Sdelphij    { { .magic = "\037\240" },	2, gzip_args, NULL },	/* 4, SCO LZH */
184362844Sdelphij    /* the standard pack utilities do not accept standard input */
185362844Sdelphij    { { .magic = "\037\036" },	2, gzip_args, NULL },	/* 5, packed */
186362844Sdelphij    { { .magic = "PK\3\4" },	4, gzip_args, NULL },	/* 6, pkziped */
187362844Sdelphij    /* ...only first file examined */
188362844Sdelphij    { { .magic = "BZh" },	3, bzip2_args, do_bzlib },/* 7, bzip2-ed */
189362844Sdelphij    { { .magic = "LZIP" },	4, lzip_args, NULL },	/* 8, lzip-ed */
190362844Sdelphij    { { .magic = "\3757zXZ\0" },6, xz_args, NULL },	/* 9, XZ Util */
191362844Sdelphij    { { .magic = "LRZI" },	4, lrzip_args, NULL },	/* 10, LRZIP */
192362844Sdelphij    { { .magic = "\004\"M\030" },4, lz4_args, NULL },	/* 11, LZ4 */
193362844Sdelphij    { { .magic = "\x28\xB5\x2F\xFD" }, 4, zstd_args, NULL },/* 12, zstd */
194362844Sdelphij    { { .func = lzmacmp },	-13, xz_args, NULL },	/* 13, lzma */
195298192Sdelphij#ifdef ZLIBSUPPORT
196362844Sdelphij    { { .func = zlibcmp },	-2, zlib_args, NULL },	/* 14, zlib */
197298192Sdelphij#endif
19868349Sobrien};
19968349Sobrien
200298192Sdelphij#define OKDATA 	0
201298192Sdelphij#define NODATA	1
202298192Sdelphij#define ERRDATA	2
20368349Sobrien
204133359Sobrienprivate ssize_t swrite(int, const void *, size_t);
205226048Sobrien#if HAVE_FORK
206354939Sdelphijprivate size_t ncompr = __arraycount(compr);
207298192Sdelphijprivate int uncompressbuf(int, size_t, size_t, const unsigned char *,
208298192Sdelphij    unsigned char **, size_t *);
209175296Sobrien#ifdef BUILTIN_DECOMPRESS
210298192Sdelphijprivate int uncompresszlib(const unsigned char *, unsigned char **, size_t,
211298192Sdelphij    size_t *, int);
212298192Sdelphijprivate int uncompressgzipped(const unsigned char *, unsigned char **, size_t,
213298192Sdelphij    size_t *);
214103373Sobrien#endif
215354939Sdelphij#ifdef BUILTIN_BZLIB
216354939Sdelphijprivate int uncompressbzlib(const unsigned char *, unsigned char **, size_t,
217360521Sdelphij    size_t *);
218354939Sdelphij#endif
219360521Sdelphij#ifdef BUILTIN_XZLIB
220360521Sdelphijprivate int uncompressxzlib(const unsigned char *, unsigned char **, size_t,
221360521Sdelphij    size_t *);
222360521Sdelphij#endif
223354939Sdelphij
224298192Sdelphijstatic int makeerror(unsigned char **, size_t *, const char *, ...)
225298192Sdelphij    __attribute__((__format__(__printf__, 3, 4)));
226298192Sdelphijprivate const char *methodname(size_t);
22768349Sobrien
228337827Seadlerprivate int
229337827Seadlerformat_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf)
230337827Seadler{
231337827Seadler	unsigned char *p;
232337827Seadler	int mime = ms->flags & MAGIC_MIME;
233337827Seadler
234337827Seadler	if (!mime)
235337827Seadler		return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf);
236337827Seadler
237337827Seadler	for (p = buf; *p; p++)
238337827Seadler		if (!isalnum(*p))
239337827Seadler			*p = '-';
240337827Seadler
241337827Seadler	return file_printf(ms, "application/x-decompression-error-%s-%s",
242337827Seadler	    methodname(i), buf);
243337827Seadler}
244337827Seadler
245133359Sobrienprotected int
246337827Seadlerfile_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
24768349Sobrien{
248133359Sobrien	unsigned char *newbuf = NULL;
249133359Sobrien	size_t i, nsz;
250298192Sdelphij	char *rbuf;
251298192Sdelphij	file_pushbuf_t *pb;
252299736Sdelphij	int urv, prv, rv = 0;
253175296Sobrien	int mime = ms->flags & MAGIC_MIME;
254337827Seadler	int fd = b->fd;
255354939Sdelphij	const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
256337827Seadler	size_t nbytes = b->flen;
257354939Sdelphij	int sa_saved = 0;
258354939Sdelphij	struct sigaction sig_act;
25968349Sobrien
260133359Sobrien	if ((ms->flags & MAGIC_COMPRESS) == 0)
261133359Sobrien		return 0;
262133359Sobrien
26368349Sobrien	for (i = 0; i < ncompr; i++) {
264298192Sdelphij		int zm;
265360521Sdelphij		if (nbytes < CAST(size_t, abs(compr[i].maglen)))
26668349Sobrien			continue;
267360521Sdelphij		if (compr[i].maglen < 0) {
268362844Sdelphij			zm = (*compr[i].u.func)(buf);
269360521Sdelphij		} else {
270362844Sdelphij			zm = memcmp(buf, compr[i].u.magic,
271360521Sdelphij			    CAST(size_t, compr[i].maglen)) == 0;
272360521Sdelphij		}
273298192Sdelphij
274298192Sdelphij		if (!zm)
275298192Sdelphij			continue;
276354939Sdelphij
277354939Sdelphij		/* Prevent SIGPIPE death if child dies unexpectedly */
278354939Sdelphij		if (!sa_saved) {
279354939Sdelphij			//We can use sig_act for both new and old, but
280354939Sdelphij			struct sigaction new_act;
281354939Sdelphij			memset(&new_act, 0, sizeof(new_act));
282354939Sdelphij			new_act.sa_handler = SIG_IGN;
283354939Sdelphij			sa_saved = sigaction(SIGPIPE, &new_act, &sig_act) != -1;
284354939Sdelphij		}
285354939Sdelphij
286298192Sdelphij		nsz = nbytes;
287299736Sdelphij		urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
288354939Sdelphij		DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv,
289354939Sdelphij		    (char *)newbuf, nsz);
290299736Sdelphij		switch (urv) {
291298192Sdelphij		case OKDATA:
292298192Sdelphij		case ERRDATA:
293133359Sobrien			ms->flags &= ~MAGIC_COMPRESS;
294299736Sdelphij			if (urv == ERRDATA)
295337827Seadler				prv = format_decompression_error(ms, i, newbuf);
296298192Sdelphij			else
297354939Sdelphij				prv = file_buffer(ms, -1, NULL, name, newbuf, nsz);
298299736Sdelphij			if (prv == -1)
299133359Sobrien				goto error;
300299736Sdelphij			rv = 1;
301298192Sdelphij			if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
302298192Sdelphij				goto out;
303298192Sdelphij			if (mime != MAGIC_MIME && mime != 0)
304298192Sdelphij				goto out;
305298192Sdelphij			if ((file_printf(ms,
306298192Sdelphij			    mime ? " compressed-encoding=" : " (")) == -1)
307298192Sdelphij				goto error;
308298192Sdelphij			if ((pb = file_push_buffer(ms)) == NULL)
309298192Sdelphij				goto error;
310299736Sdelphij			/*
311299736Sdelphij			 * XXX: If file_buffer fails here, we overwrite
312299736Sdelphij			 * the compressed text. FIXME.
313299736Sdelphij			 */
314354939Sdelphij			if (file_buffer(ms, -1, NULL, NULL, buf, nbytes) == -1) {
315354939Sdelphij				if (file_pop_buffer(ms, pb) != NULL)
316354939Sdelphij					abort();
317298192Sdelphij				goto error;
318354939Sdelphij			}
319298192Sdelphij			if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
320298192Sdelphij				if (file_printf(ms, "%s", rbuf) == -1) {
321298192Sdelphij					free(rbuf);
322175296Sobrien					goto error;
323298192Sdelphij				}
324298192Sdelphij				free(rbuf);
325175296Sobrien			}
326298192Sdelphij			if (!mime && file_printf(ms, ")") == -1)
327298192Sdelphij				goto error;
328299736Sdelphij			/*FALLTHROUGH*/
329298192Sdelphij		case NODATA:
330299736Sdelphij			break;
331298192Sdelphij		default:
332298192Sdelphij			abort();
333299736Sdelphij			/*NOTREACHED*/
334299736Sdelphij		error:
335299736Sdelphij			rv = -1;
336299736Sdelphij			break;
33768349Sobrien		}
33868349Sobrien	}
339298192Sdelphijout:
340299736Sdelphij	DPRINTF("rv = %d\n", rv);
341299736Sdelphij
342354939Sdelphij	if (sa_saved && sig_act.sa_handler != SIG_IGN)
343354939Sdelphij		(void)sigaction(SIGPIPE, &sig_act, NULL);
344354939Sdelphij
345234250Sobrien	free(newbuf);
346133359Sobrien	ms->flags |= MAGIC_COMPRESS;
347298192Sdelphij	DPRINTF("Zmagic returns %d\n", rv);
348133359Sobrien	return rv;
34968349Sobrien}
350226048Sobrien#endif
35175937Sobrien/*
35275937Sobrien * `safe' write for sockets and pipes.
35375937Sobrien */
354133359Sobrienprivate ssize_t
355103373Sobrienswrite(int fd, const void *buf, size_t n)
35675937Sobrien{
357226048Sobrien	ssize_t rv;
35875937Sobrien	size_t rn = n;
35968349Sobrien
36075937Sobrien	do
36175937Sobrien		switch (rv = write(fd, buf, n)) {
36275937Sobrien		case -1:
36375937Sobrien			if (errno == EINTR)
36475937Sobrien				continue;
36575937Sobrien			return -1;
36675937Sobrien		default:
36775937Sobrien			n -= rv;
368226048Sobrien			buf = CAST(const char *, buf) + rv;
36975937Sobrien			break;
37075937Sobrien		}
37175937Sobrien	while (n > 0);
37275937Sobrien	return rn;
37375937Sobrien}
37475937Sobrien
37575937Sobrien
37675937Sobrien/*
37775937Sobrien * `safe' read for sockets and pipes.
37875937Sobrien */
379169942Sobrienprotected ssize_t
380267843Sdelphijsread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__)))
38175937Sobrien{
382226048Sobrien	ssize_t rv;
383169942Sobrien#ifdef FIONREAD
384169942Sobrien	int t = 0;
385169942Sobrien#endif
38675937Sobrien	size_t rn = n;
38775937Sobrien
388169942Sobrien	if (fd == STDIN_FILENO)
389169942Sobrien		goto nocheck;
390169942Sobrien
391169942Sobrien#ifdef FIONREAD
392267843Sdelphij	if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) {
393169942Sobrien#ifdef FD_ZERO
394267843Sdelphij		ssize_t cnt;
395169962Sobrien		for (cnt = 0;; cnt++) {
396169942Sobrien			fd_set check;
397169942Sobrien			struct timeval tout = {0, 100 * 1000};
398169962Sobrien			int selrv;
399169942Sobrien
400169942Sobrien			FD_ZERO(&check);
401169942Sobrien			FD_SET(fd, &check);
402169942Sobrien
403169942Sobrien			/*
404169942Sobrien			 * Avoid soft deadlock: do not read if there
405169942Sobrien			 * is nothing to read from sockets and pipes.
406169942Sobrien			 */
407169962Sobrien			selrv = select(fd + 1, &check, NULL, NULL, &tout);
408169962Sobrien			if (selrv == -1) {
409169942Sobrien				if (errno == EINTR || errno == EAGAIN)
410169942Sobrien					continue;
411169962Sobrien			} else if (selrv == 0 && cnt >= 5) {
412169942Sobrien				return 0;
413169962Sobrien			} else
414169962Sobrien				break;
415169942Sobrien		}
416169942Sobrien#endif
417169942Sobrien		(void)ioctl(fd, FIONREAD, &t);
418169942Sobrien	}
419169942Sobrien
420354939Sdelphij	if (t > 0 && CAST(size_t, t) < n) {
421169942Sobrien		n = t;
422169942Sobrien		rn = n;
423169942Sobrien	}
424169942Sobrien#endif
425169942Sobrien
426169942Sobriennocheck:
42775937Sobrien	do
428169942Sobrien		switch ((rv = read(fd, buf, n))) {
42975937Sobrien		case -1:
43075937Sobrien			if (errno == EINTR)
43175937Sobrien				continue;
43275937Sobrien			return -1;
433103373Sobrien		case 0:
434103373Sobrien			return rn - n;
43575937Sobrien		default:
43675937Sobrien			n -= rv;
437309847Sdelphij			buf = CAST(char *, CCAST(void *, buf)) + rv;
43875937Sobrien			break;
43975937Sobrien		}
44075937Sobrien	while (n > 0);
44175937Sobrien	return rn;
44275937Sobrien}
44375937Sobrien
444133359Sobrienprotected int
445133359Sobrienfile_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
446133359Sobrien    size_t nbytes)
447103373Sobrien{
448103373Sobrien	char buf[4096];
449226048Sobrien	ssize_t r;
450226048Sobrien	int tfd;
451103373Sobrien
452191736Sobrien	(void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
453103373Sobrien#ifndef HAVE_MKSTEMP
454103373Sobrien	{
455103373Sobrien		char *ptr = mktemp(buf);
456103373Sobrien		tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
457103373Sobrien		r = errno;
458103373Sobrien		(void)unlink(ptr);
459103373Sobrien		errno = r;
460103373Sobrien	}
461103373Sobrien#else
462267843Sdelphij	{
463267843Sdelphij		int te;
464354939Sdelphij		mode_t ou = umask(0);
465267843Sdelphij		tfd = mkstemp(buf);
466354939Sdelphij		(void)umask(ou);
467267843Sdelphij		te = errno;
468267843Sdelphij		(void)unlink(buf);
469267843Sdelphij		errno = te;
470267843Sdelphij	}
471103373Sobrien#endif
472103373Sobrien	if (tfd == -1) {
473133359Sobrien		file_error(ms, errno,
474133359Sobrien		    "cannot create temporary file for pipe copy");
475133359Sobrien		return -1;
476103373Sobrien	}
477103373Sobrien
478354939Sdelphij	if (swrite(tfd, startbuf, nbytes) != CAST(ssize_t, nbytes))
479103373Sobrien		r = 1;
480103373Sobrien	else {
481169962Sobrien		while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
482354939Sdelphij			if (swrite(tfd, buf, CAST(size_t, r)) != r)
483103373Sobrien				break;
484103373Sobrien	}
485103373Sobrien
486103373Sobrien	switch (r) {
487103373Sobrien	case -1:
488133359Sobrien		file_error(ms, errno, "error copying from pipe to temp file");
489133359Sobrien		return -1;
490103373Sobrien	case 0:
491103373Sobrien		break;
492103373Sobrien	default:
493133359Sobrien		file_error(ms, errno, "error while writing to temp file");
494133359Sobrien		return -1;
495103373Sobrien	}
496103373Sobrien
497103373Sobrien	/*
498103373Sobrien	 * We duplicate the file descriptor, because fclose on a
499103373Sobrien	 * tmpfile will delete the file, but any open descriptors
500103373Sobrien	 * can still access the phantom inode.
501103373Sobrien	 */
502103373Sobrien	if ((fd = dup2(tfd, fd)) == -1) {
503133359Sobrien		file_error(ms, errno, "could not dup descriptor for temp file");
504133359Sobrien		return -1;
505103373Sobrien	}
506103373Sobrien	(void)close(tfd);
507354939Sdelphij	if (lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) {
508133359Sobrien		file_badseek(ms);
509133359Sobrien		return -1;
510103373Sobrien	}
511103373Sobrien	return fd;
512103373Sobrien}
513226048Sobrien#if HAVE_FORK
514175296Sobrien#ifdef BUILTIN_DECOMPRESS
515103373Sobrien
516103373Sobrien#define FHCRC		(1 << 1)
517103373Sobrien#define FEXTRA		(1 << 2)
518103373Sobrien#define FNAME		(1 << 3)
519103373Sobrien#define FCOMMENT	(1 << 4)
520103373Sobrien
521298192Sdelphij
522298192Sdelphijprivate int
523298192Sdelphijuncompressgzipped(const unsigned char *old, unsigned char **newch,
524298192Sdelphij    size_t bytes_max, size_t *n)
52568349Sobrien{
526103373Sobrien	unsigned char flg = old[3];
527133359Sobrien	size_t data_start = 10;
528103373Sobrien
529133359Sobrien	if (flg & FEXTRA) {
530298192Sdelphij		if (data_start + 1 >= *n)
531298192Sdelphij			goto err;
532103373Sobrien		data_start += 2 + old[data_start] + old[data_start + 1] * 256;
533133359Sobrien	}
534103373Sobrien	if (flg & FNAME) {
535298192Sdelphij		while(data_start < *n && old[data_start])
536103373Sobrien			data_start++;
537103373Sobrien		data_start++;
538103373Sobrien	}
539298192Sdelphij	if (flg & FCOMMENT) {
540298192Sdelphij		while(data_start < *n && old[data_start])
541103373Sobrien			data_start++;
542103373Sobrien		data_start++;
543103373Sobrien	}
544298192Sdelphij	if (flg & FHCRC)
545103373Sobrien		data_start += 2;
546103373Sobrien
547298192Sdelphij	if (data_start >= *n)
548298192Sdelphij		goto err;
549298192Sdelphij
550298192Sdelphij	*n -= data_start;
551298192Sdelphij	old += data_start;
552298192Sdelphij	return uncompresszlib(old, newch, bytes_max, n, 0);
553298192Sdelphijerr:
554298192Sdelphij	return makeerror(newch, n, "File too short");
555298192Sdelphij}
556298192Sdelphij
557298192Sdelphijprivate int
558298192Sdelphijuncompresszlib(const unsigned char *old, unsigned char **newch,
559298192Sdelphij    size_t bytes_max, size_t *n, int zlib)
560298192Sdelphij{
561298192Sdelphij	int rc;
562298192Sdelphij	z_stream z;
563298192Sdelphij
564354939Sdelphij	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
565298192Sdelphij		return makeerror(newch, n, "No buffer, %s", strerror(errno));
566298192Sdelphij
567298192Sdelphij	z.next_in = CCAST(Bytef *, old);
568298192Sdelphij	z.avail_in = CAST(uint32_t, *n);
569103373Sobrien	z.next_out = *newch;
570328874Seadler	z.avail_out = CAST(unsigned int, bytes_max);
571103373Sobrien	z.zalloc = Z_NULL;
572103373Sobrien	z.zfree = Z_NULL;
573103373Sobrien	z.opaque = Z_NULL;
574103373Sobrien
575226048Sobrien	/* LINTED bug in header macro */
576298192Sdelphij	rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
577298192Sdelphij	if (rc != Z_OK)
578298192Sdelphij		goto err;
579103373Sobrien
580103373Sobrien	rc = inflate(&z, Z_SYNC_FLUSH);
581298192Sdelphij	if (rc != Z_OK && rc != Z_STREAM_END)
582298192Sdelphij		goto err;
583103373Sobrien
584354939Sdelphij	*n = CAST(size_t, z.total_out);
585298192Sdelphij	rc = inflateEnd(&z);
586298192Sdelphij	if (rc != Z_OK)
587298192Sdelphij		goto err;
588354939Sdelphij
589103373Sobrien	/* let's keep the nul-terminate tradition */
590298192Sdelphij	(*newch)[*n] = '\0';
591103373Sobrien
592298192Sdelphij	return OKDATA;
593298192Sdelphijerr:
594354939Sdelphij	strlcpy(RCAST(char *, *newch), z.msg ? z.msg : zError(rc), bytes_max);
595354939Sdelphij	*n = strlen(RCAST(char *, *newch));
596298192Sdelphij	return ERRDATA;
597298192Sdelphij}
598298192Sdelphij#endif
599298192Sdelphij
600360521Sdelphij#ifdef BUILTIN_BZLIB
601360521Sdelphijprivate int
602360521Sdelphijuncompressbzlib(const unsigned char *old, unsigned char **newch,
603360521Sdelphij    size_t bytes_max, size_t *n)
604360521Sdelphij{
605360521Sdelphij	int rc;
606360521Sdelphij	bz_stream bz;
607360521Sdelphij
608360521Sdelphij	memset(&bz, 0, sizeof(bz));
609360521Sdelphij	rc = BZ2_bzDecompressInit(&bz, 0, 0);
610360521Sdelphij	if (rc != BZ_OK)
611360521Sdelphij		goto err;
612360521Sdelphij
613360521Sdelphij	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
614360521Sdelphij		return makeerror(newch, n, "No buffer, %s", strerror(errno));
615360521Sdelphij
616360521Sdelphij	bz.next_in = CCAST(char *, RCAST(const char *, old));
617360521Sdelphij	bz.avail_in = CAST(uint32_t, *n);
618360521Sdelphij	bz.next_out = RCAST(char *, *newch);
619360521Sdelphij	bz.avail_out = CAST(unsigned int, bytes_max);
620360521Sdelphij
621360521Sdelphij	rc = BZ2_bzDecompress(&bz);
622360521Sdelphij	if (rc != BZ_OK && rc != BZ_STREAM_END)
623360521Sdelphij		goto err;
624360521Sdelphij
625360521Sdelphij	/* Assume byte_max is within 32bit */
626360521Sdelphij	/* assert(bz.total_out_hi32 == 0); */
627360521Sdelphij	*n = CAST(size_t, bz.total_out_lo32);
628360521Sdelphij	rc = BZ2_bzDecompressEnd(&bz);
629360521Sdelphij	if (rc != BZ_OK)
630360521Sdelphij		goto err;
631360521Sdelphij
632360521Sdelphij	/* let's keep the nul-terminate tradition */
633360521Sdelphij	(*newch)[*n] = '\0';
634360521Sdelphij
635360521Sdelphij	return OKDATA;
636360521Sdelphijerr:
637360521Sdelphij	snprintf(RCAST(char *, *newch), bytes_max, "bunzip error %d", rc);
638360521Sdelphij	*n = strlen(RCAST(char *, *newch));
639360521Sdelphij	return ERRDATA;
640360521Sdelphij}
641360521Sdelphij#endif
642360521Sdelphij
643360521Sdelphij#ifdef BUILTIN_XZLIB
644360521Sdelphijprivate int
645360521Sdelphijuncompressxzlib(const unsigned char *old, unsigned char **newch,
646360521Sdelphij    size_t bytes_max, size_t *n)
647360521Sdelphij{
648360521Sdelphij	int rc;
649360521Sdelphij	lzma_stream xz;
650360521Sdelphij
651360521Sdelphij	memset(&xz, 0, sizeof(xz));
652360521Sdelphij	rc = lzma_auto_decoder(&xz, UINT64_MAX, 0);
653360521Sdelphij	if (rc != LZMA_OK)
654360521Sdelphij		goto err;
655360521Sdelphij
656360521Sdelphij	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
657360521Sdelphij		return makeerror(newch, n, "No buffer, %s", strerror(errno));
658360521Sdelphij
659360521Sdelphij	xz.next_in = CCAST(const uint8_t *, old);
660360521Sdelphij	xz.avail_in = CAST(uint32_t, *n);
661360521Sdelphij	xz.next_out = RCAST(uint8_t *, *newch);
662360521Sdelphij	xz.avail_out = CAST(unsigned int, bytes_max);
663360521Sdelphij
664360521Sdelphij	rc = lzma_code(&xz, LZMA_RUN);
665360521Sdelphij	if (rc != LZMA_OK && rc != LZMA_STREAM_END)
666360521Sdelphij		goto err;
667360521Sdelphij
668360521Sdelphij	*n = CAST(size_t, xz.total_out);
669360521Sdelphij
670360521Sdelphij	lzma_end(&xz);
671360521Sdelphij
672360521Sdelphij	/* let's keep the nul-terminate tradition */
673360521Sdelphij	(*newch)[*n] = '\0';
674360521Sdelphij
675360521Sdelphij	return OKDATA;
676360521Sdelphijerr:
677360521Sdelphij	snprintf(RCAST(char *, *newch), bytes_max, "unxz error %d", rc);
678360521Sdelphij	*n = strlen(RCAST(char *, *newch));
679360521Sdelphij	return ERRDATA;
680360521Sdelphij}
681360521Sdelphij#endif
682360521Sdelphij
683360521Sdelphij
684298192Sdelphijstatic int
685298192Sdelphijmakeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
686298192Sdelphij{
687298192Sdelphij	char *msg;
688298192Sdelphij	va_list ap;
689298192Sdelphij	int rv;
690298192Sdelphij
691298192Sdelphij	va_start(ap, fmt);
692298192Sdelphij	rv = vasprintf(&msg, fmt, ap);
693298192Sdelphij	va_end(ap);
694298192Sdelphij	if (rv < 0) {
695298192Sdelphij		*buf = NULL;
696298192Sdelphij		*len = 0;
697298192Sdelphij		return NODATA;
698298192Sdelphij	}
699354939Sdelphij	*buf = RCAST(unsigned char *, msg);
700298192Sdelphij	*len = strlen(msg);
701298192Sdelphij	return ERRDATA;
702298192Sdelphij}
703298192Sdelphij
704298192Sdelphijstatic void
705298192Sdelphijclosefd(int *fd, size_t i)
706298192Sdelphij{
707298192Sdelphij	if (fd[i] == -1)
708298192Sdelphij		return;
709298192Sdelphij	(void) close(fd[i]);
710298192Sdelphij	fd[i] = -1;
711298192Sdelphij}
712298192Sdelphij
713298192Sdelphijstatic void
714298192Sdelphijclosep(int *fd)
715298192Sdelphij{
716298192Sdelphij	size_t i;
717298192Sdelphij	for (i = 0; i < 2; i++)
718298192Sdelphij		closefd(fd, i);
719298192Sdelphij}
720298192Sdelphij
721354939Sdelphijstatic int
722354939Sdelphijcopydesc(int i, int fd)
723298192Sdelphij{
724354939Sdelphij	if (fd == i)
725354939Sdelphij		return 0; /* "no dup was necessary" */
726354939Sdelphij	if (dup2(fd, i) == -1) {
727354939Sdelphij		DPRINTF("dup(%d, %d) failed (%s)\n", fd, i, strerror(errno));
728298192Sdelphij		exit(1);
729298192Sdelphij	}
730354939Sdelphij	return 1;
731298192Sdelphij}
732298192Sdelphij
733354939Sdelphijstatic pid_t
734354939Sdelphijwritechild(int fd, const void *old, size_t n)
735298192Sdelphij{
736354939Sdelphij	pid_t pid;
737298192Sdelphij
738354939Sdelphij	/*
739298192Sdelphij	 * fork again, to avoid blocking because both
740298192Sdelphij	 * pipes filled
741298192Sdelphij	 */
742354939Sdelphij	pid = fork();
743354939Sdelphij	if (pid == -1) {
744354939Sdelphij		DPRINTF("Fork failed (%s)\n", strerror(errno));
745354939Sdelphij		exit(1);
746354939Sdelphij	}
747354939Sdelphij	if (pid == 0) {
748354939Sdelphij		/* child */
749354939Sdelphij		if (swrite(fd, old, n) != CAST(ssize_t, n)) {
750298192Sdelphij			DPRINTF("Write failed (%s)\n", strerror(errno));
751298192Sdelphij			exit(1);
752298192Sdelphij		}
753298192Sdelphij		exit(0);
754298192Sdelphij	}
755354939Sdelphij	/* parent */
756354939Sdelphij	return pid;
757298192Sdelphij}
758298192Sdelphij
759298192Sdelphijstatic ssize_t
760298192Sdelphijfilter_error(unsigned char *ubuf, ssize_t n)
761298192Sdelphij{
762298192Sdelphij	char *p;
763298192Sdelphij	char *buf;
764298192Sdelphij
765298192Sdelphij	ubuf[n] = '\0';
766354939Sdelphij	buf = RCAST(char *, ubuf);
767354939Sdelphij	while (isspace(CAST(unsigned char, *buf)))
768298192Sdelphij		buf++;
769298192Sdelphij	DPRINTF("Filter error[[[%s]]]\n", buf);
770354939Sdelphij	if ((p = strchr(CAST(char *, buf), '\n')) != NULL)
771298192Sdelphij		*p = '\0';
772354939Sdelphij	if ((p = strchr(CAST(char *, buf), ';')) != NULL)
773298192Sdelphij		*p = '\0';
774354939Sdelphij	if ((p = strrchr(CAST(char *, buf), ':')) != NULL) {
775298192Sdelphij		++p;
776354939Sdelphij		while (isspace(CAST(unsigned char, *p)))
777298192Sdelphij			p++;
778298192Sdelphij		n = strlen(p);
779328874Seadler		memmove(ubuf, p, CAST(size_t, n + 1));
780298192Sdelphij	}
781298192Sdelphij	DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
782298192Sdelphij	if (islower(*ubuf))
783298192Sdelphij		*ubuf = toupper(*ubuf);
784103373Sobrien	return n;
785103373Sobrien}
786298192Sdelphij
787298192Sdelphijprivate const char *
788298192Sdelphijmethodname(size_t method)
789298192Sdelphij{
790360521Sdelphij	switch (method) {
791298192Sdelphij#ifdef BUILTIN_DECOMPRESS
792360521Sdelphij	case METH_FROZEN:
793360521Sdelphij	case METH_ZLIB:
794360521Sdelphij		return "zlib";
795103373Sobrien#endif
796360521Sdelphij#ifdef BUILTIN_BZLIB
797360521Sdelphij	case METH_BZIP:
798360521Sdelphij		return "bzlib";
799360521Sdelphij#endif
800360521Sdelphij#ifdef BUILTIN_XZLIB
801360521Sdelphij	case METH_XZ:
802360521Sdelphij	case METH_LZMA:
803360521Sdelphij		return "xzlib";
804360521Sdelphij#endif
805360521Sdelphij	default:
806360521Sdelphij		return compr[method].argv[0];
807360521Sdelphij	}
808298192Sdelphij}
809103373Sobrien
810298192Sdelphijprivate int
811298192Sdelphijuncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
812298192Sdelphij    unsigned char **newch, size_t* n)
813103373Sobrien{
814298192Sdelphij	int fdp[3][2];
815354939Sdelphij	int status, rv, w;
816354939Sdelphij	pid_t pid;
817354939Sdelphij	pid_t writepid = -1;
818298192Sdelphij	size_t i;
819226048Sobrien	ssize_t r;
82068349Sobrien
821360521Sdelphij	switch (method) {
822175296Sobrien#ifdef BUILTIN_DECOMPRESS
823360521Sdelphij	case METH_FROZEN:
824298192Sdelphij		return uncompressgzipped(old, newch, bytes_max, n);
825360521Sdelphij	case METH_ZLIB:
826298192Sdelphij		return uncompresszlib(old, newch, bytes_max, n, 1);
827103373Sobrien#endif
828360521Sdelphij#ifdef BUILTIN_BZLIB
829360521Sdelphij	case METH_BZIP:
830360521Sdelphij		return uncompressbzlib(old, newch, bytes_max, n);
831360521Sdelphij#endif
832360521Sdelphij#ifdef BUILTIN_XZLIB
833360521Sdelphij	case METH_XZ:
834360521Sdelphij	case METH_LZMA:
835360521Sdelphij		return uncompressxzlib(old, newch, bytes_max, n);
836360521Sdelphij#endif
837360521Sdelphij	default:
838360521Sdelphij		break;
839360521Sdelphij	}
840360521Sdelphij
841159764Sobrien	(void)fflush(stdout);
842159764Sobrien	(void)fflush(stderr);
843103373Sobrien
844298192Sdelphij	for (i = 0; i < __arraycount(fdp); i++)
845298192Sdelphij		fdp[i][0] = fdp[i][1] = -1;
846298192Sdelphij
847298192Sdelphij	if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
848298192Sdelphij	    pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
849298192Sdelphij		closep(fdp[STDIN_FILENO]);
850298192Sdelphij		closep(fdp[STDOUT_FILENO]);
851298192Sdelphij		return makeerror(newch, n, "Cannot create pipe, %s",
852298192Sdelphij		    strerror(errno));
85368349Sobrien	}
854354939Sdelphij
855354939Sdelphij	/* For processes with large mapped virtual sizes, vfork
856354939Sdelphij	 * may be _much_ faster (10-100 times) than fork.
857354939Sdelphij	 */
858354939Sdelphij	pid = vfork();
859354939Sdelphij	if (pid == -1) {
860354939Sdelphij		return makeerror(newch, n, "Cannot vfork, %s",
861354939Sdelphij		    strerror(errno));
862354939Sdelphij	}
863354939Sdelphij	if (pid == 0) {
864354939Sdelphij		/* child */
865354939Sdelphij		/* Note: we are after vfork, do not modify memory
866354939Sdelphij		 * in a way which confuses parent. In particular,
867354939Sdelphij		 * do not modify fdp[i][j].
868354939Sdelphij		 */
869159764Sobrien		if (fd != -1) {
870354939Sdelphij			(void) lseek(fd, CAST(off_t, 0), SEEK_SET);
871354939Sdelphij			if (copydesc(STDIN_FILENO, fd))
872354939Sdelphij				(void) close(fd);
873354939Sdelphij		} else {
874354939Sdelphij			if (copydesc(STDIN_FILENO, fdp[STDIN_FILENO][0]))
875354939Sdelphij				(void) close(fdp[STDIN_FILENO][0]);
876354939Sdelphij			if (fdp[STDIN_FILENO][1] > 2)
877354939Sdelphij				(void) close(fdp[STDIN_FILENO][1]);
878159764Sobrien		}
879354939Sdelphij///FIXME: if one of the fdp[i][j] is 0 or 1, this can bomb spectacularly
880354939Sdelphij		if (copydesc(STDOUT_FILENO, fdp[STDOUT_FILENO][1]))
881354939Sdelphij			(void) close(fdp[STDOUT_FILENO][1]);
882354939Sdelphij		if (fdp[STDOUT_FILENO][0] > 2)
883354939Sdelphij			(void) close(fdp[STDOUT_FILENO][0]);
88468349Sobrien
885354939Sdelphij		if (copydesc(STDERR_FILENO, fdp[STDERR_FILENO][1]))
886354939Sdelphij			(void) close(fdp[STDERR_FILENO][1]);
887354939Sdelphij		if (fdp[STDERR_FILENO][0] > 2)
888354939Sdelphij			(void) close(fdp[STDERR_FILENO][0]);
889354939Sdelphij
890169962Sobrien		(void)execvp(compr[method].argv[0],
891354939Sdelphij		    RCAST(char *const *, RCAST(intptr_t, compr[method].argv)));
892354939Sdelphij		dprintf(STDERR_FILENO, "exec `%s' failed, %s",
893159764Sobrien		    compr[method].argv[0], strerror(errno));
894354939Sdelphij		_exit(1); /* _exit(), not exit(), because of vfork */
895354939Sdelphij	}
896354939Sdelphij	/* parent */
897354939Sdelphij	/* Close write sides of child stdout/err pipes */
898354939Sdelphij	for (i = 1; i < __arraycount(fdp); i++)
899354939Sdelphij		closefd(fdp[i], 1);
900354939Sdelphij	/* Write the buffer data to child stdin, if we don't have fd */
901354939Sdelphij	if (fd == -1) {
902354939Sdelphij		closefd(fdp[STDIN_FILENO], 0);
903354939Sdelphij		writepid = writechild(fdp[STDIN_FILENO][1], old, *n);
904354939Sdelphij		closefd(fdp[STDIN_FILENO], 1);
905354939Sdelphij	}
906354939Sdelphij
907354939Sdelphij	*newch = CAST(unsigned char *, malloc(bytes_max + 1));
908354939Sdelphij	if (*newch == NULL) {
909354939Sdelphij		rv = makeerror(newch, n, "No buffer, %s",
910298192Sdelphij		    strerror(errno));
911354939Sdelphij		goto err;
912354939Sdelphij	}
913354939Sdelphij	rv = OKDATA;
914354939Sdelphij	r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0);
915354939Sdelphij	if (r <= 0) {
916298192Sdelphij		DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
917298192Sdelphij		    r != -1 ? strerror(errno) : "no data");
918298192Sdelphij
919298192Sdelphij		rv = ERRDATA;
920298192Sdelphij		if (r == 0 &&
921298192Sdelphij		    (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
922298192Sdelphij		{
923298192Sdelphij			r = filter_error(*newch, r);
924354939Sdelphij			goto ok;
92568349Sobrien		}
926298192Sdelphij		free(*newch);
927298192Sdelphij		if  (r == 0)
928298192Sdelphij			rv = makeerror(newch, n, "Read failed, %s",
929275698Sdelphij			    strerror(errno));
930298192Sdelphij		else
931298192Sdelphij			rv = makeerror(newch, n, "No data");
932298192Sdelphij		goto err;
933298192Sdelphij	}
934354939Sdelphijok:
935298192Sdelphij	*n = r;
936298192Sdelphij	/* NUL terminate, as every buffer is handled here. */
937298192Sdelphij	(*newch)[*n] = '\0';
938298192Sdelphijerr:
939298192Sdelphij	closefd(fdp[STDIN_FILENO], 1);
940298192Sdelphij	closefd(fdp[STDOUT_FILENO], 0);
941298192Sdelphij	closefd(fdp[STDERR_FILENO], 0);
942354939Sdelphij
943354939Sdelphij	w = waitpid(pid, &status, 0);
944354939Sdelphijwait_err:
945354939Sdelphij	if (w == -1) {
946298192Sdelphij		free(*newch);
947298192Sdelphij		rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
948298192Sdelphij		DPRINTF("Child wait return %#x\n", status);
949298192Sdelphij	} else if (!WIFEXITED(status)) {
950328874Seadler		DPRINTF("Child not exited (%#x)\n", status);
951298192Sdelphij	} else if (WEXITSTATUS(status) != 0) {
952328874Seadler		DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status));
95368349Sobrien	}
954354939Sdelphij	if (writepid > 0) {
955354939Sdelphij		/* _After_ we know decompressor has exited, our input writer
956354939Sdelphij		 * definitely will exit now (at worst, writing fails in it,
957354939Sdelphij		 * since output fd is closed now on the reading size).
958354939Sdelphij		 */
959354939Sdelphij		w = waitpid(writepid, &status, 0);
960354939Sdelphij		writepid = -1;
961354939Sdelphij		goto wait_err;
962354939Sdelphij	}
963298192Sdelphij
964354939Sdelphij	closefd(fdp[STDIN_FILENO], 0); //why? it is already closed here!
965354939Sdelphij	DPRINTF("Returning %p n=%" SIZE_T_FORMAT "u rv=%d\n", *newch, *n, rv);
966354939Sdelphij
967298192Sdelphij	return rv;
96868349Sobrien}
969226048Sobrien#endif
970