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*5f0216bdSXin LI FILE_RCSID("@(#)$File: compress.c,v 1.80 2015/06/03 18:21:24 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*5f0216bdSXin LI #ifdef HAVE_SIGNAL_H 494460e5b0SXin LI #include <signal.h> 50*5f0216bdSXin LI # ifndef HAVE_SIG_T 51*5f0216bdSXin LI typedef void (*sig_t)(int); 52*5f0216bdSXin LI # endif /* HAVE_SIG_T */ 53*5f0216bdSXin LI #endif 54c2931133SXin LI #if !defined(__MINGW32__) && !defined(WIN32) 55b6cee71dSXin LI #include <sys/ioctl.h> 56b6cee71dSXin LI #endif 57b6cee71dSXin LI #ifdef HAVE_SYS_WAIT_H 58b6cee71dSXin LI #include <sys/wait.h> 59b6cee71dSXin LI #endif 60b6cee71dSXin LI #if defined(HAVE_SYS_TIME_H) 61b6cee71dSXin LI #include <sys/time.h> 62b6cee71dSXin LI #endif 63b6cee71dSXin LI #if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) 64b6cee71dSXin LI #define BUILTIN_DECOMPRESS 65b6cee71dSXin LI #include <zlib.h> 66b6cee71dSXin LI #endif 67b6cee71dSXin LI 68b6cee71dSXin LI private const struct { 69b6cee71dSXin LI const char magic[8]; 70b6cee71dSXin LI size_t maglen; 71b6cee71dSXin LI const char *argv[3]; 72b6cee71dSXin LI int silent; 73b6cee71dSXin LI } compr[] = { 74b6cee71dSXin LI { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 }, /* compressed */ 75b6cee71dSXin LI /* Uncompress can get stuck; so use gzip first if we have it 76b6cee71dSXin LI * Idea from Damien Clark, thanks! */ 77b6cee71dSXin LI { "\037\235", 2, { "uncompress", "-c", NULL }, 1 }, /* compressed */ 78b6cee71dSXin LI { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 }, /* gzipped */ 79b6cee71dSXin LI { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 }, /* frozen */ 80b6cee71dSXin LI { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */ 81b6cee71dSXin LI /* the standard pack utilities do not accept standard input */ 82b6cee71dSXin LI { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 }, /* packed */ 83b6cee71dSXin LI { "PK\3\4", 4, { "gzip", "-cdq", NULL }, 1 }, /* pkzipped, */ 84b6cee71dSXin LI /* ...only first file examined */ 85b6cee71dSXin LI { "BZh", 3, { "bzip2", "-cd", NULL }, 1 }, /* bzip2-ed */ 86b6cee71dSXin LI { "LZIP", 4, { "lzip", "-cdq", NULL }, 1 }, 87b6cee71dSXin LI { "\3757zXZ\0",6,{ "xz", "-cd", NULL }, 1 }, /* XZ Utils */ 88b6cee71dSXin LI { "LRZI", 4, { "lrzip", "-dqo-", NULL }, 1 }, /* LRZIP */ 89b6cee71dSXin LI { "\004\"M\030", 4, { "lz4", "-cd", NULL }, 1 }, /* LZ4 */ 90b6cee71dSXin LI }; 91b6cee71dSXin LI 92b6cee71dSXin LI #define NODATA ((size_t)~0) 93b6cee71dSXin LI 94b6cee71dSXin LI private ssize_t swrite(int, const void *, size_t); 95b6cee71dSXin LI #if HAVE_FORK 96b6cee71dSXin LI private size_t ncompr = sizeof(compr) / sizeof(compr[0]); 97b6cee71dSXin LI private size_t uncompressbuf(struct magic_set *, int, size_t, 98b6cee71dSXin LI const unsigned char *, unsigned char **, size_t); 99b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 100b6cee71dSXin LI private size_t uncompressgzipped(struct magic_set *, const unsigned char *, 101b6cee71dSXin LI unsigned char **, size_t); 102b6cee71dSXin LI #endif 103b6cee71dSXin LI 104b6cee71dSXin LI protected int 105b6cee71dSXin LI file_zmagic(struct magic_set *ms, int fd, const char *name, 106b6cee71dSXin LI const unsigned char *buf, size_t nbytes) 107b6cee71dSXin LI { 108b6cee71dSXin LI unsigned char *newbuf = NULL; 109b6cee71dSXin LI size_t i, nsz; 110b6cee71dSXin LI int rv = 0; 111b6cee71dSXin LI int mime = ms->flags & MAGIC_MIME; 112*5f0216bdSXin LI #ifdef HAVE_SIGNAL_H 1134460e5b0SXin LI sig_t osigpipe; 114*5f0216bdSXin LI #endif 115b6cee71dSXin LI 116b6cee71dSXin LI if ((ms->flags & MAGIC_COMPRESS) == 0) 117b6cee71dSXin LI return 0; 118b6cee71dSXin LI 119*5f0216bdSXin LI #ifdef HAVE_SIGNAL_H 1204460e5b0SXin LI osigpipe = signal(SIGPIPE, SIG_IGN); 121*5f0216bdSXin LI #endif 122b6cee71dSXin LI for (i = 0; i < ncompr; i++) { 123b6cee71dSXin LI if (nbytes < compr[i].maglen) 124b6cee71dSXin LI continue; 125b6cee71dSXin LI if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 && 126b6cee71dSXin LI (nsz = uncompressbuf(ms, fd, i, buf, &newbuf, 127b6cee71dSXin LI nbytes)) != NODATA) { 128b6cee71dSXin LI ms->flags &= ~MAGIC_COMPRESS; 129b6cee71dSXin LI rv = -1; 130b6cee71dSXin LI if (file_buffer(ms, -1, name, newbuf, nsz) == -1) 131b6cee71dSXin LI goto error; 132b6cee71dSXin LI 133*5f0216bdSXin LI if ((ms->flags & MAGIC_COMPRESS_TRANSP) == 0 && 134*5f0216bdSXin LI (mime == MAGIC_MIME || mime == 0)) { 135b6cee71dSXin LI if (file_printf(ms, mime ? 136b6cee71dSXin LI " compressed-encoding=" : " (") == -1) 137b6cee71dSXin LI goto error; 138b6cee71dSXin LI if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) 139b6cee71dSXin LI goto error; 140b6cee71dSXin LI if (!mime && file_printf(ms, ")") == -1) 141b6cee71dSXin LI goto error; 142b6cee71dSXin LI } 143b6cee71dSXin LI 144b6cee71dSXin LI rv = 1; 145b6cee71dSXin LI break; 146b6cee71dSXin LI } 147b6cee71dSXin LI } 148b6cee71dSXin LI error: 149*5f0216bdSXin LI #ifdef HAVE_SIGNAL_H 1504460e5b0SXin LI (void)signal(SIGPIPE, osigpipe); 151*5f0216bdSXin LI #endif 152b6cee71dSXin LI free(newbuf); 153b6cee71dSXin LI ms->flags |= MAGIC_COMPRESS; 154b6cee71dSXin LI return rv; 155b6cee71dSXin LI } 156b6cee71dSXin LI #endif 157b6cee71dSXin LI /* 158b6cee71dSXin LI * `safe' write for sockets and pipes. 159b6cee71dSXin LI */ 160b6cee71dSXin LI private ssize_t 161b6cee71dSXin LI swrite(int fd, const void *buf, size_t n) 162b6cee71dSXin LI { 163b6cee71dSXin LI ssize_t rv; 164b6cee71dSXin LI size_t rn = n; 165b6cee71dSXin LI 166b6cee71dSXin LI do 167b6cee71dSXin LI switch (rv = write(fd, buf, n)) { 168b6cee71dSXin LI case -1: 169b6cee71dSXin LI if (errno == EINTR) 170b6cee71dSXin LI continue; 171b6cee71dSXin LI return -1; 172b6cee71dSXin LI default: 173b6cee71dSXin LI n -= rv; 174b6cee71dSXin LI buf = CAST(const char *, buf) + rv; 175b6cee71dSXin LI break; 176b6cee71dSXin LI } 177b6cee71dSXin LI while (n > 0); 178b6cee71dSXin LI return rn; 179b6cee71dSXin LI } 180b6cee71dSXin LI 181b6cee71dSXin LI 182b6cee71dSXin LI /* 183b6cee71dSXin LI * `safe' read for sockets and pipes. 184b6cee71dSXin LI */ 185b6cee71dSXin LI protected ssize_t 186b6cee71dSXin LI sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) 187b6cee71dSXin LI { 188b6cee71dSXin LI ssize_t rv; 189b6cee71dSXin LI #ifdef FIONREAD 190b6cee71dSXin LI int t = 0; 191b6cee71dSXin LI #endif 192b6cee71dSXin LI size_t rn = n; 193b6cee71dSXin LI 194b6cee71dSXin LI if (fd == STDIN_FILENO) 195b6cee71dSXin LI goto nocheck; 196b6cee71dSXin LI 197b6cee71dSXin LI #ifdef FIONREAD 198b6cee71dSXin LI if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { 199b6cee71dSXin LI #ifdef FD_ZERO 200b6cee71dSXin LI ssize_t cnt; 201b6cee71dSXin LI for (cnt = 0;; cnt++) { 202b6cee71dSXin LI fd_set check; 203b6cee71dSXin LI struct timeval tout = {0, 100 * 1000}; 204b6cee71dSXin LI int selrv; 205b6cee71dSXin LI 206b6cee71dSXin LI FD_ZERO(&check); 207b6cee71dSXin LI FD_SET(fd, &check); 208b6cee71dSXin LI 209b6cee71dSXin LI /* 210b6cee71dSXin LI * Avoid soft deadlock: do not read if there 211b6cee71dSXin LI * is nothing to read from sockets and pipes. 212b6cee71dSXin LI */ 213b6cee71dSXin LI selrv = select(fd + 1, &check, NULL, NULL, &tout); 214b6cee71dSXin LI if (selrv == -1) { 215b6cee71dSXin LI if (errno == EINTR || errno == EAGAIN) 216b6cee71dSXin LI continue; 217b6cee71dSXin LI } else if (selrv == 0 && cnt >= 5) { 218b6cee71dSXin LI return 0; 219b6cee71dSXin LI } else 220b6cee71dSXin LI break; 221b6cee71dSXin LI } 222b6cee71dSXin LI #endif 223b6cee71dSXin LI (void)ioctl(fd, FIONREAD, &t); 224b6cee71dSXin LI } 225b6cee71dSXin LI 226b6cee71dSXin LI if (t > 0 && (size_t)t < n) { 227b6cee71dSXin LI n = t; 228b6cee71dSXin LI rn = n; 229b6cee71dSXin LI } 230b6cee71dSXin LI #endif 231b6cee71dSXin LI 232b6cee71dSXin LI nocheck: 233b6cee71dSXin LI do 234b6cee71dSXin LI switch ((rv = read(fd, buf, n))) { 235b6cee71dSXin LI case -1: 236b6cee71dSXin LI if (errno == EINTR) 237b6cee71dSXin LI continue; 238b6cee71dSXin LI return -1; 239b6cee71dSXin LI case 0: 240b6cee71dSXin LI return rn - n; 241b6cee71dSXin LI default: 242b6cee71dSXin LI n -= rv; 243b6cee71dSXin LI buf = ((char *)buf) + rv; 244b6cee71dSXin LI break; 245b6cee71dSXin LI } 246b6cee71dSXin LI while (n > 0); 247b6cee71dSXin LI return rn; 248b6cee71dSXin LI } 249b6cee71dSXin LI 250b6cee71dSXin LI protected int 251b6cee71dSXin LI file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, 252b6cee71dSXin LI size_t nbytes) 253b6cee71dSXin LI { 254b6cee71dSXin LI char buf[4096]; 255b6cee71dSXin LI ssize_t r; 256b6cee71dSXin LI int tfd; 257b6cee71dSXin LI 258b6cee71dSXin LI (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); 259b6cee71dSXin LI #ifndef HAVE_MKSTEMP 260b6cee71dSXin LI { 261b6cee71dSXin LI char *ptr = mktemp(buf); 262b6cee71dSXin LI tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); 263b6cee71dSXin LI r = errno; 264b6cee71dSXin LI (void)unlink(ptr); 265b6cee71dSXin LI errno = r; 266b6cee71dSXin LI } 267b6cee71dSXin LI #else 268b6cee71dSXin LI { 269b6cee71dSXin LI int te; 270b6cee71dSXin LI tfd = mkstemp(buf); 271b6cee71dSXin LI te = errno; 272b6cee71dSXin LI (void)unlink(buf); 273b6cee71dSXin LI errno = te; 274b6cee71dSXin LI } 275b6cee71dSXin LI #endif 276b6cee71dSXin LI if (tfd == -1) { 277b6cee71dSXin LI file_error(ms, errno, 278b6cee71dSXin LI "cannot create temporary file for pipe copy"); 279b6cee71dSXin LI return -1; 280b6cee71dSXin LI } 281b6cee71dSXin LI 282b6cee71dSXin LI if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes) 283b6cee71dSXin LI r = 1; 284b6cee71dSXin LI else { 285b6cee71dSXin LI while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) 286b6cee71dSXin LI if (swrite(tfd, buf, (size_t)r) != r) 287b6cee71dSXin LI break; 288b6cee71dSXin LI } 289b6cee71dSXin LI 290b6cee71dSXin LI switch (r) { 291b6cee71dSXin LI case -1: 292b6cee71dSXin LI file_error(ms, errno, "error copying from pipe to temp file"); 293b6cee71dSXin LI return -1; 294b6cee71dSXin LI case 0: 295b6cee71dSXin LI break; 296b6cee71dSXin LI default: 297b6cee71dSXin LI file_error(ms, errno, "error while writing to temp file"); 298b6cee71dSXin LI return -1; 299b6cee71dSXin LI } 300b6cee71dSXin LI 301b6cee71dSXin LI /* 302b6cee71dSXin LI * We duplicate the file descriptor, because fclose on a 303b6cee71dSXin LI * tmpfile will delete the file, but any open descriptors 304b6cee71dSXin LI * can still access the phantom inode. 305b6cee71dSXin LI */ 306b6cee71dSXin LI if ((fd = dup2(tfd, fd)) == -1) { 307b6cee71dSXin LI file_error(ms, errno, "could not dup descriptor for temp file"); 308b6cee71dSXin LI return -1; 309b6cee71dSXin LI } 310b6cee71dSXin LI (void)close(tfd); 311b6cee71dSXin LI if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 312b6cee71dSXin LI file_badseek(ms); 313b6cee71dSXin LI return -1; 314b6cee71dSXin LI } 315b6cee71dSXin LI return fd; 316b6cee71dSXin LI } 317b6cee71dSXin LI #if HAVE_FORK 318b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 319b6cee71dSXin LI 320b6cee71dSXin LI #define FHCRC (1 << 1) 321b6cee71dSXin LI #define FEXTRA (1 << 2) 322b6cee71dSXin LI #define FNAME (1 << 3) 323b6cee71dSXin LI #define FCOMMENT (1 << 4) 324b6cee71dSXin LI 325b6cee71dSXin LI private size_t 326b6cee71dSXin LI uncompressgzipped(struct magic_set *ms, const unsigned char *old, 327b6cee71dSXin LI unsigned char **newch, size_t n) 328b6cee71dSXin LI { 329b6cee71dSXin LI unsigned char flg = old[3]; 330b6cee71dSXin LI size_t data_start = 10; 331b6cee71dSXin LI z_stream z; 332b6cee71dSXin LI int rc; 333b6cee71dSXin LI 334b6cee71dSXin LI if (flg & FEXTRA) { 335b6cee71dSXin LI if (data_start+1 >= n) 336b6cee71dSXin LI return 0; 337b6cee71dSXin LI data_start += 2 + old[data_start] + old[data_start + 1] * 256; 338b6cee71dSXin LI } 339b6cee71dSXin LI if (flg & FNAME) { 340b6cee71dSXin LI while(data_start < n && old[data_start]) 341b6cee71dSXin LI data_start++; 342b6cee71dSXin LI data_start++; 343b6cee71dSXin LI } 344b6cee71dSXin LI if(flg & FCOMMENT) { 345b6cee71dSXin LI while(data_start < n && old[data_start]) 346b6cee71dSXin LI data_start++; 347b6cee71dSXin LI data_start++; 348b6cee71dSXin LI } 349b6cee71dSXin LI if(flg & FHCRC) 350b6cee71dSXin LI data_start += 2; 351b6cee71dSXin LI 352b6cee71dSXin LI if (data_start >= n) 353b6cee71dSXin LI return 0; 354b6cee71dSXin LI if ((*newch = CAST(unsigned char *, malloc(HOWMANY + 1))) == NULL) { 355b6cee71dSXin LI return 0; 356b6cee71dSXin LI } 357b6cee71dSXin LI 358b6cee71dSXin LI /* XXX: const castaway, via strchr */ 359b6cee71dSXin LI z.next_in = (Bytef *)strchr((const char *)old + data_start, 360b6cee71dSXin LI old[data_start]); 361b6cee71dSXin LI z.avail_in = CAST(uint32_t, (n - data_start)); 362b6cee71dSXin LI z.next_out = *newch; 363b6cee71dSXin LI z.avail_out = HOWMANY; 364b6cee71dSXin LI z.zalloc = Z_NULL; 365b6cee71dSXin LI z.zfree = Z_NULL; 366b6cee71dSXin LI z.opaque = Z_NULL; 367b6cee71dSXin LI 368b6cee71dSXin LI /* LINTED bug in header macro */ 369b6cee71dSXin LI rc = inflateInit2(&z, -15); 370b6cee71dSXin LI if (rc != Z_OK) { 371b6cee71dSXin LI file_error(ms, 0, "zlib: %s", z.msg); 372b6cee71dSXin LI return 0; 373b6cee71dSXin LI } 374b6cee71dSXin LI 375b6cee71dSXin LI rc = inflate(&z, Z_SYNC_FLUSH); 376b6cee71dSXin LI if (rc != Z_OK && rc != Z_STREAM_END) { 377b6cee71dSXin LI file_error(ms, 0, "zlib: %s", z.msg); 378b6cee71dSXin LI return 0; 379b6cee71dSXin LI } 380b6cee71dSXin LI 381b6cee71dSXin LI n = (size_t)z.total_out; 382b6cee71dSXin LI (void)inflateEnd(&z); 383b6cee71dSXin LI 384b6cee71dSXin LI /* let's keep the nul-terminate tradition */ 385b6cee71dSXin LI (*newch)[n] = '\0'; 386b6cee71dSXin LI 387b6cee71dSXin LI return n; 388b6cee71dSXin LI } 389b6cee71dSXin LI #endif 390b6cee71dSXin LI 391b6cee71dSXin LI private size_t 392b6cee71dSXin LI uncompressbuf(struct magic_set *ms, int fd, size_t method, 393b6cee71dSXin LI const unsigned char *old, unsigned char **newch, size_t n) 394b6cee71dSXin LI { 395b6cee71dSXin LI int fdin[2], fdout[2]; 396c2931133SXin LI int status; 397b6cee71dSXin LI ssize_t r; 398b6cee71dSXin LI 399b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 400b6cee71dSXin LI /* FIXME: This doesn't cope with bzip2 */ 401b6cee71dSXin LI if (method == 2) 402b6cee71dSXin LI return uncompressgzipped(ms, old, newch, n); 403b6cee71dSXin LI #endif 404b6cee71dSXin LI (void)fflush(stdout); 405b6cee71dSXin LI (void)fflush(stderr); 406b6cee71dSXin LI 407b6cee71dSXin LI if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) { 408b6cee71dSXin LI file_error(ms, errno, "cannot create pipe"); 409b6cee71dSXin LI return NODATA; 410b6cee71dSXin LI } 411*5f0216bdSXin LI switch (fork()) { 412b6cee71dSXin LI case 0: /* child */ 413b6cee71dSXin LI (void) close(0); 414b6cee71dSXin LI if (fd != -1) { 415b6cee71dSXin LI if (dup(fd) == -1) 416b6cee71dSXin LI _exit(1); 417b6cee71dSXin LI (void) lseek(0, (off_t)0, SEEK_SET); 418b6cee71dSXin LI } else { 419b6cee71dSXin LI if (dup(fdin[0]) == -1) 420b6cee71dSXin LI _exit(1); 421b6cee71dSXin LI (void) close(fdin[0]); 422b6cee71dSXin LI (void) close(fdin[1]); 423b6cee71dSXin LI } 424b6cee71dSXin LI 425b6cee71dSXin LI (void) close(1); 426b6cee71dSXin LI if (dup(fdout[1]) == -1) 427b6cee71dSXin LI _exit(1); 428b6cee71dSXin LI (void) close(fdout[0]); 429b6cee71dSXin LI (void) close(fdout[1]); 430b6cee71dSXin LI #ifndef DEBUG 431b6cee71dSXin LI if (compr[method].silent) 432b6cee71dSXin LI (void)close(2); 433b6cee71dSXin LI #endif 434b6cee71dSXin LI 435b6cee71dSXin LI (void)execvp(compr[method].argv[0], 436b6cee71dSXin LI (char *const *)(intptr_t)compr[method].argv); 437b6cee71dSXin LI #ifdef DEBUG 438b6cee71dSXin LI (void)fprintf(stderr, "exec `%s' failed (%s)\n", 439b6cee71dSXin LI compr[method].argv[0], strerror(errno)); 440b6cee71dSXin LI #endif 441b6cee71dSXin LI exit(1); 442b6cee71dSXin LI /*NOTREACHED*/ 443b6cee71dSXin LI case -1: 444b6cee71dSXin LI file_error(ms, errno, "could not fork"); 445b6cee71dSXin LI return NODATA; 446b6cee71dSXin LI 447b6cee71dSXin LI default: /* parent */ 448b6cee71dSXin LI (void) close(fdout[1]); 449b6cee71dSXin LI if (fd == -1) { 450b6cee71dSXin LI (void) close(fdin[0]); 451b6cee71dSXin LI /* 452b6cee71dSXin LI * fork again, to avoid blocking because both 453b6cee71dSXin LI * pipes filled 454b6cee71dSXin LI */ 455b6cee71dSXin LI switch (fork()) { 456b6cee71dSXin LI case 0: /* child */ 457b6cee71dSXin LI (void)close(fdout[0]); 458b6cee71dSXin LI if (swrite(fdin[1], old, n) != (ssize_t)n) { 459b6cee71dSXin LI #ifdef DEBUG 460b6cee71dSXin LI (void)fprintf(stderr, 461b6cee71dSXin LI "Write failed (%s)\n", 462b6cee71dSXin LI strerror(errno)); 463b6cee71dSXin LI #endif 464b6cee71dSXin LI exit(1); 465b6cee71dSXin LI } 466b6cee71dSXin LI exit(0); 467b6cee71dSXin LI /*NOTREACHED*/ 468b6cee71dSXin LI 469b6cee71dSXin LI case -1: 470b6cee71dSXin LI #ifdef DEBUG 471b6cee71dSXin LI (void)fprintf(stderr, "Fork failed (%s)\n", 472b6cee71dSXin LI strerror(errno)); 473b6cee71dSXin LI #endif 474b6cee71dSXin LI exit(1); 475b6cee71dSXin LI /*NOTREACHED*/ 476b6cee71dSXin LI 477b6cee71dSXin LI default: /* parent */ 478c2931133SXin LI if (wait(&status) == -1) { 479c2931133SXin LI #ifdef DEBUG 480c2931133SXin LI (void)fprintf(stderr, 481c2931133SXin LI "Wait failed (%s)\n", 482c2931133SXin LI strerror(errno)); 483c2931133SXin LI #endif 484c2931133SXin LI exit(1); 485c2931133SXin LI } 486c2931133SXin LI exit(WIFEXITED(status) ? 487c2931133SXin LI WEXITSTATUS(status) : 1); 488c2931133SXin LI /*NOTREACHED*/ 489b6cee71dSXin LI } 490b6cee71dSXin LI (void) close(fdin[1]); 491b6cee71dSXin LI fdin[1] = -1; 492b6cee71dSXin LI } 493b6cee71dSXin LI 494b6cee71dSXin LI if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) { 495b6cee71dSXin LI #ifdef DEBUG 496b6cee71dSXin LI (void)fprintf(stderr, "Malloc failed (%s)\n", 497b6cee71dSXin LI strerror(errno)); 498b6cee71dSXin LI #endif 499c2931133SXin LI n = NODATA; 500b6cee71dSXin LI goto err; 501b6cee71dSXin LI } 502b6cee71dSXin LI if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) { 503b6cee71dSXin LI #ifdef DEBUG 504b6cee71dSXin LI (void)fprintf(stderr, "Read failed (%s)\n", 505b6cee71dSXin LI strerror(errno)); 506b6cee71dSXin LI #endif 507b6cee71dSXin LI free(*newch); 508c2931133SXin LI n = NODATA; 509b6cee71dSXin LI *newch = NULL; 510b6cee71dSXin LI goto err; 511b6cee71dSXin LI } else { 512b6cee71dSXin LI n = r; 513b6cee71dSXin LI } 514b6cee71dSXin LI /* NUL terminate, as every buffer is handled here. */ 515b6cee71dSXin LI (*newch)[n] = '\0'; 516b6cee71dSXin LI err: 517b6cee71dSXin LI if (fdin[1] != -1) 518b6cee71dSXin LI (void) close(fdin[1]); 519b6cee71dSXin LI (void) close(fdout[0]); 520c2931133SXin LI if (wait(&status) == -1) { 521c2931133SXin LI #ifdef DEBUG 522c2931133SXin LI (void)fprintf(stderr, "Wait failed (%s)\n", 523c2931133SXin LI strerror(errno)); 524b6cee71dSXin LI #endif 525c2931133SXin LI n = NODATA; 5264460e5b0SXin LI } else if (!WIFEXITED(status)) { 527c2931133SXin LI #ifdef DEBUG 5284460e5b0SXin LI (void)fprintf(stderr, "Child not exited (0x%x)\n", 5294460e5b0SXin LI status); 530c2931133SXin LI #endif 5314460e5b0SXin LI } else if (WEXITSTATUS(status) != 0) { 5324460e5b0SXin LI #ifdef DEBUG 5334460e5b0SXin LI (void)fprintf(stderr, "Child exited (0x%d)\n", 5344460e5b0SXin LI WEXITSTATUS(status)); 5354460e5b0SXin LI #endif 536c2931133SXin LI } 537c2931133SXin LI 538b6cee71dSXin LI (void) close(fdin[0]); 539b6cee71dSXin LI 540b6cee71dSXin LI return n; 541b6cee71dSXin LI } 542b6cee71dSXin LI } 543b6cee71dSXin LI #endif 544