1 #include <lib/base/console.h>
2 #include <lib/base/eerror.h>
3 #include <sys/vfs.h> // for statfs
11 int bidirpipe(int pfd[], char *cmd , char *argv[])
13 int pfdin[2]; /* from child to parent */
14 int pfdout[2]; /* from parent to child */
15 int pfderr[2]; /* stderr from child to parent */
16 int pid; /* child's pid */
18 if ( pipe(pfdin) == -1 || pipe(pfdout) == -1 || pipe(pfderr) == -1)
21 if ( ( pid = vfork() ) == -1 )
23 else if (pid == 0) /* child process */
26 if ( close(0) == -1 || close(1) == -1 || close(2) == -1 )
29 if (dup(pfdout[0]) != 0 || dup(pfdin[1]) != 1 || dup(pfderr[1]) != 2 )
32 if (close(pfdout[0]) == -1 || close(pfdout[1]) == -1 ||
33 close(pfdin[0]) == -1 || close(pfdin[1]) == -1 ||
34 close(pfderr[0]) == -1 || close(pfderr[1]) == -1 )
37 for (unsigned int i=3; i < 90; ++i )
43 if (close(pfdout[0]) == -1 || close(pfdin[1]) == -1 || close(pfderr[1]) == -1)
53 eConsoleAppContainer::eConsoleAppContainer()
54 :pid(-1), killstate(0), in(0), out(0), err(0)
56 for (int i=0; i < 3; ++i)
60 static char brakets[][2] = {
70 static char *find_bracket(char ch)
73 while (idx < sizeof(brakets)/2) {
74 if (brakets[idx][0] == ch)
75 return &brakets[idx][0];
81 int eConsoleAppContainer::execute( const char *cmd )
88 int cnt=0, slen=strlen(cmd);
90 char *tmp=0, *argv[64], *path=buf, *cmds = buf;
91 memcpy(buf, cmd, slen+1);
93 // printf("cmd = %s, len %d\n", cmd, slen);
95 // kill spaces at beginning
96 while(path[0] == ' ') {
102 // kill spaces at the end
103 while(slen && path[slen-1] == ' ') {
111 tmp = strchr(path, ' ');
115 while(*cmds && *cmds == ' ')
121 memset(argv, 0, sizeof(argv));
125 char *argb=NULL, *it=NULL;
126 while ( (tmp = strchr(cmds, ' ')) ) {
127 if (!it && *cmds && (it = find_bracket(*cmds)) )
128 *cmds = 'X'; // replace open braket...
129 if (!argb) // not arg begin
131 if (it && *(tmp-1) == it[1]) {
132 *argb = it[0]; // set old char for open braket
135 if (!it) { // end of arg
138 argb=0; // reset arg begin
141 while (*cmds && *cmds == ' ')
144 argv[cnt++] = argb ? argb : cmds;
146 *argv[cnt-1] = it[0]; // set old char for open braket
151 // eDebug("%d is %s", tmp, argv[tmp++]);
153 // get one read ,one write and the err pipe to the prog..
154 pid = bidirpipe(fd, argv[0], argv);
159 // eDebug("pipe in = %d, out = %d, err = %d", fd[0], fd[1], fd[2]);
161 in = new eSocketNotifier(eApp, fd[0], eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Hungup );
162 out = new eSocketNotifier(eApp, fd[1], eSocketNotifier::Write, false);
163 err = new eSocketNotifier(eApp, fd[2], eSocketNotifier::Read|eSocketNotifier::Priority );
164 CONNECT(in->activated, eConsoleAppContainer::readyRead);
165 CONNECT(out->activated, eConsoleAppContainer::readyWrite);
166 CONNECT(err->activated, eConsoleAppContainer::readyErrRead);
171 eConsoleAppContainer::~eConsoleAppContainer()
176 void eConsoleAppContainer::kill()
178 if ( killstate != -1 && pid != -1 )
180 eDebug("user kill(SIGKILL) console App");
183 * Use a negative pid value, to signal the whole process group
184 * ('pid' might not even be running anymore at this point)
186 ::kill(-pid, SIGKILL);
189 while( outbuf.size() ) // cleanup out buffer
191 queue_data d = outbuf.front();
201 void eConsoleAppContainer::sendCtrlC()
203 if ( killstate != -1 && pid != -1 )
205 eDebug("user send SIGINT(Ctrl-C) to console App");
207 * Use a negative pid value, to signal the whole process group
208 * ('pid' might not even be running anymore at this point)
210 ::kill(-pid, SIGINT);
214 void eConsoleAppContainer::closePipes()
237 eDebug("pipes closed");
238 while( outbuf.size() ) // cleanup out buffer
240 queue_data d = outbuf.front();
247 void eConsoleAppContainer::readyRead(int what)
249 bool hungup = what & eSocketNotifier::Hungup;
250 if (what & (eSocketNotifier::Priority|eSocketNotifier::Read))
252 // eDebug("what = %d");
255 while((rd = read(fd[0], buf, 2047)) > 0)
257 /* for ( int i = 0; i < rd; i++ )
258 eDebug("%d = %c (%02x)", i, buf[i], buf[i] );*/
260 /*emit*/ dataAvail(buf);
267 eDebug("child has terminated");
270 int retval = killstate;
272 * We have to call 'wait' on the child process, in order to avoid zombies.
273 * Also, this gives us the chance to provide better exit status info to appClosed.
275 if (::waitpid(pid, &childstatus, 0) > 0)
277 if (WIFEXITED(childstatus))
279 retval = WEXITSTATUS(childstatus);
282 /*emit*/ appClosed(retval);
286 void eConsoleAppContainer::readyErrRead(int what)
288 if (what & (eSocketNotifier::Priority|eSocketNotifier::Read))
290 // eDebug("what = %d");
293 while((rd = read(fd[2], buf, 2047)) > 0)
295 /* for ( int i = 0; i < rd; i++ )
296 eDebug("%d = %c (%02x)", i, buf[i], buf[i] );*/
298 /*emit*/ dataAvail(buf);
303 void eConsoleAppContainer::write( const char *data, int len )
305 char *tmp = new char[len];
306 memcpy(tmp, data, len);
307 outbuf.push(queue_data(tmp,len));
311 void eConsoleAppContainer::readyWrite(int what)
313 if (what&eSocketNotifier::Write && outbuf.size() )
315 queue_data d = outbuf.front();
317 if ( ::write( fd[1], d.data, d.len ) != d.len )
319 /* emit */ dataSent(-1);
320 // eDebug("writeError");
324 /* emit */ dataSent(0);
325 // eDebug("write ok");
329 if ( !outbuf.size() )