1/*
2
3 This file is part of the KDE libraries
4 Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
5 Copyright (C) 2010 KDE e.V. <kde-ev-board@kde.org>
6 Author Adriaan de Groot <groot@kde.org>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22*/
23
24#include "kptydevice.h"
25#include "kpty_p.h"
26
27#include <config.h>
28#include <config-pty.h>
29
30#include <QSocketNotifier>
31
32#include <klocale.h>
33
34#include <unistd.h>
35#include <errno.h>
36#include <signal.h>
37#include <termios.h>
38#include <fcntl.h>
39#include <sys/ioctl.h>
40#ifdef HAVE_SYS_FILIO_H
41# include <sys/filio.h>
42#endif
43#ifdef HAVE_SYS_TIME_H
44# include <sys/time.h>
45#endif
46
47#if defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
48 // "the other end's output queue size" - kinda braindead, huh?
49# define PTY_BYTES_AVAILABLE TIOCOUTQ
50#elif defined(TIOCINQ)
51 // "our end's input queue size"
52# define PTY_BYTES_AVAILABLE TIOCINQ
53#else
54 // likewise. more generic ioctl (theoretically)
55# define PTY_BYTES_AVAILABLE FIONREAD
56#endif
57
58#define KMAXINT ((int)(~0U >> 1))
59
60/////////////////////////////////////////////////////
61// Helper. Remove when QRingBuffer becomes public. //
62/////////////////////////////////////////////////////
63
64#include <QtCore/qbytearray.h>
65#include <QtCore/qlinkedlist.h>
66
67#define CHUNKSIZE 4096
68
69class KRingBuffer
70{
71public:
72 KRingBuffer()
73 {
74 clear();
75 }
76
77 void clear()
78 {
79 buffers.clear();
80 QByteArray tmp;
81 tmp.resize(CHUNKSIZE);
82 buffers << tmp;
83 head = tail = 0;
84 totalSize = 0;
85 }
86
87 inline bool isEmpty() const
88 {
89 return buffers.count() == 1 && !tail;
90 }
91
92 inline int size() const
93 {
94 return totalSize;
95 }
96
97 inline int readSize() const
98 {
99 return (buffers.count() == 1 ? tail : buffers.first().size()) - head;
100 }
101
102 inline const char *readPointer() const
103 {
104 Q_ASSERT(totalSize > 0);
105 return buffers.first().constData() + head;
106 }
107
108 void free(int bytes)
109 {
110 totalSize -= bytes;
111 Q_ASSERT(totalSize >= 0);
112
113 forever {
114 int nbs = readSize();
115
116 if (bytes < nbs) {
117 head += bytes;
118 if (head == tail && buffers.count() == 1) {
119 buffers.first().resize(CHUNKSIZE);
120 head = tail = 0;
121 }
122 break;
123 }
124
125 bytes -= nbs;
126 if (buffers.count() == 1) {
127 buffers.first().resize(CHUNKSIZE);
128 head = tail = 0;
129 break;
130 }
131
132 buffers.removeFirst();
133 head = 0;
134 }
135 }
136
137 char *reserve(int bytes)
138 {
139 totalSize += bytes;
140
141 char *ptr;
142 if (tail + bytes <= buffers.last().size()) {
143 ptr = buffers.last().data() + tail;
144 tail += bytes;
145 } else {
146 buffers.last().resize(tail);
147 QByteArray tmp;
148 tmp.resize(qMax(CHUNKSIZE, bytes));
149 ptr = tmp.data();
150 buffers << tmp;
151 tail = bytes;
152 }
153 return ptr;
154 }
155
156 // release a trailing part of the last reservation
157 inline void unreserve(int bytes)
158 {
159 totalSize -= bytes;
160 tail -= bytes;
161 }
162
163 inline void write(const char *data, int len)
164 {
165 memcpy(reserve(len), data, len);
166 }
167
168 // Find the first occurrence of c and return the index after it.
169 // If c is not found until maxLength, maxLength is returned, provided
170 // it is smaller than the buffer size. Otherwise -1 is returned.
171 int indexAfter(char c, int maxLength = KMAXINT) const
172 {
173 int index = 0;
174 int start = head;
175 QLinkedList<QByteArray>::ConstIterator it = buffers.begin();
176 forever {
177 if (!maxLength)
178 return index;
179 if (index == size())
180 return -1;
181 const QByteArray &buf = *it;
182 ++it;
183 int len = qMin((it == buffers.end() ? tail : buf.size()) - start,
184 maxLength);
185 const char *ptr = buf.data() + start;
186 if (const char *rptr = (const char *)memchr(ptr, c, len))
187 return index + (rptr - ptr) + 1;
188 index += len;
189 maxLength -= len;
190 start = 0;
191 }
192 }
193
194 inline int lineSize(int maxLength = KMAXINT) const
195 {
196 return indexAfter('\n', maxLength);
197 }
198
199 inline bool canReadLine() const
200 {
201 return lineSize() != -1;
202 }
203
204 int read(char *data, int maxLength)
205 {
206 int bytesToRead = qMin(size(), maxLength);
207 int readSoFar = 0;
208 while (readSoFar < bytesToRead) {
209 const char *ptr = readPointer();
210 int bs = qMin(bytesToRead - readSoFar, readSize());
211 memcpy(data + readSoFar, ptr, bs);
212 readSoFar += bs;
213 free(bs);
214 }
215 return readSoFar;
216 }
217
218 int readLine(char *data, int maxLength)
219 {
220 return read(data, lineSize(qMin(maxLength, size())));
221 }
222
223private:
224 QLinkedList<QByteArray> buffers;
225 int head, tail;
226 int totalSize;
227};
228
229//////////////////
230// private data //
231//////////////////
232
233// Lifted from Qt. I don't think they would mind. ;)
234// Re-lift again from Qt whenever a proper replacement for pthread_once appears
235static void qt_ignore_sigpipe()
236{
237 static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
238 if (atom.testAndSetRelaxed(0, 1)) {
239 struct sigaction noaction;
240 memset(&noaction, 0, sizeof(noaction));
241 noaction.sa_handler = SIG_IGN;
242 sigaction(SIGPIPE, &noaction, 0);
243 }
244}
245
246#define NO_INTR(ret,func) do { ret = func; } while (ret < 0 && errno == EINTR)
247
248struct KPtyDevicePrivate : public KPtyPrivate {
249 Q_DECLARE_PUBLIC(KPtyDevice)
250
251 KPtyDevicePrivate(KPty* parent) :
252 KPtyPrivate(parent),
253 emittedReadyRead(false), emittedBytesWritten(false),
254 readNotifier(0), writeNotifier(0)
255 {
256 }
257
258 bool _k_canRead();
259 bool _k_canWrite();
260
261 bool doWait(int msecs, bool reading);
262 void finishOpen(QIODevice::OpenMode mode);
263
264 bool emittedReadyRead;
265 bool emittedBytesWritten;
266 QSocketNotifier *readNotifier;
267 QSocketNotifier *writeNotifier;
268 KRingBuffer readBuffer;
269 KRingBuffer writeBuffer;
270};
271
272bool KPtyDevicePrivate::_k_canRead()
273{
274 Q_Q(KPtyDevice);
275 qint64 readBytes = 0;
276
277#ifdef Q_OS_IRIX // this should use a config define, but how to check it?
278 size_t available;
279#else
280 int available;
281#endif
282 if (!::ioctl(q->masterFd(), PTY_BYTES_AVAILABLE, (char *) &available)) {
283#ifdef Q_OS_SOLARIS
284 // A Pty is a STREAMS module, and those can be activated
285 // with 0 bytes available. This happens either when ^C is
286 // pressed, or when an application does an explicit write(a,b,0)
287 // which happens in experiments fairly often. When 0 bytes are
288 // available, you must read those 0 bytes to clear the STREAMS
289 // module, but we don't want to hit the !readBytes case further down.
290 if (!available) {
291 char c;
292 // Read the 0-byte STREAMS message
293 NO_INTR(readBytes, read(q->masterFd(), &c, 0));
294 // Should return 0 bytes read; -1 is error
295 if (readBytes < 0) {
296 readNotifier->setEnabled(false);
297 emit q->readEof();
298 return false;
299 }
300 return true;
301 }
302#endif
303
304 char *ptr = readBuffer.reserve(available);
305#ifdef Q_OS_SOLARIS
306 // Even if available > 0, it is possible for read()
307 // to return 0 on Solaris, due to 0-byte writes in the stream.
308 // Ignore them and keep reading until we hit *some* data.
309 // In Solaris it is possible to have 15 bytes available
310 // and to (say) get 0, 0, 6, 0 and 9 bytes in subsequent reads.
311 // Because the stream is set to O_NONBLOCK in finishOpen(),
312 // an EOF read will return -1.
313 readBytes = 0;
314 while (!readBytes)
315#endif
316 // Useless block braces except in Solaris
317 {
318 NO_INTR(readBytes, read(q->masterFd(), ptr, available));
319 }
320 if (readBytes < 0) {
321 readBuffer.unreserve(available);
322 q->setErrorString(i18n("Error reading from PTY"));
323 return false;
324 }
325 readBuffer.unreserve(available - readBytes); // *should* be a no-op
326 }
327
328 if (!readBytes) {
329 readNotifier->setEnabled(false);
330 emit q->readEof();
331 return false;
332 } else {
333 if (!emittedReadyRead) {
334 emittedReadyRead = true;
335 emit q->readyRead();
336 emittedReadyRead = false;
337 }
338 return true;
339 }
340}
341
342bool KPtyDevicePrivate::_k_canWrite()
343{
344 Q_Q(KPtyDevice);
345
346 writeNotifier->setEnabled(false);
347 if (writeBuffer.isEmpty())
348 return false;
349
350 qt_ignore_sigpipe();
351 int wroteBytes;
352 NO_INTR(wroteBytes,
353 write(q->masterFd(),
354 writeBuffer.readPointer(), writeBuffer.readSize()));
355 if (wroteBytes < 0) {
356 q->setErrorString(i18n("Error writing to PTY"));
357 return false;
358 }
359 writeBuffer.free(wroteBytes);
360
361 if (!emittedBytesWritten) {
362 emittedBytesWritten = true;
363 emit q->bytesWritten(wroteBytes);
364 emittedBytesWritten = false;
365 }
366
367 if (!writeBuffer.isEmpty())
368 writeNotifier->setEnabled(true);
369 return true;
370}
371
372#ifndef timeradd
373// Lifted from GLIBC
374# define timeradd(a, b, result) \
375 do { \
376 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
377 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
378 if ((result)->tv_usec >= 1000000) { \
379 ++(result)->tv_sec; \
380 (result)->tv_usec -= 1000000; \
381 } \
382 } while (0)
383# define timersub(a, b, result) \
384 do { \
385 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
386 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
387 if ((result)->tv_usec < 0) { \
388 --(result)->tv_sec; \
389 (result)->tv_usec += 1000000; \
390 } \
391 } while (0)
392#endif
393
394bool KPtyDevicePrivate::doWait(int msecs, bool reading)
395{
396 Q_Q(KPtyDevice);
397#ifndef __linux__
398 struct timeval etv;
399#endif
400 struct timeval tv, *tvp;
401
402 if (msecs < 0)
403 tvp = 0;
404 else {
405 tv.tv_sec = msecs / 1000;
406 tv.tv_usec = (msecs % 1000) * 1000;
407#ifndef __linux__
408 gettimeofday(&etv, 0);
409 timeradd(&tv, &etv, &etv);
410#endif
411 tvp = &tv;
412 }
413
414 while (reading ? readNotifier->isEnabled() : !writeBuffer.isEmpty()) {
415 fd_set rfds;
416 fd_set wfds;
417
418 FD_ZERO(&rfds);
419 FD_ZERO(&wfds);
420
421 if (readNotifier->isEnabled())
422 FD_SET(q->masterFd(), &rfds);
423 if (!writeBuffer.isEmpty())
424 FD_SET(q->masterFd(), &wfds);
425
426#ifndef __linux__
427 if (tvp) {
428 gettimeofday(&tv, 0);
429 timersub(&etv, &tv, &tv);
430 if (tv.tv_sec < 0)
431 tv.tv_sec = tv.tv_usec = 0;
432 }
433#endif
434
435 switch (select(q->masterFd() + 1, &rfds, &wfds, 0, tvp)) {
436 case -1:
437 if (errno == EINTR)
438 break;
439 return false;
440 case 0:
441 q->setErrorString(i18n("PTY operation timed out"));
442 return false;
443 default:
444 if (FD_ISSET(q->masterFd(), &rfds)) {
445 bool canRead = _k_canRead();
446 if (reading && canRead)
447 return true;
448 }
449 if (FD_ISSET(q->masterFd(), &wfds)) {
450 bool canWrite = _k_canWrite();
451 if (!reading)
452 return canWrite;
453 }
454 break;
455 }
456 }
457 return false;
458}
459
460void KPtyDevicePrivate::finishOpen(QIODevice::OpenMode mode)
461{
462 Q_Q(KPtyDevice);
463
464 q->QIODevice::open(mode);
465 fcntl(q->masterFd(), F_SETFL, O_NONBLOCK);
466 readBuffer.clear();
467 readNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Read, q);
468 writeNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Write, q);
469 QObject::connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_k_canRead()));
470 QObject::connect(writeNotifier, SIGNAL(activated(int)), q, SLOT(_k_canWrite()));
471 readNotifier->setEnabled(true);
472}
473
474/////////////////////////////
475// public member functions //
476/////////////////////////////
477
478KPtyDevice::KPtyDevice(QObject *parent) :
479 QIODevice(parent),
480 KPty(new KPtyDevicePrivate(this))
481{
482}
483
484KPtyDevice::~KPtyDevice()
485{
486 close();
487}
488
489bool KPtyDevice::open(OpenMode mode)
490{
491 Q_D(KPtyDevice);
492
493 if (masterFd() >= 0)
494 return true;
495
496 if (!KPty::open()) {
497 setErrorString(i18n("Error opening PTY"));
498 return false;
499 }
500
501 d->finishOpen(mode);
502
503 return true;
504}
505
506bool KPtyDevice::open(int fd, OpenMode mode)
507{
508 Q_D(KPtyDevice);
509
510 if (!KPty::open(fd)) {
511 setErrorString(i18n("Error opening PTY"));
512 return false;
513 }
514
515 d->finishOpen(mode);
516
517 return true;
518}
519
520void KPtyDevice::close()
521{
522 Q_D(KPtyDevice);
523
524 if (masterFd() < 0)
525 return;
526
527 delete d->readNotifier;
528 delete d->writeNotifier;
529
530 QIODevice::close();
531
532 KPty::close();
533}
534
535bool KPtyDevice::isSequential() const
536{
537 return true;
538}
539
540bool KPtyDevice::canReadLine() const
541{
542 Q_D(const KPtyDevice);
543 return QIODevice::canReadLine() || d->readBuffer.canReadLine();
544}
545
546bool KPtyDevice::atEnd() const
547{
548 Q_D(const KPtyDevice);
549 return QIODevice::atEnd() && d->readBuffer.isEmpty();
550}
551
552qint64 KPtyDevice::bytesAvailable() const
553{
554 Q_D(const KPtyDevice);
555 return QIODevice::bytesAvailable() + d->readBuffer.size();
556}
557
558qint64 KPtyDevice::bytesToWrite() const
559{
560 Q_D(const KPtyDevice);
561 return d->writeBuffer.size();
562}
563
564bool KPtyDevice::waitForReadyRead(int msecs)
565{
566 Q_D(KPtyDevice);
567 return d->doWait(msecs, true);
568}
569
570bool KPtyDevice::waitForBytesWritten(int msecs)
571{
572 Q_D(KPtyDevice);
573 return d->doWait(msecs, false);
574}
575
576void KPtyDevice::setSuspended(bool suspended)
577{
578 Q_D(KPtyDevice);
579 d->readNotifier->setEnabled(!suspended);
580}
581
582bool KPtyDevice::isSuspended() const
583{
584 Q_D(const KPtyDevice);
585 return !d->readNotifier->isEnabled();
586}
587
588// protected
589qint64 KPtyDevice::readData(char *data, qint64 maxlen)
590{
591 Q_D(KPtyDevice);
592 return d->readBuffer.read(data, (int)qMin<qint64>(maxlen, KMAXINT));
593}
594
595// protected
596qint64 KPtyDevice::readLineData(char *data, qint64 maxlen)
597{
598 Q_D(KPtyDevice);
599 return d->readBuffer.readLine(data, (int)qMin<qint64>(maxlen, KMAXINT));
600}
601
602// protected
603qint64 KPtyDevice::writeData(const char *data, qint64 len)
604{
605 Q_D(KPtyDevice);
606 Q_ASSERT(len <= KMAXINT);
607
608 d->writeBuffer.write(data, len);
609 d->writeNotifier->setEnabled(true);
610 return len;
611}
612
613#include "kptydevice.moc"
614