1248590Smm/*- 2248590Smm * Copyright (c) 2007 Joerg Sonnenberger 3248590Smm * Copyright (c) 2012 Michihiro NAKAJIMA 4248590Smm * All rights reserved. 5248590Smm * 6248590Smm * Redistribution and use in source and binary forms, with or without 7248590Smm * modification, are permitted provided that the following conditions 8248590Smm * are met: 9248590Smm * 1. Redistributions of source code must retain the above copyright 10248590Smm * notice, this list of conditions and the following disclaimer. 11248590Smm * 2. Redistributions in binary form must reproduce the above copyright 12248590Smm * notice, this list of conditions and the following disclaimer in the 13248590Smm * documentation and/or other materials provided with the distribution. 14248590Smm * 15248590Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16248590Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17248590Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18248590Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19248590Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20248590Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21248590Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22248590Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23248590Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24248590Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25248590Smm */ 26248590Smm 27248590Smm#include "archive_platform.h" 28248590Smm 29248590Smm/* This capability is only available on POSIX systems. */ 30248590Smm#if defined(HAVE_PIPE) && defined(HAVE_FCNTL) && \ 31248590Smm (defined(HAVE_FORK) || defined(HAVE_VFORK) || defined(HAVE_POSIX_SPAWNP)) 32248590Smm 33248590Smm__FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00Z kientzle $"); 34248590Smm 35248590Smm#if defined(HAVE_SYS_TYPES_H) 36248590Smm# include <sys/types.h> 37248590Smm#endif 38248590Smm#ifdef HAVE_ERRNO_H 39248590Smm# include <errno.h> 40248590Smm#endif 41248590Smm#ifdef HAVE_STRING_H 42248590Smm# include <string.h> 43248590Smm#endif 44248590Smm#if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)) 45248590Smm# if defined(HAVE_POLL_H) 46248590Smm# include <poll.h> 47248590Smm# elif defined(HAVE_SYS_POLL_H) 48248590Smm# include <sys/poll.h> 49248590Smm# endif 50248590Smm#elif defined(HAVE_SELECT) 51248590Smm# if defined(HAVE_SYS_SELECT_H) 52248590Smm# include <sys/select.h> 53248590Smm# elif defined(HAVE_UNISTD_H) 54248590Smm# include <unistd.h> 55248590Smm# endif 56248590Smm#endif 57248590Smm#ifdef HAVE_FCNTL_H 58248590Smm# include <fcntl.h> 59248590Smm#endif 60248590Smm#ifdef HAVE_SPAWN_H 61248590Smm# include <spawn.h> 62248590Smm#endif 63248590Smm#ifdef HAVE_STDLIB_H 64248590Smm# include <stdlib.h> 65248590Smm#endif 66248590Smm#ifdef HAVE_UNISTD_H 67248590Smm# include <unistd.h> 68248590Smm#endif 69248590Smm 70248590Smm#include "archive.h" 71248590Smm#include "archive_cmdline_private.h" 72248590Smm 73248590Smm#include "filter_fork.h" 74248590Smm 75248590Smmpid_t 76248590Smm__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout) 77248590Smm{ 78248590Smm pid_t child; 79248590Smm int stdin_pipe[2], stdout_pipe[2], tmp; 80248590Smm#if HAVE_POSIX_SPAWNP 81248590Smm posix_spawn_file_actions_t actions; 82248590Smm int r; 83248590Smm#endif 84248590Smm struct archive_cmdline *cmdline; 85248590Smm 86248590Smm cmdline = __archive_cmdline_allocate(); 87248590Smm if (cmdline == NULL) 88248590Smm goto state_allocated; 89248590Smm if (__archive_cmdline_parse(cmdline, cmd) != ARCHIVE_OK) 90248590Smm goto state_allocated; 91248590Smm 92248590Smm if (pipe(stdin_pipe) == -1) 93248590Smm goto state_allocated; 94248590Smm if (stdin_pipe[0] == 1 /* stdout */) { 95248590Smm if ((tmp = dup(stdin_pipe[0])) == -1) 96248590Smm goto stdin_opened; 97248590Smm close(stdin_pipe[0]); 98248590Smm stdin_pipe[0] = tmp; 99248590Smm } 100248590Smm if (pipe(stdout_pipe) == -1) 101248590Smm goto stdin_opened; 102248590Smm if (stdout_pipe[1] == 0 /* stdin */) { 103248590Smm if ((tmp = dup(stdout_pipe[1])) == -1) 104248590Smm goto stdout_opened; 105248590Smm close(stdout_pipe[1]); 106248590Smm stdout_pipe[1] = tmp; 107248590Smm } 108248590Smm 109248590Smm#if HAVE_POSIX_SPAWNP 110248590Smm 111248590Smm r = posix_spawn_file_actions_init(&actions); 112248590Smm if (r != 0) { 113248590Smm errno = r; 114248590Smm goto stdout_opened; 115248590Smm } 116248590Smm r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[1]); 117248590Smm if (r != 0) 118248590Smm goto actions_inited; 119248590Smm r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[0]); 120248590Smm if (r != 0) 121248590Smm goto actions_inited; 122248590Smm /* Setup for stdin. */ 123248590Smm r = posix_spawn_file_actions_adddup2(&actions, stdin_pipe[0], 0); 124248590Smm if (r != 0) 125248590Smm goto actions_inited; 126248590Smm if (stdin_pipe[0] != 0 /* stdin */) { 127248590Smm r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[0]); 128248590Smm if (r != 0) 129248590Smm goto actions_inited; 130248590Smm } 131248590Smm /* Setup for stdout. */ 132248590Smm r = posix_spawn_file_actions_adddup2(&actions, stdout_pipe[1], 1); 133248590Smm if (r != 0) 134248590Smm goto actions_inited; 135248590Smm if (stdout_pipe[1] != 1 /* stdout */) { 136248590Smm r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[1]); 137248590Smm if (r != 0) 138248590Smm goto actions_inited; 139248590Smm } 140248590Smm r = posix_spawnp(&child, cmdline->path, &actions, NULL, 141248590Smm cmdline->argv, NULL); 142248590Smm if (r != 0) 143248590Smm goto actions_inited; 144248590Smm posix_spawn_file_actions_destroy(&actions); 145248590Smm 146248590Smm#else /* HAVE_POSIX_SPAWNP */ 147248590Smm 148248590Smm#if HAVE_VFORK 149248590Smm child = vfork(); 150248590Smm#else 151248590Smm child = fork(); 152248590Smm#endif 153248590Smm if (child == -1) 154248590Smm goto stdout_opened; 155248590Smm if (child == 0) { 156248590Smm close(stdin_pipe[1]); 157248590Smm close(stdout_pipe[0]); 158248590Smm if (dup2(stdin_pipe[0], 0 /* stdin */) == -1) 159248590Smm _exit(254); 160248590Smm if (stdin_pipe[0] != 0 /* stdin */) 161248590Smm close(stdin_pipe[0]); 162248590Smm if (dup2(stdout_pipe[1], 1 /* stdout */) == -1) 163248590Smm _exit(254); 164248590Smm if (stdout_pipe[1] != 1 /* stdout */) 165248590Smm close(stdout_pipe[1]); 166248590Smm execvp(cmdline->path, cmdline->argv); 167248590Smm _exit(254); 168248590Smm } 169248590Smm#endif /* HAVE_POSIX_SPAWNP */ 170248590Smm 171248590Smm close(stdin_pipe[0]); 172248590Smm close(stdout_pipe[1]); 173248590Smm 174248590Smm *child_stdin = stdin_pipe[1]; 175248590Smm fcntl(*child_stdin, F_SETFL, O_NONBLOCK); 176248590Smm *child_stdout = stdout_pipe[0]; 177248590Smm fcntl(*child_stdout, F_SETFL, O_NONBLOCK); 178248590Smm __archive_cmdline_free(cmdline); 179248590Smm 180248590Smm return child; 181248590Smm 182248590Smm#if HAVE_POSIX_SPAWNP 183248590Smmactions_inited: 184248590Smm errno = r; 185248590Smm posix_spawn_file_actions_destroy(&actions); 186248590Smm#endif 187248590Smmstdout_opened: 188248590Smm close(stdout_pipe[0]); 189248590Smm close(stdout_pipe[1]); 190248590Smmstdin_opened: 191248590Smm close(stdin_pipe[0]); 192248590Smm close(stdin_pipe[1]); 193248590Smmstate_allocated: 194248590Smm __archive_cmdline_free(cmdline); 195248590Smm return -1; 196248590Smm} 197248590Smm 198248590Smmvoid 199248590Smm__archive_check_child(int in, int out) 200248590Smm{ 201248590Smm#if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)) 202248590Smm struct pollfd fds[2]; 203248590Smm int idx; 204248590Smm 205248590Smm idx = 0; 206248590Smm if (in != -1) { 207248590Smm fds[idx].fd = in; 208248590Smm fds[idx].events = POLLOUT; 209248590Smm ++idx; 210248590Smm } 211248590Smm if (out != -1) { 212248590Smm fds[idx].fd = out; 213248590Smm fds[idx].events = POLLIN; 214248590Smm ++idx; 215248590Smm } 216248590Smm 217248590Smm poll(fds, idx, -1); /* -1 == INFTIM, wait forever */ 218248590Smm#elif defined(HAVE_SELECT) 219248590Smm fd_set fds_in, fds_out, fds_error; 220248590Smm 221248590Smm FD_ZERO(&fds_in); 222248590Smm FD_ZERO(&fds_out); 223248590Smm FD_ZERO(&fds_error); 224248590Smm if (out != -1) { 225248590Smm FD_SET(out, &fds_in); 226248590Smm FD_SET(out, &fds_error); 227248590Smm } 228248590Smm if (in != -1) { 229248590Smm FD_SET(in, &fds_out); 230248590Smm FD_SET(in, &fds_error); 231248590Smm } 232248590Smm select(in < out ? out + 1 : in + 1, &fds_in, &fds_out, &fds_error, NULL); 233248590Smm#else 234248590Smm sleep(1); 235248590Smm#endif 236248590Smm} 237248590Smm 238248590Smm#endif /* defined(HAVE_PIPE) && defined(HAVE_VFORK) && defined(HAVE_FCNTL) */ 239