summaryrefslogtreecommitdiff
path: root/core/apps/embeddedkonsole/MyPty.cpp
Unidiff
Diffstat (limited to 'core/apps/embeddedkonsole/MyPty.cpp') (more/less context) (show 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 @@
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(fd < 0) return;
104 ioctl(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(fd);
114
115 if (cpid) {
116 kill(cpid, SIGHUP);
117 waitpid(cpid, &status, 0);
118 }
119
120 emit done(status);
121}
122
123
124const char* MyPty::deviceName()
125{
126 return ttynam;
127}
128
129
130void MyPty::error()
131{
132 // This is code from the Qt DumbTerminal example
133 donePty();
134}
135
136
137/*!
138 start the client program.
139*/
140int MyPty::run(const char* cmd, QStrList &, const char*, int)
141{
142 // This is code from the Qt DumbTerminal example
143 cpid = fork();
144
145 if ( !cpid ) {
146 // child - exec shell on tty
147 for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL);
148 int ttyfd = open(ttynam, O_RDWR);
149 dup2(ttyfd, STDIN_FILENO);
150 dup2(ttyfd, STDOUT_FILENO);
151 dup2(ttyfd, STDERR_FILENO);
152 // should be done with tty, so close it
153 close(ttyfd);
154 static struct termios ttmode;
155 if ( setsid() < 0 )
156 perror( "failed to set process group" );
157#if defined (TIOCSCTTY)
158 // grabbed from APUE by Stevens
159 ioctl(STDIN_FILENO, TIOCSCTTY, 0);
160#endif
161 tcgetattr( STDIN_FILENO, &ttmode );
162 ttmode.c_cc[VINTR] = 3;
163 ttmode.c_cc[VERASE] = 8;
164 tcsetattr( STDIN_FILENO, TCSANOW, &ttmode );
165 setenv("TERM","vt100",1);
166 setenv("COLORTERM","0",1);
167
168 if (getuid() == 0) {
169 char msg[] = "WARNING: You are running this shell as root!\n";
170 write(ttyfd, msg, sizeof(msg));
171 }
172 execl(cmd, cmd, 0);
173
174 donePty();
175 exit(-1);
176 }
177
178 // parent - continue as a widget
179 QSocketNotifier* sn_r = new QSocketNotifier(fd,QSocketNotifier::Read,this);
180 QSocketNotifier* sn_e = new QSocketNotifier(fd,QSocketNotifier::Exception,this);
181 connect(sn_r,SIGNAL(activated(int)),this,SLOT(readPty()));
182 connect(sn_e,SIGNAL(activated(int)),this,SLOT(error()));
183
184 return 0;
185}
186
187int MyPty::openPty()
188{
189 // This is code from the Qt DumbTerminal example
190 int ptyfd = -1;
191
192#ifdef HAVE_OPENPTY
193 int ttyfd;
194 if ( openpty(&ptyfd,&ttyfd,ttynam,0,0) )
195 ptyfd = -1;
196 else
197 close(ttyfd); // we open the ttynam ourselves.
198#else
199 for (const char* c0 = "pqrstuvwxyzabcde"; ptyfd < 0 && *c0 != 0; c0++) {
200 for (const char* c1 = "0123456789abcdef"; ptyfd < 0 && *c1 != 0; c1++) {
201 sprintf(ptynam,"/dev/pty%c%c",*c0,*c1);
202 sprintf(ttynam,"/dev/tty%c%c",*c0,*c1);
203 if ((ptyfd = ::open(ptynam,O_RDWR)) >= 0) {
204 if (geteuid() != 0 && !access(ttynam,R_OK|W_OK) == 0) {
205 ::close(ptyfd);
206 ptyfd = -1;
207 }
208 }
209 }
210 }
211#endif
212
213 if ( ptyfd < 0 ) {
214 qApp->exit(1);
215 return -1;
216 }
217
218 return ptyfd;
219}
220
221/*!
222 Create an instance.
223*/
224MyPty::MyPty() : cpid(0)
225{
226 fd = openPty();
227}
228
229/*!
230 Destructor.
231 Note that the related client program is not killed
232 (yet) when a instance is deleted.
233*/
234MyPty::~MyPty()
235{
236 donePty();
237}
238
239
240/*! sends len bytes through the line */
241void MyPty::send_bytes(const char* s, int len)
242{
243
244#ifdef VERBOSE_DEBUG
245 // verbose debug
246 printf("sending bytes:\n");
247 for (int i = 0; i < len; i++)
248 printf("%c", s[i]);
249 printf("\n");
250#endif
251
252 ::write(fd, s, len);
253}
254
255/*! indicates that a block of data is received */
256void MyPty::readPty()
257{
258 char buf[4096];
259
260 int len = ::read( fd, buf, 4096 );
261
262 if (len == -1)
263 donePty();
264
265 if (len < 0)
266 return;
267
268 emit block_in(buf,len);
269
270#ifdef VERBOSE_DEBUG
271 // verbose debug
272 printf("read bytes:\n");
273 for (int i = 0; i < len; i++)
274 printf("%c", buf[i]);
275 printf("\n");
276#endif
277
278}
279