X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5..acf619a3c304992a7ec093cd95fdd6c0805cca66:/lib/base/console.cpp diff --git a/lib/base/console.cpp b/lib/base/console.cpp index 2609582f..3f73fba1 100644 --- a/lib/base/console.cpp +++ b/lib/base/console.cpp @@ -1,32 +1,10 @@ -/* - * console.cpp - * - * Copyright (C) 2002 Felix Domke - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id: console.cpp,v 1.1 2003-10-17 15:35:47 tmbinc Exp $ - */ - #include - -#include +#include #include // for statfs #include #include #include +#include int bidirpipe(int pfd[], char *cmd , char *argv[]) { @@ -42,6 +20,7 @@ int bidirpipe(int pfd[], char *cmd , char *argv[]) return(-1); else if (pid == 0) /* child process */ { + setsid(); if ( close(0) == -1 || close(1) == -1 || close(2) == -1 ) _exit(0); @@ -53,7 +32,10 @@ int bidirpipe(int pfd[], char *cmd , char *argv[]) close(pfderr[0]) == -1 || close(pfderr[1]) == -1 ) _exit(0); - execv(cmd,argv); + for (unsigned int i=3; i < 90; ++i ) + close(i); + + execvp(cmd,argv); _exit(0); } if (close(pfdout[0]) == -1 || close(pfdin[1]) == -1 || close(pfderr[1]) == -1) @@ -66,40 +48,75 @@ int bidirpipe(int pfd[], char *cmd , char *argv[]) return(pid); } -eConsoleAppContainer::eConsoleAppContainer( const eString &cmd ) -:pid(-1), killstate(0), outbuf(0) +eConsoleAppContainer::eConsoleAppContainer() +:pid(-1), killstate(0), in(0), out(0), err(0) +{ + for (int i=0; i < 3; ++i) + fd[i]=-1; +} + +int eConsoleAppContainer::execute( const std::string &cmd ) { + if (running()) + return -1; + pid=-1; + killstate=0; // eDebug("cmd = %s", cmd.c_str() ); - memset(fd, 0, sizeof(fd) ); int cnt=2; // path to app + terminated 0 - eString str(cmd?cmd:""); - - while( str.length() && str[0] == ' ' ) // kill spaces at beginning - str = str.mid(1); - - while( str.length() && str[str.length()-1] == ' ' ) // kill spaces at the end - str = str.left( str.length() - 1 ); - - if (!str.length()) - return; - - unsigned int idx=0; - eString path = str.left( (idx = str.find(' ')) != eString::npos ? idx : str.length() ); + std::string str(cmd.length()?cmd:""); + + // kill spaces at beginning + unsigned int pos = str.find_first_not_of(' '); + if (pos != std::string::npos && pos) + str = str.substr(pos); + + // kill spaces at the end + pos = str.find_last_not_of(' '); + if (pos != std::string::npos && (pos+1) < str.length()) + str = str.erase(pos+1); + + unsigned int slen=str.length(); + if (!slen) + return -2; + + std::map brackets; + brackets.insert(std::pair('\'','\'')); + brackets.insert(std::pair('"','"')); + brackets.insert(std::pair('`','`')); + brackets.insert(std::pair('(',')')); + brackets.insert(std::pair('{','}')); + brackets.insert(std::pair('[',']')); + brackets.insert(std::pair('<','>')); + + unsigned int idx=str.find(' '); + std::string path = str.substr(0, idx != std::string::npos ? idx : slen ); // eDebug("path = %s", path.c_str() ); + unsigned int plen = path.length(); - eString cmds = str.mid( path.length()+1 ); + std::string cmds = slen > plen ? str.substr( plen+1 ) : ""; + unsigned int clen = cmds.length(); // eDebug("cmds = %s", cmds.c_str() ); idx = 0; - while ( (idx = cmds.find(' ',idx) ) != eString::npos ) // count args + std::map::iterator it = brackets.find(cmds[idx]); + while ( (idx = cmds.find(' ',idx) ) != std::string::npos ) // count args { - cnt++; + if (it != brackets.end()) + { + if (cmds[idx-1] == it->second) + it = brackets.end(); + } + if (it == brackets.end()) + { + cnt++; + it = brackets.find(cmds[idx+1]); + } idx++; } // eDebug("idx = %d, %d counted spaces", idx, cnt-2); - if ( cmds.length() ) + if ( clen ) { cnt++; // eDebug("increase cnt"); @@ -107,7 +124,9 @@ eConsoleAppContainer::eConsoleAppContainer( const eString &cmd ) // eDebug("%d args", cnt-2); char **argv = new char*[cnt]; // min two args... path and terminating 0 - argv[0] = new char[ path.length() ]; +// eDebug("%d args", cnt); + argv[0] = new char[ plen+1 ]; +// eDebug("new argv[0] %d bytes (%s)", plen+1, path.c_str()); strcpy( argv[0], path.c_str() ); argv[cnt-1] = 0; // set terminating null @@ -115,90 +134,170 @@ eConsoleAppContainer::eConsoleAppContainer( const eString &cmd ) { cnt=1; // do not overwrite path in argv[0] - while ( (idx = cmds.find(' ')) != eString::npos ) // parse all args.. + it = brackets.find(cmds[0]); + idx=0; + while ( (idx = cmds.find(' ',idx)) != std::string::npos ) // parse all args.. + { + bool bracketClosed=false; + if ( it != brackets.end() ) + { + if (cmds[idx-1]==it->second) + { + it = brackets.end(); + bracketClosed=true; + } + } + if ( it == brackets.end() ) + { + std::string tmp = cmds.substr(0, idx); + if (bracketClosed) + { + tmp.erase(0,1); + tmp.erase(tmp.length()-1, 1); + bracketClosed=false; + } +// eDebug("new argv[%d] %d bytes (%s)", cnt, tmp.length()+1, tmp.c_str()); + argv[cnt] = new char[ tmp.length()+1 ]; +// eDebug("idx=%d, arg = %s", idx, tmp.c_str() ); + strcpy( argv[cnt++], tmp.c_str() ); + cmds.erase(0, idx+1); +// eDebug("str = %s", cmds.c_str() ); + it = brackets.find(cmds[0]); + idx=0; + } + else + idx++; + } + if ( it != brackets.end() ) { - argv[cnt] = new char[ idx ]; -// eDebug("idx=%d, arg = %s", idx, cmds.left(idx).c_str() ); - strcpy( argv[cnt++], cmds.left( idx ).c_str() ); - cmds = cmds.mid(idx+1); -// eDebug("str = %s", cmds.c_str() ); + cmds.erase(0,1); + cmds.erase(cmds.length()-1, 1); } // store the last arg - argv[cnt] = new char[ cmds.length() ]; +// eDebug("new argv[%d] %d bytes (%s)", cnt, cmds.length()+1, cmds.c_str()); + argv[cnt] = new char[ cmds.length()+1 ]; strcpy( argv[cnt], cmds.c_str() ); } + else + cnt=1; // get one read ,one write and the err pipe to the prog.. + +// int tmp=0; +// while(argv[tmp]) +// eDebug("%d is %s", tmp, argv[tmp++]); - if ( (pid = bidirpipe(fd, argv[0], argv)) == -1 ) + pid = bidirpipe(fd, argv[0], argv); + + while ( cnt >= 0 ) // release heap memory { - while ( cnt-- > 0 ) - delete [] argv[cnt]; - delete [] argv; - return; +// eDebug("delete argv[%d]", cnt); + delete [] argv[cnt--]; } - - while ( cnt-- > 0 ) // release heap memory - delete [] argv[cnt]; +// eDebug("delete argv"); delete [] argv; + + if ( pid == -1 ) + return -3; - eDebug("pipe in = %d, out = %d, err = %d", fd[0], fd[1], fd[2]); +// eDebug("pipe in = %d, out = %d, err = %d", fd[0], fd[1], fd[2]); - in = new eSocketNotifier(eApp, fd[0], 19 ); // 19 = POLLIN, POLLPRI, POLLHUP - out = new eSocketNotifier(eApp, fd[1], eSocketNotifier::Write); // POLLOUT - err = new eSocketNotifier(eApp, fd[2], 19 ); // 19 = POLLIN, POLLPRI, POLLHUP + in = new eSocketNotifier(eApp, fd[0], eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Hungup ); + out = new eSocketNotifier(eApp, fd[1], eSocketNotifier::Write, false); + err = new eSocketNotifier(eApp, fd[2], eSocketNotifier::Read|eSocketNotifier::Priority ); CONNECT(in->activated, eConsoleAppContainer::readyRead); CONNECT(out->activated, eConsoleAppContainer::readyWrite); CONNECT(err->activated, eConsoleAppContainer::readyErrRead); - signal(SIGCHLD, SIG_IGN); // no zombie when child killed + return 0; } eConsoleAppContainer::~eConsoleAppContainer() { - if ( running() ) + kill(); +} + +void eConsoleAppContainer::kill() +{ + if ( killstate != -1 && pid != -1 ) { + eDebug("user kill(SIGKILL) console App"); killstate=-1; - kill(); + ::kill(pid, SIGKILL); + closePipes(); } - if ( outbuf ) - delete [] outbuf; + while( outbuf.size() ) // cleanup out buffer + { + queue_data d = outbuf.front(); + outbuf.pop(); + delete [] d.data; + } + delete in; + delete out; + delete err; + in=out=err=0; } -void eConsoleAppContainer::kill() +void eConsoleAppContainer::sendCtrlC() { - killstate=-1; - system( eString().sprintf("kill %d", pid).c_str() ); - eDebug("user kill console App"); + if ( killstate != -1 && pid != -1 ) + { + eDebug("user send SIGINT(Ctrl-C) to console App"); + ::kill(pid, SIGINT); + } } void eConsoleAppContainer::closePipes() { - in->stop(); - out->stop(); - err->stop(); - ::close(fd[0]); - fd[0]=0; - ::close(fd[1]); - fd[1]=0; - ::close(fd[2]); - fd[2]=0; + if (in) + in->stop(); + if (out) + out->stop(); + if (err) + err->stop(); + if (fd[0] != -1) + { + ::close(fd[0]); + fd[0]=-1; + } + if (fd[1] != -1) + { + ::close(fd[1]); + fd[1]=-1; + } + if (fd[2] != -1) + { + ::close(fd[2]); + fd[2]=-1; + } eDebug("pipes closed"); + while( outbuf.size() ) // cleanup out buffer + { + queue_data d = outbuf.front(); + outbuf.pop(); + delete [] d.data; + } + pid = -1; } void eConsoleAppContainer::readyRead(int what) { - if (what & POLLPRI|POLLIN) + bool hungup = what & eSocketNotifier::Hungup; + if (what & (eSocketNotifier::Priority|eSocketNotifier::Read)) { - eDebug("what = %d"); +// eDebug("what = %d"); char buf[2048]; - int readed = read(fd[0], buf, 2048); - eDebug("%d bytes read", readed); - if ( readed != -1 && readed ) - /*emit*/ dataAvail( eString( buf ) ); - else if (readed == -1) - eDebug("readerror %d", errno); + int rd; + while((rd = read(fd[0], buf, 2047)) > 0) + { +/* for ( int i = 0; i < rd; i++ ) + eDebug("%d = %c (%02x)", i, buf[i], buf[i] );*/ + buf[rd]=0; + /*emit*/ dataAvail(buf); + if (!hungup) + break; + } } - if (what & eSocketNotifier::Hungup) + if (hungup) { eDebug("child has terminated"); closePipes(); @@ -208,41 +307,47 @@ void eConsoleAppContainer::readyRead(int what) void eConsoleAppContainer::readyErrRead(int what) { - if (what & POLLPRI|POLLIN) + if (what & (eSocketNotifier::Priority|eSocketNotifier::Read)) { - eDebug("what = %d"); +// eDebug("what = %d"); char buf[2048]; - int readed = read(fd[2], buf, 2048); - eDebug("%d bytes read", readed); - if ( readed != -1 && readed ) - /*emit*/ dataAvail( eString( buf ) ); - else if (readed == -1) - eDebug("readerror %d", errno); + int rd; + while((rd = read(fd[2], buf, 2047)) > 0) + { +/* for ( int i = 0; i < rd; i++ ) + eDebug("%d = %c (%02x)", i, buf[i], buf[i] );*/ + buf[rd]=0; + /*emit*/ dataAvail(buf); + } } } -void eConsoleAppContainer::write( const eString & str ) +void eConsoleAppContainer::write( const char *data, int len ) { - outbuf = new char[ str.length()]; - strcpy( outbuf, str.c_str() ); + char *tmp = new char[len]; + memcpy(tmp, data, len); + outbuf.push(queue_data(tmp,len)); + out->start(); } void eConsoleAppContainer::readyWrite(int what) { - if (what == 4 && outbuf) + if (what&eSocketNotifier::Write && outbuf.size() ) { - if ( ::write( fd[1], outbuf, strlen(outbuf) ) != (int) strlen(outbuf) ) + queue_data d = outbuf.front(); + outbuf.pop(); + if ( ::write( fd[1], d.data, d.len ) != d.len ) { /* emit */ dataSent(-1); - eDebug("writeError"); +// eDebug("writeError"); } else { /* emit */ dataSent(0); - eDebug("write ok"); +// eDebug("write ok"); } - - delete outbuf; - outbuf=0; + delete [] d.data; } + if ( !outbuf.size() ) + out->stop(); }