1 /* 2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34 #include "PosixPlatform.h" 35 36 #ifdef POSIX 37 38 #include "PlatformString.h" 39 #include "FilePath.h" 40 #include "Helpers.h" 41 42 #include <assert.h> 43 #include <stdbool.h> 44 #include <sys/types.h> 45 #include <unistd.h> 46 #include <sys/sysctl.h> 47 #include <iostream> 48 #include <dlfcn.h> 49 #include <signal.h> 50 51 52 PosixPlatform::PosixPlatform(void) { 53 } 54 55 PosixPlatform::~PosixPlatform(void) { 56 } 57 58 MessageResponse PosixPlatform::ShowResponseMessage(TString title, TString description) { 59 MessageResponse result = mrCancel; 60 61 printf("%s %s (Y/N)\n", PlatformString(title).toPlatformString(), PlatformString(description).toPlatformString()); 62 fflush(stdout); 63 64 std::string input; 65 std::cin >> input; 66 67 if (input == "Y") { 68 result = mrOK; 69 } 70 71 return result; 72 } 73 74 //MessageResponse PosixPlatform::ShowResponseMessageB(TString description) { 75 // TString appname = GetModuleFileName(); 76 // appname = FilePath::ExtractFileName(appname); 77 // return ShowResponseMessage(appname, description); 78 //} 79 80 void PosixPlatform::SetCurrentDirectory(TString Value) { 81 chdir(StringToFileSystemString(Value)); 82 } 83 84 Module PosixPlatform::LoadLibrary(TString FileName) { 85 return dlopen(StringToFileSystemString(FileName), RTLD_LAZY); 86 } 87 88 void PosixPlatform::FreeLibrary(Module AModule) { 89 dlclose(AModule); 90 } 91 92 Procedure PosixPlatform::GetProcAddress(Module AModule, std::string MethodName) { 93 return dlsym(AModule, PlatformString(MethodName)); 94 } 95 96 std::vector<std::string> PosixPlatform::GetLibraryImports(const TString FileName) { 97 std::vector<TString> result; 98 return result; 99 } 100 101 std::vector<TString> PosixPlatform::FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports) { 102 std::vector<TString> result; 103 return result; 104 } 105 106 Process* PosixPlatform::CreateProcess() { 107 return new PosixProcess(); 108 } 109 110 //-------------------------------------------------------------------------------------------------- 111 112 113 PosixProcess::PosixProcess() : Process() { 114 FChildPID = 0; 115 FRunning = false; 116 FOutputHandle = 0; 117 FInputHandle = 0; 118 } 119 120 PosixProcess::~PosixProcess() { 121 Terminate(); 122 } 123 124 void PosixProcess::Cleanup() { 125 if (FOutputHandle != 0) { 126 close(FOutputHandle); 127 FOutputHandle = 0; 128 } 129 130 if (FInputHandle != 0) { 131 close(FInputHandle); 132 FInputHandle = 0; 133 } 134 135 #ifdef MAC 136 sigaction(SIGINT, &savintr, (struct sigaction *)0); 137 sigaction(SIGQUIT, &savequit, (struct sigaction *)0); 138 sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *)0); 139 #endif //MAC 140 } 141 142 bool PosixProcess::ReadOutput() { 143 bool result = false; 144 145 if (FOutputHandle != 0 && IsRunning() == true) { 146 char buffer[4096]; 147 //select(p[0] + 1, &rfds, NULL, NULL, NULL); 148 149 ssize_t count = read(FOutputHandle, buffer, sizeof(buffer)); 150 151 if (count == -1) { 152 if (errno == EINTR) { 153 //continue; 154 } else { 155 perror("read"); 156 exit(1); 157 } 158 } else if (count == 0) { 159 //break; 160 } else { 161 if (buffer[count] == EOF) { 162 buffer[count] = '\0'; 163 } 164 165 std::list<TString> output = Helpers::StringToArray(buffer); 166 FOutput.splice(FOutput.end(), output, output.begin(), output.end()); 167 result = true; 168 } 169 } 170 171 return false; 172 } 173 174 bool PosixProcess::IsRunning() { 175 bool result = false; 176 177 if (kill(FChildPID, 0) == 0) { 178 result = true; 179 } 180 181 return result; 182 } 183 184 bool PosixProcess::Terminate() { 185 bool result = false; 186 187 if (IsRunning() == true && FRunning == true) { 188 FRunning = false; 189 Cleanup(); 190 int status = kill(FChildPID, SIGTERM); 191 192 if (status == 0) { 193 result = true; 194 } 195 else { 196 #ifdef DEBUG 197 if (errno == EINVAL) 198 printf("Kill error: The value of the sig argument is an invalid or unsupported signal number."); 199 else if (errno == EPERM) 200 printf("Kill error: The process does not have permission to send the signal to any receiving process."); 201 else if (errno == ESRCH) 202 printf("Kill error: No process or process group can be found corresponding to that specified by pid."); 203 #endif //DEBUG 204 if (IsRunning() == true) { 205 status = kill(FChildPID, SIGKILL); 206 207 if (status == 0) { 208 result = true; 209 } 210 } 211 } 212 } 213 214 return result; 215 } 216 217 #define PIPE_READ 0 218 #define PIPE_WRITE 1 219 220 bool PosixProcess::Execute(const TString Application, const std::vector<TString> Arguments, bool AWait) { 221 bool result = false; 222 223 if (FRunning == false) { 224 FRunning = true; 225 226 int handles[2]; 227 228 if (pipe(handles) == -1) { 229 //perror("pipe"); 230 //exit(1); 231 return false; 232 } 233 234 struct sigaction sa; 235 sa.sa_handler = SIG_IGN; 236 sigemptyset(&sa.sa_mask); 237 sa.sa_flags = 0; 238 #ifdef MAC 239 sigemptyset(&savintr.sa_mask); 240 sigemptyset(&savequit.sa_mask); 241 sigaction(SIGINT, &sa, &savintr); 242 sigaction(SIGQUIT, &sa, &savequit); 243 sigaddset(&sa.sa_mask, SIGCHLD); 244 sigprocmask(SIG_BLOCK, &sa.sa_mask, &saveblock); 245 #endif //MAC 246 FChildPID = fork(); 247 248 // PID returned by vfork is 0 for the child process and the PID of the child 249 // process for the parent. 250 if (FChildPID == -1) { 251 // Error 252 TString message = PlatformString::Format(_T("Error: Unable to create process %s"), Application.data()); 253 throw Exception(message); 254 } 255 else if (FChildPID == 0) { 256 Cleanup(); 257 TString command = Application; 258 259 for (std::vector<TString>::const_iterator iterator = Arguments.begin(); iterator != Arguments.end(); iterator++) { 260 command += TString(_T(" ")) + *iterator; 261 } 262 #ifdef DEBUG 263 printf("%s\n", command.data()); 264 #endif //DEBUG 265 // dup2(FOutputHandle, STDOUT_FILENO); 266 // dup2(FInputHandle, STDIN_FILENO); 267 // close(FOutputHandle); 268 // close(FInputHandle); 269 270 dup2(handles[PIPE_READ], STDIN_FILENO); 271 dup2(handles[PIPE_WRITE], STDOUT_FILENO); 272 // setvbuf(stdout,NULL,_IONBF,0); 273 // setvbuf(stdin,NULL,_IONBF,0); 274 275 close(handles[PIPE_READ]); 276 close(handles[PIPE_WRITE]); 277 278 execl("/bin/sh", "sh", "-c", command.data(), (char *)0); 279 280 _exit(127); 281 } else { 282 // close(handles[PIPE_READ]); 283 // close(handles[PIPE_WRITE]); 284 285 // close(output[1]); 286 // int nbytes = read(output[0], foo, sizeof(foo)); 287 // printf("Output: (%.*s)\n", nbytes, foo); 288 // wait(NULL); 289 FOutputHandle = handles[PIPE_READ]; 290 FInputHandle = handles[PIPE_WRITE]; 291 292 if (AWait == true) { 293 ReadOutput(); 294 Wait(); 295 Cleanup(); 296 FRunning = false; 297 result = true; 298 } 299 else { 300 result = true; 301 } 302 } 303 } 304 305 return result; 306 } 307 308 bool PosixProcess::Wait() { 309 bool result = false; 310 311 int status = 0; 312 pid_t wpid = -1; 313 314 //TODO Use waitpid instead of wait 315 #ifdef LINUX 316 wait(); 317 #endif 318 #ifdef MAC 319 wpid = wait(&status); 320 #endif 321 322 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 323 if (errno != EINTR){ 324 status = -1; 325 } 326 } 327 328 #ifdef DEBUG 329 if (WIFEXITED(status)) { 330 printf("child exited, status=%d\n", WEXITSTATUS(status)); 331 } else if (WIFSIGNALED(status)) { 332 printf("child killed (signal %d)\n", WTERMSIG(status)); 333 } else if (WIFSTOPPED(status)) { 334 printf("child stopped (signal %d)\n", WSTOPSIG(status)); 335 #ifdef WIFCONTINUED // Not all implementations support this 336 } else if (WIFCONTINUED(status)) { 337 printf("child continued\n"); 338 #endif //WIFCONTINUED 339 } else { // Non-standard case -- may never happen 340 printf("Unexpected status (0x%x)\n", status); 341 } 342 #endif //DEBUG 343 344 if (wpid != -1) { 345 result = true; 346 } 347 348 return result; 349 } 350 351 TProcessID PosixProcess::GetProcessID() { 352 return FChildPID; 353 } 354 355 void PosixProcess::SetInput(TString Value) { 356 if (FInputHandle != 0) { 357 write(FInputHandle, Value.data(), Value.size()); 358 } 359 } 360 361 std::list<TString> PosixProcess::GetOutput() { 362 ReadOutput(); 363 return Process::GetOutput(); 364 } 365 366 #endif //POSIX