void JNICALL Java_java_lang_Runtime_00024SubProcess_createProcess0()

in vm/vmcore/src/kernel_classes/native/Runtime_lnx.cpp [67:251]


void JNICALL Java_java_lang_Runtime_00024SubProcess_createProcess0 (JNIEnv *env, jobject obj, jobjectArray cmdarray, jobjectArray envp, jstring dir, jlongArray la){
    jobject jo; 

     const char *strChain;
     int i;

     char *cmdDir = NULL;
     char *strCmd = NULL; 

     // Get the working directory of the subprocess:
     if ( dir != NULL ) {
         char* str = (char *)env->GetStringUTFChars(dir, 0);
         cmdDir = (char *)malloc(1+strlen(str)); // + NUL symbol
         *cmdDir = '\0';
         strcat(cmdDir, str);
         env->ReleaseStringUTFChars(dir, str);
     }  

     // Get the the command to call and its arguments (it must be non-null):
     int lenargv = 0;
     lenargv = env->GetArrayLength(cmdarray);
     char *argv[lenargv+1];
     for ( i = 0; i < lenargv; i++ ) {
         jo = env->GetObjectArrayElement((jobjectArray)((jobject)cmdarray), (jsize) i);
         strChain = env->GetStringUTFChars((jstring) jo, 0);
         strCmd = (char *)malloc(1+strlen(strChain)); // + NUL symbol
         *strCmd = '\0';
         strcat(strCmd, strChain);
         argv[i] = strCmd;
         env->ReleaseStringUTFChars((jstring) jo, strChain);
     }
     argv[lenargv] = (char *) 0; // NULL pointer

     // Get the array, each element of which has environment variable settings:
     int lenEnvp = 0;
     if (envp != NULL) {
         lenEnvp += env->GetArrayLength(envp);
     }
     char *strEnvpBeginAA[lenEnvp + 1];
     if (envp != NULL) {
         for ( i = 0; i < lenEnvp; i++ ) {
             jo = env->GetObjectArrayElement((jobjectArray)((jobject)envp), (jsize) i);
             strChain = env->GetStringUTFChars((jstring) jo, 0);
             strCmd = (char *)malloc(1+strlen(strChain)); // + NUL symbol
             *strCmd = '\0';
             strcat(strCmd, strChain);
             strEnvpBeginAA[i] = strCmd;
             env->ReleaseStringUTFChars((jstring) jo, strChain);
         }
     }

     strEnvpBeginAA[lenEnvp] = (char *) 0; // NULL pointer

     //define stdI/O/E for future process:
     int fildesO[2] = {-1,-1};
     int fildesE[2] = {-1,-1};
     int fildesI[2] = {-1,-1};
     // Controlling pipe.
     // Child process if successfully executed will close the handle (by system)
     // If execv failed the write(..) call will write 4 bytes in this stream.
     // Thus we can distinguish executed proccesses and failed ones.
     int fildesInfo[2] = {-1,-1};

     if (pipe(fildesO) == -1
             || pipe(fildesI) == -1
             || pipe(fildesE) == -1
             || pipe(fildesInfo) == -1) {
         if (fildesO[0] != -1) close(fildesO[0]);
         if (fildesO[1] != -1) close(fildesO[1]);
         if (fildesE[0] != -1) close(fildesE[0]);
         if (fildesE[1] != -1) close(fildesE[1]);
         if (fildesI[0] != -1) close(fildesI[0]);
         if (fildesI[1] != -1) close(fildesI[1]);
         if (fildesInfo[0] != -1) close(fildesInfo[0]);
         if (fildesInfo[1] != -1) close(fildesInfo[1]);
         Error("Stdin/stdout pipes creation failed:", env, la); 
         Error(strerror(errno), env, la); 
         return;
     }
     int spid = fork();
 
     if (spid == -1) {
         close(fildesI[0]);
         close(fildesI[1]);
         close(fildesO[0]);
         close(fildesO[1]);
         close(fildesE[0]);
         close(fildesE[1]);
         close(fildesInfo[0]);
         close(fildesInfo[1]);
         Error("Fork failed\n", env, la); 
     }

     if (spid==0) {
         ///// Child process code ///////////////
         dup2(fildesI[0], 0);
         dup2(fildesO[1], 1);
         dup2(fildesE[1], 2);
         close(fildesI[0]);
         close(fildesI[1]);
         close(fildesO[0]);
         close(fildesO[1]);
         close(fildesE[0]);
         close(fildesE[1]);
         close(fildesInfo[0]);
         long close_on_exec = FD_CLOEXEC; // set close on exec bit
         fcntl(fildesInfo[1], F_SETFD, close_on_exec);

         // Get the working directory of the subprocess:
         if ( cmdDir != NULL ) {
             int res = chdir(cmdDir);
             if (res == -1) {
                 write(fildesInfo[1], &errno, sizeof(int));
                 INFO("chdir failed: " << strerror(errno));
                 kill(getpid(), 9);
             }
             free(cmdDir);
         }
         
         if (lenEnvp == 0) {
             execvp(argv[0], argv);
         } else {
             execve(argv[0], argv, strEnvpBeginAA);
             if(strchr(argv[0], '/') == NULL) {
                 char* curDir = NULL;
                 char* cmdPath = NULL;
                 char* dirs = NULL;
                 if ((dirs = getenv("PATH")) != NULL) {
                     int len = 0;
                     curDir = strtok(dirs, ":");
                     while(curDir != NULL) {
                         if((len = strlen(curDir)) != 0) {
                             cmdPath = (char *)malloc(len+1+strlen(argv[0])+1);
                             *cmdPath = '\0';
                             strcat(strcat(strcat(cmdPath, curDir), "/"), argv[0]);
                             if (fopen(cmdPath, "r") != NULL) {
                                 execve(cmdPath, argv, strEnvpBeginAA);
                                 //XXX: should we inform only of a last error among all possible execve atempts?
                             }
                             free(cmdPath);
                         }
                         curDir = strtok(NULL, ":");
                     }
                 }
             }
         }
         write(fildesInfo[1], &errno, sizeof(int));
         INFO("Process initiation failed: " << strerror(errno));
         // kill self
         kill(getpid(), 9);
     }
     ///// End of child process code ////////////

     close(fildesO[1]);
     close(fildesI[0]);
     close(fildesE[1]);
     close(fildesInfo[1]);
     free(cmdDir);
     free(strCmd);

     // get execution status from child
     int errno_child;
     int res = read(fildesInfo[0], &errno_child, sizeof(int));
     if (res == 4) {
         Error("Process initiation failed", env, la);
         Error(strerror(errno_child), env, la);
         close(fildesO[0]);
         close(fildesI[1]);
         close(fildesE[0]);
         close(fildesInfo[0]);
         return;
     }

   jboolean jb = true;
   jlong *lp = (jlong*)env->GetLongArrayElements(la, &jb);
   lp[0] = (jlong) spid; // new process number 
   lp[1] = (jlong) fildesI[1];
   lp[2] = (jlong) fildesO[0];
   lp[3] = (jlong) fildesE[0];
   fcntl(fildesO[0], F_SETFL, 0); //XXX:to set !O_NONBLOCK because it is sometimes set by default and it should be investigated
   fcntl(fildesE[0], F_SETFL, 0); //XXX:to set !O_NONBLOCK because it is sometimes set by default and it should be investigated
   env->ReleaseLongArrayElements(la, lp, 0);

   close(fildesInfo[0]);
}