1/*- 2 * Copyright (c) 2007 Joerg Sonnenberger 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "archive_platform.h" 27 28/* This capability is only available on POSIX systems. */ 29#if defined(HAVE_PIPE) && defined(HAVE_FCNTL) && \ 30 (defined(HAVE_FORK) || defined(HAVE_VFORK)) 31 32__FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00Z kientzle $"); 33 34#if defined(HAVE_POLL) 35# if defined(HAVE_POLL_H) 36# include <poll.h> 37# elif defined(HAVE_SYS_POLL_H) 38# include <sys/poll.h> 39# endif 40#elif defined(HAVE_SELECT) 41# if defined(HAVE_SYS_SELECT_H) 42# include <sys/select.h> 43# elif defined(HAVE_UNISTD_H) 44# include <unistd.h> 45# endif 46#endif 47#ifdef HAVE_FCNTL_H 48# include <fcntl.h> 49#endif 50#ifdef HAVE_UNISTD_H 51# include <unistd.h> 52#endif 53 54#include "filter_fork.h" 55 56pid_t 57__archive_create_child(const char *path, int *child_stdin, int *child_stdout) 58{ 59 pid_t child; 60 int stdin_pipe[2], stdout_pipe[2], tmp; 61 62 if (pipe(stdin_pipe) == -1) 63 goto state_allocated; 64 if (stdin_pipe[0] == 1 /* stdout */) { 65 if ((tmp = dup(stdin_pipe[0])) == -1) 66 goto stdin_opened; 67 close(stdin_pipe[0]); 68 stdin_pipe[0] = tmp; 69 } 70 if (pipe(stdout_pipe) == -1) 71 goto stdin_opened; 72 if (stdout_pipe[1] == 0 /* stdin */) { 73 if ((tmp = dup(stdout_pipe[1])) == -1) 74 goto stdout_opened; 75 close(stdout_pipe[1]); 76 stdout_pipe[1] = tmp; 77 } 78 79#if HAVE_VFORK 80 switch ((child = vfork())) { 81#else 82 switch ((child = fork())) { 83#endif 84 case -1: 85 goto stdout_opened; 86 case 0: 87 close(stdin_pipe[1]); 88 close(stdout_pipe[0]); 89 if (dup2(stdin_pipe[0], 0 /* stdin */) == -1) 90 _exit(254); 91 if (stdin_pipe[0] != 0 /* stdin */) 92 close(stdin_pipe[0]); 93 if (dup2(stdout_pipe[1], 1 /* stdout */) == -1) 94 _exit(254); 95 if (stdout_pipe[1] != 1 /* stdout */) 96 close(stdout_pipe[1]); 97 execlp(path, path, (char *)NULL); 98 _exit(254); 99 default: 100 close(stdin_pipe[0]); 101 close(stdout_pipe[1]); 102 103 *child_stdin = stdin_pipe[1]; 104 fcntl(*child_stdin, F_SETFL, O_NONBLOCK); 105 *child_stdout = stdout_pipe[0]; 106 fcntl(*child_stdout, F_SETFL, O_NONBLOCK); 107 } 108 109 return child; 110 111stdout_opened: 112 close(stdout_pipe[0]); 113 close(stdout_pipe[1]); 114stdin_opened: 115 close(stdin_pipe[0]); 116 close(stdin_pipe[1]); 117state_allocated: 118 return -1; 119} 120 121void 122__archive_check_child(int in, int out) 123{ 124#if defined(HAVE_POLL) 125 struct pollfd fds[2]; 126 int idx; 127 128 idx = 0; 129 if (in != -1) { 130 fds[idx].fd = in; 131 fds[idx].events = POLLOUT; 132 ++idx; 133 } 134 if (out != -1) { 135 fds[idx].fd = out; 136 fds[idx].events = POLLIN; 137 ++idx; 138 } 139 140 poll(fds, idx, -1); /* -1 == INFTIM, wait forever */ 141#elif defined(HAVE_SELECT) 142 fd_set fds_in, fds_out, fds_error; 143 144 FD_ZERO(&fds_in); 145 FD_ZERO(&fds_out); 146 FD_ZERO(&fds_error); 147 if (out != -1) { 148 FD_SET(out, &fds_in); 149 FD_SET(out, &fds_error); 150 } 151 if (in != -1) { 152 FD_SET(in, &fds_out); 153 FD_SET(in, &fds_error); 154 } 155 select(in < out ? out + 1 : in + 1, &fds_in, &fds_out, &fds_error, NULL); 156#else 157 sleep(1); 158#endif 159} 160 161#endif /* defined(HAVE_PIPE) && defined(HAVE_VFORK) && defined(HAVE_FCNTL) */ 162