1 #include <lib/base/console.h>
2 #include <lib/base/eerror.h>
3 #include <sys/vfs.h> // for statfs
9 int bidirpipe(int pfd[], char *cmd , char *argv[])
11 int pfdin[2]; /* from child to parent */
12 int pfdout[2]; /* from parent to child */
13 int pfderr[2]; /* stderr from child to parent */
14 int pid; /* child's pid */
16 if ( pipe(pfdin) == -1 || pipe(pfdout) == -1 || pipe(pfderr) == -1)
19 if ( ( pid = fork() ) == -1 )
21 else if (pid == 0) /* child process */
24 if ( close(0) == -1 || close(1) == -1 || close(2) == -1 )
27 if (dup(pfdout[0]) != 0 || dup(pfdin[1]) != 1 || dup(pfderr[1]) != 2 )
30 if (close(pfdout[0]) == -1 || close(pfdout[1]) == -1 ||
31 close(pfdin[0]) == -1 || close(pfdin[1]) == -1 ||
32 close(pfderr[0]) == -1 || close(pfderr[1]) == -1 )
35 for (unsigned int i=3; i < 90; ++i )
41 if (close(pfdout[0]) == -1 || close(pfdin[1]) == -1 || close(pfderr[1]) == -1)
51 eConsoleAppContainer::eConsoleAppContainer()
52 :pid(-1), killstate(0), in(0), out(0), err(0)
54 for (int i=0; i < 3; ++i)
58 int eConsoleAppContainer::execute( const std::string &cmd )
64 // eDebug("cmd = %s", cmd.c_str() );
65 int cnt=2; // path to app + terminated 0
66 std::string str(cmd.length()?cmd:"");
68 // kill spaces at beginning
69 unsigned int pos = str.find_first_not_of(' ');
70 if (pos != std::string::npos && pos)
71 str = str.substr(pos);
73 // kill spaces at the end
74 pos = str.find_last_not_of(' ');
75 if (pos != std::string::npos && (pos+1) < str.length())
76 str = str.erase(pos+1);
78 unsigned int slen=str.length();
82 std::map<char,char> brackets;
83 brackets.insert(std::pair<char,char>('\'','\''));
84 brackets.insert(std::pair<char,char>('"','"'));
85 brackets.insert(std::pair<char,char>('`','`'));
86 brackets.insert(std::pair<char,char>('(',')'));
87 brackets.insert(std::pair<char,char>('{','}'));
88 brackets.insert(std::pair<char,char>('[',']'));
89 brackets.insert(std::pair<char,char>('<','>'));
91 unsigned int idx=str.find(' ');
92 std::string path = str.substr(0, idx != std::string::npos ? idx : slen );
93 // eDebug("path = %s", path.c_str() );
94 unsigned int plen = path.length();
96 std::string cmds = slen > plen ? str.substr( plen+1 ) : "";
97 unsigned int clen = cmds.length();
98 // eDebug("cmds = %s", cmds.c_str() );
101 std::map<char,char>::iterator it = brackets.find(cmds[idx]);
102 while ( (idx = cmds.find(' ',idx) ) != std::string::npos ) // count args
104 if (it != brackets.end())
106 if (cmds[idx-1] == it->second)
109 if (it == brackets.end())
112 it = brackets.find(cmds[idx+1]);
117 // eDebug("idx = %d, %d counted spaces", idx, cnt-2);
122 // eDebug("increase cnt");
125 // eDebug("%d args", cnt-2);
126 char **argv = new char*[cnt]; // min two args... path and terminating 0
127 // eDebug("%d args", cnt);
128 argv[0] = new char[ plen+1 ];
129 // eDebug("new argv[0] %d bytes (%s)", plen+1, path.c_str());
130 strcpy( argv[0], path.c_str() );
131 argv[cnt-1] = 0; // set terminating null
133 if ( cnt > 2 ) // more then default args?
135 cnt=1; // do not overwrite path in argv[0]
137 it = brackets.find(cmds[0]);
139 while ( (idx = cmds.find(' ',idx)) != std::string::npos ) // parse all args..
141 bool bracketClosed=false;
142 if ( it != brackets.end() )
144 if (cmds[idx-1]==it->second)
150 if ( it == brackets.end() )
152 std::string tmp = cmds.substr(0, idx);
156 tmp.erase(tmp.length()-1, 1);
159 // eDebug("new argv[%d] %d bytes (%s)", cnt, tmp.length()+1, tmp.c_str());
160 argv[cnt] = new char[ tmp.length()+1 ];
161 // eDebug("idx=%d, arg = %s", idx, tmp.c_str() );
162 strcpy( argv[cnt++], tmp.c_str() );
163 cmds.erase(0, idx+1);
164 // eDebug("str = %s", cmds.c_str() );
165 it = brackets.find(cmds[0]);
171 if ( it != brackets.end() )
174 cmds.erase(cmds.length()-1, 1);
176 // store the last arg
177 // eDebug("new argv[%d] %d bytes (%s)", cnt, cmds.length()+1, cmds.c_str());
178 argv[cnt] = new char[ cmds.length()+1 ];
179 strcpy( argv[cnt], cmds.c_str() );
184 // get one read ,one write and the err pipe to the prog..
188 // eDebug("%d is %s", tmp, argv[tmp++]);
190 pid = bidirpipe(fd, argv[0], argv);
192 while ( cnt >= 0 ) // release heap memory
194 // eDebug("delete argv[%d]", cnt);
195 delete [] argv[cnt--];
197 // eDebug("delete argv");
203 eDebug("pipe in = %d, out = %d, err = %d", fd[0], fd[1], fd[2]);
205 in = new eSocketNotifier(eApp, fd[0], POLLIN|POLLPRI|POLLHUP );
206 out = new eSocketNotifier(eApp, fd[1], POLLOUT, false);
207 err = new eSocketNotifier(eApp, fd[2], POLLIN|POLLPRI );
208 CONNECT(in->activated, eConsoleAppContainer::readyRead);
209 CONNECT(out->activated, eConsoleAppContainer::readyWrite);
210 CONNECT(err->activated, eConsoleAppContainer::readyErrRead);
214 eConsoleAppContainer::~eConsoleAppContainer()
219 void eConsoleAppContainer::kill()
221 if ( killstate != -1 )
223 eDebug("user kill(SIGKILL) console App");
225 ::kill(pid, SIGKILL);
228 while( outbuf.size() ) // cleanup out buffer
230 queue_data d = outbuf.front();
240 void eConsoleAppContainer::sendCtrlC()
242 if ( killstate != -1 )
244 eDebug("user send SIGINT(Ctrl-C) to console App");
249 void eConsoleAppContainer::closePipes()
272 eDebug("pipes closed");
273 while( outbuf.size() ) // cleanup out buffer
275 queue_data d = outbuf.front();
281 void eConsoleAppContainer::readyRead(int what)
283 if (what & POLLPRI|POLLIN)
285 // eDebug("what = %d");
287 int readed = read(fd[0], buf, 2047);
288 // eDebug("%d bytes read", readed);
289 if ( readed != -1 && readed )
291 /* for ( int i = 0; i < readed; i++ )
292 eDebug("%d = %c (%02x)", i, buf[i], buf[i] );*/
294 /*emit*/ dataAvail(buf);
296 else if (readed == -1)
297 eDebug("readerror %d", errno);
299 if (what & eSocketNotifier::Hungup)
301 eDebug("child has terminated");
303 /*emit*/ appClosed(killstate);
307 void eConsoleAppContainer::readyErrRead(int what)
309 if (what & POLLPRI|POLLIN)
311 // eDebug("what = %d");
313 int readed = read(fd[2], buf, 2047);
314 // eDebug("%d bytes read", readed);
315 if ( readed != -1 && readed )
317 /* for ( int i = 0; i < readed; i++ )
318 eDebug("%d = %c (%02x)", i, buf[i], buf[i] );*/
320 /*emit*/ dataAvail(buf);
322 else if (readed == -1)
323 eDebug("readerror %d", errno);
327 void eConsoleAppContainer::write( const char *data, int len )
329 char *tmp = new char[len];
330 memcpy(tmp, data, len);
331 outbuf.push(queue_data(tmp,len));
335 void eConsoleAppContainer::readyWrite(int what)
337 if (what&POLLOUT && outbuf.size() )
339 queue_data d = outbuf.front();
341 if ( ::write( fd[1], d.data, d.len ) != d.len )
343 /* emit */ dataSent(-1);
344 // eDebug("writeError");
348 /* emit */ dataSent(0);
349 // eDebug("write ok");
353 if ( !outbuf.size() )