1 /* 2 * Copyright (c) 2014, 2015, 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 41 #include <assert.h> 42 #include <stdbool.h> 43 #include <sys/types.h> 44 #include <unistd.h> 45 #include <sys/sysctl.h> 46 #include <iostream> 47 #include <dlfcn.h> 48 #include <signal.h> 49 50 51 PosixPlatform::PosixPlatform(void) { 52 } 53 54 PosixPlatform::~PosixPlatform(void) { 55 } 56 57 MessageResponse PosixPlatform::ShowResponseMessage(TString title, TString description) { 58 MessageResponse result = mrCancel; 59 60 printf("%s %s (Y/N)\n", PlatformString(title).toPlatformString(), PlatformString(description).toPlatformString()); 61 fflush(stdout); 62 63 std::string input; 64 std::cin >> input; 65 66 if (input == "Y") { 67 result = mrOK; 68 } 69 70 return result; 71 } 72 73 //MessageResponse PosixPlatform::ShowResponseMessageB(TString description) { 74 // TString appname = GetModuleFileName(); 75 // appname = FilePath::ExtractFileName(appname); 76 // return ShowResponseMessage(appname, description); 77 //} 78 79 void PosixPlatform::SetCurrentDirectory(TString Value) { 80 chdir(StringToFileSystemString(Value)); 81 } 82 83 Module PosixPlatform::LoadLibrary(TString FileName) { 84 return dlopen(StringToFileSystemString(FileName), RTLD_LAZY); 85 } 86 87 void PosixPlatform::FreeLibrary(Module AModule) { 88 dlclose(AModule); 89 } 90 91 Procedure PosixPlatform::GetProcAddress(Module AModule, std::string MethodName) { 92 return dlsym(AModule, PlatformString(MethodName)); 93 } 94 95 std::vector<std::string> PosixPlatform::GetLibraryImports(const TString FileName) { 96 std::vector<TString> result; 97 return result; 98 } 99 100 std::vector<TString> PosixPlatform::FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports) { 101 std::vector<TString> result; 102 return result; 103 } 104 105 Process* PosixPlatform::CreateProcess() { 106 return new PosixProcess(); 107 } 108 109 //-------------------------------------------------------------------------------------------------- 110 111 112 PosixProcess::PosixProcess() : Process() { 113 FChildPID = 0; 114 FRunning = false; 115 } 116 117 PosixProcess::~PosixProcess() { 118 Terminate(); 119 } 120 121 void PosixProcess::Cleanup() { 122 #ifdef MAC 123 sigaction(SIGINT, &savintr, (struct sigaction *)0); 124 sigaction(SIGQUIT, &savequit, (struct sigaction *)0); 125 sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *)0); 126 #endif //MAC 127 } 128 129 bool PosixProcess::IsRunning() { 130 bool result = false; 131 132 if (kill(FChildPID, 0) == 0) { 133 result = true; 134 } 135 136 return result; 137 } 138 139 bool PosixProcess::Terminate() { 140 bool result = false; 141 142 if (IsRunning() == true && FRunning == true) { 143 FRunning = false; 144 Cleanup(); 145 int status = kill(FChildPID, SIGTERM); 146 147 if (status == 0) { 148 result = true; 149 } 150 else { 151 #ifdef DEBUG 152 if (errno == EINVAL) 153 printf("Kill error: The value of the sig argument is an invalid or unsupported signal number."); 154 else if (errno == EPERM) 155 printf("Kill error: The process does not have permission to send the signal to any receiving process."); 156 else if (errno == ESRCH) 157 printf("Kill error: No process or process group can be found corresponding to that specified by pid."); 158 #endif //DEBUG 159 if (IsRunning() == true) { 160 status = kill(FChildPID, SIGKILL); 161 162 if (status == 0) { 163 result = true; 164 } 165 } 166 } 167 } 168 169 return result; 170 } 171 172 bool PosixProcess::Execute(const TString Application, const std::vector<TString> Arguments, bool AWait) { 173 bool result = false; 174 175 if (FRunning == false) { 176 FRunning = true; 177 178 struct sigaction sa; 179 sa.sa_handler = SIG_IGN; 180 sigemptyset(&sa.sa_mask); 181 sa.sa_flags = 0; 182 #ifdef MAC 183 sigemptyset(&savintr.sa_mask); 184 sigemptyset(&savequit.sa_mask); 185 sigaction(SIGINT, &sa, &savintr); 186 sigaction(SIGQUIT, &sa, &savequit); 187 sigaddset(&sa.sa_mask, SIGCHLD); 188 sigprocmask(SIG_BLOCK, &sa.sa_mask, &saveblock); 189 #endif //MAC 190 FChildPID = fork(); 191 192 // PID returned by vfork is 0 for the child process and the PID of the child 193 // process for the parent. 194 if (FChildPID == -1) { 195 // Error 196 TString message = PlatformString::Format(_T("Error: Unable to create process %s"), Application.data()); 197 throw Exception(message); 198 } 199 else if (FChildPID == 0) { 200 Cleanup(); 201 TString command = Application; 202 203 for (std::vector<TString>::const_iterator iterator = Arguments.begin(); iterator != Arguments.end(); iterator++) { 204 command += TString(_T(" ")) + *iterator; 205 } 206 #ifdef DEBUG 207 printf("%s\n", command.data()); 208 #endif //DEBUG 209 execl("/bin/sh", "sh", "-c", command.data(), (char *)0); 210 _exit(127); 211 } else { 212 if (AWait == true) { 213 Wait(); 214 Cleanup(); 215 FRunning = false; 216 result = true; 217 } 218 else { 219 result = true; 220 } 221 } 222 } 223 224 return result; 225 } 226 227 bool PosixProcess::Wait() { 228 bool result = false; 229 230 int status = 0; 231 pid_t wpid; 232 233 //TODO Use waitpid instead of wait 234 #ifdef LINUX 235 wait(); 236 #endif 237 #ifdef MAC 238 wpid = wait(&status); 239 #endif 240 241 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 242 if (errno != EINTR){ 243 status = -1; 244 } 245 } 246 247 #ifdef DEBUG 248 if (WIFEXITED(status)) { 249 printf("child exited, status=%d\n", WEXITSTATUS(status)); 250 } else if (WIFSIGNALED(status)) { 251 printf("child killed (signal %d)\n", WTERMSIG(status)); 252 } else if (WIFSTOPPED(status)) { 253 printf("child stopped (signal %d)\n", WSTOPSIG(status)); 254 #ifdef WIFCONTINUED // Not all implementations support this 255 } else if (WIFCONTINUED(status)) { 256 printf("child continued\n"); 257 #endif //WIFCONTINUED 258 } else { // Non-standard case -- may never happen 259 printf("Unexpected status (0x%x)\n", status); 260 } 261 #endif //DEBUG 262 263 if (wpid != -1) { 264 result = true; 265 } 266 267 return result; 268 } 269 270 TProcessID PosixProcess::GetProcessID() { 271 return FChildPID; 272 } 273 274 #endif //POSIX