📄 vk_process.cpp
字号:
the environment variable LD_LIBRARY_PATH, then this variable is inherited from the starting process; under Windows the same applies for the environment variable PATH. Returns true if the process could be started; otherwise returns false. You can write data to the process's standard input with writeToStdin(). You can close standard input with closeStdin() and you can terminate the process with tryTerminate(), or with kill(). You can call this function even if you've used this instance to create a another process which is still running. In such cases, VKProcess closes the old process's standard input and deletes pending data, i.e., you lose all control over the old process, but the old process is not terminated. This applies also if the process could not be started. (On operating systems that have zombie processes, Qt will also wait() on the old process.) */ bool VKProcess::start( QStringList *env ) {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcess::start()" );#endif reset(); int sFDin[2]; int sStdin[2]; int sFDout[2]; int sStdout[2]; int sStderr[2]; // open sockets for piping#ifndef Q_OS_QNX6 if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) {#else if ( (comms & Stdin) && qnx6SocketPairReplacement(sStdin) == -1 ) {#endif return false; }#ifndef Q_OS_QNX6 if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) {#else if ( (comms & Stderr) && qnx6SocketPairReplacement(sStderr) == -1 ) {#endif if ( comms & Stdin ) { ::close( sStdin[0] ); ::close( sStdin[1] ); } return false; }#ifndef Q_OS_QNX6 if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) {#else if ( (comms & Stdout) && qnx6SocketPairReplacement(sStdout) == -1 ) {#endif if ( comms & Stdin ) { ::close( sStdin[0] ); ::close( sStdin[1] ); } if ( comms & Stderr ) { ::close( sStderr[0] ); ::close( sStderr[1] ); } return false; }#ifndef Q_OS_QNX6 if ( (comms & FDin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sFDin ) == -1 ) {#else if ( (comms & FDin) && qnx6SocketPairReplacement(sFDin) == -1 ) {#endif if ( comms & Stdin ) { ::close( sStdin[0] ); ::close( sStdin[1] ); } if ( comms & Stderr ) { ::close( sStderr[0] ); ::close( sStderr[1] ); } if ( comms & Stdout ) { ::close( sStdout[0] ); ::close( sStdout[1] ); } return false; }#ifndef Q_OS_QNX6 if ( (comms & FDout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sFDout ) == -1 ) {#else if ( (comms & FDout) && qnx6SocketPairReplacement(sFDout) == -1 ) {#endif if ( comms & Stdin ) { ::close( sStdin[0] ); ::close( sStdin[1] ); } if ( comms & Stderr ) { ::close( sStderr[0] ); ::close( sStderr[1] ); } if ( comms & Stdout ) { ::close( sStdout[0] ); ::close( sStdout[1] ); } if ( comms & FDin ) { ::close( sFDin[0] ); ::close( sFDin[1] ); } return false; } /* the following pipe is only used to determine if the process could be started */ int fd[2]; if ( pipe( fd ) < 0 ) { // non critical error, go on fd[0] = 0; fd[1] = 0; } // construct the arguments for exec QCString *arglistQ = new QCString[ _arguments.count() + 1 ]; const char** arglist = new const char*[ _arguments.count() + 1 ]; int i = 0; for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) { arglistQ[i] = (*it).local8Bit(); arglist[i] = arglistQ[i];#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcess::start(): arg %d = %s", i, arglist[i] );#endif i++; }#ifdef Q_OS_MACX if(i) { QCString arg_bundle = arglistQ[0]; QFileInfo fi(arg_bundle); if(fi.exists() && fi.isDir() && arg_bundle.right(4) == ".app") { QCString exe = arg_bundle; int lslash = exe.findRev('/'); if(lslash != -1) exe = exe.mid(lslash+1); exe = QCString(arg_bundle + "/Contents/MacOS/" + exe); exe = exe.left(exe.length() - 4); //chop off the .app if(QFile::exists(exe)) { arglistQ[0] = exe; arglist[0] = arglistQ[0]; } } }#endif arglist[i] = 0; /* Must make sure signal handlers are installed before exec'ing in case the process exits quickly. */ if ( d->procManager == 0 ) { d->procManager = new VKProcessManager; qAddPostRoutine(vkprocess_cleanup); } // fork and exec QApplication::flushX(); pid_t pid = fork(); if ( pid == 0 ) { // child d->closeOpenSocketsForChild(); if ( comms & FDin ) { ::close( sFDin[1] ); ::dup2( sFDin[0], filedesc_in ); } if ( comms & FDout ) { ::close( sFDout[0] ); ::dup2( sFDout[1], filedesc_out ); } if ( comms & Stdin ) { ::close( sStdin[1] ); ::dup2( sStdin[0], STDIN_FILENO ); } if ( comms & Stdout ) { ::close( sStdout[0] ); ::dup2( sStdout[1], STDOUT_FILENO ); } if ( comms & Stderr ) { ::close( sStderr[0] ); ::dup2( sStderr[1], STDERR_FILENO ); } if ( comms & DupStderr ) { ::dup2( STDOUT_FILENO, STDERR_FILENO ); } ::chdir( workingDir.absPath().latin1() ); if ( fd[0] ) ::close( fd[0] ); if ( fd[1] ) ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess if ( env == 0 ) { // inherit environment and start process QString command = _arguments[0];#if defined(Q_OS_MACX) //look in a bundle const QString mac_bundle_suffix = ".app/Contents/MacOS/"; if(!QFile::exists(command) && QFile::exists(command + mac_bundle_suffix)) { QString exec = command; int lslash = command.findRev('/'); if(lslash != -1) exec = command.mid(lslash+1); QFileInfo fileInfo( command + mac_bundle_suffix + exec ); if ( fileInfo.isExecutable() ) command = fileInfo.absFilePath().local8Bit(); }#endif#ifndef Q_OS_QNX4 ::execvp( command, (char*const*)arglist ); // ### cast not nice#else ::execvp( command, (char const*const*)arglist ); // ### cast not nice#endif } else { // start process with environment settins as specified in env // construct the environment for exec int numEntries = env->count();#if defined(Q_OS_MACX) QString ld_library_path("DYLD_LIBRARY_PATH");#else QString ld_library_path("LD_LIBRARY_PATH");#endif bool setLibraryPath = env->grep( QRegExp( "^" + ld_library_path + "=" ) ).empty() && getenv( ld_library_path ) != 0; if ( setLibraryPath ) numEntries++; QCString *envlistQ = new QCString[ numEntries + 1 ]; const char** envlist = new const char*[ numEntries + 1 ]; int i = 0; if ( setLibraryPath ) { envlistQ[i] = QString( ld_library_path + "=%1" ).arg( getenv( ld_library_path ) ).local8Bit(); envlist[i] = envlistQ[i]; i++; } for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) { envlistQ[i] = (*it).local8Bit(); envlist[i] = envlistQ[i]; i++; } envlist[i] = 0; // look for the executable in the search path if ( _arguments.count()>0 && getenv("PATH")!=0 ) { QString command = _arguments[0]; if ( !command.contains( '/' ) ) { QStringList pathList = QStringList::split( ':', getenv( "PATH" ) ); for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) { QString dir = *it;#if defined(Q_OS_MACX) //look in a bundle if ( !QFile::exists(dir + "/" + command) && QFile::exists(dir + "/" + command + ".app") ) dir += "/" + command + ".app/Contents/MacOS";#endif QFileInfo fileInfo( dir, command ); if ( fileInfo.isExecutable() ) {#if defined(Q_OS_MACX) arglistQ[0] = fileInfo.absFilePath().local8Bit();#else arglistQ[0] = fileInfo.filePath().local8Bit();#endif arglist[0] = arglistQ[0]; break; } } } }#if defined(Q_OS_MACX) if ( ! QFile::exists( arglist[0] ) ) { QString command = arglist[0]; const QString mac_bundle_suffix = ".app/Contents/MacOS/"; if ( QFile::exists(command + mac_bundle_suffix ) ) { QString exec = command; int lslash = command.findRev('/'); if(lslash != -1) exec = command.mid(lslash+1); QFileInfo fileInfo( command + mac_bundle_suffix + exec ); if ( fileInfo.isExecutable() ) { arglistQ[0] = fileInfo.absFilePath().local8Bit(); arglist[0] = arglistQ[0]; } } }#endif#ifndef Q_OS_QNX4 ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice#else ::execve( arglist[0], (char const*const*)arglist,(char const*const*)envlist ); // ### casts not nice#endif } if ( fd[1] ) { char buf = 0; ::write( fd[1], &buf, 1 ); ::close( fd[1] ); } ::_exit( -1 ); } else if ( pid == -1 ) { // error forking goto error; } // test if exec was successful if ( fd[1] ) ::close( fd[1] ); if ( fd[0] ) { char buf; for ( ;; ) { int n = ::read( fd[0], &buf, 1 ); if ( n==1 ) { // socket was not closed => error if ( ::waitpid( pid, 0, WNOHANG ) != pid ) { /* The wait did not succeed yet, so try again when we get the sigchild (to avoid zombies). */ d->newProc( pid, 0 ); } d->proc = 0; goto error; } else if ( n==-1 ) { if ( errno==EAGAIN || errno==EINTR ) // try it again continue; } break; } ::close( fd[0] ); } d->newProc( pid, this ); if ( comms & FDin ) { ::close( sFDin[0] ); d->proc->socketFDin = sFDin[1]; // Select non-blocking mode int originalFlags = fcntl(d->proc->socketFDin, F_GETFL, 0); fcntl(d->proc->socketFDin, F_SETFL, originalFlags | O_NONBLOCK); d->notifierFDin = new QSocketNotifier( sFDin[1], QSocketNotifier::Write ); connect( d->notifierFDin, SIGNAL(activated(int)), this, SLOT(socketWrite(int)) ); // setup notifiers for the sockets if ( !d->fdinBuf.isEmpty() ) { d->notifierFDin->setEnabled( true ); } } if ( comms & Stdin ) { ::close( sStdin[0] ); d->proc->socketStdin = sStdin[1]; // Select non-blocking mode int originalFlags = fcntl(d->proc->socketStdin, F_GETFL, 0); fcntl(d->proc->socketStdin, F_SETFL, originalFlags | O_NONBLOCK); d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write ); connect( d->notifierStdin, SIGNAL(activated(int)), this, SLOT(socketWrite(int)) ); // setup notifiers fo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -