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     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             std::list<TString> output = Helpers::StringToArray(buffer);
 216             FOutput.splice(FOutput.end(), output, output.begin(), output.end());
 217             result = true;
 218         }
 219     }
 220 
 221     return false;
 222 }
 223 
 224 bool PosixProcess::IsRunning() {
 225     bool result = false;
 226 
 227     if (kill(FChildPID, 0) == 0) {
 228         result = true;
 229     }
 230 
 231     return result;
 232 }
 233 
 234 bool PosixProcess::Terminate() {
 235     bool result = false;
 236 
 237     if (IsRunning() == true && FRunning == true) {
 238         FRunning = false;
 239         Cleanup();
 240         int status = kill(FChildPID, SIGTERM);
 241 
 242         if (status == 0) {
 243             result = true;
 244         } else {
 245 #ifdef DEBUG
 246             if (errno == EINVAL) {
 247                 printf("Kill error: The value of the sig argument is an invalid or unsupported signal number.");
 248             } else if (errno == EPERM) {
 249                 printf("Kill error: The process does not have permission to send the signal to any receiving process.");
 250             } else if (errno == ESRCH) {
 251                 printf("Kill error: No process or process group can be found corresponding to that specified by pid.");
 252             }
 253 #endif // DEBUG
 254             if (IsRunning() == true) {
 255                 status = kill(FChildPID, SIGKILL);
 256 
 257                 if (status == 0) {
 258                     result = true;
 259                 }
 260             }
 261         }
 262     }
 263 
 264     return result;
 265 }
 266 
 267 bool PosixProcess::Wait() {
 268     bool result = false;
 269 
 270     int status = 0;
 271     pid_t wpid = 0;
 272 
 273     wpid = wait(&status);
 274     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
 275         if (errno != EINTR) {
 276             status = -1;
 277         }
 278     }
 279 
 280 #ifdef DEBUG
 281     if (WIFEXITED(status)) {
 282         printf("child exited, status=%d\n", WEXITSTATUS(status));
 283     } else if (WIFSIGNALED(status)) {
 284         printf("child killed (signal %d)\n", WTERMSIG(status));
 285     } else if (WIFSTOPPED(status)) {
 286         printf("child stopped (signal %d)\n", WSTOPSIG(status));
 287 #ifdef WIFCONTINUED // Not all implementations support this
 288     } else if (WIFCONTINUED(status)) {
 289         printf("child continued\n");
 290 #endif // WIFCONTINUED
 291     } else { // Non-standard case -- may never happen
 292         printf("Unexpected status (0x%x)\n", status);
 293     }
 294 #endif // DEBUG
 295 
 296     if (wpid != -1) {
 297         result = true;
 298     }
 299 
 300     return result;
 301 }
 302 
 303 TProcessID PosixProcess::GetProcessID() {
 304     return FChildPID;
 305 }
 306 
 307 void PosixProcess::SetInput(TString Value) {
 308     if (FInputHandle != 0) {
 309         write(FInputHandle, Value.data(), Value.size());
 310     }
 311 }
 312 
 313 std::list<TString> PosixProcess::GetOutput() {
 314     ReadOutput();
 315     return Process::GetOutput();
 316 }