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 16 PipedAppRunner::PipedAppRunner() 17 : fOutputLock(), 18 fPipe(NULL), 19 fOutput(), 20 fReader(-1) 21 { 22 } 23 24 // destructor 25 PipedAppRunner::~PipedAppRunner() 26 { 27 if (fReader >= 0) { 28 _ClosePipe(); 29 int32 result; 30 wait_for_thread(fReader, &result); 31 } 32 } 33 34 // Run 35 status_t 36 PipedAppRunner::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 87 bool 88 PipedAppRunner::HasQuitted() 89 { 90 BAutolock locker(fOutputLock); 91 return !fPipe; 92 } 93 94 // WaitFor 95 void 96 PipedAppRunner::WaitFor() 97 { 98 while (!HasQuitted()) 99 snooze(10000); 100 } 101 102 // GetOutput 103 status_t 104 PipedAppRunner::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 120 ssize_t 121 PipedAppRunner::ReadOutput(void *buffer, size_t size) 122 { 123 BAutolock locker(fOutputLock); 124 return fOutput.Read(buffer, size); 125 } 126 127 // ReadOutputAt 128 ssize_t 129 PipedAppRunner::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 136 int32 137 PipedAppRunner::_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 146 int32 147 PipedAppRunner::_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 167 void 168 PipedAppRunner::_ClosePipe() 169 { 170 if (fOutputLock.Lock()) { 171 if (fPipe) { 172 pclose(fPipe); 173 fPipe = NULL; 174 } 175 fOutputLock.Unlock(); 176 } 177 } 178 179