1// PipedAppRunner.cpp 2 3#include <errno.h> 4#include <unistd.h> 5 6#include <Autolock.h> 7#include <String.h> 8 9#include <TestShell.h> 10#include <TestUtils.h> 11#include <cppunit/TestAssert.h> 12 13#include "PipedAppRunner.h" 14 15// constructor 16PipedAppRunner::PipedAppRunner() 17 : fOutputLock(), 18 fPipe(NULL), 19 fOutput(), 20 fReader(-1) 21{ 22} 23 24// destructor 25PipedAppRunner::~PipedAppRunner() 26{ 27 if (fReader >= 0) { 28 _ClosePipe(); 29 int32 result; 30 wait_for_thread(fReader, &result); 31 } 32} 33 34// Run 35status_t 36PipedAppRunner::Run(const char *command, const char *args, bool findCommand) 37{ 38 status_t error = (HasQuitted() ? B_OK : B_ERROR); 39 // get the app path 40 BString appPath; 41 if (findCommand) { 42 appPath = BTestShell::GlobalTestDir(); 43 appPath.CharacterEscape(" \t\n!\"'`$&()?*+{}[]<>|", '\\'); 44 appPath += "/"; 45 appPath += command; 46 #ifdef TEST_R5 47 appPath += "_r5"; 48 #endif 49 command = appPath.String(); 50 } 51 // add args, i.e. compose the command line 52 BString cmdLine(command); 53 if (args) { 54 cmdLine += " "; 55 cmdLine += args; 56 } 57 // run the command 58 if (error == B_OK) { 59 fPipe = popen(cmdLine.String(), "r"); 60 if (!fPipe) 61 error = errno; 62 } 63 // spawn the reader thread 64 if (error == B_OK) { 65 fReader = spawn_thread(&_ReaderEntry, "PipedAppRunner reader", 66 B_NORMAL_PRIORITY, (void*)this); 67 if (fReader >= 0) 68 error = resume_thread(fReader); 69 else 70 error = fReader; 71 } 72 // cleanup on error 73 if (error != B_OK) { 74 if (fReader >= 0) { 75 kill_thread(fReader); 76 fReader = -1; 77 } 78 if (fPipe) { 79 pclose(fPipe); 80 fPipe = NULL; 81 } 82 } 83 return error; 84} 85 86// HasQuitted 87bool 88PipedAppRunner::HasQuitted() 89{ 90 BAutolock locker(fOutputLock); 91 return !fPipe; 92} 93 94// WaitFor 95void 96PipedAppRunner::WaitFor() 97{ 98 while (!HasQuitted()) 99 snooze(10000); 100} 101 102// GetOutput 103status_t 104PipedAppRunner::GetOutput(BString *buffer) 105{ 106 status_t error = (buffer ? B_OK : B_BAD_VALUE); 107 if (error == B_OK) { 108 BAutolock locker(fOutputLock); 109 size_t size = fOutput.BufferLength(); 110 const void *output = fOutput.Buffer(); 111 if (size > 0) 112 buffer->SetTo((const char*)output, size); 113 else 114 *buffer = ""; 115 } 116 return error; 117} 118 119// ReadOutput 120ssize_t 121PipedAppRunner::ReadOutput(void *buffer, size_t size) 122{ 123 BAutolock locker(fOutputLock); 124 return fOutput.Read(buffer, size); 125} 126 127// ReadOutputAt 128ssize_t 129PipedAppRunner::ReadOutputAt(off_t position, void *buffer, size_t size) 130{ 131 BAutolock locker(fOutputLock); 132 return fOutput.ReadAt(position, buffer, size); 133} 134 135// _ReaderEntry 136int32 137PipedAppRunner::_ReaderEntry(void *data) 138{ 139 int32 result = 0; 140 if (PipedAppRunner *me = (PipedAppRunner*)data) 141 result = me->_ReaderLoop(); 142 return result; 143} 144 145// _ReaderLoop 146int32 147PipedAppRunner::_ReaderLoop() 148{ 149 char buffer[10240]; 150 fOutputLock.Lock(); 151 FILE *pipe = fPipe; 152 fOutputLock.Unlock(); 153 while (!feof(pipe)) { 154 size_t bytes = fread(buffer, 1, sizeof(buffer), pipe); 155 if (bytes > 0) { 156 BAutolock locker(fOutputLock); 157 off_t oldPosition = fOutput.Seek(0, SEEK_END); 158 fOutput.Write(buffer, bytes); 159 fOutput.Seek(oldPosition, SEEK_SET); 160 } 161 } 162 _ClosePipe(); 163 return 0; 164} 165 166// _ClosePipe 167void 168PipedAppRunner::_ClosePipe() 169{ 170 if (fOutputLock.Lock()) { 171 if (fPipe) { 172 pclose(fPipe); 173 fPipe = NULL; 174 } 175 fOutputLock.Unlock(); 176 } 177} 178 179