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