JError JExecute ( const JCharacter* argv[], const JSize size, pid_t* childPID, const JExecuteAction toAction, int* toFD, const JExecuteAction origFromAction, int* fromFD, const JExecuteAction errAction, int* errFD ) { assert( size > sizeof(JCharacter*) ); assert( argv[ (size/sizeof(JCharacter*)) - 1 ] == NULL ); const JExecuteAction fromAction = (origFromAction == kJForceNonblockingPipe ? kJCreatePipe : origFromAction); assert( toAction != kJTossOutput && toAction != kJAttachToFromFD && toAction != kJForceNonblockingPipe ); assert( fromAction != kJAttachToFromFD ); assert( errAction != kJForceNonblockingPipe ); assert( (toAction != kJCreatePipe && toAction != kJAttachToFD) || toFD != NULL ); assert( (fromAction != kJCreatePipe && fromAction != kJAttachToFD) || fromFD != NULL ); assert( (errAction != kJCreatePipe && errAction != kJAttachToFD) || errFD != NULL ); JString progName; if (!JProgramAvailable(argv[0], &progName)) { return JProgramNotAvailable(argv[0]); } argv[0] = progName.GetCString(); int fd[3][2]; if (toAction == kJCreatePipe) { const JError err = JCreatePipe(fd[0]); if (!err.OK()) { return err; } } if (fromAction == kJCreatePipe) { const JError err = JCreatePipe(fd[1]); if (!err.OK()) { if (toAction == kJCreatePipe) { close(fd[0][0]); close(fd[0][1]); } return err; } } if (errAction == kJCreatePipe) { const JError err = JCreatePipe(fd[2]); if (!err.OK()) { if (toAction == kJCreatePipe) { close(fd[0][0]); close(fd[0][1]); } if (fromAction == kJCreatePipe) { close(fd[1][0]); close(fd[1][1]); } return err; } } pid_t pid; const JError err = JThisProcess::Fork(&pid); if (!err.OK()) { if (toAction == kJCreatePipe) { close(fd[0][0]); close(fd[0][1]); } if (fromAction == kJCreatePipe) { close(fd[1][0]); close(fd[1][1]); } if (errAction == kJCreatePipe) { close(fd[2][0]); close(fd[2][1]); } return err; } // child else if (pid == 0) { const int stdinFD = fileno(stdin); if (toAction == kJCreatePipe) { dup2(fd[0][0], stdinFD); close(fd[0][0]); close(fd[0][1]); } else if (toAction == kJAttachToFD) { dup2(*toFD, stdinFD); close(*toFD); } const int stdoutFD = fileno(stdout); if (fromAction == kJCreatePipe) { dup2(fd[1][1], stdoutFD); close(fd[1][0]); close(fd[1][1]); } else if (fromAction == kJAttachToFD) { dup2(*fromFD, stdoutFD); close(*fromFD); } else if (fromAction == kJTossOutput) { FILE* nullFile = fopen("/dev/null", "a"); int nullfd = fileno(nullFile); dup2(nullfd, stdoutFD); fclose(nullFile); } const int stderrFD = fileno(stderr); if (errAction == kJCreatePipe) { dup2(fd[2][1], stderrFD); close(fd[2][0]); close(fd[2][1]); } else if (errAction == kJAttachToFD) { dup2(*errFD, stderrFD); close(*errFD); } else if (errAction == kJTossOutput) { FILE* nullFile = fopen("/dev/null", "a"); int nullfd = fileno(nullFile); dup2(nullfd, stderrFD); fclose(nullFile); } else if (errAction == kJAttachToFromFD && fromAction != kJIgnoreConnection) { dup2(stdoutFD, stderrFD); } ACE_OS::execvp(argv[0], const_cast<char* const*>(argv)); cerr << "Unable to run program \"" << argv[0] << '"' << endl; cerr << endl; cerr << "JExecute()::execvp() failed" << endl; cerr << "Errno value: " << jerrno() << endl; JThisProcess::Exit(1); return JNoError(); } // parent else { if (origFromAction == kJForceNonblockingPipe) { pid_t pid2; const JError err2 = JThisProcess::Fork(&pid2); if (err2.OK() && pid2 == 0) { for (int i=0; i<150; i++) { JWait(0.1); int value = fcntl(fd[1][1], F_GETFL, 0); if (value & O_NONBLOCK) { cerr << "turning off nonblocking for cout: " << value << endl; fcntl(fd[1][1], F_SETFL, value & (~ O_NONBLOCK)); } } JThisProcess::Exit(0); return JNoError(); } JProcess* p = new JProcess(pid2); p->KillAtExit(kJTrue); } if (toAction == kJCreatePipe) { close(fd[0][0]); *toFD = fd[0][1]; } if (fromAction == kJCreatePipe) { close(fd[1][1]); *fromFD = fd[1][0]; } if (errAction == kJCreatePipe) { close(fd[2][1]); *errFD = fd[2][0]; } if (childPID == NULL) { return JWaitForChild(pid); } else { *childPID = pid; return JNoError(); } } }