1 /* 2 * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "PosixPlatform.h" 27 28 #include "PlatformString.h" 29 #include "FilePath.h" 30 #include "Helpers.h" 31 32 #include <assert.h> 33 #include <stdbool.h> 34 #include <sys/types.h> 35 #include <unistd.h> 36 #include <sys/sysctl.h> 37 #include <sys/file.h> 38 #include <sys/stat.h> 39 #include <sys/wait.h> 40 #include <errno.h> 41 #include <limits.h> 42 #include <pwd.h> 43 #include <iostream> 44 #include <algorithm> 45 #include <dlfcn.h> 46 #include <signal.h> 47 48 using namespace std; 49 50 PosixPlatform::PosixPlatform(void) { 51 } 52 53 PosixPlatform::~PosixPlatform(void) { 54 } 55 56 TString PosixPlatform::GetTempDirectory() { 57 struct passwd* pw = getpwuid(getuid()); 58 TString homedir(pw->pw_dir); 59 homedir += getTmpDirString(); 60 if (!FilePath::DirectoryExists(homedir)) { 61 if (!FilePath::CreateDirectory(homedir, false)) { 62 homedir.clear(); 63 } 64 } 65 66 return homedir; 67 } 68 69 TString PosixPlatform::fixName(const TString& name) { 70 TString fixedName(name); 71 const TString chars("?:*<>/\\"); 72 for (TString::const_iterator it = chars.begin(); it != chars.end(); it++) { 73 fixedName.erase(std::remove(fixedName.begin(), 74 fixedName.end(), *it), fixedName.end()); 75 } 76 return fixedName; 77 } 78 79 MessageResponse PosixPlatform::ShowResponseMessage(TString title, 80 TString description) { 81 MessageResponse result = mrCancel; 82 83 printf("%s %s (Y/N)\n", PlatformString(title).toPlatformString(), 84 PlatformString(description).toPlatformString()); 85 fflush(stdout); 86 87 std::string input; 88 std::cin >> input; 89 90 if (input == "Y") { 91 result = mrOK; 92 } 93 94 return result; 95 } 96 97 void PosixPlatform::SetCurrentDirectory(TString Value) { 98 int ignored = chdir(StringToFileSystemString(Value)); 99 } 100 101 Module PosixPlatform::LoadLibrary(TString FileName) { 102 return dlopen(StringToFileSystemString(FileName), RTLD_LAZY); 103 } 104 105 void PosixPlatform::FreeLibrary(Module AModule) { 106 dlclose(AModule); 107 } 108 109 Procedure PosixPlatform::GetProcAddress(Module AModule, 110 std::string MethodName) { 111 return dlsym(AModule, PlatformString(MethodName)); 112 } 113 114 Process* PosixPlatform::CreateProcess() { 115 return new PosixProcess(); 116 } 117 118 void PosixPlatform::addPlatformDependencies(JavaLibrary *pJavaLibrary) { 119 } 120 121 void Platform::CopyString(char *Destination, 122 size_t NumberOfElements, const char *Source) { 123 strncpy(Destination, Source, NumberOfElements); 124 125 if (NumberOfElements > 0) { 126 Destination[NumberOfElements - 1] = '\0'; 127 } 128 } 129 130 void Platform::CopyString(wchar_t *Destination, 131 size_t NumberOfElements, const wchar_t *Source) { 132 wcsncpy(Destination, Source, NumberOfElements); 133 134 if (NumberOfElements > 0) { 135 Destination[NumberOfElements - 1] = '\0'; 136 } 137 } 138 139 // Owner must free the return value. 140 141 MultibyteString Platform::WideStringToMultibyteString( 142 const wchar_t* value) { 143 MultibyteString result; 144 size_t count = 0; 145 146 if (value == NULL) { 147 return result; 148 } 149 150 count = wcstombs(NULL, value, 0); 151 if (count > 0) { 152 result.data = new char[count + 1]; 153 result.data[count] = '\0'; 154 result.length = count; 155 wcstombs(result.data, value, count); 156 } 157 158 return result; 159 } 160 161 // Owner must free the return value. 162 163 WideString Platform::MultibyteStringToWideString(const char* value) { 164 WideString result; 165 size_t count = 0; 166 167 if (value == NULL) { 168 return result; 169 } 170 171 count = mbstowcs(NULL, value, 0); 172 if (count > 0) { 173 result.data = new wchar_t[count + 1]; 174 result.data[count] = '\0'; 175 result.length = count; 176 mbstowcs(result.data, value, count); 177 } 178 179 return result; 180 } 181 182 void PosixPlatform::InitStreamLocale(wios *stream) { 183 // Nothing to do for POSIX platforms. 184 } 185 186 PosixProcess::PosixProcess() : Process() { 187 FChildPID = 0; 188 FRunning = false; 189 FOutputHandle = 0; 190 FInputHandle = 0; 191 } 192 193 PosixProcess::~PosixProcess() { 194 Terminate(); 195 } 196 197 bool PosixProcess::ReadOutput() { 198 bool result = false; 199 200 if (FOutputHandle != 0 && IsRunning() == true) { 201 char buffer[4096] = {0}; 202 203 ssize_t count = read(FOutputHandle, buffer, sizeof (buffer)); 204 205 if (count == -1) { 206 if (errno == EINTR) { 207 // continue; 208 } else { 209 perror("read"); 210 exit(1); 211 } 212 } else if (count == 0) { 213 // break; 214 } else { 215 /* 216 if (buffer[count - 1] == EOF) { 217 buffer[count - 1] = '\0'; 218 } 219 */ 220 221 std::list<TString> output = Helpers::StringToArray(buffer); 222 FOutput.splice(FOutput.end(), output, output.begin(), output.end()); 223 result = true; 224 } 225 } 226 227 return false; 228 } 229 230 bool PosixProcess::IsRunning() { 231 bool result = false; 232 233 if (kill(FChildPID, 0) == 0) { 234 result = true; 235 } 236 237 return result; 238 } 239 240 bool PosixProcess::Terminate() { 241 bool result = false; 242 243 if (IsRunning() == true && FRunning == true) { 244 FRunning = false; 245 Cleanup(); 246 int status = kill(FChildPID, SIGTERM); 247 248 if (status == 0) { 249 result = true; 250 } else { 251 #ifdef DEBUG 252 if (errno == EINVAL) { 253 printf("Kill error: The value of the sig argument is an invalid or unsupported signal number."); 254 } else if (errno == EPERM) { 255 printf("Kill error: The process does not have permission to send the signal to any receiving process."); 256 } else if (errno == ESRCH) { 257 printf("Kill error: No process or process group can be found corresponding to that specified by pid."); 258 } 259 #endif // DEBUG 260 if (IsRunning() == true) { 261 status = kill(FChildPID, SIGKILL); 262 263 if (status == 0) { 264 result = true; 265 } 266 } 267 } 268 } 269 270 return result; 271 } 272 273 bool PosixProcess::Wait() { 274 bool result = false; 275 276 int status = 0; 277 pid_t wpid = 0; 278 279 wpid = wait(&status); 280 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 281 if (errno != EINTR) { 282 status = -1; 283 } 284 } 285 286 #ifdef DEBUG 287 if (WIFEXITED(status)) { 288 printf("child exited, status=%d\n", WEXITSTATUS(status)); 289 } else if (WIFSIGNALED(status)) { 290 printf("child killed (signal %d)\n", WTERMSIG(status)); 291 } else if (WIFSTOPPED(status)) { 292 printf("child stopped (signal %d)\n", WSTOPSIG(status)); 293 #ifdef WIFCONTINUED // Not all implementations support this 294 } else if (WIFCONTINUED(status)) { 295 printf("child continued\n"); 296 #endif // WIFCONTINUED 297 } else { // Non-standard case -- may never happen 298 printf("Unexpected status (0x%x)\n", status); 299 } 300 #endif // DEBUG 301 302 if (wpid != -1) { 303 result = true; 304 } 305 306 return result; 307 } 308 309 TProcessID PosixProcess::GetProcessID() { 310 return FChildPID; 311 } 312 313 void PosixProcess::SetInput(TString Value) { 314 if (FInputHandle != 0) { 315 ssize_t ignored = write(FInputHandle, Value.data(), Value.size()); 316 } 317 } 318 319 std::list<TString> PosixProcess::GetOutput() { 320 ReadOutput(); 321 return Process::GetOutput(); 322 }