9204bcca3520fd39820ac4596751308022f4ca61
[enigma2.git] / 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         const char *str;
621         if (PyArg_ParseTuple(argt, "s", &str))
622                 return PyInt_FromLong(self->cont->execute(str));
623         PyErr_SetString(PyExc_TypeError,
624                 "argument is not a string");
625         return NULL;
626 }
627
628 static PyObject *
629 eConsolePy_write(eConsolePy* self, PyObject *args)
630 {
631         int len;
632         char *data;
633         if (PyArg_ParseTuple(args, "si", &data, &len))
634                 ;
635         else
636         {
637                 PyObject *ob;
638                 if (!PyArg_ParseTuple(args, "O", &ob) || !PyString_Check(ob))
639                 {
640                         PyErr_SetString(PyExc_TypeError,
641                                 "1st arg must be a string, optionaly 2nd arg can be the string length");
642                         return NULL;
643                 }
644                 else
645                 {
646                         Py_ssize_t length;
647                         if (!PyString_AsStringAndSize(ob, &data, &length))
648                                 len = length;
649                         else
650                                 len = 0;
651                 }
652         }
653         self->cont->write(data, len);
654         Py_RETURN_NONE;
655 }
656
657 static PyObject *
658 eConsolePy_getPID(eConsolePy* self)
659 {
660         return PyInt_FromLong(self->cont->getPID());
661 }
662
663 static PyObject *
664 eConsolePy_setCWD(eConsolePy* self, PyObject *args)
665 {
666         const char *path=0;
667         if (!PyArg_ParseTuple(args, "s", &path))
668                 return NULL;
669         self->cont->setCWD(path);
670         Py_RETURN_NONE;
671 }
672
673 static PyObject *
674 eConsolePy_kill(eConsolePy* self)
675 {
676         self->cont->kill();
677         Py_RETURN_NONE;
678 }
679
680 static PyObject *
681 eConsolePy_sendCtrlC(eConsolePy* self)
682 {
683         self->cont->sendCtrlC();
684         Py_RETURN_NONE;
685 }
686
687 static PyObject *
688 eConsolePy_sendEOF(eConsolePy* self)
689 {
690         self->cont->sendEOF();
691         Py_RETURN_NONE;
692 }
693
694 static PyObject *
695 eConsolePy_dumpToFile(eConsolePy* self, PyObject *args)
696 {
697         char *filename;
698         if (!PyArg_ParseTuple(args, "s", &filename))
699         {
700                 PyErr_SetString(PyExc_TypeError,
701                         "arg must be a string (filename)");
702                 return NULL;
703         }
704         else
705         {
706                 int fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
707                 self->cont->setFileFD(1, fd);
708                 eDebug("eConsoleAppContainer::dumpToFile open(%s, O_WRONLY|O_CREAT|O_TRUNC, 0644)=%d", filename, fd);
709         }
710         Py_RETURN_NONE;
711 }
712
713 static PyObject *
714 eConsolePy_readFromFile(eConsolePy* self, PyObject *args)
715 {
716         char *filename;
717         if (!PyArg_ParseTuple(args, "s", &filename))
718         {
719                 PyErr_SetString(PyExc_TypeError,
720                         "arg must be a string (filename)");
721                 return NULL;
722         }
723         else
724         {
725                 int fd = open(filename, O_RDONLY);
726                 if (fd >= 0)
727                 {
728                         char readbuf[32*1024];
729                         int rsize = read(fd, readbuf, 32*1024);
730                         self->cont->setFileFD(0, fd);
731                         eDebug("eConsoleAppContainer::readFromFile open(%s, O_RDONLY)=%d, read: %d", filename, fd, rsize);
732                         self->cont->write(readbuf, rsize);
733                 }
734                 else
735                 {
736                         eDebug("eConsoleAppContainer::readFromFile %s not exist!", filename);
737                         self->cont->setFileFD(0, -1);
738                 }
739         }
740         Py_RETURN_NONE;
741 }
742
743 static PyMethodDef eConsolePy_methods[] = {
744         {"setCWD", (PyCFunction)eConsolePy_setCWD, METH_VARARGS,
745          "set working dir"
746         },
747         {"execute", (PyCFunction)eConsolePy_execute, METH_VARARGS,
748          "execute command"
749         },
750         {"dumpToFile", (PyCFunction)eConsolePy_dumpToFile, METH_VARARGS,
751          "set output file"
752         },
753         {"readFromFile", (PyCFunction)eConsolePy_readFromFile, METH_VARARGS,
754          "set input file"
755         },
756         {"getPID", (PyCFunction)eConsolePy_getPID, METH_NOARGS,
757          "execute command"
758         },
759         {"kill", (PyCFunction)eConsolePy_kill, METH_NOARGS,
760          "kill application"
761         },
762         {"sendCtrlC", (PyCFunction)eConsolePy_sendCtrlC, METH_NOARGS,
763          "send Ctrl-C to application"
764         },
765         {"sendEOF", (PyCFunction)eConsolePy_sendEOF, METH_NOARGS,
766          "send EOF to application"
767         },
768         {"write", (PyCFunction)eConsolePy_write, METH_VARARGS,
769          "write data to application"
770         },
771         {"running", (PyCFunction)eConsolePy_running, METH_NOARGS,
772          "returns the running state"
773         },
774         {NULL}  /* Sentinel */
775 };
776
777 static PyTypeObject eConsolePyType = {
778         PyObject_HEAD_INIT(NULL)
779         0, /*ob_size*/
780         "eConsoleImpl.eConsoleAppContainer", /*tp_name*/
781         sizeof(eConsolePy), /*tp_basicsize*/
782         0, /*tp_itemsize*/
783         (destructor)eConsolePy_dealloc, /*tp_dealloc*/
784         0, /*tp_print*/
785         0, /*tp_getattr*/
786         0, /*tp_setattr*/
787         0, /*tp_compare*/
788         0, /*tp_repr*/
789         0, /*tp_as_number*/
790         0, /*tp_as_sequence*/
791         0, /*tp_as_mapping*/
792         0, /*tp_hash */
793         0, /*tp_call*/
794         0, /*tp_str*/
795         0, /*tp_getattro*/
796         0, /*tp_setattro*/
797         0, /*tp_as_buffer*/
798         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
799         "eConsoleAppContainer objects", /* tp_doc */
800         (traverseproc)eConsolePy_traverse, /* tp_traverse */
801         (inquiry)eConsolePy_clear, /* tp_clear */
802         0, /* tp_richcompare */
803         offsetof(eConsolePy, in_weakreflist), /* tp_weaklistoffset */
804         0, /* tp_iter */
805         0, /* tp_iternext */
806         eConsolePy_methods, /* tp_methods */
807         0, /* tp_members */
808         eConsolePy_getseters, /* tp_getset */
809         0, /* tp_base */
810         0, /* tp_dict */
811         0, /* tp_descr_get */
812         0, /* tp_descr_set */
813         0, /* tp_dictoffset */
814         0, /* tp_init */
815         0, /* tp_alloc */
816         eConsolePy_new, /* tp_new */
817 };
818
819 static PyMethodDef module_methods[] = {
820         {NULL}  /* Sentinel */
821 };
822
823 void eConsoleInit(void)
824 {
825         PyObject* m = Py_InitModule3("eConsoleImpl", module_methods,
826                 "Module that implements eConsoleAppContainer with working cyclic garbage collection.");
827
828         if (m == NULL)
829                 return;
830
831 #ifdef COMPATIBILITY_MODE
832         if (!PyType_Ready(&eListCompatibilityWrapperType))
833         {
834                 Org_Py_INCREF((PyObject*)&eListCompatibilityWrapperType);
835                 PyModule_AddObject(m, "eListCompatibilityWrapper", (PyObject*)&eListCompatibilityWrapperType);
836         }
837 #endif
838         if (!PyType_Ready(&eConsolePyType))
839         {
840                 Org_Py_INCREF((PyObject*)&eConsolePyType);
841                 PyModule_AddObject(m, "eConsoleAppContainer", (PyObject*)&eConsolePyType);
842         }
843 }
844 }