1b6cee71dSXin LI /* 2b6cee71dSXin LI * Copyright (c) Ian F. Darwin 1986-1995. 3b6cee71dSXin LI * Software written by Ian F. Darwin and others; 4b6cee71dSXin LI * maintained 1995-present by Christos Zoulas and others. 5b6cee71dSXin LI * 6b6cee71dSXin LI * Redistribution and use in source and binary forms, with or without 7b6cee71dSXin LI * modification, are permitted provided that the following conditions 8b6cee71dSXin LI * are met: 9b6cee71dSXin LI * 1. Redistributions of source code must retain the above copyright 10b6cee71dSXin LI * notice immediately at the beginning of the file, without modification, 11b6cee71dSXin LI * this list of conditions, and the following disclaimer. 12b6cee71dSXin LI * 2. Redistributions in binary form must reproduce the above copyright 13b6cee71dSXin LI * notice, this list of conditions and the following disclaimer in the 14b6cee71dSXin LI * documentation and/or other materials provided with the distribution. 15b6cee71dSXin LI * 16b6cee71dSXin LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17b6cee71dSXin LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18b6cee71dSXin LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19b6cee71dSXin LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20b6cee71dSXin LI * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21b6cee71dSXin LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22b6cee71dSXin LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23b6cee71dSXin LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24b6cee71dSXin LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25b6cee71dSXin LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26b6cee71dSXin LI * SUCH DAMAGE. 27b6cee71dSXin LI */ 28b6cee71dSXin LI /* 29b6cee71dSXin LI * compress routines: 30b6cee71dSXin LI * zmagic() - returns 0 if not recognized, uncompresses and prints 31b6cee71dSXin LI * information if recognized 32b6cee71dSXin LI * uncompress(method, old, n, newch) - uncompress old into new, 33b6cee71dSXin LI * using method, return sizeof new 34b6cee71dSXin LI */ 35b6cee71dSXin LI #include "file.h" 36b6cee71dSXin LI 37b6cee71dSXin LI #ifndef lint 38*4460e5b0SXin LI FILE_RCSID("@(#)$File: compress.c,v 1.77 2014/12/12 16:33:01 christos Exp $") 39b6cee71dSXin LI #endif 40b6cee71dSXin LI 41b6cee71dSXin LI #include "magic.h" 42b6cee71dSXin LI #include <stdlib.h> 43b6cee71dSXin LI #ifdef HAVE_UNISTD_H 44b6cee71dSXin LI #include <unistd.h> 45b6cee71dSXin LI #endif 46b6cee71dSXin LI #include <string.h> 47b6cee71dSXin LI #include <errno.h> 48*4460e5b0SXin LI #include <signal.h> 49c2931133SXin LI #if !defined(__MINGW32__) && !defined(WIN32) 50b6cee71dSXin LI #include <sys/ioctl.h> 51b6cee71dSXin LI #endif 52b6cee71dSXin LI #ifdef HAVE_SYS_WAIT_H 53b6cee71dSXin LI #include <sys/wait.h> 54b6cee71dSXin LI #endif 55b6cee71dSXin LI #if defined(HAVE_SYS_TIME_H) 56b6cee71dSXin LI #include <sys/time.h> 57b6cee71dSXin LI #endif 58b6cee71dSXin LI #if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) 59b6cee71dSXin LI #define BUILTIN_DECOMPRESS 60b6cee71dSXin LI #include <zlib.h> 61b6cee71dSXin LI #endif 62b6cee71dSXin LI 63b6cee71dSXin LI private const struct { 64b6cee71dSXin LI const char magic[8]; 65b6cee71dSXin LI size_t maglen; 66b6cee71dSXin LI const char *argv[3]; 67b6cee71dSXin LI int silent; 68b6cee71dSXin LI } compr[] = { 69b6cee71dSXin LI { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 }, /* compressed */ 70b6cee71dSXin LI /* Uncompress can get stuck; so use gzip first if we have it 71b6cee71dSXin LI * Idea from Damien Clark, thanks! */ 72b6cee71dSXin LI { "\037\235", 2, { "uncompress", "-c", NULL }, 1 }, /* compressed */ 73b6cee71dSXin LI { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 }, /* gzipped */ 74b6cee71dSXin LI { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 }, /* frozen */ 75b6cee71dSXin LI { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */ 76b6cee71dSXin LI /* the standard pack utilities do not accept standard input */ 77b6cee71dSXin LI { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 }, /* packed */ 78b6cee71dSXin LI { "PK\3\4", 4, { "gzip", "-cdq", NULL }, 1 }, /* pkzipped, */ 79b6cee71dSXin LI /* ...only first file examined */ 80b6cee71dSXin LI { "BZh", 3, { "bzip2", "-cd", NULL }, 1 }, /* bzip2-ed */ 81b6cee71dSXin LI { "LZIP", 4, { "lzip", "-cdq", NULL }, 1 }, 82b6cee71dSXin LI { "\3757zXZ\0",6,{ "xz", "-cd", NULL }, 1 }, /* XZ Utils */ 83b6cee71dSXin LI { "LRZI", 4, { "lrzip", "-dqo-", NULL }, 1 }, /* LRZIP */ 84b6cee71dSXin LI { "\004\"M\030", 4, { "lz4", "-cd", NULL }, 1 }, /* LZ4 */ 85b6cee71dSXin LI }; 86b6cee71dSXin LI 87b6cee71dSXin LI #define NODATA ((size_t)~0) 88b6cee71dSXin LI 89b6cee71dSXin LI private ssize_t swrite(int, const void *, size_t); 90b6cee71dSXin LI #if HAVE_FORK 91b6cee71dSXin LI private size_t ncompr = sizeof(compr) / sizeof(compr[0]); 92b6cee71dSXin LI private size_t uncompressbuf(struct magic_set *, int, size_t, 93b6cee71dSXin LI const unsigned char *, unsigned char **, size_t); 94b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 95b6cee71dSXin LI private size_t uncompressgzipped(struct magic_set *, const unsigned char *, 96b6cee71dSXin LI unsigned char **, size_t); 97b6cee71dSXin LI #endif 98b6cee71dSXin LI 99b6cee71dSXin LI protected int 100b6cee71dSXin LI file_zmagic(struct magic_set *ms, int fd, const char *name, 101b6cee71dSXin LI const unsigned char *buf, size_t nbytes) 102b6cee71dSXin LI { 103b6cee71dSXin LI unsigned char *newbuf = NULL; 104b6cee71dSXin LI size_t i, nsz; 105b6cee71dSXin LI int rv = 0; 106b6cee71dSXin LI int mime = ms->flags & MAGIC_MIME; 107*4460e5b0SXin LI sig_t osigpipe; 108b6cee71dSXin LI 109b6cee71dSXin LI if ((ms->flags & MAGIC_COMPRESS) == 0) 110b6cee71dSXin LI return 0; 111b6cee71dSXin LI 112*4460e5b0SXin LI osigpipe = signal(SIGPIPE, SIG_IGN); 113b6cee71dSXin LI for (i = 0; i < ncompr; i++) { 114b6cee71dSXin LI if (nbytes < compr[i].maglen) 115b6cee71dSXin LI continue; 116b6cee71dSXin LI if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 && 117b6cee71dSXin LI (nsz = uncompressbuf(ms, fd, i, buf, &newbuf, 118b6cee71dSXin LI nbytes)) != NODATA) { 119b6cee71dSXin LI ms->flags &= ~MAGIC_COMPRESS; 120b6cee71dSXin LI rv = -1; 121b6cee71dSXin LI if (file_buffer(ms, -1, name, newbuf, nsz) == -1) 122b6cee71dSXin LI goto error; 123b6cee71dSXin LI 124b6cee71dSXin LI if (mime == MAGIC_MIME || mime == 0) { 125b6cee71dSXin LI if (file_printf(ms, mime ? 126b6cee71dSXin LI " compressed-encoding=" : " (") == -1) 127b6cee71dSXin LI goto error; 128b6cee71dSXin LI if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) 129b6cee71dSXin LI goto error; 130b6cee71dSXin LI if (!mime && file_printf(ms, ")") == -1) 131b6cee71dSXin LI goto error; 132b6cee71dSXin LI } 133b6cee71dSXin LI 134b6cee71dSXin LI rv = 1; 135b6cee71dSXin LI break; 136b6cee71dSXin LI } 137b6cee71dSXin LI } 138b6cee71dSXin LI error: 139*4460e5b0SXin LI (void)signal(SIGPIPE, osigpipe); 140b6cee71dSXin LI free(newbuf); 141b6cee71dSXin LI ms->flags |= MAGIC_COMPRESS; 142b6cee71dSXin LI return rv; 143b6cee71dSXin LI } 144b6cee71dSXin LI #endif 145b6cee71dSXin LI /* 146b6cee71dSXin LI * `safe' write for sockets and pipes. 147b6cee71dSXin LI */ 148b6cee71dSXin LI private ssize_t 149b6cee71dSXin LI swrite(int fd, const void *buf, size_t n) 150b6cee71dSXin LI { 151b6cee71dSXin LI ssize_t rv; 152b6cee71dSXin LI size_t rn = n; 153b6cee71dSXin LI 154b6cee71dSXin LI do 155b6cee71dSXin LI switch (rv = write(fd, buf, n)) { 156b6cee71dSXin LI case -1: 157b6cee71dSXin LI if (errno == EINTR) 158b6cee71dSXin LI continue; 159b6cee71dSXin LI return -1; 160b6cee71dSXin LI default: 161b6cee71dSXin LI n -= rv; 162b6cee71dSXin LI buf = CAST(const char *, buf) + rv; 163b6cee71dSXin LI break; 164b6cee71dSXin LI } 165b6cee71dSXin LI while (n > 0); 166b6cee71dSXin LI return rn; 167b6cee71dSXin LI } 168b6cee71dSXin LI 169b6cee71dSXin LI 170b6cee71dSXin LI /* 171b6cee71dSXin LI * `safe' read for sockets and pipes. 172b6cee71dSXin LI */ 173b6cee71dSXin LI protected ssize_t 174b6cee71dSXin LI sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) 175b6cee71dSXin LI { 176b6cee71dSXin LI ssize_t rv; 177b6cee71dSXin LI #ifdef FIONREAD 178b6cee71dSXin LI int t = 0; 179b6cee71dSXin LI #endif 180b6cee71dSXin LI size_t rn = n; 181b6cee71dSXin LI 182b6cee71dSXin LI if (fd == STDIN_FILENO) 183b6cee71dSXin LI goto nocheck; 184b6cee71dSXin LI 185b6cee71dSXin LI #ifdef FIONREAD 186b6cee71dSXin LI if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { 187b6cee71dSXin LI #ifdef FD_ZERO 188b6cee71dSXin LI ssize_t cnt; 189b6cee71dSXin LI for (cnt = 0;; cnt++) { 190b6cee71dSXin LI fd_set check; 191b6cee71dSXin LI struct timeval tout = {0, 100 * 1000}; 192b6cee71dSXin LI int selrv; 193b6cee71dSXin LI 194b6cee71dSXin LI FD_ZERO(&check); 195b6cee71dSXin LI FD_SET(fd, &check); 196b6cee71dSXin LI 197b6cee71dSXin LI /* 198b6cee71dSXin LI * Avoid soft deadlock: do not read if there 199b6cee71dSXin LI * is nothing to read from sockets and pipes. 200b6cee71dSXin LI */ 201b6cee71dSXin LI selrv = select(fd + 1, &check, NULL, NULL, &tout); 202b6cee71dSXin LI if (selrv == -1) { 203b6cee71dSXin LI if (errno == EINTR || errno == EAGAIN) 204b6cee71dSXin LI continue; 205b6cee71dSXin LI } else if (selrv == 0 && cnt >= 5) { 206b6cee71dSXin LI return 0; 207b6cee71dSXin LI } else 208b6cee71dSXin LI break; 209b6cee71dSXin LI } 210b6cee71dSXin LI #endif 211b6cee71dSXin LI (void)ioctl(fd, FIONREAD, &t); 212b6cee71dSXin LI } 213b6cee71dSXin LI 214b6cee71dSXin LI if (t > 0 && (size_t)t < n) { 215b6cee71dSXin LI n = t; 216b6cee71dSXin LI rn = n; 217b6cee71dSXin LI } 218b6cee71dSXin LI #endif 219b6cee71dSXin LI 220b6cee71dSXin LI nocheck: 221b6cee71dSXin LI do 222b6cee71dSXin LI switch ((rv = read(fd, buf, n))) { 223b6cee71dSXin LI case -1: 224b6cee71dSXin LI if (errno == EINTR) 225b6cee71dSXin LI continue; 226b6cee71dSXin LI return -1; 227b6cee71dSXin LI case 0: 228b6cee71dSXin LI return rn - n; 229b6cee71dSXin LI default: 230b6cee71dSXin LI n -= rv; 231b6cee71dSXin LI buf = ((char *)buf) + rv; 232b6cee71dSXin LI break; 233b6cee71dSXin LI } 234b6cee71dSXin LI while (n > 0); 235b6cee71dSXin LI return rn; 236b6cee71dSXin LI } 237b6cee71dSXin LI 238b6cee71dSXin LI protected int 239b6cee71dSXin LI file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, 240b6cee71dSXin LI size_t nbytes) 241b6cee71dSXin LI { 242b6cee71dSXin LI char buf[4096]; 243b6cee71dSXin LI ssize_t r; 244b6cee71dSXin LI int tfd; 245b6cee71dSXin LI 246b6cee71dSXin LI (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); 247b6cee71dSXin LI #ifndef HAVE_MKSTEMP 248b6cee71dSXin LI { 249b6cee71dSXin LI char *ptr = mktemp(buf); 250b6cee71dSXin LI tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); 251b6cee71dSXin LI r = errno; 252b6cee71dSXin LI (void)unlink(ptr); 253b6cee71dSXin LI errno = r; 254b6cee71dSXin LI } 255b6cee71dSXin LI #else 256b6cee71dSXin LI { 257b6cee71dSXin LI int te; 258b6cee71dSXin LI tfd = mkstemp(buf); 259b6cee71dSXin LI te = errno; 260b6cee71dSXin LI (void)unlink(buf); 261b6cee71dSXin LI errno = te; 262b6cee71dSXin LI } 263b6cee71dSXin LI #endif 264b6cee71dSXin LI if (tfd == -1) { 265b6cee71dSXin LI file_error(ms, errno, 266b6cee71dSXin LI "cannot create temporary file for pipe copy"); 267b6cee71dSXin LI return -1; 268b6cee71dSXin LI } 269b6cee71dSXin LI 270b6cee71dSXin LI if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes) 271b6cee71dSXin LI r = 1; 272b6cee71dSXin LI else { 273b6cee71dSXin LI while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) 274b6cee71dSXin LI if (swrite(tfd, buf, (size_t)r) != r) 275b6cee71dSXin LI break; 276b6cee71dSXin LI } 277b6cee71dSXin LI 278b6cee71dSXin LI switch (r) { 279b6cee71dSXin LI case -1: 280b6cee71dSXin LI file_error(ms, errno, "error copying from pipe to temp file"); 281b6cee71dSXin LI return -1; 282b6cee71dSXin LI case 0: 283b6cee71dSXin LI break; 284b6cee71dSXin LI default: 285b6cee71dSXin LI file_error(ms, errno, "error while writing to temp file"); 286b6cee71dSXin LI return -1; 287b6cee71dSXin LI } 288b6cee71dSXin LI 289b6cee71dSXin LI /* 290b6cee71dSXin LI * We duplicate the file descriptor, because fclose on a 291b6cee71dSXin LI * tmpfile will delete the file, but any open descriptors 292b6cee71dSXin LI * can still access the phantom inode. 293b6cee71dSXin LI */ 294b6cee71dSXin LI if ((fd = dup2(tfd, fd)) == -1) { 295b6cee71dSXin LI file_error(ms, errno, "could not dup descriptor for temp file"); 296b6cee71dSXin LI return -1; 297b6cee71dSXin LI } 298b6cee71dSXin LI (void)close(tfd); 299b6cee71dSXin LI if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 300b6cee71dSXin LI file_badseek(ms); 301b6cee71dSXin LI return -1; 302b6cee71dSXin LI } 303b6cee71dSXin LI return fd; 304b6cee71dSXin LI } 305b6cee71dSXin LI #if HAVE_FORK 306b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 307b6cee71dSXin LI 308b6cee71dSXin LI #define FHCRC (1 << 1) 309b6cee71dSXin LI #define FEXTRA (1 << 2) 310b6cee71dSXin LI #define FNAME (1 << 3) 311b6cee71dSXin LI #define FCOMMENT (1 << 4) 312b6cee71dSXin LI 313b6cee71dSXin LI private size_t 314b6cee71dSXin LI uncompressgzipped(struct magic_set *ms, const unsigned char *old, 315b6cee71dSXin LI unsigned char **newch, size_t n) 316b6cee71dSXin LI { 317b6cee71dSXin LI unsigned char flg = old[3]; 318b6cee71dSXin LI size_t data_start = 10; 319b6cee71dSXin LI z_stream z; 320b6cee71dSXin LI int rc; 321b6cee71dSXin LI 322b6cee71dSXin LI if (flg & FEXTRA) { 323b6cee71dSXin LI if (data_start+1 >= n) 324b6cee71dSXin LI return 0; 325b6cee71dSXin LI data_start += 2 + old[data_start] + old[data_start + 1] * 256; 326b6cee71dSXin LI } 327b6cee71dSXin LI if (flg & FNAME) { 328b6cee71dSXin LI while(data_start < n && old[data_start]) 329b6cee71dSXin LI data_start++; 330b6cee71dSXin LI data_start++; 331b6cee71dSXin LI } 332b6cee71dSXin LI if(flg & FCOMMENT) { 333b6cee71dSXin LI while(data_start < n && old[data_start]) 334b6cee71dSXin LI data_start++; 335b6cee71dSXin LI data_start++; 336b6cee71dSXin LI } 337b6cee71dSXin LI if(flg & FHCRC) 338b6cee71dSXin LI data_start += 2; 339b6cee71dSXin LI 340b6cee71dSXin LI if (data_start >= n) 341b6cee71dSXin LI return 0; 342b6cee71dSXin LI if ((*newch = CAST(unsigned char *, malloc(HOWMANY + 1))) == NULL) { 343b6cee71dSXin LI return 0; 344b6cee71dSXin LI } 345b6cee71dSXin LI 346b6cee71dSXin LI /* XXX: const castaway, via strchr */ 347b6cee71dSXin LI z.next_in = (Bytef *)strchr((const char *)old + data_start, 348b6cee71dSXin LI old[data_start]); 349b6cee71dSXin LI z.avail_in = CAST(uint32_t, (n - data_start)); 350b6cee71dSXin LI z.next_out = *newch; 351b6cee71dSXin LI z.avail_out = HOWMANY; 352b6cee71dSXin LI z.zalloc = Z_NULL; 353b6cee71dSXin LI z.zfree = Z_NULL; 354b6cee71dSXin LI z.opaque = Z_NULL; 355b6cee71dSXin LI 356b6cee71dSXin LI /* LINTED bug in header macro */ 357b6cee71dSXin LI rc = inflateInit2(&z, -15); 358b6cee71dSXin LI if (rc != Z_OK) { 359b6cee71dSXin LI file_error(ms, 0, "zlib: %s", z.msg); 360b6cee71dSXin LI return 0; 361b6cee71dSXin LI } 362b6cee71dSXin LI 363b6cee71dSXin LI rc = inflate(&z, Z_SYNC_FLUSH); 364b6cee71dSXin LI if (rc != Z_OK && rc != Z_STREAM_END) { 365b6cee71dSXin LI file_error(ms, 0, "zlib: %s", z.msg); 366b6cee71dSXin LI return 0; 367b6cee71dSXin LI } 368b6cee71dSXin LI 369b6cee71dSXin LI n = (size_t)z.total_out; 370b6cee71dSXin LI (void)inflateEnd(&z); 371b6cee71dSXin LI 372b6cee71dSXin LI /* let's keep the nul-terminate tradition */ 373b6cee71dSXin LI (*newch)[n] = '\0'; 374b6cee71dSXin LI 375b6cee71dSXin LI return n; 376b6cee71dSXin LI } 377b6cee71dSXin LI #endif 378b6cee71dSXin LI 379b6cee71dSXin LI private size_t 380b6cee71dSXin LI uncompressbuf(struct magic_set *ms, int fd, size_t method, 381b6cee71dSXin LI const unsigned char *old, unsigned char **newch, size_t n) 382b6cee71dSXin LI { 383b6cee71dSXin LI int fdin[2], fdout[2]; 384c2931133SXin LI int status; 385b6cee71dSXin LI ssize_t r; 386b6cee71dSXin LI pid_t pid; 387b6cee71dSXin LI 388b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 389b6cee71dSXin LI /* FIXME: This doesn't cope with bzip2 */ 390b6cee71dSXin LI if (method == 2) 391b6cee71dSXin LI return uncompressgzipped(ms, old, newch, n); 392b6cee71dSXin LI #endif 393b6cee71dSXin LI (void)fflush(stdout); 394b6cee71dSXin LI (void)fflush(stderr); 395b6cee71dSXin LI 396b6cee71dSXin LI if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) { 397b6cee71dSXin LI file_error(ms, errno, "cannot create pipe"); 398b6cee71dSXin LI return NODATA; 399b6cee71dSXin LI } 400b6cee71dSXin LI switch (pid = fork()) { 401b6cee71dSXin LI case 0: /* child */ 402b6cee71dSXin LI (void) close(0); 403b6cee71dSXin LI if (fd != -1) { 404b6cee71dSXin LI if (dup(fd) == -1) 405b6cee71dSXin LI _exit(1); 406b6cee71dSXin LI (void) lseek(0, (off_t)0, SEEK_SET); 407b6cee71dSXin LI } else { 408b6cee71dSXin LI if (dup(fdin[0]) == -1) 409b6cee71dSXin LI _exit(1); 410b6cee71dSXin LI (void) close(fdin[0]); 411b6cee71dSXin LI (void) close(fdin[1]); 412b6cee71dSXin LI } 413b6cee71dSXin LI 414b6cee71dSXin LI (void) close(1); 415b6cee71dSXin LI if (dup(fdout[1]) == -1) 416b6cee71dSXin LI _exit(1); 417b6cee71dSXin LI (void) close(fdout[0]); 418b6cee71dSXin LI (void) close(fdout[1]); 419b6cee71dSXin LI #ifndef DEBUG 420b6cee71dSXin LI if (compr[method].silent) 421b6cee71dSXin LI (void)close(2); 422b6cee71dSXin LI #endif 423b6cee71dSXin LI 424b6cee71dSXin LI (void)execvp(compr[method].argv[0], 425b6cee71dSXin LI (char *const *)(intptr_t)compr[method].argv); 426b6cee71dSXin LI #ifdef DEBUG 427b6cee71dSXin LI (void)fprintf(stderr, "exec `%s' failed (%s)\n", 428b6cee71dSXin LI compr[method].argv[0], strerror(errno)); 429b6cee71dSXin LI #endif 430b6cee71dSXin LI exit(1); 431b6cee71dSXin LI /*NOTREACHED*/ 432b6cee71dSXin LI case -1: 433b6cee71dSXin LI file_error(ms, errno, "could not fork"); 434b6cee71dSXin LI return NODATA; 435b6cee71dSXin LI 436b6cee71dSXin LI default: /* parent */ 437b6cee71dSXin LI (void) close(fdout[1]); 438b6cee71dSXin LI if (fd == -1) { 439b6cee71dSXin LI (void) close(fdin[0]); 440b6cee71dSXin LI /* 441b6cee71dSXin LI * fork again, to avoid blocking because both 442b6cee71dSXin LI * pipes filled 443b6cee71dSXin LI */ 444b6cee71dSXin LI switch (fork()) { 445b6cee71dSXin LI case 0: /* child */ 446b6cee71dSXin LI (void)close(fdout[0]); 447b6cee71dSXin LI if (swrite(fdin[1], old, n) != (ssize_t)n) { 448b6cee71dSXin LI #ifdef DEBUG 449b6cee71dSXin LI (void)fprintf(stderr, 450b6cee71dSXin LI "Write failed (%s)\n", 451b6cee71dSXin LI strerror(errno)); 452b6cee71dSXin LI #endif 453b6cee71dSXin LI exit(1); 454b6cee71dSXin LI } 455b6cee71dSXin LI exit(0); 456b6cee71dSXin LI /*NOTREACHED*/ 457b6cee71dSXin LI 458b6cee71dSXin LI case -1: 459b6cee71dSXin LI #ifdef DEBUG 460b6cee71dSXin LI (void)fprintf(stderr, "Fork failed (%s)\n", 461b6cee71dSXin LI strerror(errno)); 462b6cee71dSXin LI #endif 463b6cee71dSXin LI exit(1); 464b6cee71dSXin LI /*NOTREACHED*/ 465b6cee71dSXin LI 466b6cee71dSXin LI default: /* parent */ 467c2931133SXin LI if (wait(&status) == -1) { 468c2931133SXin LI #ifdef DEBUG 469c2931133SXin LI (void)fprintf(stderr, 470c2931133SXin LI "Wait failed (%s)\n", 471c2931133SXin LI strerror(errno)); 472c2931133SXin LI #endif 473c2931133SXin LI exit(1); 474c2931133SXin LI } 475c2931133SXin LI exit(WIFEXITED(status) ? 476c2931133SXin LI WEXITSTATUS(status) : 1); 477c2931133SXin LI /*NOTREACHED*/ 478b6cee71dSXin LI } 479b6cee71dSXin LI (void) close(fdin[1]); 480b6cee71dSXin LI fdin[1] = -1; 481b6cee71dSXin LI } 482b6cee71dSXin LI 483b6cee71dSXin LI if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) { 484b6cee71dSXin LI #ifdef DEBUG 485b6cee71dSXin LI (void)fprintf(stderr, "Malloc failed (%s)\n", 486b6cee71dSXin LI strerror(errno)); 487b6cee71dSXin LI #endif 488c2931133SXin LI n = NODATA; 489b6cee71dSXin LI goto err; 490b6cee71dSXin LI } 491b6cee71dSXin LI if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) { 492b6cee71dSXin LI #ifdef DEBUG 493b6cee71dSXin LI (void)fprintf(stderr, "Read failed (%s)\n", 494b6cee71dSXin LI strerror(errno)); 495b6cee71dSXin LI #endif 496b6cee71dSXin LI free(*newch); 497c2931133SXin LI n = NODATA; 498b6cee71dSXin LI *newch = NULL; 499b6cee71dSXin LI goto err; 500b6cee71dSXin LI } else { 501b6cee71dSXin LI n = r; 502b6cee71dSXin LI } 503b6cee71dSXin LI /* NUL terminate, as every buffer is handled here. */ 504b6cee71dSXin LI (*newch)[n] = '\0'; 505b6cee71dSXin LI err: 506b6cee71dSXin LI if (fdin[1] != -1) 507b6cee71dSXin LI (void) close(fdin[1]); 508b6cee71dSXin LI (void) close(fdout[0]); 509c2931133SXin LI if (wait(&status) == -1) { 510c2931133SXin LI #ifdef DEBUG 511c2931133SXin LI (void)fprintf(stderr, "Wait failed (%s)\n", 512c2931133SXin LI strerror(errno)); 513b6cee71dSXin LI #endif 514c2931133SXin LI n = NODATA; 515*4460e5b0SXin LI } else if (!WIFEXITED(status)) { 516c2931133SXin LI #ifdef DEBUG 517*4460e5b0SXin LI (void)fprintf(stderr, "Child not exited (0x%x)\n", 518*4460e5b0SXin LI status); 519c2931133SXin LI #endif 520*4460e5b0SXin LI } else if (WEXITSTATUS(status) != 0) { 521*4460e5b0SXin LI #ifdef DEBUG 522*4460e5b0SXin LI (void)fprintf(stderr, "Child exited (0x%d)\n", 523*4460e5b0SXin LI WEXITSTATUS(status)); 524*4460e5b0SXin LI #endif 525c2931133SXin LI } 526c2931133SXin LI 527b6cee71dSXin LI (void) close(fdin[0]); 528b6cee71dSXin LI 529b6cee71dSXin LI return n; 530b6cee71dSXin LI } 531b6cee71dSXin LI } 532b6cee71dSXin LI #endif 533