-rw-r--r-- | noncore/apps/opie-console/MyPty.cpp | 22 | ||||
-rw-r--r-- | noncore/apps/opie-console/procctl.cpp | 2 |
2 files changed, 18 insertions, 6 deletions
diff --git a/noncore/apps/opie-console/MyPty.cpp b/noncore/apps/opie-console/MyPty.cpp index 10828b0..cacb4ce 100644 --- a/noncore/apps/opie-console/MyPty.cpp +++ b/noncore/apps/opie-console/MyPty.cpp | |||
@@ -37,263 +37,275 @@ | |||
37 | One can create many instances of this class within a program. | 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 | 38 | As a side effect of using this class, a signal(2) handler is |
39 | installed on SIGCHLD. | 39 | installed on SIGCHLD. |
40 | 40 | ||
41 | \par FIXME | 41 | \par FIXME |
42 | 42 | ||
43 | [NOTE: much of the technical stuff below will be replaced by forkpty.] | 43 | [NOTE: much of the technical stuff below will be replaced by forkpty.] |
44 | 44 | ||
45 | publish the SIGCHLD signal if not related to an instance. | 45 | publish the SIGCHLD signal if not related to an instance. |
46 | 46 | ||
47 | clearify TEPty::done vs. TEPty::~TEPty semantics. | 47 | clearify TEPty::done vs. TEPty::~TEPty semantics. |
48 | check if pty is restartable via run after done. | 48 | check if pty is restartable via run after done. |
49 | 49 | ||
50 | \par Pseudo terminals | 50 | \par Pseudo terminals |
51 | 51 | ||
52 | Pseudo terminals are a unique feature of UNIX, and always come in form of | 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 | 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 | 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 | 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 | 56 | simultanous instances of this class is (globally) limited by the number of |
57 | those device pairs, which is 256. | 57 | those device pairs, which is 256. |
58 | 58 | ||
59 | Another technic are UNIX 98 PTY's. These are supported also, and prefered | 59 | Another technic are UNIX 98 PTY's. These are supported also, and prefered |
60 | over the (obsolete) predecessor. | 60 | over the (obsolete) predecessor. |
61 | 61 | ||
62 | There's a sinister ioctl(2), signal(2) and job control stuff | 62 | There's a sinister ioctl(2), signal(2) and job control stuff |
63 | nessesary to make everything work as it should. | 63 | nessesary to make everything work as it should. |
64 | */ | 64 | */ |
65 | 65 | ||
66 | 66 | ||
67 | #include <qapplication.h> | 67 | #include <qapplication.h> |
68 | #include <qsocketnotifier.h> | 68 | #include <qsocketnotifier.h> |
69 | #include <qstring.h> | 69 | #include <qstring.h> |
70 | 70 | ||
71 | #include <stdlib.h> | 71 | #include <stdlib.h> |
72 | #include <stdio.h> | 72 | #include <stdio.h> |
73 | #include <signal.h> | 73 | #include <signal.h> |
74 | #include <fcntl.h> | 74 | #include <fcntl.h> |
75 | #include <unistd.h> | 75 | #include <unistd.h> |
76 | #include <termios.h> | 76 | #include <termios.h> |
77 | #include <sys/types.h> | 77 | #include <sys/types.h> |
78 | #include <sys/ioctl.h> | 78 | #include <sys/ioctl.h> |
79 | #include <sys/wait.h> | 79 | #include <sys/wait.h> |
80 | 80 | ||
81 | #ifdef HAVE_OPENPTY | 81 | #ifdef HAVE_OPENPTY |
82 | #include <pty.h> | 82 | #include <pty.h> |
83 | #endif | 83 | #endif |
84 | 84 | ||
85 | #include "procctl.h" | ||
85 | #include "MyPty.h" | 86 | #include "MyPty.h" |
86 | 87 | ||
87 | 88 | ||
88 | #undef VERBOSE_DEBUG | 89 | #undef VERBOSE_DEBUG |
89 | 90 | ||
90 | 91 | ||
91 | /* -------------------------------------------------------------------------- */ | 92 | /* -------------------------------------------------------------------------- */ |
92 | 93 | ||
93 | /*! | 94 | /*! |
94 | Informs the client program about the | 95 | Informs the client program about the |
95 | actual size of the window. | 96 | actual size of the window. |
96 | */ | 97 | */ |
97 | 98 | ||
98 | void MyPty::setSize(int lines, int columns) | 99 | void MyPty::setSize(int lines, int columns) |
99 | { | 100 | { |
100 | struct winsize wsize; | 101 | struct winsize wsize; |
101 | wsize.ws_row = (unsigned short)lines; | 102 | wsize.ws_row = (unsigned short)lines; |
102 | wsize.ws_col = (unsigned short)columns; | 103 | wsize.ws_col = (unsigned short)columns; |
103 | if(m_fd < 0) return; | 104 | if(m_fd < 0) return; |
104 | ioctl(m_fd,TIOCSWINSZ,(char *)&wsize); | 105 | ioctl(m_fd,TIOCSWINSZ,(char *)&wsize); |
105 | } | 106 | } |
106 | 107 | ||
107 | 108 | ||
108 | void MyPty::donePty() | 109 | void MyPty::donePty() |
109 | { | 110 | { |
110 | // This is code from the Qt DumbTerminal example | 111 | // This is code from the Qt DumbTerminal example |
111 | int status = 0; | 112 | int status = 0; |
112 | 113 | ||
113 | ::close(m_fd); | 114 | ::close(m_fd); |
114 | 115 | ||
115 | if (m_cpid) { | 116 | if (m_cpid) { |
117 | qWarning("killing!!!"); | ||
116 | kill(m_cpid, SIGHUP); | 118 | kill(m_cpid, SIGHUP); |
117 | waitpid(m_cpid, &status, 0); | 119 | waitpid(m_cpid, &status, 0); |
118 | } | 120 | } |
119 | 121 | ||
120 | emit done(status); | 122 | m_cpid = 0; |
123 | // emit done(status); | ||
121 | } | 124 | } |
122 | 125 | ||
123 | 126 | ||
124 | const char* MyPty::deviceName() | 127 | const char* MyPty::deviceName() |
125 | { | 128 | { |
126 | return m_ttynam; | 129 | return m_ttynam; |
127 | } | 130 | } |
128 | 131 | ||
129 | 132 | ||
130 | void MyPty::error() | 133 | void MyPty::error() |
131 | { | 134 | { |
135 | qWarning("error"); | ||
132 | // This is code from the Qt DumbTerminal example | 136 | // This is code from the Qt DumbTerminal example |
133 | donePty(); | 137 | donePty(); |
134 | } | 138 | } |
135 | 139 | ||
136 | void MyPty::start() { | 140 | void MyPty::start() { |
137 | char* cmd = "/bin/sh"; | 141 | char* cmd = "/bin/sh"; |
138 | QStrList lis; | 142 | QStrList lis; |
139 | int r =run(cmd, lis, 0, 0); | 143 | int r =run(cmd, lis, 0, 0); |
140 | r = r; | 144 | r = r; |
141 | } | 145 | } |
142 | /*! | 146 | /*! |
143 | start the client program. | 147 | start the client program. |
144 | */ | 148 | */ |
145 | int MyPty::run(const char* cmd, QStrList &, const char*, int) | 149 | int MyPty::run(const char* cmd, QStrList &, const char*, int) |
146 | { | 150 | { |
147 | // This is code from the Qt DumbTerminal example | 151 | // This is code from the Qt DumbTerminal example |
148 | m_cpid = fork(); | 152 | m_cpid = fork(); |
149 | 153 | ||
150 | if ( !m_cpid ) { | 154 | if ( !m_cpid ) { |
151 | // child - exec shell on tty | 155 | // child - exec shell on tty |
152 | for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL); | 156 | for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL); |
153 | int ttyfd = ::open(m_ttynam, O_RDWR); | 157 | int ttyfd = ::open(m_ttynam, O_RDWR); |
154 | dup2(ttyfd, STDIN_FILENO); | 158 | dup2(ttyfd, STDIN_FILENO); |
155 | dup2(ttyfd, STDOUT_FILENO); | 159 | dup2(ttyfd, STDOUT_FILENO); |
156 | dup2(ttyfd, STDERR_FILENO); | 160 | dup2(ttyfd, STDERR_FILENO); |
157 | // should be done with tty, so close it | 161 | // should be done with tty, so close it |
158 | ::close(ttyfd); | 162 | ::close(ttyfd); |
159 | static struct termios ttmode; | 163 | static struct termios ttmode; |
160 | if ( setsid() < 0 ) | 164 | if ( setsid() < 0 ) |
161 | perror( "failed to set process group" ); | 165 | perror( "failed to set process group" ); |
162 | #if defined (TIOCSCTTY) | 166 | #if defined (TIOCSCTTY) |
163 | // grabbed from APUE by Stevens | 167 | // grabbed from APUE by Stevens |
164 | ioctl(STDIN_FILENO, TIOCSCTTY, 0); | 168 | ioctl(STDIN_FILENO, TIOCSCTTY, 0); |
165 | #endif | 169 | #endif |
166 | tcgetattr( STDIN_FILENO, &ttmode ); | 170 | tcgetattr( STDIN_FILENO, &ttmode ); |
167 | ttmode.c_cc[VINTR] = 3; | 171 | ttmode.c_cc[VINTR] = 3; |
168 | ttmode.c_cc[VERASE] = 8; | 172 | ttmode.c_cc[VERASE] = 8; |
169 | tcsetattr( STDIN_FILENO, TCSANOW, &ttmode ); | 173 | tcsetattr( STDIN_FILENO, TCSANOW, &ttmode ); |
170 | setenv("TERM","vt100",1); | 174 | setenv("TERM","vt100",1); |
171 | setenv("COLORTERM","0",1); | 175 | setenv("COLORTERM","0",1); |
172 | 176 | ||
173 | if (getuid() == 0) { | 177 | if (getuid() == 0) { |
174 | char msg[] = "WARNING: You are running this shell as root!\n"; | 178 | char msg[] = "WARNING: You are running this shell as root!\n"; |
175 | write(ttyfd, msg, sizeof(msg)); | 179 | write(ttyfd, msg, sizeof(msg)); |
176 | } | 180 | } |
177 | execl(cmd, cmd, 0); | 181 | execl(cmd, cmd, 0); |
178 | 182 | ||
179 | donePty(); | 183 | donePty(); |
180 | exit(-1); | 184 | exit(-1); |
181 | } | 185 | } |
182 | 186 | ||
183 | // parent - continue as a widget | 187 | // parent - continue as a widget |
184 | QSocketNotifier* sn_r = new QSocketNotifier(m_fd,QSocketNotifier::Read,this); | 188 | QSocketNotifier* sn_r = new QSocketNotifier(m_fd,QSocketNotifier::Read,this); |
185 | QSocketNotifier* sn_e = new QSocketNotifier(m_fd,QSocketNotifier::Exception,this); | 189 | // QSocketNotifier* sn_e = new QSocketNotifier(m_fd,QSocketNotifier::Exception,this); |
186 | connect(sn_r,SIGNAL(activated(int)),this,SLOT(readPty())); | 190 | connect(sn_r,SIGNAL(activated(int)),this,SLOT(readPty())); |
187 | connect(sn_e,SIGNAL(activated(int)),this,SLOT(error())); | 191 | // connect(sn_e,SIGNAL(activated(int)),this,SLOT(error())); |
188 | 192 | ||
189 | return 0; | 193 | return 0; |
190 | } | 194 | } |
191 | 195 | ||
192 | int MyPty::openPty() | 196 | int MyPty::openPty() |
193 | { | 197 | { |
194 | // This is code from the Qt DumbTerminal example | 198 | // This is code from the Qt DumbTerminal example |
195 | int ptyfd = -1; | 199 | int ptyfd = -1; |
196 | 200 | ||
197 | #ifdef HAVE_OPENPTY | 201 | #ifdef HAVE_OPENPTY |
198 | int ttyfd; | 202 | int ttyfd; |
199 | if ( openpty(&ptyfd,&ttyfd,ttynam,0,0) ) | 203 | if ( openpty(&ptyfd,&ttyfd,ttynam,0,0) ) |
200 | ptyfd = -1; | 204 | ptyfd = -1; |
201 | else | 205 | else |
202 | close(ttyfd); // we open the ttynam ourselves. | 206 | close(ttyfd); // we open the ttynam ourselves. |
203 | #else | 207 | #else |
204 | for (const char* c0 = "pqrstuvwxyzabcde"; ptyfd < 0 && *c0 != 0; c0++) { | 208 | for (const char* c0 = "pqrstuvwxyzabcde"; ptyfd < 0 && *c0 != 0; c0++) { |
205 | for (const char* c1 = "0123456789abcdef"; ptyfd < 0 && *c1 != 0; c1++) { | 209 | for (const char* c1 = "0123456789abcdef"; ptyfd < 0 && *c1 != 0; c1++) { |
206 | sprintf(m_ptynam,"/dev/pty%c%c",*c0,*c1); | 210 | sprintf(m_ptynam,"/dev/pty%c%c",*c0,*c1); |
207 | sprintf(m_ttynam,"/dev/tty%c%c",*c0,*c1); | 211 | sprintf(m_ttynam,"/dev/tty%c%c",*c0,*c1); |
208 | if ((ptyfd = ::open(m_ptynam,O_RDWR)) >= 0) { | 212 | if ((ptyfd = ::open(m_ptynam,O_RDWR)) >= 0) { |
209 | if (geteuid() != 0 && !access(m_ttynam,R_OK|W_OK) == 0) { | 213 | if (geteuid() != 0 && !access(m_ttynam,R_OK|W_OK) == 0) { |
210 | ::close(ptyfd); | 214 | ::close(ptyfd); |
211 | ptyfd = -1; | 215 | ptyfd = -1; |
212 | } | 216 | } |
213 | } | 217 | } |
214 | } | 218 | } |
215 | } | 219 | } |
216 | #endif | 220 | #endif |
217 | 221 | ||
218 | if ( ptyfd < 0 ) { | 222 | if ( ptyfd < 0 ) { |
219 | qApp->exit(1); | 223 | qApp->exit(1); |
220 | return -1; | 224 | return -1; |
221 | } | 225 | } |
222 | 226 | ||
223 | return ptyfd; | 227 | return ptyfd; |
224 | } | 228 | } |
225 | 229 | ||
226 | /*! | 230 | /*! |
227 | Create an instance. | 231 | Create an instance. |
228 | */ | 232 | */ |
229 | MyPty::MyPty(const Profile&) : m_cpid(0) | 233 | MyPty::MyPty(const Profile&) : m_cpid(0) |
230 | { | 234 | { |
231 | m_fd = openPty(); | 235 | m_fd = openPty(); |
236 | ProcCtl* ctl = ProcCtl::self(); | ||
232 | } | 237 | } |
233 | 238 | ||
234 | /*! | 239 | /*! |
235 | Destructor. | 240 | Destructor. |
236 | Note that the related client program is not killed | 241 | Note that the related client program is not killed |
237 | (yet) when a instance is deleted. | 242 | (yet) when a instance is deleted. |
238 | */ | 243 | */ |
239 | MyPty::~MyPty() | 244 | MyPty::~MyPty() |
240 | { | 245 | { |
241 | donePty(); | 246 | donePty(); |
242 | } | 247 | } |
243 | QString MyPty::identifier()const { | 248 | QString MyPty::identifier()const { |
244 | return QString::fromLatin1("term"); | 249 | return QString::fromLatin1("term"); |
245 | } | 250 | } |
246 | QString MyPty::name()const{ | 251 | QString MyPty::name()const{ |
247 | return identifier(); | 252 | return identifier(); |
248 | } | 253 | } |
249 | bool MyPty::open() { | 254 | bool MyPty::open() { |
250 | start(); | 255 | start(); |
251 | return true; | 256 | return true; |
252 | } | 257 | } |
253 | void MyPty::close() { | 258 | void MyPty::close() { |
254 | donePty(); | 259 | donePty(); |
255 | } | 260 | } |
256 | void MyPty::reload( const Profile& ) { | 261 | void MyPty::reload( const Profile& ) { |
257 | 262 | ||
258 | } | 263 | } |
259 | /*! sends len bytes through the line */ | 264 | /*! sends len bytes through the line */ |
260 | void MyPty::send(const QByteArray& ar) | 265 | void MyPty::send(const QByteArray& ar) |
261 | { | 266 | { |
262 | 267 | qWarning("sending!"); | |
263 | #ifdef VERBOSE_DEBUG | 268 | #ifdef VERBOSE_DEBUG |
264 | // verbose debug | 269 | // verbose debug |
265 | printf("sending bytes:\n"); | 270 | printf("sending bytes:\n"); |
266 | for (uint i = 0; i < ar.count(); i++) | 271 | for (uint i = 0; i < ar.count(); i++) |
267 | printf("%c", ar[i]); | 272 | printf("%c", ar[i]); |
268 | printf("\n"); | 273 | printf("\n"); |
269 | #endif | 274 | #endif |
270 | 275 | ||
271 | ::write(m_fd, ar.data(), ar.count()); | 276 | ::write(m_fd, ar.data(), ar.count()); |
272 | } | 277 | } |
273 | 278 | ||
274 | /*! indicates that a block of data is received */ | 279 | /*! indicates that a block of data is received */ |
275 | void MyPty::readPty() | 280 | void MyPty::readPty() |
276 | { | 281 | { |
282 | qWarning("read"); | ||
277 | QByteArray buf(4096); | 283 | QByteArray buf(4096); |
278 | 284 | ||
279 | int len = ::read( m_fd, buf.data(), 4096 ); | 285 | int len = ::read( m_fd, buf.data(), 4096 ); |
280 | 286 | ||
281 | if (len == -1) | 287 | if (len == -1 || len == 0) { |
288 | qWarning("donePty!!! now!"); | ||
282 | donePty(); | 289 | donePty(); |
290 | qWarning("return %s", sender()->className() ); | ||
291 | delete sender(); | ||
292 | return; | ||
293 | } | ||
283 | 294 | ||
284 | if (len < 0) | 295 | if (len < 0) |
285 | return; | 296 | return; |
286 | 297 | ||
298 | |||
287 | buf.resize(len); | 299 | buf.resize(len); |
288 | emit received(buf); | 300 | emit received(buf); |
289 | 301 | ||
290 | #ifdef VERBOSE_DEBUG | 302 | #ifdef VERBOSE_DEBUG |
291 | // verbose debug | 303 | // verbose debug |
292 | printf("read bytes:\n"); | 304 | printf("read bytes:\n"); |
293 | for (uint i = 0; i < buf.count(); i++) | 305 | for (uint i = 0; i < buf.count(); i++) |
294 | printf("%c", buf[i]); | 306 | printf("%c", buf[i]); |
295 | printf("\n"); | 307 | printf("\n"); |
296 | #endif | 308 | #endif |
297 | 309 | ||
298 | } | 310 | } |
299 | 311 | ||
diff --git a/noncore/apps/opie-console/procctl.cpp b/noncore/apps/opie-console/procctl.cpp index b0b6846..d1cfaf6 100644 --- a/noncore/apps/opie-console/procctl.cpp +++ b/noncore/apps/opie-console/procctl.cpp | |||
@@ -26,72 +26,72 @@ void ProcCtl::add(pid_t pi, int fd ) { | |||
26 | con->status = 0; | 26 | con->status = 0; |
27 | con->prev = m_last; | 27 | con->prev = m_last; |
28 | 28 | ||
29 | m_last = con; | 29 | m_last = con; |
30 | 30 | ||
31 | } | 31 | } |
32 | void ProcCtl::remove( pid_t pi ) { | 32 | void ProcCtl::remove( pid_t pi ) { |
33 | /* | 33 | /* |
34 | * We first check if the last item | 34 | * We first check if the last item |
35 | * is equal to pi the we | 35 | * is equal to pi the we |
36 | * | 36 | * |
37 | */ | 37 | */ |
38 | ProcContainer* con; | 38 | ProcContainer* con; |
39 | if (m_last->pid == pi ) { | 39 | if (m_last->pid == pi ) { |
40 | con = m_last; | 40 | con = m_last; |
41 | m_last = con->prev; | 41 | m_last = con->prev; |
42 | delete con; | 42 | delete con; |
43 | return; | 43 | return; |
44 | } | 44 | } |
45 | 45 | ||
46 | con = m_last; | 46 | con = m_last; |
47 | ProcContainer* forw = 0l; | 47 | ProcContainer* forw = 0l; |
48 | while (con ) { | 48 | while (con ) { |
49 | /* remove it */ | 49 | /* remove it */ |
50 | if ( pi == con->pid ) { | 50 | if ( pi == con->pid ) { |
51 | forw->prev = con->prev; | 51 | forw->prev = con->prev; |
52 | delete con; | 52 | delete con; |
53 | return; | 53 | return; |
54 | } | 54 | } |
55 | 55 | ||
56 | forw = con; | 56 | forw = con; |
57 | con = con->prev; | 57 | con = con->prev; |
58 | } | 58 | } |
59 | 59 | ||
60 | } | 60 | } |
61 | void ProcCtl::remove( ProcContainer con ) { | 61 | void ProcCtl::remove( ProcContainer con ) { |
62 | remove( con.pid ); | 62 | remove( con.pid ); |
63 | } | 63 | } |
64 | int ProcCtl::status(pid_t pid )const{ | 64 | int ProcCtl::status(pid_t pid )const{ |
65 | ProcContainer *con = m_last; | 65 | ProcContainer *con = m_last; |
66 | while (con) { | 66 | while (con) { |
67 | if (con->pid == pid ) | 67 | if (con->pid == pid ) |
68 | return con->status; | 68 | return con->status; |
69 | con = con->prev; | 69 | con = con->prev; |
70 | } | 70 | } |
71 | return -1; | 71 | return -1; |
72 | } | 72 | } |
73 | void ProcCtl::signal_handler(int) { | 73 | void ProcCtl::signal_handler(int) { |
74 | qWarning("signal handler"); | 74 | qWarning("signal handler in ProcCtl"); |
75 | int status; | 75 | int status; |
76 | signal( SIGCHLD, signal_handler ); | 76 | signal( SIGCHLD, signal_handler ); |
77 | pid_t pi = waitpid( -1, &status, WNOHANG ); | 77 | pid_t pi = waitpid( -1, &status, WNOHANG ); |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * find the container for pid | 80 | * find the container for pid |
81 | * | 81 | * |
82 | */ | 82 | */ |
83 | if ( pi < 0 ) { | 83 | if ( pi < 0 ) { |
84 | return; | 84 | return; |
85 | } | 85 | } |
86 | 86 | ||
87 | ProcContainer* con = m_last; | 87 | ProcContainer* con = m_last; |
88 | while (con) { | 88 | while (con) { |
89 | if ( con->pid == pi ) { | 89 | if ( con->pid == pi ) { |
90 | con->status = status; | 90 | con->status = status; |
91 | char result = 1; | 91 | char result = 1; |
92 | /* give a 'signal' */ | 92 | /* give a 'signal' */ |
93 | ::write(con->fd, &result, 1 ); | 93 | ::write(con->fd, &result, 1 ); |
94 | } | 94 | } |
95 | con = con->prev; | 95 | con = con->prev; |
96 | } | 96 | } |
97 | } | 97 | } |