src/jdk.jpackager/share/native/library/common/PosixPlatform.cpp
branchJDK-8200758-branch
changeset 57017 1b08af362a30
parent 56982 e094d5483bd6
equal deleted inserted replaced
57016:f63f13da91c0 57017:1b08af362a30
       
     1 /*
       
     2  * Copyright (c) 2014, 2018, 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 #ifdef POSIX
       
    29 
       
    30 #include "PlatformString.h"
       
    31 #include "FilePath.h"
       
    32 #include "Helpers.h"
       
    33 
       
    34 #include <assert.h>
       
    35 #include <stdbool.h>
       
    36 #include <sys/types.h>
       
    37 #include <unistd.h>
       
    38 #include <sys/sysctl.h>
       
    39 #include <sys/file.h>
       
    40 #include <sys/stat.h>
       
    41 #ifdef LINUX
       
    42 #include <sys/wait.h>
       
    43 #endif
       
    44 #include <errno.h>
       
    45 #include <limits.h>
       
    46 #include <pwd.h>
       
    47 #include <iostream>
       
    48 #include <algorithm>
       
    49 #include <dlfcn.h>
       
    50 #include <signal.h>
       
    51 
       
    52 
       
    53 PosixPlatform::PosixPlatform(void) {
       
    54 }
       
    55 
       
    56 PosixPlatform::~PosixPlatform(void) {
       
    57     if (!SingleInstanceFile.empty()) {
       
    58         unlink(SingleInstanceFile.c_str());
       
    59     }
       
    60 }
       
    61 
       
    62 TString PosixPlatform::GetTempDirectory() {
       
    63     struct passwd* pw = getpwuid(getuid());
       
    64     TString homedir(pw->pw_dir);
       
    65     homedir += getTmpDirString();
       
    66     if (!FilePath::DirectoryExists(homedir)) {
       
    67         if (!FilePath::CreateDirectory(homedir, false)) {
       
    68             homedir.clear();
       
    69         }
       
    70     }
       
    71 
       
    72     return homedir;
       
    73 }
       
    74 
       
    75 TString PosixPlatform::fixName(const TString& name) {
       
    76     TString fixedName(name);
       
    77     const TString chars("?:*<>/\\");
       
    78     for (TString::const_iterator it = chars.begin(); it != chars.end(); it++) {
       
    79         fixedName.erase(std::remove(fixedName.begin(),
       
    80                 fixedName.end(), *it), fixedName.end());
       
    81     }
       
    82     return fixedName;
       
    83 }
       
    84 
       
    85 // returns true if another instance is already running.
       
    86 // if false, we need to continue regular launch.
       
    87 bool PosixPlatform::CheckForSingleInstance(TString appName) {
       
    88     TString tmpDir = GetTempDirectory();
       
    89     if (tmpDir.empty()) {
       
    90         printf("Unable to check for single instance.\n");
       
    91         return false;
       
    92     }
       
    93 
       
    94     TString lockFile = tmpDir + "/" + fixName(appName);
       
    95     SingleInstanceFile = lockFile;
       
    96     int pid_file = open(lockFile.c_str(), O_CREAT | O_RDWR, 0666);
       
    97     int rc = flock(pid_file, LOCK_EX | LOCK_NB);
       
    98 
       
    99     if (rc) {
       
   100         if (EWOULDBLOCK == errno) {
       
   101             // another instance is running
       
   102             pid_t pid = 0;
       
   103             read(pid_file, (void*)&pid, sizeof(pid_t));
       
   104             printf("Another instance is running PID: %d\n", pid);
       
   105             if (pid != 0) {
       
   106                 singleInstanceProcessId = pid;
       
   107                 SingleInstanceFile.clear();
       
   108                 return true;
       
   109             }
       
   110         } else {
       
   111             printf("Unable to check for single instance.\n");
       
   112         }
       
   113     } else {
       
   114         // It is the first instance.
       
   115         pid_t pid = getpid();
       
   116         write(pid_file, (void*)&pid, sizeof(pid_t));
       
   117     }
       
   118 
       
   119     return false;
       
   120 }
       
   121 
       
   122 MessageResponse PosixPlatform::ShowResponseMessage(TString title,
       
   123         TString description) {
       
   124     MessageResponse result = mrCancel;
       
   125 
       
   126     printf("%s %s (Y/N)\n", PlatformString(title).toPlatformString(),
       
   127             PlatformString(description).toPlatformString());
       
   128     fflush(stdout);
       
   129 
       
   130     std::string input;
       
   131     std::cin >> input;
       
   132 
       
   133     if (input == "Y") {
       
   134         result = mrOK;
       
   135     }
       
   136 
       
   137     return result;
       
   138 }
       
   139 
       
   140 void PosixPlatform::SetCurrentDirectory(TString Value) {
       
   141     chdir(StringToFileSystemString(Value));
       
   142 }
       
   143 
       
   144 Module PosixPlatform::LoadLibrary(TString FileName) {
       
   145     return dlopen(StringToFileSystemString(FileName), RTLD_LAZY);
       
   146 }
       
   147 
       
   148 void PosixPlatform::FreeLibrary(Module AModule) {
       
   149     dlclose(AModule);
       
   150 }
       
   151 
       
   152 Procedure PosixPlatform::GetProcAddress(Module AModule,
       
   153         std::string MethodName) {
       
   154     return dlsym(AModule, PlatformString(MethodName));
       
   155 }
       
   156 
       
   157 std::vector<std::string> PosixPlatform::GetLibraryImports(
       
   158        const TString FileName) {
       
   159  std::vector<TString> result;
       
   160  return result;
       
   161 }
       
   162 
       
   163 std::vector<TString> PosixPlatform::FilterOutRuntimeDependenciesForPlatform(
       
   164        std::vector<TString> Imports) {
       
   165  std::vector<TString> result;
       
   166  return result;
       
   167 }
       
   168 
       
   169 Process* PosixPlatform::CreateProcess() {
       
   170     return new PosixProcess();
       
   171 }
       
   172 
       
   173 PosixProcess::PosixProcess() : Process() {
       
   174     FChildPID = 0;
       
   175     FRunning = false;
       
   176     FOutputHandle = 0;
       
   177     FInputHandle = 0;
       
   178 }
       
   179 
       
   180 PosixProcess::~PosixProcess() {
       
   181     Terminate();
       
   182 }
       
   183 
       
   184 void PosixProcess::Cleanup() {
       
   185     if (FOutputHandle != 0) {
       
   186         close(FOutputHandle);
       
   187         FOutputHandle = 0;
       
   188     }
       
   189 
       
   190     if (FInputHandle != 0) {
       
   191         close(FInputHandle);
       
   192         FInputHandle = 0;
       
   193     }
       
   194 
       
   195 #ifdef MAC
       
   196     sigaction(SIGINT, &savintr, (struct sigaction *)0);
       
   197     sigaction(SIGQUIT, &savequit, (struct sigaction *)0);
       
   198     sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *)0);
       
   199 #endif //MAC
       
   200 }
       
   201 
       
   202 bool PosixProcess::ReadOutput() {
       
   203     bool result = false;
       
   204 
       
   205     if (FOutputHandle != 0 && IsRunning() == true) {
       
   206         char buffer[4096];
       
   207 
       
   208         ssize_t count = read(FOutputHandle, buffer, sizeof(buffer));
       
   209 
       
   210         if (count == -1) {
       
   211             if (errno == EINTR) {
       
   212                 // continue;
       
   213             } else {
       
   214                 perror("read");
       
   215                 exit(1);
       
   216             }
       
   217         } else if (count == 0) {
       
   218             // break;
       
   219         } else {
       
   220             if (buffer[count] == EOF) {
       
   221                 buffer[count] = '\0';
       
   222             }
       
   223 
       
   224             std::list<TString> output = Helpers::StringToArray(buffer);
       
   225             FOutput.splice(FOutput.end(), output, output.begin(), output.end());
       
   226             result = true;
       
   227         }
       
   228     }
       
   229 
       
   230     return false;
       
   231 }
       
   232 
       
   233 bool PosixProcess::IsRunning() {
       
   234     bool result = false;
       
   235 
       
   236     if (kill(FChildPID, 0) == 0) {
       
   237         result = true;
       
   238     }
       
   239 
       
   240     return result;
       
   241 }
       
   242 
       
   243 bool PosixProcess::Terminate() {
       
   244     bool result = false;
       
   245 
       
   246     if (IsRunning() == true && FRunning == true) {
       
   247         FRunning = false;
       
   248         Cleanup();
       
   249         int status = kill(FChildPID, SIGTERM);
       
   250 
       
   251         if (status == 0) {
       
   252             result = true;
       
   253         } else {
       
   254 #ifdef DEBUG
       
   255             if (errno == EINVAL) {
       
   256                 printf("Kill error: The value of the sig argument is an invalid or unsupported signal number.");
       
   257             } else if (errno == EPERM) {
       
   258                 printf("Kill error: The process does not have permission to send the signal to any receiving process.");
       
   259             } else if (errno == ESRCH) {
       
   260                 printf("Kill error: No process or process group can be found corresponding to that specified by pid.");
       
   261             }
       
   262 #endif // DEBUG
       
   263             if (IsRunning() == true) {
       
   264                 status = kill(FChildPID, SIGKILL);
       
   265 
       
   266                 if (status == 0) {
       
   267                     result = true;
       
   268                 }
       
   269             }
       
   270         }
       
   271     }
       
   272 
       
   273     return result;
       
   274 }
       
   275 
       
   276 #define PIPE_READ 0
       
   277 #define PIPE_WRITE 1
       
   278 
       
   279 bool PosixProcess::Execute(const TString Application,
       
   280         const std::vector<TString> Arguments, bool AWait) {
       
   281     bool result = false;
       
   282 
       
   283     if (FRunning == false) {
       
   284         FRunning = true;
       
   285 
       
   286         int handles[2];
       
   287 
       
   288         if (pipe(handles) == -1) {
       
   289             return false;
       
   290         }
       
   291 
       
   292         struct sigaction sa;
       
   293         sa.sa_handler = SIG_IGN;
       
   294         sigemptyset(&sa.sa_mask);
       
   295         sa.sa_flags = 0;
       
   296 #ifdef MAC
       
   297         sigemptyset(&savintr.sa_mask);
       
   298         sigemptyset(&savequit.sa_mask);
       
   299         sigaction(SIGINT, &sa, &savintr);
       
   300         sigaction(SIGQUIT, &sa, &savequit);
       
   301         sigaddset(&sa.sa_mask, SIGCHLD);
       
   302         sigprocmask(SIG_BLOCK, &sa.sa_mask, &saveblock);
       
   303 #endif // MAC
       
   304         FChildPID = fork();
       
   305 
       
   306         // PID returned by vfork is 0 for the child process and the
       
   307         // PID of the child process for the parent.
       
   308         if (FChildPID == -1) {
       
   309             // Error
       
   310             TString message = PlatformString::Format(
       
   311                     _T("Error: Unable to create process %s"),
       
   312                     Application.data());
       
   313             throw Exception(message);
       
   314         }
       
   315         else if (FChildPID == 0) {
       
   316             Cleanup();
       
   317             TString command = Application;
       
   318 
       
   319             for (std::vector<TString>::const_iterator iterator =
       
   320                     Arguments.begin(); iterator != Arguments.end();
       
   321                     iterator++) {
       
   322                 command += TString(_T(" ")) + *iterator;
       
   323             }
       
   324 #ifdef DEBUG
       
   325             printf("%s\n", command.data());
       
   326 #endif // DEBUG
       
   327 
       
   328             dup2(handles[PIPE_READ], STDIN_FILENO);
       
   329             dup2(handles[PIPE_WRITE], STDOUT_FILENO);
       
   330 
       
   331             close(handles[PIPE_READ]);
       
   332             close(handles[PIPE_WRITE]);
       
   333 
       
   334             execl("/bin/sh", "sh", "-c", command.data(), (char *)0);
       
   335 
       
   336             _exit(127);
       
   337         } else {
       
   338             FOutputHandle = handles[PIPE_READ];
       
   339             FInputHandle = handles[PIPE_WRITE];
       
   340 
       
   341             if (AWait == true) {
       
   342                 ReadOutput();
       
   343                 Wait();
       
   344                 Cleanup();
       
   345                 FRunning = false;
       
   346                 result = true;
       
   347             }
       
   348             else {
       
   349                 result = true;
       
   350             }
       
   351         }
       
   352     }
       
   353 
       
   354     return result;
       
   355 }
       
   356 
       
   357 bool PosixProcess::Wait() {
       
   358     bool result = false;
       
   359 
       
   360     int status = 0;
       
   361     pid_t wpid = 0;
       
   362 
       
   363 #ifdef LINUX
       
   364     wpid = wait(&status);
       
   365 #endif
       
   366 #ifdef MAC
       
   367     wpid = wait(&status);
       
   368 #endif
       
   369 
       
   370     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
       
   371         if (errno != EINTR){
       
   372             status = -1;
       
   373         }
       
   374     }
       
   375 
       
   376 #ifdef DEBUG
       
   377     if (WIFEXITED(status)) {
       
   378         printf("child exited, status=%d\n", WEXITSTATUS(status));
       
   379     } else if (WIFSIGNALED(status)) {
       
   380         printf("child killed (signal %d)\n", WTERMSIG(status));
       
   381     } else if (WIFSTOPPED(status)) {
       
   382         printf("child stopped (signal %d)\n", WSTOPSIG(status));
       
   383 #ifdef WIFCONTINUED // Not all implementations support this
       
   384     } else if (WIFCONTINUED(status)) {
       
   385         printf("child continued\n");
       
   386 #endif // WIFCONTINUED
       
   387     } else { // Non-standard case -- may never happen
       
   388         printf("Unexpected status (0x%x)\n", status);
       
   389     }
       
   390 #endif // DEBUG
       
   391 
       
   392     if (wpid != -1) {
       
   393         result = true;
       
   394     }
       
   395 
       
   396     return result;
       
   397 }
       
   398 
       
   399 TProcessID PosixProcess::GetProcessID() {
       
   400     return FChildPID;
       
   401 }
       
   402 
       
   403 void PosixProcess::SetInput(TString Value) {
       
   404     if (FInputHandle != 0) {
       
   405         write(FInputHandle, Value.data(), Value.size());
       
   406     }
       
   407 }
       
   408 
       
   409 std::list<TString> PosixProcess::GetOutput() {
       
   410     ReadOutput();
       
   411     return Process::GetOutput();
       
   412 }
       
   413 
       
   414 #endif // POSIX