📄 qprocess_unix.cpp
字号:
#endif stdinBufRead = 0; notifierStdin = 0; notifierStdout = 0; notifierStderr = 0; exitValuesCalculated = FALSE; socketReadCalled = FALSE; proc = 0;}QProcessPrivate::~QProcessPrivate(){#if defined(QT_QPROCESS_DEBUG) qDebug( "QProcessPrivate: Destructor" );#endif if ( proc != 0 ) { if ( proc->socketStdin != 0 ) { ::close( proc->socketStdin ); proc->socketStdin = 0; } proc->process = 0; } while ( !stdinBuf.isEmpty() ) { delete stdinBuf.dequeue(); } delete notifierStdin; delete notifierStdout; delete notifierStderr;}/* Closes all open sockets in the child process that are not needed by the child process. Otherwise one child may have an open socket on standard input, etc. of another child.*/void QProcessPrivate::closeOpenSocketsForChild(){ if ( procManager != 0 ) { if ( procManager->sigchldFd[0] != 0 ) ::close( procManager->sigchldFd[0] ); if ( procManager->sigchldFd[1] != 0 ) ::close( procManager->sigchldFd[1] ); // close also the sockets from other QProcess instances QProc *proc; for ( proc=procManager->procList->first(); proc!=0; proc=procManager->procList->next() ) { ::close( proc->socketStdin ); ::close( proc->socketStdout ); ::close( proc->socketStderr ); } }}void QProcessPrivate::newProc( pid_t pid, QProcess *process ){ proc = new QProc( pid, process ); if ( procManager == 0 ) { procManager = new QProcessManager; qprocess_cleanup_procmanager.add( &procManager ); } // the QProcessManager takes care of deleting the QProc instances procManager->append( proc );}/*********************************************************************** * * sigchld handler callback * **********************************************************************/QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS ){ if ( QProcessPrivate::procManager == 0 ) return; if ( QProcessPrivate::procManager->sigchldFd[0] == 0 ) return; char a = 1; ::write( QProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );}QT_SIGNAL_RETTYPE qt_C_sigpipeHnd( QT_SIGNAL_ARGS ){ // Ignore (but in a way somehow different to SIG_IGN).}/*********************************************************************** * * QProcess * **********************************************************************//*! This private class does basic initialization.*/void QProcess::init(){ d = new QProcessPrivate(); exitStat = 0; exitNormal = FALSE;}/*! This private class resets the process variables, etc. so that it can be used for another process to start.*/void QProcess::reset(){ delete d; d = new QProcessPrivate(); exitStat = 0; exitNormal = FALSE; d->bufStdout.resize( 0 ); d->bufStderr.resize( 0 );}QByteArray* QProcess::bufStdout(){ if ( d->proc && d->proc->socketStdout ) { // ### can this cause a blocking behaviour (maybe do a ioctl() to see // if data is available)? socketRead( d->proc->socketStdout ); } return &d->bufStdout;}QByteArray* QProcess::bufStderr(){ if ( d->proc && d->proc->socketStderr ) { // ### can this cause a blocking behaviour (maybe do a ioctl() to see // if data is available)? socketRead( d->proc->socketStderr ); } return &d->bufStderr;}void QProcess::consumeBufStdout( int consume ){ uint n = d->bufStdout.size(); if ( consume==-1 || (uint)consume >= n ) { d->bufStdout.resize( 0 ); } else { QByteArray tmp( n - consume ); memcpy( tmp.data(), d->bufStdout.data()+consume, n-consume ); d->bufStdout = tmp; }}void QProcess::consumeBufStderr( int consume ){ uint n = d->bufStderr.size(); if ( consume==-1 || (uint)consume >= n ) { d->bufStderr.resize( 0 ); } else { QByteArray tmp( n - consume ); memcpy( tmp.data(), d->bufStderr.data()+consume, n-consume ); d->bufStderr = tmp; }}/*! Destroys the class. If the process is running, it is NOT terminated! Standard input, standard output and standard error of the process are closed. You can connect the destroyed() signal to the kill() slot, if you want the process to be terminated automatically when the class is destroyed. \sa tryTerminate() kill()*/QProcess::~QProcess(){ delete d;}/*! Tries to run a process for the command and arguments that were specified with setArguments(), addArgument() or that were specified in the constructor. The command is searched in the path for executable programs; you can also use an absolute path to the command. If \a env is null, then the process is started with the same environment as the starting process. If \a env is non-null, then the values in the stringlist are interpreted as environment setttings of the form \c {key=value} and the process is started in these environment settings. For convenience, there is a small exception to this rule: under Unix, if \a env does not contain any settings for the environment variable \c LD_LIBRARY_PATH, then this variable is inherited from the starting process; under Windows the same applies for the enverionment varialbe \c PATH. Returns TRUE if the process could be started, otherwise FALSE. You can write data to standard input of the process with writeToStdin(), you can close standard input with closeStdin() and you can terminate the process tryTerminate() resp. kill(). You can call this function even when there already is a running process in this object. In this case, QProcess closes standard input of the old process and deletes pending data, i.e., you loose all control over that process, but the 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.) \sa launch() closeStdin()*/bool QProcess::start( QStringList *env ){#if defined(QT_QPROCESS_DEBUG) qDebug( "QProcess::start()" );#endif reset(); int sStdin[2]; int sStdout[2]; int sStderr[2]; // open sockets for piping if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) { return FALSE; } if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) { return FALSE; } if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -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(QT_QPROCESS_DEBUG) qDebug( "QProcess::start(): arg %d = %s", i, arglist[i] );#endif i++; } 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 QProcessManager; qprocess_cleanup_procmanager.add( &d->procManager ); } // fork and exec QApplication::flushX(); pid_t pid = fork(); if ( pid == 0 ) { // child d->closeOpenSocketsForChild(); 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 ); }#ifndef QT_NO_DIR ::chdir( workingDir.absPath().latin1() );#endif if ( fd[0] ) ::close( fd[0] ); if ( fd[1] ) ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess // put the child process into its parent's process group ::setpgid( ::getpid(), ::getppid() ); if ( env == 0 ) { // inherit environment and start process ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice } else { // start process with environment settins as specified in env // construct the environment for exec int numEntries = env->count(); bool setLibraryPath = env->grep( QRegExp( "^LD_LIBRARY_PATH=" ) ).isEmpty() && 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;#ifdef Q_OS_MACX if(QFile::exists(dir + "/" + command + ".app")) //look in a bundle dir += "/" + command + ".app/Contents/MacOS";#endif#ifndef QT_NO_DIR QFileInfo fileInfo( dir, command );#else QFileInfo fileInfo( dir + "/" + command );#endif if ( fileInfo.isExecutable() ) { arglistQ[0] = fileInfo.filePath().local8Bit(); arglist[0] = arglistQ[0]; break; } } } } ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice } 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 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 & Stdin ) { ::close( sStdin[0] ); d->proc->socketStdin = sStdin[1]; d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write ); connect( d->notifierStdin, SIGNAL(activated(int)), this, SLOT(socketWrite(int)) ); // setup notifiers for the sockets if ( !d->stdinBuf.isEmpty() ) { d->notifierStdin->setEnabled( TRUE ); } } if ( comms & Stdout ) { ::close( sStdout[1] ); d->proc->socketStdout = sStdout[0]; d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read ); connect( d->notifierStdout, SIGNAL(activated(int)), this, SLOT(socketRead(int)) ); if ( ioRedirection ) d->notifierStdout->setEnabled( TRUE ); } if ( comms & Stderr ) { ::close( sStderr[1] ); d->proc->socketStderr = sStderr[0];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -