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 Module PosixPlatform::LoadLibrary(TString FileName) {
  98     return dlopen(StringToFileSystemString(FileName), RTLD_LAZY);
  99 }
 100 
 101 void PosixPlatform::FreeLibrary(Module AModule) {
 102     dlclose(AModule);
 103 }
 104 
 105 Procedure PosixPlatform::GetProcAddress(Module AModule,
 106         std::string MethodName) {
 107     return dlsym(AModule, PlatformString(MethodName));
 108 }
 109 
 110 Process* PosixPlatform::CreateProcess() {
 111     return new PosixProcess();
 112 }
 113 
 114 void PosixPlatform::addPlatformDependencies(JavaLibrary *pJavaLibrary) {
 115 }
 116 
 117 void Platform::CopyString(char *Destination,
 118         size_t NumberOfElements, const char *Source) {
 119     strncpy(Destination, Source, NumberOfElements);
 120 
 121     if (NumberOfElements > 0) {
 122         Destination[NumberOfElements - 1] = '\0';
 123     }
 124 }
 125 
 126 void Platform::CopyString(wchar_t *Destination,
 127         size_t NumberOfElements, const wchar_t *Source) {
 128     wcsncpy(Destination, Source, NumberOfElements);
 129 
 130     if (NumberOfElements > 0) {
 131         Destination[NumberOfElements - 1] = '\0';
 132     }
 133 }
 134 
 135 // Owner must free the return value.
 136 
 137 MultibyteString Platform::WideStringToMultibyteString(
 138         const wchar_t* value) {
 139     MultibyteString result;
 140     size_t count = 0;
 141 
 142     if (value == NULL) {
 143         return result;
 144     }
 145 
 146     count = wcstombs(NULL, value, 0);
 147     if (count > 0) {
 148         result.data = new char[count + 1];
 149         result.data[count] = '\0';
 150         result.length = count;
 151         wcstombs(result.data, value, count);
 152     }
 153 
 154     return result;
 155 }
 156 
 157 // Owner must free the return value.
 158 
 159 WideString Platform::MultibyteStringToWideString(const char* value) {
 160     WideString result;
 161     size_t count = 0;
 162 
 163     if (value == NULL) {
 164         return result;
 165     }
 166 
 167     count = mbstowcs(NULL, value, 0);
 168     if (count > 0) {
 169         result.data = new wchar_t[count + 1];
 170         result.data[count] = '\0';
 171         result.length = count;
 172         mbstowcs(result.data, value, count);
 173     }
 174 
 175     return result;
 176 }
 177 
 178 void PosixPlatform::InitStreamLocale(wios *stream) {
 179     // Nothing to do for POSIX platforms.
 180 }
 181 
 182 PosixProcess::PosixProcess() : Process() {
 183     FChildPID = 0;
 184     FRunning = false;
 185     FOutputHandle = 0;
 186     FInputHandle = 0;
 187 }
 188 
 189 PosixProcess::~PosixProcess() {
 190     Terminate();
 191 }
 192 
 193 bool PosixProcess::ReadOutput() {
 194     bool result = false;
 195 
 196     if (FOutputHandle != 0 && IsRunning() == true) {
 197         char buffer[4096] = {0};
 198 
 199         ssize_t count = read(FOutputHandle, buffer, sizeof (buffer));
 200 
 201         if (count == -1) {
 202             if (errno == EINTR) {
 203                 // continue;
 204             } else {
 205                 perror("read");
 206                 exit(1);
 207             }
 208         } else if (count == 0) {
 209             // break;
 210         } else {
 211             std::list<TString> output = Helpers::StringToArray(buffer);
 212             FOutput.splice(FOutput.end(), output, output.begin(), output.end());
 213             result = true;
 214         }
 215     }
 216 
 217     return false;
 218 }
 219 
 220 bool PosixProcess::IsRunning() {
 221     bool result = false;
 222 
 223     if (kill(FChildPID, 0) == 0) {
 224         result = true;
 225     }
 226 
 227     return result;
 228 }
 229 
 230 bool PosixProcess::Terminate() {
 231     bool result = false;
 232 
 233     if (IsRunning() == true && FRunning == true) {
 234         FRunning = false;
 235         Cleanup();
 236         int status = kill(FChildPID, SIGTERM);
 237 
 238         if (status == 0) {
 239             result = true;
 240         } else {
 241 #ifdef DEBUG
 242             if (errno == EINVAL) {
 243                 printf("Kill error: The value of the sig argument is an invalid or unsupported signal number.");
 244             } else if (errno == EPERM) {
 245                 printf("Kill error: The process does not have permission to send the signal to any receiving process.");
 246             } else if (errno == ESRCH) {
 247                 printf("Kill error: No process or process group can be found corresponding to that specified by pid.");
 248             }
 249 #endif // DEBUG
 250             if (IsRunning() == true) {
 251                 status = kill(FChildPID, SIGKILL);
 252 
 253                 if (status == 0) {
 254                     result = true;
 255                 }
 256             }
 257         }
 258     }
 259 
 260     return result;
 261 }
 262 
 263 bool PosixProcess::Wait() {
 264     bool result = false;
 265 
 266     int status = 0;
 267     pid_t wpid = 0;
 268 
 269     wpid = wait(&status);
 270     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
 271         if (errno != EINTR) {
 272             status = -1;
 273         }
 274     }
 275 
 276 #ifdef DEBUG
 277     if (WIFEXITED(status)) {
 278         printf("child exited, status=%d\n", WEXITSTATUS(status));
 279     } else if (WIFSIGNALED(status)) {
 280         printf("child killed (signal %d)\n", WTERMSIG(status));
 281     } else if (WIFSTOPPED(status)) {
 282         printf("child stopped (signal %d)\n", WSTOPSIG(status));
 283 #ifdef WIFCONTINUED // Not all implementations support this
 284     } else if (WIFCONTINUED(status)) {
 285         printf("child continued\n");
 286 #endif // WIFCONTINUED
 287     } else { // Non-standard case -- may never happen
 288         printf("Unexpected status (0x%x)\n", status);
 289     }
 290 #endif // DEBUG
 291 
 292     if (wpid != -1) {
 293         result = true;
 294     }
 295 
 296     return result;
 297 }
 298 
 299 TProcessID PosixProcess::GetProcessID() {
 300     return FChildPID;
 301 }
 302 
 303 void PosixProcess::SetInput(TString Value) {
 304     if (FInputHandle != 0) {
 305         if (write(FInputHandle, Value.data(), Value.size()) < 0) {
 306             throw Exception(_T("Internal Error - write failed"));
 307         }
 308     }
 309 }
 310 
 311 std::list<TString> PosixProcess::GetOutput() {
 312     ReadOutput();
 313     return Process::GetOutput();
 314 }