/* * Copyright 2010, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Ithamar R. Adema */ #include "FilterIO.h" #include #include #include #include #include FilterIO::FilterIO(const BString& cmdline) : BDataIO() { BString cmd(cmdline); const char* argv[4]; argv[0] = strdup("/bin/sh"); argv[1] = strdup("-c"); argv[2] = strdup(cmd.String()); argv[3] = NULL; InitData(3, argv); free((void*)argv[0]); free((void*)argv[1]); free((void*)argv[2]); } FilterIO::FilterIO(int argc, const char **argv, const char **envp) : BDataIO() { InitData(argc, argv, envp); } status_t FilterIO::InitData(int argc, const char** argv, const char** envp) { fStdIn = fStdOut = fStdErr = -1; fInitErr = B_OK; fThreadId = PipeCommand(argc, argv, fStdIn, fStdOut, fStdErr, envp); if (fThreadId < 0) fInitErr = fThreadId; // lower the command priority since it is a background task. set_thread_priority(fThreadId, B_LOW_PRIORITY); resume_thread(fThreadId); return fInitErr; } FilterIO::~FilterIO() { ::close(fStdIn); ::close(fStdOut); ::close(fStdErr); } ssize_t FilterIO::Read(void* buffer, size_t size) { return ::read(fStdOut, buffer, size); } ssize_t FilterIO::Write(const void* buffer, size_t size) { return ::write(fStdIn, buffer, size); } thread_id FilterIO::PipeCommand(int argc, const char** argv, int& in, int& out, int& err, const char** envp) { // This function written by Peter Folk // and published in the BeDevTalk FAQ // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209 if (!envp) envp = (const char**)environ; // Save current FDs int old_in = dup(0); int old_out = dup(1); int old_err = dup(2); int filedes[2]; // Create new pipe FDs as stdin, stdout, stderr pipe(filedes); dup2(filedes[0], 0); close(filedes[0]); in = filedes[1]; // Write to in, appears on cmd's stdin pipe(filedes); dup2(filedes[1], 1); close(filedes[1]); out = filedes[0]; // Read from out, taken from cmd's stdout pipe(filedes); dup2(filedes[1], 2); close(filedes[1]); err = filedes[0]; // Read from err, taken from cmd's stderr // "load" command. thread_id ret = load_image(argc, argv, envp); if (ret < B_OK) goto cleanup; // thread ret is now suspended. setpgid(ret, ret); cleanup: // Restore old FDs close(0); dup(old_in); close(old_in); close(1); dup(old_out); close(old_out); close(2); dup(old_err); close(old_err); /* Theoretically I should do loads of error checking, but the calls aren't very likely to fail, and that would muddy up the example quite a bit. YMMV. */ return ret; }