1/* 2* Copyright 2010, Haiku. All rights reserved. 3* Distributed under the terms of the MIT License. 4* 5* Authors: 6* Ithamar R. Adema <ithamar.adema@team-embedded.nl> 7*/ 8 9 10#include "FilterIO.h" 11 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15 16#include <image.h> 17 18#include <String.h> 19 20 21FilterIO::FilterIO(const BString& cmdline) 22 : 23 BDataIO() 24{ 25 BString cmd(cmdline); 26 const char* argv[4]; 27 28 argv[0] = strdup("/bin/sh"); 29 argv[1] = strdup("-c"); 30 argv[2] = strdup(cmd.String()); 31 argv[3] = NULL; 32 33 InitData(3, argv); 34 35 free((void*)argv[0]); 36 free((void*)argv[1]); 37 free((void*)argv[2]); 38} 39 40 41FilterIO::FilterIO(int argc, const char **argv, const char **envp) 42 : 43 BDataIO() 44{ 45 InitData(argc, argv, envp); 46} 47 48 49status_t 50FilterIO::InitData(int argc, const char** argv, const char** envp) 51{ 52 fStdIn = fStdOut = fStdErr = -1; 53 fInitErr = B_OK; 54 55 fThreadId = PipeCommand(argc, argv, fStdIn, fStdOut, fStdErr, envp); 56 if (fThreadId < 0) 57 fInitErr = fThreadId; 58 59 // lower the command priority since it is a background task. 60 set_thread_priority(fThreadId, B_LOW_PRIORITY); 61 resume_thread(fThreadId); 62 63 return fInitErr; 64} 65 66 67FilterIO::~FilterIO() 68{ 69 ::close(fStdIn); 70 ::close(fStdOut); 71 ::close(fStdErr); 72} 73 74 75ssize_t 76FilterIO::Read(void* buffer, size_t size) 77{ 78 return ::read(fStdOut, buffer, size); 79} 80 81 82ssize_t 83FilterIO::Write(const void* buffer, size_t size) 84{ 85 return ::write(fStdIn, buffer, size); 86} 87 88 89thread_id 90FilterIO::PipeCommand(int argc, const char** argv, int& in, int& out, int& err, 91 const char** envp) 92{ 93 // This function written by Peter Folk <pfolk@uni.uiuc.edu> 94 // and published in the BeDevTalk FAQ 95 // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209 96 97 if (!envp) 98 envp = (const char**)environ; 99 100 // Save current FDs 101 int old_in = dup(0); 102 int old_out = dup(1); 103 int old_err = dup(2); 104 105 int filedes[2]; 106 107 // Create new pipe FDs as stdin, stdout, stderr 108 pipe(filedes); dup2(filedes[0], 0); close(filedes[0]); 109 in = filedes[1]; // Write to in, appears on cmd's stdin 110 pipe(filedes); dup2(filedes[1], 1); close(filedes[1]); 111 out = filedes[0]; // Read from out, taken from cmd's stdout 112 pipe(filedes); dup2(filedes[1], 2); close(filedes[1]); 113 err = filedes[0]; // Read from err, taken from cmd's stderr 114 115 // "load" command. 116 thread_id ret = load_image(argc, argv, envp); 117 if (ret < B_OK) 118 goto cleanup; 119 120 // thread ret is now suspended. 121 122 setpgid(ret, ret); 123 124cleanup: 125 // Restore old FDs 126 close(0); dup(old_in); close(old_in); 127 close(1); dup(old_out); close(old_out); 128 close(2); dup(old_err); close(old_err); 129 130 /* Theoretically I should do loads of error checking, but 131 the calls aren't very likely to fail, and that would 132 muddy up the example quite a bit. YMMV. */ 133 134 return ret; 135} 136