summaryrefslogtreecommitdiff
path: root/core/apps/embeddedkonsole/MyPty.cpp
authorkergoth <kergoth>2002-01-25 22:14:26 (UTC)
committer kergoth <kergoth>2002-01-25 22:14:26 (UTC)
commit15318cad33835e4e2dc620d033e43cd930676cdd (patch) (side-by-side diff)
treec2fa0399a2c47fda8e2cd0092c73a809d17f68eb /core/apps/embeddedkonsole/MyPty.cpp
downloadopie-15318cad33835e4e2dc620d033e43cd930676cdd.zip
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2
Initial revision
Diffstat (limited to 'core/apps/embeddedkonsole/MyPty.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/apps/embeddedkonsole/MyPty.cpp279
1 files changed, 279 insertions, 0 deletions
diff --git a/core/apps/embeddedkonsole/MyPty.cpp b/core/apps/embeddedkonsole/MyPty.cpp
new file mode 100644
index 0000000..3622d48
--- a/dev/null
+++ b/core/apps/embeddedkonsole/MyPty.cpp
@@ -0,0 +1,279 @@
+/* -------------------------------------------------------------------------- */
+/* */
+/* [MyPty.C] Pseudo Terminal Device */
+/* */
+/* -------------------------------------------------------------------------- */
+/* */
+/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */
+/* */
+/* This file is part of Konsole - an X terminal for KDE */
+/* -------------------------------------------------------------------------- */
+/* */
+/* Ported Konsole to Qt/Embedded */
+/* */
+/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */
+/* */
+/* -------------------------------------------------------------------------- */
+
+/* If you're compiling konsole on non-Linux platforms and find
+ problems that you can track down to this file, please have
+ a look into ../README.ports, too.
+*/
+
+/*! \file
+*/
+
+/*! \class TEPty
+
+ \brief Ptys provide a pseudo terminal connection to a program.
+
+ Although closely related to pipes, these pseudo terminal connections have
+ some ability, that makes it nessesary to uses them. Most importent, they
+ know about changing screen sizes and UNIX job control.
+
+ Within the terminal emulation framework, this class represents the
+ host side of the terminal together with the connecting serial line.
+
+ One can create many instances of this class within a program.
+ As a side effect of using this class, a signal(2) handler is
+ installed on SIGCHLD.
+
+ \par FIXME
+
+ [NOTE: much of the technical stuff below will be replaced by forkpty.]
+
+ publish the SIGCHLD signal if not related to an instance.
+
+ clearify TEPty::done vs. TEPty::~TEPty semantics.
+ check if pty is restartable via run after done.
+
+ \par Pseudo terminals
+
+ Pseudo terminals are a unique feature of UNIX, and always come in form of
+ pairs of devices (/dev/ptyXX and /dev/ttyXX), which are connected to each
+ other by the operating system. One may think of them as two serial devices
+ linked by a null-modem cable. Being based on devices the number of
+ simultanous instances of this class is (globally) limited by the number of
+ those device pairs, which is 256.
+
+ Another technic are UNIX 98 PTY's. These are supported also, and prefered
+ over the (obsolete) predecessor.
+
+ There's a sinister ioctl(2), signal(2) and job control stuff
+ nessesary to make everything work as it should.
+*/
+
+
+#include <qapplication.h>
+#include <qsocketnotifier.h>
+#include <qstring.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_OPENPTY
+#include <pty.h>
+#endif
+
+#include "MyPty.h"
+
+
+#undef VERBOSE_DEBUG
+
+
+/* -------------------------------------------------------------------------- */
+
+/*!
+ Informs the client program about the
+ actual size of the window.
+*/
+
+void MyPty::setSize(int lines, int columns)
+{
+ struct winsize wsize;
+ wsize.ws_row = (unsigned short)lines;
+ wsize.ws_col = (unsigned short)columns;
+ if(fd < 0) return;
+ ioctl(fd,TIOCSWINSZ,(char *)&wsize);
+}
+
+
+void MyPty::donePty()
+{
+ // This is code from the Qt DumbTerminal example
+ int status = 0;
+
+ ::close(fd);
+
+ if (cpid) {
+ kill(cpid, SIGHUP);
+ waitpid(cpid, &status, 0);
+ }
+
+ emit done(status);
+}
+
+
+const char* MyPty::deviceName()
+{
+ return ttynam;
+}
+
+
+void MyPty::error()
+{
+ // This is code from the Qt DumbTerminal example
+ donePty();
+}
+
+
+/*!
+ start the client program.
+*/
+int MyPty::run(const char* cmd, QStrList &, const char*, int)
+{
+ // This is code from the Qt DumbTerminal example
+ cpid = fork();
+
+ if ( !cpid ) {
+ // child - exec shell on tty
+ for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL);
+ int ttyfd = open(ttynam, O_RDWR);
+ dup2(ttyfd, STDIN_FILENO);
+ dup2(ttyfd, STDOUT_FILENO);
+ dup2(ttyfd, STDERR_FILENO);
+ // should be done with tty, so close it
+ close(ttyfd);
+ static struct termios ttmode;
+ if ( setsid() < 0 )
+ perror( "failed to set process group" );
+#if defined (TIOCSCTTY)
+ // grabbed from APUE by Stevens
+ ioctl(STDIN_FILENO, TIOCSCTTY, 0);
+#endif
+ tcgetattr( STDIN_FILENO, &ttmode );
+ ttmode.c_cc[VINTR] = 3;
+ ttmode.c_cc[VERASE] = 8;
+ tcsetattr( STDIN_FILENO, TCSANOW, &ttmode );
+ setenv("TERM","vt100",1);
+ setenv("COLORTERM","0",1);
+
+ if (getuid() == 0) {
+ char msg[] = "WARNING: You are running this shell as root!\n";
+ write(ttyfd, msg, sizeof(msg));
+ }
+ execl(cmd, cmd, 0);
+
+ donePty();
+ exit(-1);
+ }
+
+ // parent - continue as a widget
+ QSocketNotifier* sn_r = new QSocketNotifier(fd,QSocketNotifier::Read,this);
+ QSocketNotifier* sn_e = new QSocketNotifier(fd,QSocketNotifier::Exception,this);
+ connect(sn_r,SIGNAL(activated(int)),this,SLOT(readPty()));
+ connect(sn_e,SIGNAL(activated(int)),this,SLOT(error()));
+
+ return 0;
+}
+
+int MyPty::openPty()
+{
+ // This is code from the Qt DumbTerminal example
+ int ptyfd = -1;
+
+#ifdef HAVE_OPENPTY
+ int ttyfd;
+ if ( openpty(&ptyfd,&ttyfd,ttynam,0,0) )
+ ptyfd = -1;
+ else
+ close(ttyfd); // we open the ttynam ourselves.
+#else
+ for (const char* c0 = "pqrstuvwxyzabcde"; ptyfd < 0 && *c0 != 0; c0++) {
+ for (const char* c1 = "0123456789abcdef"; ptyfd < 0 && *c1 != 0; c1++) {
+ sprintf(ptynam,"/dev/pty%c%c",*c0,*c1);
+ sprintf(ttynam,"/dev/tty%c%c",*c0,*c1);
+ if ((ptyfd = ::open(ptynam,O_RDWR)) >= 0) {
+ if (geteuid() != 0 && !access(ttynam,R_OK|W_OK) == 0) {
+ ::close(ptyfd);
+ ptyfd = -1;
+ }
+ }
+ }
+ }
+#endif
+
+ if ( ptyfd < 0 ) {
+ qApp->exit(1);
+ return -1;
+ }
+
+ return ptyfd;
+}
+
+/*!
+ Create an instance.
+*/
+MyPty::MyPty() : cpid(0)
+{
+ fd = openPty();
+}
+
+/*!
+ Destructor.
+ Note that the related client program is not killed
+ (yet) when a instance is deleted.
+*/
+MyPty::~MyPty()
+{
+ donePty();
+}
+
+
+/*! sends len bytes through the line */
+void MyPty::send_bytes(const char* s, int len)
+{
+
+#ifdef VERBOSE_DEBUG
+ // verbose debug
+ printf("sending bytes:\n");
+ for (int i = 0; i < len; i++)
+ printf("%c", s[i]);
+ printf("\n");
+#endif
+
+ ::write(fd, s, len);
+}
+
+/*! indicates that a block of data is received */
+void MyPty::readPty()
+{
+ char buf[4096];
+
+ int len = ::read( fd, buf, 4096 );
+
+ if (len == -1)
+ donePty();
+
+ if (len < 0)
+ return;
+
+ emit block_in(buf,len);
+
+#ifdef VERBOSE_DEBUG
+ // verbose debug
+ printf("read bytes:\n");
+ for (int i = 0; i < len; i++)
+ printf("%c", buf[i]);
+ printf("\n");
+#endif
+
+}
+