small cleanup
[vuplus_dvbapp] / lib / base / console.cpp
1 #include <lib/base/console.h>
2 #include <lib/base/eerror.h>
3 #include <sys/vfs.h> // for statfs
4 #include <unistd.h>
5 #include <signal.h>
6 #include <errno.h>
7 #include <poll.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <fcntl.h>
11
12 int bidirpipe(int pfd[], const char *cmd , const char * const argv[], const char *cwd )
13 {
14         int pfdin[2];  /* from child to parent */
15         int pfdout[2]; /* from parent to child */
16         int pfderr[2]; /* stderr from child to parent */
17         int pid;       /* child's pid */
18
19         if ( pipe(pfdin) == -1 || pipe(pfdout) == -1 || pipe(pfderr) == -1)
20                 return(-1);
21
22         if ( ( pid = vfork() ) == -1 )
23                 return(-1);
24         else if (pid == 0) /* child process */
25         {
26                 setsid();
27                 if ( close(0) == -1 || close(1) == -1 || close(2) == -1 )
28                         _exit(0);
29
30                 if (dup(pfdout[0]) != 0 || dup(pfdin[1]) != 1 || dup(pfderr[1]) != 2 )
31                         _exit(0);
32
33                 if (close(pfdout[0]) == -1 || close(pfdout[1]) == -1 ||
34                                 close(pfdin[0]) == -1 || close(pfdin[1]) == -1 ||
35                                 close(pfderr[0]) == -1 || close(pfderr[1]) == -1 )
36                         _exit(0);
37
38                 for (unsigned int i=3; i < 90; ++i )
39                         close(i);
40
41                 if (cwd)
42                         chdir(cwd);
43
44                 execvp(cmd, (char * const *)argv); 
45                                 /* the vfork will actually suspend the parent thread until execvp is called. thus it's ok to use the shared arg/cmdline pointers here. */
46                 _exit(0);
47         }
48         if (close(pfdout[0]) == -1 || close(pfdin[1]) == -1 || close(pfderr[1]) == -1)
49                         return(-1);
50
51         pfd[0] = pfdin[0];
52         pfd[1] = pfdout[1];
53         pfd[2] = pfderr[0];
54
55         return(pid);
56 }
57
58 eConsoleAppContainer::eConsoleAppContainer()
59 :pid(-1), killstate(0), in(0), out(0), err(0)
60 {
61         for (int i=0; i < 3; ++i)
62         {
63                 fd[i]=-1;
64                 filefd[i]=-1;
65         }
66 }
67
68 int eConsoleAppContainer::setCWD( const char *path )
69 {
70         struct stat dir_stat;
71
72         if (stat(path, &dir_stat) == -1)
73                 return -1;
74
75         if (!S_ISDIR(dir_stat.st_mode))
76                 return -2;
77
78         m_cwd = path;
79         return 0;
80 }
81
82 int eConsoleAppContainer::execute( const char *cmd )
83 {
84         int argc = 3;
85         const char *argv[argc + 1];
86         argv[0] = "/bin/sh";
87         argv[1] = "-c";
88         argv[2] = cmd;
89         argv[argc] = NULL;
90
91         return execute(argv[0], argv);
92 }
93
94 int eConsoleAppContainer::execute(const char *cmdline, const char * const argv[])
95 {
96         if (running())
97                 return -1;
98
99         pid=-1;
100         killstate=0;
101
102         // get one read ,one write and the err pipe to the prog..
103         pid = bidirpipe(fd, cmdline, argv, m_cwd.length() ? m_cwd.c_str() : 0);
104
105         if ( pid == -1 )
106                 return -3;
107
108 //      eDebug("pipe in = %d, out = %d, err = %d", fd[0], fd[1], fd[2]);
109
110         ::fcntl(fd[1], F_SETFL, O_NONBLOCK);
111         ::fcntl(fd[2], F_SETFL, O_NONBLOCK);
112         in = new eSocketNotifier(eApp, fd[0], eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Hungup );
113         out = new eSocketNotifier(eApp, fd[1], eSocketNotifier::Write, false);  
114         err = new eSocketNotifier(eApp, fd[2], eSocketNotifier::Read|eSocketNotifier::Priority );
115         CONNECT(in->activated, eConsoleAppContainer::readyRead);
116         CONNECT(out->activated, eConsoleAppContainer::readyWrite);
117         CONNECT(err->activated, eConsoleAppContainer::readyErrRead);
118
119         return 0;
120 }
121
122 eConsoleAppContainer::~eConsoleAppContainer()
123 {
124         kill();
125 }
126
127 void eConsoleAppContainer::kill()
128 {
129         if ( killstate != -1 && pid != -1 )
130         {
131                 eDebug("user kill(SIGKILL) console App");
132                 killstate=-1;
133                 /*
134                  * Use a negative pid value, to signal the whole process group
135                  * ('pid' might not even be running anymore at this point)
136                  */
137                 ::kill(-pid, SIGKILL);
138                 closePipes();
139         }
140         while( outbuf.size() ) // cleanup out buffer
141         {
142                 queue_data d = outbuf.front();
143                 outbuf.pop();
144                 delete [] d.data;
145         }
146         delete in;
147         delete out;
148         delete err;
149         in=out=err=0;
150
151         for (int i=0; i < 3; ++i)
152         {
153                 if ( filefd[i] > 0 )
154                         close(filefd[i]);
155         }
156 }
157
158 void eConsoleAppContainer::sendCtrlC()
159 {
160         if ( killstate != -1 && pid != -1 )
161         {
162                 eDebug("user send SIGINT(Ctrl-C) to console App");
163                 /*
164                  * Use a negative pid value, to signal the whole process group
165                  * ('pid' might not even be running anymore at this point)
166                  */
167                 ::kill(-pid, SIGINT);
168         }
169 }
170
171 void eConsoleAppContainer::sendEOF()
172 {
173         if (out)
174                 out->stop();
175         if (fd[1] != -1)
176         {
177                 ::close(fd[1]);
178                 fd[1]=-1;
179         }
180 }
181
182 void eConsoleAppContainer::closePipes()
183 {
184         if (in)
185                 in->stop();
186         if (out)
187                 out->stop();
188         if (err)
189                 err->stop();
190         if (fd[0] != -1)
191         {
192                 ::close(fd[0]);
193                 fd[0]=-1;
194         }
195         if (fd[1] != -1)
196         {
197                 ::close(fd[1]);
198                 fd[1]=-1;
199         }
200         if (fd[2] != -1)
201         {
202                 ::close(fd[2]);
203                 fd[2]=-1;
204         }
205         eDebug("pipes closed");
206         while( outbuf.size() ) // cleanup out buffer
207         {
208                 queue_data d = outbuf.front();
209                 outbuf.pop();
210                 delete [] d.data;
211         }
212         pid = -1;
213 }
214
215 void eConsoleAppContainer::readyRead(int what)
216 {
217         bool hungup = what & eSocketNotifier::Hungup;
218         if (what & (eSocketNotifier::Priority|eSocketNotifier::Read))
219         {
220 //              eDebug("what = %d");
221                 char buf[2049];
222                 int rd;
223                 while((rd = read(fd[0], buf, 2048)) > 0)
224                 {
225                         buf[rd]=0;
226                         /*emit*/ dataAvail(buf);
227                         stdoutAvail(buf);
228                         if ( filefd[1] > 0 )
229                                 ::write(filefd[1], buf, rd);
230                         if (!hungup)
231                                 break;
232                 }
233         }
234         readyErrRead(eSocketNotifier::Priority|eSocketNotifier::Read); /* be sure to flush all data which might be already written */
235         if (hungup)
236         {
237                 eDebug("child has terminated");
238                 closePipes();
239                 int childstatus;
240                 int retval = killstate;
241                 /*
242                  * We have to call 'wait' on the child process, in order to avoid zombies.
243                  * Also, this gives us the chance to provide better exit status info to appClosed.
244                  */
245                 if (::waitpid(pid, &childstatus, 0) > 0)
246                 {
247                         if (WIFEXITED(childstatus))
248                         {
249                                 retval = WEXITSTATUS(childstatus);
250                         }
251                 }
252                 /*emit*/ appClosed(retval);
253         }
254 }
255
256 void eConsoleAppContainer::readyErrRead(int what)
257 {
258         if (what & (eSocketNotifier::Priority|eSocketNotifier::Read))
259         {
260 //              eDebug("what = %d");
261                 char buf[2049];
262                 int rd;
263                 while((rd = read(fd[2], buf, 2048)) > 0)
264                 {
265 /*                      for ( int i = 0; i < rd; i++ )
266                                 eDebug("%d = %c (%02x)", i, buf[i], buf[i] );*/
267                         buf[rd]=0;
268                         /*emit*/ dataAvail(buf);
269                         stderrAvail(buf);
270                 }
271         }
272 }
273
274 void eConsoleAppContainer::write( const char *data, int len )
275 {
276         char *tmp = new char[len];
277         memcpy(tmp, data, len);
278         outbuf.push(queue_data(tmp,len));
279         if (out)
280                 out->start();
281 }
282
283 void eConsoleAppContainer::readyWrite(int what)
284 {
285         if (what&eSocketNotifier::Write && outbuf.size() )
286         {
287                 queue_data &d = outbuf.front();
288                 int wr = ::write( fd[1], d.data+d.dataSent, d.len-d.dataSent );
289                 if (wr < 0)
290                         eDebug("eConsoleAppContainer write failed (%m)");
291                 else
292                         d.dataSent += wr;
293                 if (d.dataSent == d.len)
294                 {
295                         outbuf.pop();
296                         delete [] d.data;
297                         if ( filefd[0] == -1 )
298                         /* emit */ dataSent(0);
299                 }
300         }
301         if ( !outbuf.size() )
302         {
303                 if ( filefd[0] > 0 )
304                 {
305                         char readbuf[32*1024];
306                         int rsize = read(filefd[0], readbuf, 32*1024);
307                         if ( rsize > 0 )
308                                 write(readbuf, rsize);
309                         else
310                         {
311                                 close(filefd[0]);
312                                 filefd[0] = -1;
313                                 ::close(fd[1]);
314                                 eDebug("readFromFile done - closing eConsoleAppContainer stdin pipe");
315                                 fd[1]=-1;
316                                 dataSent(0);
317                                 out->stop();
318                         }
319                 }
320                 else
321                         out->stop();
322         }
323 }
324
325 #include "structmember.h"
326
327 extern "C" {
328
329 struct eConsolePy
330 {
331         PyObject_HEAD
332         eConsoleAppContainer *cont;
333         PyObject *in_weakreflist; /* List of weak references */
334 };
335
336 #define COMPATIBILITY_MODE
337 // with COMPATIBILITY_MODE enabled the callback list is accessed via console.appClosed.get()
338 // we remove this code after next enigma2 release... then the list should be accessed via console.appClosed ( without .get() )
339
340 #ifdef COMPATIBILITY_MODE
341 struct eListCompatibilityWrapper
342 {
343         PyObject_HEAD
344         PyObject *list;
345         PyObject *in_weakreflist; /* List of weak references */
346 };
347
348 static int
349 eListCompatibilityWrapper_traverse(eListCompatibilityWrapper *self, visitproc visit, void *arg)
350 {
351         Py_VISIT(self->list);
352         return 0;
353 }
354
355 static int
356 eListCompatibilityWrapper_clear(eListCompatibilityWrapper *self)
357 {
358         Py_CLEAR(self->list);
359         return 0;
360 }
361
362 static void
363 eListCompatibilityWrapper_dealloc(eListCompatibilityWrapper* self)
364 {
365         if (self->in_weakreflist != NULL)
366                 PyObject_ClearWeakRefs((PyObject *) self);
367         eListCompatibilityWrapper_clear(self);
368         Org_Py_DECREF(self->list);
369         self->ob_type->tp_free((PyObject*)self);
370 }
371
372 static PyObject *
373 eListCompatibilityWrapper_get(eListCompatibilityWrapper *self, void *closure)
374 {
375         Org_Py_INCREF(self->list);
376         return self->list;
377 }
378
379 static PyMethodDef eListCompatibilityWrapper_methods[] = {
380         {"get", (PyCFunction)eListCompatibilityWrapper_get, METH_NOARGS,
381          "returns the list"
382         },
383         {NULL}  /* Sentinel */
384 };
385
386 static PyGetSetDef eListCompatibilityWrapper_getseters[] = {
387         {NULL} /* Sentinel */
388 };
389
390 static PyTypeObject eListCompatibilityWrapperType = {
391         PyObject_HEAD_INIT(NULL)
392         0, /*ob_size*/
393         "eConsoleImpl.eListCompatibilityWrapper", /*tp_name*/
394         sizeof(eListCompatibilityWrapper), /*tp_basicsize*/
395         0, /*tp_itemsize*/
396         (destructor)eListCompatibilityWrapper_dealloc, /*tp_dealloc*/
397         0, /*tp_print*/
398         0, /*tp_getattr*/
399         0, /*tp_setattr*/
400         0, /*tp_compare*/
401         0, /*tp_repr*/
402         0, /*tp_as_number*/
403         0, /*tp_as_sequence*/
404         0, /*tp_as_mapping*/
405         0, /*tp_hash */
406         0, /*tp_call*/
407         0, /*tp_str*/
408         0, /*tp_getattro*/
409         0, /*tp_setattro*/
410         0, /*tp_as_buffer*/
411         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
412         "eListCompatibilityWrapper objects", /* tp_doc */
413         (traverseproc)eListCompatibilityWrapper_traverse, /* tp_traverse */
414         (inquiry)eListCompatibilityWrapper_clear, /* tp_clear */
415         0, /* tp_richcompare */
416         offsetof(eListCompatibilityWrapper, in_weakreflist), /* tp_weaklistoffset */
417         0, /* tp_iter */
418         0, /* tp_iternext */
419         eListCompatibilityWrapper_methods, /* tp_methods */
420         0, /* tp_members */
421         eListCompatibilityWrapper_getseters, /* tp_getset */
422         0, /* tp_base */
423         0, /* tp_dict */
424         0, /* tp_descr_get */
425         0, /* tp_descr_set */
426         0, /* tp_dictoffset */
427         0, /* tp_init */
428         0, /* tp_alloc */
429         0, /* tp_new */
430 };
431
432 static PyObject *
433 eConsolePy_dataAvail(eConsolePy *self, void *closure)
434 {
435         eListCompatibilityWrapper *wrapper = (eListCompatibilityWrapper *)eListCompatibilityWrapperType.tp_alloc(&eListCompatibilityWrapperType, 0);
436         Org_Py_INCREF((PyObject*)wrapper);
437         wrapper->list = self->cont->dataAvail.get();
438         wrapper->in_weakreflist = NULL;
439         return (PyObject*)wrapper;
440 }
441
442 static PyObject *
443 eConsolePy_stdoutAvail(eConsolePy *self, void *closure)
444 {
445         eListCompatibilityWrapper *wrapper = (eListCompatibilityWrapper *)eListCompatibilityWrapperType.tp_alloc(&eListCompatibilityWrapperType, 0);
446         Org_Py_INCREF((PyObject*)wrapper);
447         wrapper->list = self->cont->stdoutAvail.get();
448         wrapper->in_weakreflist = NULL;
449         return (PyObject*)wrapper;
450 }
451
452 static PyObject *
453 eConsolePy_stderrAvail(eConsolePy *self, void *closure)
454 {
455         eListCompatibilityWrapper *wrapper = (eListCompatibilityWrapper *)eListCompatibilityWrapperType.tp_alloc(&eListCompatibilityWrapperType, 0);
456         Org_Py_INCREF((PyObject*)wrapper);
457         wrapper->list = self->cont->stderrAvail.get();
458         wrapper->in_weakreflist = NULL;
459         return (PyObject*)wrapper;
460 }
461
462 static PyObject *
463 eConsolePy_dataSent(eConsolePy *self, void *closure)
464 {
465         eListCompatibilityWrapper *wrapper = (eListCompatibilityWrapper *)eListCompatibilityWrapperType.tp_alloc(&eListCompatibilityWrapperType, 0);
466         Org_Py_INCREF((PyObject*)wrapper);
467         wrapper->list = self->cont->dataSent.get();
468         wrapper->in_weakreflist = NULL;
469         return (PyObject*)wrapper;
470 }
471
472 static PyObject *
473 eConsolePy_appClosed(eConsolePy *self, void *closure)
474 {
475         eListCompatibilityWrapper *wrapper = (eListCompatibilityWrapper *)eListCompatibilityWrapperType.tp_alloc(&eListCompatibilityWrapperType, 0);
476         Org_Py_INCREF((PyObject*)wrapper);
477         wrapper->list = self->cont->appClosed.get();
478         wrapper->in_weakreflist = NULL;
479         return (PyObject*)wrapper;
480 }
481 #else
482 static PyObject *
483 eConsolePy_dataAvail(eConsolePy *self, void *closure)
484 {
485         return self->cont->dataAvail.get();
486 }
487
488 static PyObject *
489 eConsolePy_stdoutAvail(eConsolePy *self, void *closure)
490 {
491         return self->cont->stdoutAvail.get();
492 }
493
494 static PyObject *
495 eConsolePy_stderrAvail(eConsolePy *self, void *closure)
496 {
497         return self->cont->stderrAvail.get();
498 }
499
500 static PyObject *
501 eConsolePy_dataSent(eConsolePy *self, void *closure)
502 {
503         return self->cont->dataSent.get();
504 }
505
506 static PyObject *
507 eConsolePy_appClosed(eConsolePy *self, void *closure)
508 {
509         return self->cont->appClosed.get();
510 }
511 #endif
512
513 static PyGetSetDef eConsolePy_getseters[] = {
514         {"dataAvail",
515          (getter)eConsolePy_dataAvail, (setter)0,
516          "dataAvail callback list",
517          NULL},
518         {"stdoutAvail",
519          (getter)eConsolePy_stdoutAvail, (setter)0,
520          "stdoutAvail callback list",
521          NULL},
522         {"stderrAvail",
523          (getter)eConsolePy_stderrAvail, (setter)0,
524          "stderrAvail callback list",
525          NULL},
526         {"dataSent",
527          (getter)eConsolePy_dataSent, (setter)0,
528          "dataSent callback list",
529          NULL},
530         {"appClosed",
531          (getter)eConsolePy_appClosed, (setter)0,
532          "appClosed callback list",
533          NULL},
534         {NULL} /* Sentinel */
535 };
536
537 static int
538 eConsolePy_traverse(eConsolePy *self, visitproc visit, void *arg)
539 {
540         PyObject *obj = self->cont->dataAvail.get(true);
541         if (obj) {
542                 Py_VISIT(obj);
543         }
544         obj = self->cont->stdoutAvail.get(true);
545         if (obj) {
546                 Py_VISIT(obj);
547         }
548         obj = self->cont->stderrAvail.get(true);
549         if (obj) {
550                 Py_VISIT(obj);
551         }
552         obj = self->cont->dataSent.get(true);
553         if (obj) {
554                 Py_VISIT(obj);
555         }
556         obj = self->cont->appClosed.get(true);
557         if (obj) {
558                 Py_VISIT(obj);
559         }
560         return 0;
561 }
562
563 static int
564 eConsolePy_clear(eConsolePy *self)
565 {
566         PyObject *obj = self->cont->dataAvail.get(true);
567         if (obj) {
568                 Py_CLEAR(obj);
569         }
570         obj = self->cont->stdoutAvail.get(true);
571         if (obj) {
572                 Py_CLEAR(obj);
573         }
574         obj = self->cont->stderrAvail.get(true);
575         if (obj) {
576                 Py_CLEAR(obj);
577         }
578         obj = self->cont->dataSent.get(true);
579         if (obj) {
580                 Py_CLEAR(obj);
581         }
582         obj = self->cont->appClosed.get(true);
583         if (obj) {
584                 Py_CLEAR(obj);
585         }
586         return 0;
587 }
588
589 static void
590 eConsolePy_dealloc(eConsolePy* self)
591 {
592         if (self->in_weakreflist != NULL)
593                 PyObject_ClearWeakRefs((PyObject *) self);
594         eConsolePy_clear(self);
595         delete self->cont;
596         self->ob_type->tp_free((PyObject*)self);
597 }
598
599 static PyObject *
600 eConsolePy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
601 {
602         eConsolePy *self = (eConsolePy *)type->tp_alloc(type, 0);
603         self->cont = new eConsoleAppContainer();
604         self->in_weakreflist = NULL;
605         return (PyObject *)self;
606 }
607
608 static PyObject *
609 eConsolePy_running(eConsolePy* self)
610 {
611         PyObject *ret = NULL;
612         ret = self->cont->running() ? Py_True : Py_False;
613         Org_Py_INCREF(ret);
614         return ret;
615 }
616
617 static PyObject *
618 eConsolePy_execute(eConsolePy* self, PyObject *argt)
619 {
620         if (PyTuple_Size(argt) > 1)
621         {
622                 PyObject *cmdline, *args;
623                 PyArg_ParseTuple(argt, "OO", &cmdline, &args);
624                 if (!PyString_Check(cmdline) || !PySequence_Check(args))
625                         return PyInt_FromLong(-2);
626                 else
627                 {
628                         PyObject *fast = PySequence_Fast(args, "2nd arg is not a sequence");
629                         Py_ssize_t size = PySequence_Fast_GET_SIZE(fast);
630                         const char *argv[size + 1];
631                         int i=0;
632                         for (; i < size; ++i)
633                         {
634                                 PyObject *arg = PySequence_Fast_GET_ITEM(fast, i); /* borrowed ref */
635                                 if (!PyString_Check(arg))
636                                         return PyInt_FromLong(-3);
637                                 argv[i] = PyString_AsString(arg); /* borrowed pointer */
638                         }
639                         argv[i] = 0;
640                         return PyInt_FromLong(self->cont->execute(PyString_AsString(cmdline), argv)); /* borrowed pointer */
641                 }
642         }
643         else
644         {
645                 const char *str;
646                 if (PyArg_ParseTuple(argt, "s", &str))
647                         return PyInt_FromLong(self->cont->execute(str));
648         }
649         return NULL;
650 }
651
652 static PyObject *
653 eConsolePy_write(eConsolePy* self, PyObject *args)
654 {
655         int len;
656         char *data;
657         if (PyArg_ParseTuple(args, "si", &data, &len))
658                 ;
659         else
660         {
661                 PyObject *ob;
662                 if (!PyArg_ParseTuple(args, "O", &ob) || !PyString_Check(ob))
663                         return NULL;
664                 else
665                 {
666                         Py_ssize_t length;
667                         if (!PyString_AsStringAndSize(ob, &data, &length))
668                                 len = length;
669                         else
670                                 len = 0;
671                 }
672         }
673         self->cont->write(data, len);
674         Py_RETURN_NONE;
675 }
676
677 static PyObject *
678 eConsolePy_getPID(eConsolePy* self)
679 {
680         return PyInt_FromLong(self->cont->getPID());
681 }
682
683 static PyObject *
684 eConsolePy_setCWD(eConsolePy* self, PyObject *args)
685 {
686         const char *path=0;
687         if (!PyArg_ParseTuple(args, "s", &path))
688                 return NULL;
689         self->cont->setCWD(path);
690         Py_RETURN_NONE;
691 }
692
693 static PyObject *
694 eConsolePy_kill(eConsolePy* self)
695 {
696         self->cont->kill();
697         Py_RETURN_NONE;
698 }
699
700 static PyObject *
701 eConsolePy_sendCtrlC(eConsolePy* self)
702 {
703         self->cont->sendCtrlC();
704         Py_RETURN_NONE;
705 }
706
707 static PyObject *
708 eConsolePy_sendEOF(eConsolePy* self)
709 {
710         self->cont->sendEOF();
711         Py_RETURN_NONE;
712 }
713
714 static PyObject *
715 eConsolePy_dumpToFile(eConsolePy* self, PyObject *args)
716 {
717         char *filename;
718         if (!PyArg_ParseTuple(args, "s", &filename))
719                 return NULL;
720         else
721         {
722                 int fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
723                 self->cont->setFileFD(1, fd);
724                 eDebug("eConsoleAppContainer::dumpToFile open(%s, O_WRONLY|O_CREAT|O_TRUNC, 0644)=%d", filename, fd);
725         }
726         Py_RETURN_NONE;
727 }
728
729 static PyObject *
730 eConsolePy_readFromFile(eConsolePy* self, PyObject *args)
731 {
732         char *filename;
733         if (!PyArg_ParseTuple(args, "s", &filename))
734                 return NULL;
735         else
736         {
737                 int fd = open(filename, O_RDONLY);
738                 if (fd >= 0)
739                 {
740                         char readbuf[32*1024];
741                         int rsize = read(fd, readbuf, 32*1024);
742                         self->cont->setFileFD(0, fd);
743                         eDebug("eConsoleAppContainer::readFromFile open(%s, O_RDONLY)=%d, read: %d", filename, fd, rsize);
744                         self->cont->write(readbuf, rsize);
745                 }
746                 else
747                 {
748                         eDebug("eConsoleAppContainer::readFromFile %s not exist!", filename);
749                         self->cont->setFileFD(0, -1);
750                 }
751         }
752         Py_RETURN_NONE;
753 }
754
755 static PyMethodDef eConsolePy_methods[] = {
756         {"setCWD", (PyCFunction)eConsolePy_setCWD, METH_VARARGS,
757          "set working dir"
758         },
759         {"execute", (PyCFunction)eConsolePy_execute, METH_VARARGS,
760          "execute command"
761         },
762         {"dumpToFile", (PyCFunction)eConsolePy_dumpToFile, METH_VARARGS,
763          "set output file"
764         },
765         {"readFromFile", (PyCFunction)eConsolePy_readFromFile, METH_VARARGS,
766          "set input file"
767         },
768         {"getPID", (PyCFunction)eConsolePy_getPID, METH_NOARGS,
769          "execute command"
770         },
771         {"kill", (PyCFunction)eConsolePy_kill, METH_NOARGS,
772          "kill application"
773         },
774         {"sendCtrlC", (PyCFunction)eConsolePy_sendCtrlC, METH_NOARGS,
775          "send Ctrl-C to application"
776         },
777         {"sendEOF", (PyCFunction)eConsolePy_sendEOF, METH_NOARGS,
778          "send EOF to application"
779         },
780         {"write", (PyCFunction)eConsolePy_write, METH_VARARGS,
781          "write data to application"
782         },
783         {"running", (PyCFunction)eConsolePy_running, METH_NOARGS,
784          "returns the running state"
785         },
786         {NULL}  /* Sentinel */
787 };
788
789 static PyTypeObject eConsolePyType = {
790         PyObject_HEAD_INIT(NULL)
791         0, /*ob_size*/
792         "eConsoleImpl.eConsoleAppContainer", /*tp_name*/
793         sizeof(eConsolePy), /*tp_basicsize*/
794         0, /*tp_itemsize*/
795         (destructor)eConsolePy_dealloc, /*tp_dealloc*/
796         0, /*tp_print*/
797         0, /*tp_getattr*/
798         0, /*tp_setattr*/
799         0, /*tp_compare*/
800         0, /*tp_repr*/
801         0, /*tp_as_number*/
802         0, /*tp_as_sequence*/
803         0, /*tp_as_mapping*/
804         0, /*tp_hash */
805         0, /*tp_call*/
806         0, /*tp_str*/
807         0, /*tp_getattro*/
808         0, /*tp_setattro*/
809         0, /*tp_as_buffer*/
810         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
811         "eConsoleAppContainer objects", /* tp_doc */
812         (traverseproc)eConsolePy_traverse, /* tp_traverse */
813         (inquiry)eConsolePy_clear, /* tp_clear */
814         0, /* tp_richcompare */
815         offsetof(eConsolePy, in_weakreflist), /* tp_weaklistoffset */
816         0, /* tp_iter */
817         0, /* tp_iternext */
818         eConsolePy_methods, /* tp_methods */
819         0, /* tp_members */
820         eConsolePy_getseters, /* tp_getset */
821         0, /* tp_base */
822         0, /* tp_dict */
823         0, /* tp_descr_get */
824         0, /* tp_descr_set */
825         0, /* tp_dictoffset */
826         0, /* tp_init */
827         0, /* tp_alloc */
828         eConsolePy_new, /* tp_new */
829 };
830
831 static PyMethodDef module_methods[] = {
832         {NULL}  /* Sentinel */
833 };
834
835 void eConsoleInit(void)
836 {
837         PyObject* m = Py_InitModule3("eConsoleImpl", module_methods,
838                 "Module that implements eConsoleAppContainer with working cyclic garbage collection.");
839
840         if (m == NULL)
841                 return;
842
843 #ifdef COMPATIBILITY_MODE
844         if (!PyType_Ready(&eListCompatibilityWrapperType))
845         {
846                 Org_Py_INCREF((PyObject*)&eListCompatibilityWrapperType);
847                 PyModule_AddObject(m, "eListCompatibilityWrapper", (PyObject*)&eListCompatibilityWrapperType);
848         }
849 #endif
850         if (!PyType_Ready(&eConsolePyType))
851         {
852                 Org_Py_INCREF((PyObject*)&eConsolePyType);
853                 PyModule_AddObject(m, "eConsoleAppContainer", (PyObject*)&eConsolePyType);
854         }
855 }
856 }