summaryrefslogtreecommitdiff
path: root/noncore/apps/opie-console/MyPty.cpp
Unidiff
Diffstat (limited to 'noncore/apps/opie-console/MyPty.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/apps/opie-console/MyPty.cpp299
1 files changed, 299 insertions, 0 deletions
diff --git a/noncore/apps/opie-console/MyPty.cpp b/noncore/apps/opie-console/MyPty.cpp
new file mode 100644
index 0000000..10828b0
--- a/dev/null
+++ b/noncore/apps/opie-console/MyPty.cpp
@@ -0,0 +1,299 @@
1/* -------------------------------------------------------------------------- */
2/* */
3/* [MyPty.C] Pseudo Terminal Device */
4/* */
5/* -------------------------------------------------------------------------- */
6/* */
7/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */
8/* */
9/* This file is part of Konsole - an X terminal for KDE */
10/* -------------------------------------------------------------------------- */
11 /* */
12/* Ported Konsole to Qt/Embedded */
13 /* */
14/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */
15 /* */
16/* -------------------------------------------------------------------------- */
17
18/* If you're compiling konsole on non-Linux platforms and find
19 problems that you can track down to this file, please have
20 a look into ../README.ports, too.
21*/
22
23/*! \file
24*/
25
26/*! \class TEPty
27
28 \brief Ptys provide a pseudo terminal connection to a program.
29
30 Although closely related to pipes, these pseudo terminal connections have
31 some ability, that makes it nessesary to uses them. Most importent, they
32 know about changing screen sizes and UNIX job control.
33
34 Within the terminal emulation framework, this class represents the
35 host side of the terminal together with the connecting serial line.
36
37 One can create many instances of this class within a program.
38 As a side effect of using this class, a signal(2) handler is
39 installed on SIGCHLD.
40
41 \par FIXME
42
43 [NOTE: much of the technical stuff below will be replaced by forkpty.]
44
45 publish the SIGCHLD signal if not related to an instance.
46
47 clearify TEPty::done vs. TEPty::~TEPty semantics.
48 check if pty is restartable via run after done.
49
50 \par Pseudo terminals
51
52 Pseudo terminals are a unique feature of UNIX, and always come in form of
53 pairs of devices (/dev/ptyXX and /dev/ttyXX), which are connected to each
54 other by the operating system. One may think of them as two serial devices
55 linked by a null-modem cable. Being based on devices the number of
56 simultanous instances of this class is (globally) limited by the number of
57 those device pairs, which is 256.
58
59 Another technic are UNIX 98 PTY's. These are supported also, and prefered
60 over the (obsolete) predecessor.
61
62 There's a sinister ioctl(2), signal(2) and job control stuff
63 nessesary to make everything work as it should.
64*/
65
66
67#include <qapplication.h>
68#include <qsocketnotifier.h>
69#include <qstring.h>
70
71#include <stdlib.h>
72#include <stdio.h>
73#include <signal.h>
74#include <fcntl.h>
75#include <unistd.h>
76#include <termios.h>
77#include <sys/types.h>
78#include <sys/ioctl.h>
79#include <sys/wait.h>
80
81#ifdef HAVE_OPENPTY
82#include <pty.h>
83#endif
84
85#include "MyPty.h"
86
87
88#undef VERBOSE_DEBUG
89
90
91/* -------------------------------------------------------------------------- */
92
93/*!
94 Informs the client program about the
95 actual size of the window.
96*/
97
98void MyPty::setSize(int lines, int columns)
99{
100 struct winsize wsize;
101 wsize.ws_row = (unsigned short)lines;
102 wsize.ws_col = (unsigned short)columns;
103 if(m_fd < 0) return;
104 ioctl(m_fd,TIOCSWINSZ,(char *)&wsize);
105}
106
107
108void MyPty::donePty()
109{
110 // This is code from the Qt DumbTerminal example
111 int status = 0;
112
113 ::close(m_fd);
114
115 if (m_cpid) {
116 kill(m_cpid, SIGHUP);
117 waitpid(m_cpid, &status, 0);
118 }
119
120 emit done(status);
121}
122
123
124const char* MyPty::deviceName()
125{
126 return m_ttynam;
127}
128
129
130void MyPty::error()
131{
132 // This is code from the Qt DumbTerminal example
133 donePty();
134}
135
136void MyPty::start() {
137 char* cmd = "/bin/sh";
138 QStrList lis;
139 int r =run(cmd, lis, 0, 0);
140 r = r;
141}
142/*!
143 start the client program.
144*/
145int MyPty::run(const char* cmd, QStrList &, const char*, int)
146{
147 // This is code from the Qt DumbTerminal example
148 m_cpid = fork();
149
150 if ( !m_cpid ) {
151 // child - exec shell on tty
152 for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL);
153 int ttyfd = ::open(m_ttynam, O_RDWR);
154 dup2(ttyfd, STDIN_FILENO);
155 dup2(ttyfd, STDOUT_FILENO);
156 dup2(ttyfd, STDERR_FILENO);
157 // should be done with tty, so close it
158 ::close(ttyfd);
159 static struct termios ttmode;
160 if ( setsid() < 0 )
161 perror( "failed to set process group" );
162#if defined (TIOCSCTTY)
163 // grabbed from APUE by Stevens
164 ioctl(STDIN_FILENO, TIOCSCTTY, 0);
165#endif
166 tcgetattr( STDIN_FILENO, &ttmode );
167 ttmode.c_cc[VINTR] = 3;
168 ttmode.c_cc[VERASE] = 8;
169 tcsetattr( STDIN_FILENO, TCSANOW, &ttmode );
170 setenv("TERM","vt100",1);
171 setenv("COLORTERM","0",1);
172
173 if (getuid() == 0) {
174 char msg[] = "WARNING: You are running this shell as root!\n";
175 write(ttyfd, msg, sizeof(msg));
176 }
177 execl(cmd, cmd, 0);
178
179 donePty();
180 exit(-1);
181 }
182
183 // parent - continue as a widget
184 QSocketNotifier* sn_r = new QSocketNotifier(m_fd,QSocketNotifier::Read,this);
185 QSocketNotifier* sn_e = new QSocketNotifier(m_fd,QSocketNotifier::Exception,this);
186 connect(sn_r,SIGNAL(activated(int)),this,SLOT(readPty()));
187 connect(sn_e,SIGNAL(activated(int)),this,SLOT(error()));
188
189 return 0;
190}
191
192int MyPty::openPty()
193{
194 // This is code from the Qt DumbTerminal example
195 int ptyfd = -1;
196
197#ifdef HAVE_OPENPTY
198 int ttyfd;
199 if ( openpty(&ptyfd,&ttyfd,ttynam,0,0) )
200 ptyfd = -1;
201 else
202 close(ttyfd); // we open the ttynam ourselves.
203#else
204 for (const char* c0 = "pqrstuvwxyzabcde"; ptyfd < 0 && *c0 != 0; c0++) {
205 for (const char* c1 = "0123456789abcdef"; ptyfd < 0 && *c1 != 0; c1++) {
206 sprintf(m_ptynam,"/dev/pty%c%c",*c0,*c1);
207 sprintf(m_ttynam,"/dev/tty%c%c",*c0,*c1);
208 if ((ptyfd = ::open(m_ptynam,O_RDWR)) >= 0) {
209 if (geteuid() != 0 && !access(m_ttynam,R_OK|W_OK) == 0) {
210 ::close(ptyfd);
211 ptyfd = -1;
212 }
213 }
214 }
215 }
216#endif
217
218 if ( ptyfd < 0 ) {
219 qApp->exit(1);
220 return -1;
221 }
222
223 return ptyfd;
224}
225
226/*!
227 Create an instance.
228*/
229MyPty::MyPty(const Profile&) : m_cpid(0)
230{
231 m_fd = openPty();
232}
233
234/*!
235 Destructor.
236 Note that the related client program is not killed
237 (yet) when a instance is deleted.
238*/
239MyPty::~MyPty()
240{
241 donePty();
242}
243QString MyPty::identifier()const {
244 return QString::fromLatin1("term");
245}
246QString MyPty::name()const{
247 return identifier();
248}
249bool MyPty::open() {
250 start();
251 return true;
252}
253void MyPty::close() {
254 donePty();
255}
256void MyPty::reload( const Profile& ) {
257
258}
259/*! sends len bytes through the line */
260void MyPty::send(const QByteArray& ar)
261{
262
263#ifdef VERBOSE_DEBUG
264 // verbose debug
265 printf("sending bytes:\n");
266 for (uint i = 0; i < ar.count(); i++)
267 printf("%c", ar[i]);
268 printf("\n");
269#endif
270
271 ::write(m_fd, ar.data(), ar.count());
272}
273
274/*! indicates that a block of data is received */
275void MyPty::readPty()
276{
277 QByteArray buf(4096);
278
279 int len = ::read( m_fd, buf.data(), 4096 );
280
281 if (len == -1)
282 donePty();
283
284 if (len < 0)
285 return;
286
287 buf.resize(len);
288 emit received(buf);
289
290#ifdef VERBOSE_DEBUG
291 // verbose debug
292 printf("read bytes:\n");
293 for (uint i = 0; i < buf.count(); i++)
294 printf("%c", buf[i]);
295 printf("\n");
296#endif
297
298}
299