compress.c revision 298920
1141104Sharti/* 294589Sobrien * Copyright (c) Ian F. Darwin 1986-1995. 394589Sobrien * Software written by Ian F. Darwin and others; 45814Sjkh * maintained 1995-present by Christos Zoulas and others. 51590Srgrimes * 61590Srgrimes * Redistribution and use in source and binary forms, with or without 71590Srgrimes * modification, are permitted provided that the following conditions 81590Srgrimes * are met: 91590Srgrimes * 1. Redistributions of source code must retain the above copyright 101590Srgrimes * notice immediately at the beginning of the file, without modification, 111590Srgrimes * this list of conditions, and the following disclaimer. 121590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 131590Srgrimes * notice, this list of conditions and the following disclaimer in the 141590Srgrimes * documentation and/or other materials provided with the distribution. 151590Srgrimes * 161590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 171590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 201590Srgrimes * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261590Srgrimes * SUCH DAMAGE. 271590Srgrimes */ 281590Srgrimes/* 291590Srgrimes * compress routines: 301590Srgrimes * zmagic() - returns 0 if not recognized, uncompresses and prints 311590Srgrimes * information if recognized 321590Srgrimes * uncompress(method, old, n, newch) - uncompress old into new, 331590Srgrimes * using method, return sizeof new 341590Srgrimes */ 351590Srgrimes#include "file.h" 361590Srgrimes 371590Srgrimes#ifndef lint 3862833SwsanchezFILE_RCSID("@(#)$File: compress.c,v 1.93 2016/03/31 17:51:12 christos Exp $") 3962833Swsanchez#endif 401590Srgrimes 411590Srgrimes#include "magic.h" 4262833Swsanchez#include <stdlib.h> 4394587Sobrien#ifdef HAVE_UNISTD_H 441590Srgrimes#include <unistd.h> 4535483Simp#endif 46103503Sjmallett#include <string.h> 4735483Simp#include <errno.h> 4835483Simp#include <ctype.h> 491590Srgrimes#include <stdarg.h> 501590Srgrimes#ifdef HAVE_SIGNAL_H 511590Srgrimes#include <signal.h> 521590Srgrimes# ifndef HAVE_SIG_T 531590Srgrimestypedef void (*sig_t)(int); 54144467Sharti# endif /* HAVE_SIG_T */ 551590Srgrimes#endif 56144467Sharti#if !defined(__MINGW32__) && !defined(WIN32) 57144467Sharti#include <sys/ioctl.h> 58144467Sharti#endif 59144467Sharti#ifdef HAVE_SYS_WAIT_H 60144467Sharti#include <sys/wait.h> 61144467Sharti#endif 62144467Sharti#if defined(HAVE_SYS_TIME_H) 631590Srgrimes#include <sys/time.h> 64144467Sharti#endif 65144467Sharti#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) 66144467Sharti#define BUILTIN_DECOMPRESS 67144467Sharti#include <zlib.h> 68144467Sharti#define ZLIBSUPPORT 691590Srgrimes#endif 70144467Sharti#ifdef DEBUG 71144467Shartiint tty = -1; 72144467Sharti#define DPRINTF(...) do { \ 73144467Sharti if (tty == -1) \ 741590Srgrimes tty = open("/dev/tty", O_RDWR); \ 75144467Sharti if (tty == -1) \ 761590Srgrimes abort(); \ 77144467Sharti dprintf(tty, __VA_ARGS__); \ 781590Srgrimes} while (/*CONSTCOND*/0) 79144467Sharti#else 80144467Sharti#define DPRINTF(...) 81144467Sharti#endif 821590Srgrimes 83144467Sharti#ifdef ZLIBSUPPORT 84144467Sharti/* 85144467Sharti * The following python code is not really used because ZLIBSUPPORT is only 86144467Sharti * defined if we have a built-in zlib, and the built-in zlib handles that. 871590Srgrimes */ 88144467Shartistatic const char zlibcode[] = 89144467Sharti "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))"; 90144467Sharti 911590Srgrimesstatic const char *zlib_args[] = { "python", "-c", zlibcode, NULL }; 92144467Sharti 93144467Shartistatic int 94144467Shartizlibcmp(const unsigned char *buf) 951590Srgrimes{ 96144467Sharti unsigned short x = 1; 971590Srgrimes unsigned char *s = (unsigned char *)&x; 98144467Sharti 99146132Sharti if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0) 100146132Sharti return 0; 101146132Sharti if (s[0] != 1) /* endianness test */ 102146132Sharti x = buf[0] | (buf[1] << 8); 103146132Sharti else 104146132Sharti x = buf[1] | (buf[0] << 8); 105146132Sharti if (x % 31) 106146132Sharti return 0; 107146132Sharti return 1; 108146132Sharti} 109146132Sharti#endif 1101590Srgrimes 1111590Srgrimes#define gzip_flags "-cd" 112144494Sharti#define lrzip_flags "-do" 1131590Srgrimes#define lzip_flags gzip_flags 114141104Sharti 1151590Srgrimesstatic const char *gzip_args[] = { 116107447Sru "gzip", gzip_flags, NULL 117104475Sphk}; 118107447Srustatic const char *uncompress_args[] = { 1191590Srgrimes "uncompress", "-c", NULL 120141104Sharti}; 12194506Scharnierstatic const char *bzip2_args[] = { 1225814Sjkh "bzip2", "-cd", NULL 123144665Sharti}; 1241590Srgrimesstatic const char *lzip_args[] = { 1255814Sjkh "lzip", lzip_flags, NULL 126141104Sharti}; 12780381Ssheldonhstatic const char *xz_args[] = { 12894506Scharnier "xz", "-cd", NULL 129141104Sharti}; 130141104Shartistatic const char *lrzip_args[] = { 131142457Sharti "lrzip", lrzip_flags, NULL 132146056Sharti}; 1331590Srgrimesstatic const char *lz4_args[] = { 134141104Sharti "lz4", "-cd", NULL 135141104Sharti}; 1361590Srgrimes 137141104Shartiprivate const struct { 138141104Sharti const void *magic; 1391590Srgrimes size_t maglen; 140141104Sharti const char **argv; 141146056Sharti} compr[] = { 142141104Sharti { "\037\235", 2, gzip_args }, /* compressed */ 143141104Sharti /* Uncompress can get stuck; so use gzip first if we have it 144141104Sharti * Idea from Damien Clark, thanks! */ 1451590Srgrimes { "\037\235", 2, uncompress_args }, /* compressed */ 146146057Sharti { "\037\213", 2, gzip_args }, /* gzipped */ 147146057Sharti { "\037\236", 2, gzip_args }, /* frozen */ 148146057Sharti { "\037\240", 2, gzip_args }, /* SCO LZH */ 1491590Srgrimes /* the standard pack utilities do not accept standard input */ 150146057Sharti { "\037\036", 2, gzip_args }, /* packed */ 151146057Sharti { "PK\3\4", 4, gzip_args }, /* pkzipped, */ 152146057Sharti /* ...only first file examined */ 153146057Sharti { "BZh", 3, bzip2_args }, /* bzip2-ed */ 154146057Sharti { "LZIP", 4, lzip_args }, /* lzip-ed */ 155146057Sharti { "\3757zXZ\0", 6, xz_args }, /* XZ Utils */ 156146057Sharti { "LRZI", 4, lrzip_args }, /* LRZIP */ 157146057Sharti { "\004\"M\030",4, lz4_args }, /* LZ4 */ 158146057Sharti#ifdef ZLIBSUPPORT 159144483Sharti { zlibcmp, 0, zlib_args }, /* zlib */ 160144483Sharti#endif 161144483Sharti}; 162144483Sharti 163144483Sharti#define OKDATA 0 164144483Sharti#define NODATA 1 165144483Sharti#define ERRDATA 2 166144483Sharti 167144483Shartiprivate ssize_t swrite(int, const void *, size_t); 168144483Sharti#if HAVE_FORK 169144483Shartiprivate size_t ncompr = sizeof(compr) / sizeof(compr[0]); 170144483Shartiprivate int uncompressbuf(int, size_t, size_t, const unsigned char *, 171144665Sharti unsigned char **, size_t *); 172144483Sharti#ifdef BUILTIN_DECOMPRESS 173144483Shartiprivate int uncompresszlib(const unsigned char *, unsigned char **, size_t, 174144483Sharti size_t *, int); 175144483Shartiprivate int uncompressgzipped(const unsigned char *, unsigned char **, size_t, 176144483Sharti size_t *); 177144483Sharti#endif 178144483Shartistatic int makeerror(unsigned char **, size_t *, const char *, ...) 179144483Sharti __attribute__((__format__(__printf__, 3, 4))); 180144483Shartiprivate const char *methodname(size_t); 181144483Sharti 182144483Shartiprotected int 183144483Shartifile_zmagic(struct magic_set *ms, int fd, const char *name, 184144483Sharti const unsigned char *buf, size_t nbytes) 185144483Sharti{ 186144483Sharti unsigned char *newbuf = NULL; 187144483Sharti size_t i, nsz; 188144483Sharti char *rbuf; 189144483Sharti file_pushbuf_t *pb; 190144483Sharti int rv = 0; 191144483Sharti int mime = ms->flags & MAGIC_MIME; 192144483Sharti#ifdef HAVE_SIGNAL_H 193144483Sharti sig_t osigpipe; 194144483Sharti#endif 195144483Sharti 196146061Sharti if ((ms->flags & MAGIC_COMPRESS) == 0) 197144483Sharti return 0; 198144483Sharti 199144483Sharti#ifdef HAVE_SIGNAL_H 200144483Sharti osigpipe = signal(SIGPIPE, SIG_IGN); 201144483Sharti#endif 202144483Sharti for (i = 0; i < ncompr; i++) { 203144483Sharti int zm; 204144483Sharti if (nbytes < compr[i].maglen) 205144483Sharti continue; 206144483Sharti#ifdef ZLIBSUPPORT 207144483Sharti if (compr[i].maglen == 0) 208144483Sharti zm = (CAST(int (*)(const unsigned char *), 209144483Sharti CCAST(void *, compr[i].magic)))(buf); 210146061Sharti else 211144483Sharti#endif 212144483Sharti zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0; 213144483Sharti 214144483Sharti if (!zm) 215144483Sharti continue; 216144483Sharti nsz = nbytes; 217144483Sharti rv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz); 218144483Sharti DPRINTF("uncompressbuf = %d, %s, %zu\n", rv, (char *)newbuf, 219144483Sharti nsz); 220144483Sharti switch (rv) { 221144483Sharti case OKDATA: 222144483Sharti case ERRDATA: 223144483Sharti 224144483Sharti ms->flags &= ~MAGIC_COMPRESS; 225144483Sharti if (rv == ERRDATA) 226144483Sharti rv = file_printf(ms, "%s ERROR: %s", 227144483Sharti methodname(i), newbuf); 228144483Sharti else 229144483Sharti rv = file_buffer(ms, -1, name, newbuf, nsz); 230144483Sharti if (rv == -1) 231144483Sharti goto error; 232144483Sharti DPRINTF("rv = %d\n", rv); 233144483Sharti if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0) 234144483Sharti goto out; 235144483Sharti if (mime != MAGIC_MIME && mime != 0) 236144483Sharti goto out; 237144483Sharti if ((file_printf(ms, 238144483Sharti mime ? " compressed-encoding=" : " (")) == -1) 239144483Sharti goto error; 240144483Sharti if ((pb = file_push_buffer(ms)) == NULL) 241144483Sharti goto error; 242144483Sharti if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) 243144483Sharti goto error; 244144483Sharti if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { 245144483Sharti if (file_printf(ms, "%s", rbuf) == -1) { 246144483Sharti free(rbuf); 247144483Sharti goto error; 248144483Sharti } 249144483Sharti free(rbuf); 250144483Sharti } 251144483Sharti if (!mime && file_printf(ms, ")") == -1) 252144483Sharti goto error; 253144483Sharti goto out; 254144483Sharti case NODATA: 255144483Sharti goto out; 256144494Sharti default: 257144494Sharti abort(); 258144483Sharti } 259144483Sharti } 260146061Shartiout: 261146061Sharti rv = 1; 262144483Shartierror: 263144483Sharti#ifdef HAVE_SIGNAL_H 264144483Sharti (void)signal(SIGPIPE, osigpipe); 265146061Sharti#endif 266144483Sharti free(newbuf); 267144494Sharti ms->flags |= MAGIC_COMPRESS; 268144494Sharti DPRINTF("Zmagic returns %d\n", rv); 269144483Sharti return rv; 270144483Sharti} 271144483Sharti#endif 272144483Sharti/* 273144483Sharti * `safe' write for sockets and pipes. 274144483Sharti */ 275144483Shartiprivate ssize_t 276144483Shartiswrite(int fd, const void *buf, size_t n) 277144483Sharti{ 278144483Sharti ssize_t rv; 279144483Sharti size_t rn = n; 280144483Sharti 281144483Sharti do 282144483Sharti switch (rv = write(fd, buf, n)) { 283144483Sharti case -1: 284144483Sharti if (errno == EINTR) 285144483Sharti continue; 286144483Sharti return -1; 287144483Sharti default: 288144483Sharti n -= rv; 289144483Sharti buf = CAST(const char *, buf) + rv; 290144483Sharti break; 291144483Sharti } 292144483Sharti while (n > 0); 293144483Sharti return rn; 294144483Sharti} 295144483Sharti 296144483Sharti 297144483Sharti/* 298144483Sharti * `safe' read for sockets and pipes. 299144483Sharti */ 300144483Shartiprotected ssize_t 301144483Shartisread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) 302144483Sharti{ 303144483Sharti ssize_t rv; 304144483Sharti#ifdef FIONREAD 305144483Sharti int t = 0; 306144483Sharti#endif 307144483Sharti size_t rn = n; 308144483Sharti 309144483Sharti if (fd == STDIN_FILENO) 310144483Sharti goto nocheck; 311144483Sharti 312144483Sharti#ifdef FIONREAD 313144483Sharti if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { 314144483Sharti#ifdef FD_ZERO 315144483Sharti ssize_t cnt; 316144483Sharti for (cnt = 0;; cnt++) { 317144483Sharti fd_set check; 318144483Sharti struct timeval tout = {0, 100 * 1000}; 319144483Sharti int selrv; 3208874Srgrimes 3211590Srgrimes FD_ZERO(&check); 322144467Sharti FD_SET(fd, &check); 323144467Sharti 324144467Sharti /* 325144467Sharti * Avoid soft deadlock: do not read if there 326144467Sharti * is nothing to read from sockets and pipes. 3271590Srgrimes */ 32818730Ssteve selrv = select(fd + 1, &check, NULL, NULL, &tout); 32918730Ssteve if (selrv == -1) { 33018730Ssteve if (errno == EINTR || errno == EAGAIN) 33118730Ssteve continue; 332138232Sharti } else if (selrv == 0 && cnt >= 5) { 3331590Srgrimes return 0; 3341590Srgrimes } else 3351590Srgrimes break; 3361590Srgrimes } 3371590Srgrimes#endif 3381590Srgrimes (void)ioctl(fd, FIONREAD, &t); 339144467Sharti } 3401590Srgrimes 3411590Srgrimes if (t > 0 && (size_t)t < n) { 342144467Sharti n = t; 343144467Sharti rn = n; 344144467Sharti } 345144467Sharti#endif 346144467Sharti 347144467Shartinocheck: 3481590Srgrimes do 3491590Srgrimes switch ((rv = read(fd, buf, n))) { 350144467Sharti case -1: 351146061Sharti if (errno == EINTR) 352144467Sharti continue; 353144467Sharti return -1; 3541590Srgrimes case 0: 3551590Srgrimes return rn - n; 3561590Srgrimes default: 3571590Srgrimes n -= rv; 358144483Sharti buf = ((char *)buf) + rv; 359144467Sharti break; 360144467Sharti } 361144467Sharti while (n > 0); 362144467Sharti return rn; 363144467Sharti} 364144467Sharti 365144467Shartiprotected int 366144741Shartifile_pipe2file(struct magic_set *ms, int fd, const void *startbuf, 367144467Sharti size_t nbytes) 368144467Sharti{ 369144467Sharti char buf[4096]; 370144467Sharti ssize_t r; 371144467Sharti int tfd; 372144467Sharti 373144467Sharti (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); 374144467Sharti#ifndef HAVE_MKSTEMP 375144467Sharti { 376144741Sharti char *ptr = mktemp(buf); 377144467Sharti tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); 37818730Ssteve r = errno; 379144467Sharti (void)unlink(ptr); 38018730Ssteve errno = r; 381144467Sharti } 382144467Sharti#else 383144467Sharti { 384144467Sharti int te; 385144467Sharti tfd = mkstemp(buf); 386144467Sharti te = errno; 387144467Sharti (void)unlink(buf); 388144467Sharti errno = te; 389144741Sharti } 390144467Sharti#endif 391144467Sharti if (tfd == -1) { 392144467Sharti file_error(ms, errno, 3931590Srgrimes "cannot create temporary file for pipe copy"); 3941590Srgrimes return -1; 395144467Sharti } 396144467Sharti 397144467Sharti if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes) 398144467Sharti r = 1; 399144483Sharti else { 400146059Sharti while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) 401146059Sharti if (swrite(tfd, buf, (size_t)r) != r) 4021590Srgrimes break; 403146140Sharti } 404146140Sharti 405146140Sharti switch (r) { 406146140Sharti case -1: 407146140Sharti file_error(ms, errno, "error copying from pipe to temp file"); 408146140Sharti return -1; 409144656Sharti case 0: 410138916Sharti break; 411138916Sharti default: 412144494Sharti file_error(ms, errno, "error while writing to temp file"); 413138916Sharti return -1; 414146061Sharti } 4151590Srgrimes 416137572Sphk /* 417104475Sphk * We duplicate the file descriptor, because fclose on a 418104475Sphk * tmpfile will delete the file, but any open descriptors 419104475Sphk * can still access the phantom inode. 420146061Sharti */ 4211590Srgrimes if ((fd = dup2(tfd, fd)) == -1) { 4221590Srgrimes file_error(ms, errno, "could not dup descriptor for temp file"); 4231590Srgrimes return -1; 424146061Sharti } 4251590Srgrimes (void)close(tfd); 426146061Sharti if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 4271590Srgrimes file_badseek(ms); 4281590Srgrimes return -1; 4291590Srgrimes } 430137202Sharti return fd; 431137202Sharti} 432138232Sharti#if HAVE_FORK 43318730Ssteve#ifdef BUILTIN_DECOMPRESS 4341590Srgrimes 435137252Sharti#define FHCRC (1 << 1) 436137252Sharti#define FEXTRA (1 << 2) 437137252Sharti#define FNAME (1 << 3) 4388874Srgrimes#define FCOMMENT (1 << 4) 439138916Sharti 440138916Sharti 441138916Shartiprivate int 4421590Srgrimesuncompressgzipped(const unsigned char *old, unsigned char **newch, 443144494Sharti size_t bytes_max, size_t *n) 4441590Srgrimes{ 445144656Sharti unsigned char flg = old[3]; 446144656Sharti size_t data_start = 10; 447144656Sharti 4481590Srgrimes if (flg & FEXTRA) { 449137605Sharti if (data_start + 1 >= *n) 450137605Sharti goto err; 451137605Sharti data_start += 2 + old[data_start] + old[data_start + 1] * 256; 4521590Srgrimes } 45318730Ssteve if (flg & FNAME) { 4541590Srgrimes while(data_start < *n && old[data_start]) 4551590Srgrimes data_start++; 45618730Ssteve data_start++; 4571590Srgrimes } 45818730Ssteve if (flg & FCOMMENT) { 4591590Srgrimes while(data_start < *n && old[data_start]) 4601590Srgrimes data_start++; 4611590Srgrimes data_start++; 46218730Ssteve } 46318730Ssteve if (flg & FHCRC) 46418730Ssteve data_start += 2; 46518730Ssteve 46618730Ssteve if (data_start >= *n) 46718730Ssteve goto err; 468103503Sjmallett 46918730Ssteve *n -= data_start; 470138232Sharti old += data_start; 47118730Ssteve return uncompresszlib(old, newch, bytes_max, n, 0); 47218730Ssteveerr: 47318730Ssteve return makeerror(newch, n, "File too short"); 47418730Ssteve} 47518730Ssteve 47618730Ssteveprivate int 47718730Ssteveuncompresszlib(const unsigned char *old, unsigned char **newch, 478103503Sjmallett size_t bytes_max, size_t *n, int zlib) 479103503Sjmallett{ 48018730Ssteve int rc; 481146129Sharti z_stream z; 482146129Sharti 483146129Sharti if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL) 484146129Sharti return makeerror(newch, n, "No buffer, %s", strerror(errno)); 485146129Sharti 486146129Sharti z.next_in = CCAST(Bytef *, old); 487146129Sharti z.avail_in = CAST(uint32_t, *n); 488146129Sharti z.next_out = *newch; 489146129Sharti z.avail_out = bytes_max; 490146129Sharti z.zalloc = Z_NULL; 491146129Sharti z.zfree = Z_NULL; 492146129Sharti z.opaque = Z_NULL; 493146129Sharti 494146130Sharti /* LINTED bug in header macro */ 495146130Sharti rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15); 496146129Sharti if (rc != Z_OK) 497146129Sharti goto err; 49892921Simp 49992921Simp rc = inflate(&z, Z_SYNC_FLUSH); 50092921Simp if (rc != Z_OK && rc != Z_STREAM_END) 501144483Sharti goto err; 50292921Simp 50392921Simp *n = (size_t)z.total_out; 504146129Sharti rc = inflateEnd(&z); 505146142Sharti if (rc != Z_OK) 5061590Srgrimes goto err; 507146132Sharti 508146132Sharti /* let's keep the nul-terminate tradition */ 509146132Sharti (*newch)[*n] = '\0'; 510146132Sharti 511146132Sharti return OKDATA; 512146132Shartierr: 513146132Sharti strlcpy((char *)*newch, z.msg, bytes_max); 514146132Sharti *n = strlen((char *)*newch); 515146132Sharti return ERRDATA; 516146132Sharti} 517146132Sharti#endif 518146132Sharti 519146132Shartistatic int 520146132Shartimakeerror(unsigned char **buf, size_t *len, const char *fmt, ...) 521146132Sharti{ 522146132Sharti char *msg; 523146132Sharti va_list ap; 524146132Sharti int rv; 525144467Sharti 526146129Sharti va_start(ap, fmt); 527146129Sharti rv = vasprintf(&msg, fmt, ap); 528146129Sharti va_end(ap); 529146129Sharti if (rv < 0) { 530146129Sharti *buf = NULL; 531146129Sharti *len = 0; 532146129Sharti return NODATA; 533146129Sharti } 534146129Sharti *buf = (unsigned char *)msg; 535146129Sharti *len = strlen(msg); 536146129Sharti return ERRDATA; 537146129Sharti} 538146129Sharti 539146129Shartistatic void 540146129Sharticlosefd(int *fd, size_t i) 541146129Sharti{ 542146129Sharti if (fd[i] == -1) 543146129Sharti return; 544146129Sharti (void) close(fd[i]); 545146129Sharti fd[i] = -1; 546146129Sharti} 547146129Sharti 548146129Shartistatic void 549146129Sharticlosep(int *fd) 550146129Sharti{ 551146129Sharti size_t i; 552146129Sharti for (i = 0; i < 2; i++) 553146129Sharti closefd(fd, i); 554146129Sharti} 555146129Sharti 556146129Shartistatic void 557146129Sharticopydesc(int i, int *fd) 558146129Sharti{ 559146129Sharti int j = fd[i == STDIN_FILENO ? 0 : 1]; 560146129Sharti if (j == i) 561146129Sharti return; 562146129Sharti if (dup2(j, i) == -1) { 563146129Sharti DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno)); 564146129Sharti exit(1); 565146129Sharti } 566146129Sharti closep(fd); 567146129Sharti} 568146129Sharti 569146129Shartistatic void 570146129Shartiwritechild(int fdp[3][2], const void *old, size_t n) 571146129Sharti{ 572146129Sharti int status; 573146129Sharti 574146129Sharti closefd(fdp[STDIN_FILENO], 0); 575146129Sharti /* 576146129Sharti * fork again, to avoid blocking because both 577146129Sharti * pipes filled 578146129Sharti */ 579146129Sharti switch (fork()) { 580146129Sharti case 0: /* child */ 581146129Sharti closefd(fdp[STDOUT_FILENO], 0); 582146129Sharti if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) { 583146129Sharti DPRINTF("Write failed (%s)\n", strerror(errno)); 584146129Sharti exit(1); 585146129Sharti } 586146129Sharti exit(0); 587146129Sharti /*NOTREACHED*/ 588146129Sharti 589146129Sharti case -1: 590146129Sharti DPRINTF("Fork failed (%s)\n", strerror(errno)); 591146129Sharti exit(1); 592146129Sharti /*NOTREACHED*/ 593146129Sharti 594146129Sharti default: /* parent */ 595146129Sharti if (wait(&status) == -1) { 596146129Sharti DPRINTF("Wait failed (%s)\n", strerror(errno)); 597146129Sharti exit(1); 598146129Sharti } 599146129Sharti DPRINTF("Grandchild wait return %#x\n", status); 600146129Sharti } 601146129Sharti closefd(fdp[STDIN_FILENO], 1); 602146129Sharti} 603146129Sharti 604146129Shartistatic ssize_t 605146129Shartifilter_error(unsigned char *ubuf, ssize_t n) 606146129Sharti{ 607146129Sharti char *p; 608146129Sharti char *buf; 609146129Sharti 610146129Sharti ubuf[n] = '\0'; 611146129Sharti buf = (char *)ubuf; 612146129Sharti while (isspace((unsigned char)*buf)) 613146129Sharti buf++; 614146129Sharti DPRINTF("Filter error[[[%s]]]\n", buf); 615146129Sharti if ((p = strchr((char *)buf, '\n')) != NULL) 616146129Sharti *p = '\0'; 617146129Sharti if ((p = strchr((char *)buf, ';')) != NULL) 618146131Sharti *p = '\0'; 619146130Sharti if ((p = strrchr((char *)buf, ':')) != NULL) { 620146130Sharti ++p; 621146130Sharti while (isspace((unsigned char)*p)) 622146130Sharti p++; 623146130Sharti n = strlen(p); 624146130Sharti memmove(ubuf, p, n + 1); 625146130Sharti } 626146130Sharti DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); 627146130Sharti if (islower(*ubuf)) 628146130Sharti *ubuf = toupper(*ubuf); 629146131Sharti return n; 630146131Sharti} 631146131Sharti 632146131Shartiprivate const char * 633146131Shartimethodname(size_t method) 634146131Sharti{ 635146131Sharti#ifdef BUILTIN_DECOMPRESS 636146131Sharti /* FIXME: This doesn't cope with bzip2 */ 637146131Sharti if (method == 2 || compr[method].maglen == 0) 638146131Sharti return "zlib"; 639146131Sharti#endif 640146131Sharti return compr[method].argv[0]; 641146130Sharti} 642146130Sharti 643146130Shartiprivate int 644146130Shartiuncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old, 645146130Sharti unsigned char **newch, size_t* n) 646146130Sharti{ 647137605Sharti int fdp[3][2]; 648144467Sharti int status, rv; 649144467Sharti size_t i; 650137605Sharti ssize_t r; 651137605Sharti 652137605Sharti#ifdef BUILTIN_DECOMPRESS 653137605Sharti /* FIXME: This doesn't cope with bzip2 */ 654137605Sharti if (method == 2) 655137605Sharti return uncompressgzipped(old, newch, bytes_max, n); 656137605Sharti if (compr[method].maglen == 0) 657137605Sharti return uncompresszlib(old, newch, bytes_max, n, 1); 658144467Sharti#endif 6591590Srgrimes (void)fflush(stdout); 660137252Sharti (void)fflush(stderr); 6611590Srgrimes 6621590Srgrimes for (i = 0; i < __arraycount(fdp); i++) 6631590Srgrimes fdp[i][0] = fdp[i][1] = -1; 6641590Srgrimes 6651590Srgrimes if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) || 6661590Srgrimes pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) { 667104696Sjmallett closep(fdp[STDIN_FILENO]); 6681590Srgrimes closep(fdp[STDOUT_FILENO]); 669144741Sharti return makeerror(newch, n, "Cannot create pipe, %s", 670144467Sharti strerror(errno)); 671144467Sharti } 6728874Srgrimes switch (fork()) { 673144467Sharti case 0: /* child */ 674144467Sharti if (fd != -1) { 675144467Sharti fdp[STDIN_FILENO][0] = fd; 676137605Sharti (void) lseek(fd, (off_t)0, SEEK_SET); 677144467Sharti } 678144741Sharti 679144741Sharti for (i = 0; i < __arraycount(fdp); i++) 680144741Sharti copydesc(i, fdp[i]); 681144741Sharti 682144741Sharti (void)execvp(compr[method].argv[0], 6831590Srgrimes (char *const *)(intptr_t)compr[method].argv); 684144467Sharti dprintf(STDERR_FILENO, "exec `%s' failed, %s", 685144467Sharti compr[method].argv[0], strerror(errno)); 686144467Sharti exit(1); 687144467Sharti /*NOTREACHED*/ 688144467Sharti case -1: 689144467Sharti return makeerror(newch, n, "Cannot fork, %s", 690144467Sharti strerror(errno)); 691144467Sharti 692144657Sharti default: /* parent */ 693144467Sharti for (i = 1; i < __arraycount(fdp); i++) 694144467Sharti closefd(fdp[i], 1); 6958874Srgrimes 696144467Sharti /* Write the buffer data to the child, if we don't have fd */ 697144467Sharti if (fd == -1) 698144467Sharti writechild(fdp, old, *n); 699144467Sharti 700144467Sharti *newch = CAST(unsigned char *, malloc(bytes_max + 1)); 701144467Sharti if (*newch == NULL) { 7028874Srgrimes rv = makeerror(newch, n, "No buffer, %s", 703144467Sharti strerror(errno)); 704144467Sharti goto err; 705144467Sharti } 706144467Sharti rv = OKDATA; 707144467Sharti if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0) 708144467Sharti break; 709144467Sharti DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], 710144467Sharti r != -1 ? strerror(errno) : "no data"); 711144467Sharti 712144467Sharti rv = ERRDATA; 713144467Sharti if (r == 0 && 7141590Srgrimes (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0) 715144467Sharti { 716144467Sharti r = filter_error(*newch, r); 717144467Sharti break; 7181590Srgrimes } 719144467Sharti free(*newch); 72018730Ssteve if (r == 0) 721144467Sharti rv = makeerror(newch, n, "Read failed, %s", 722144741Sharti strerror(errno)); 723144741Sharti else 724144741Sharti rv = makeerror(newch, n, "No data"); 725144741Sharti goto err; 726144741Sharti } 7271590Srgrimes 728144467Sharti *n = r; 729144467Sharti /* NUL terminate, as every buffer is handled here. */ 730144467Sharti (*newch)[*n] = '\0'; 731144467Shartierr: 7321590Srgrimes closefd(fdp[STDIN_FILENO], 1); 7331590Srgrimes closefd(fdp[STDOUT_FILENO], 0); 734144467Sharti closefd(fdp[STDERR_FILENO], 0); 7351590Srgrimes if (wait(&status) == -1) { 7361590Srgrimes free(*newch); 7371590Srgrimes rv = makeerror(newch, n, "Wait failed, %s", strerror(errno)); 7381590Srgrimes DPRINTF("Child wait return %#x\n", status); 7391590Srgrimes } else if (!WIFEXITED(status)) { 7401590Srgrimes DPRINTF("Child not exited (0x%x)\n", status); 7411590Srgrimes } else if (WEXITSTATUS(status) != 0) { 7421590Srgrimes DPRINTF("Child exited (0x%d)\n", WEXITSTATUS(status)); 7431590Srgrimes } 7441590Srgrimes 7451590Srgrimes closefd(fdp[STDIN_FILENO], 0); 74694594Sobrien DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv); 747142993Sharti 7481590Srgrimes return rv; 7491590Srgrimes} 7501590Srgrimes#endif 7511590Srgrimes