00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kptydevice.h"
00023 #include "kpty_p.h"
00024
00025 #include <config.h>
00026 #include <config-pty.h>
00027
00028 #include <QSocketNotifier>
00029
00030 #include <klocale.h>
00031
00032 #include <unistd.h>
00033 #include <errno.h>
00034 #include <signal.h>
00035 #include <termios.h>
00036 #include <fcntl.h>
00037 #include <sys/ioctl.h>
00038 #ifdef HAVE_SYS_FILIO_H
00039 # include <sys/filio.h>
00040 #endif
00041 #ifdef HAVE_SYS_TIME_H
00042 # include <sys/time.h>
00043 #endif
00044
00045 #if defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
00046
00047 # define PTY_BYTES_AVAILABLE TIOCOUTQ
00048 #elif defined(TIOCINQ)
00049
00050 # define PTY_BYTES_AVAILABLE TIOCINQ
00051 #else
00052
00053 # define PTY_BYTES_AVAILABLE FIONREAD
00054 #endif
00055
00056 #define KMAXINT ((int)(~0U >> 1))
00057
00059
00061
00062 #include <QtCore/qbytearray.h>
00063 #include <QtCore/qlinkedlist.h>
00064
00065 #define CHUNKSIZE 4096
00066
00067 class KRingBuffer
00068 {
00069 public:
00070 KRingBuffer()
00071 {
00072 clear();
00073 }
00074
00075 void clear()
00076 {
00077 buffers.clear();
00078 QByteArray tmp;
00079 tmp.resize(CHUNKSIZE);
00080 buffers << tmp;
00081 head = tail = 0;
00082 totalSize = 0;
00083 }
00084
00085 inline bool isEmpty() const
00086 {
00087 return buffers.count() == 1 && !tail;
00088 }
00089
00090 inline int size() const
00091 {
00092 return totalSize;
00093 }
00094
00095 inline int readSize() const
00096 {
00097 return (buffers.count() == 1 ? tail : buffers.first().size()) - head;
00098 }
00099
00100 inline const char *readPointer() const
00101 {
00102 Q_ASSERT(totalSize > 0);
00103 return buffers.first().constData() + head;
00104 }
00105
00106 void free(int bytes)
00107 {
00108 totalSize -= bytes;
00109 Q_ASSERT(totalSize >= 0);
00110
00111 forever {
00112 int nbs = readSize();
00113
00114 if (bytes < nbs) {
00115 head += bytes;
00116 if (head == tail && buffers.count() == 1) {
00117 buffers.first().resize(CHUNKSIZE);
00118 head = tail = 0;
00119 }
00120 break;
00121 }
00122
00123 bytes -= nbs;
00124 if (buffers.count() == 1) {
00125 buffers.first().resize(CHUNKSIZE);
00126 head = tail = 0;
00127 break;
00128 }
00129
00130 buffers.removeFirst();
00131 head = 0;
00132 }
00133 }
00134
00135 char *reserve(int bytes)
00136 {
00137 totalSize += bytes;
00138
00139 char *ptr;
00140 if (tail + bytes <= buffers.last().size()) {
00141 ptr = buffers.last().data() + tail;
00142 tail += bytes;
00143 } else {
00144 buffers.last().resize(tail);
00145 QByteArray tmp;
00146 tmp.resize(qMax(CHUNKSIZE, bytes));
00147 ptr = tmp.data();
00148 buffers << tmp;
00149 tail = bytes;
00150 }
00151 return ptr;
00152 }
00153
00154
00155 inline void unreserve(int bytes)
00156 {
00157 totalSize -= bytes;
00158 tail -= bytes;
00159 }
00160
00161 inline void write(const char *data, int len)
00162 {
00163 memcpy(reserve(len), data, len);
00164 }
00165
00166
00167
00168
00169 int indexAfter(char c, int maxLength = KMAXINT) const
00170 {
00171 int index = 0;
00172 int start = head;
00173 QLinkedList<QByteArray>::ConstIterator it = buffers.begin();
00174 forever {
00175 if (!maxLength)
00176 return index;
00177 if (index == size())
00178 return -1;
00179 const QByteArray &buf = *it;
00180 ++it;
00181 int len = qMin((it == buffers.end() ? tail : buf.size()) - start,
00182 maxLength);
00183 const char *ptr = buf.data() + start;
00184 if (const char *rptr = (const char *)memchr(ptr, c, len))
00185 return index + (rptr - ptr) + 1;
00186 index += len;
00187 maxLength -= len;
00188 start = 0;
00189 }
00190 }
00191
00192 inline int lineSize(int maxLength = KMAXINT) const
00193 {
00194 return indexAfter('\n', maxLength);
00195 }
00196
00197 inline bool canReadLine() const
00198 {
00199 return lineSize() != -1;
00200 }
00201
00202 int read(char *data, int maxLength)
00203 {
00204 int bytesToRead = qMin(size(), maxLength);
00205 int readSoFar = 0;
00206 while (readSoFar < bytesToRead) {
00207 const char *ptr = readPointer();
00208 int bs = qMin(bytesToRead - readSoFar, readSize());
00209 memcpy(data + readSoFar, ptr, bs);
00210 readSoFar += bs;
00211 free(bs);
00212 }
00213 return readSoFar;
00214 }
00215
00216 int readLine(char *data, int maxLength)
00217 {
00218 return read(data, lineSize(qMin(maxLength, size())));
00219 }
00220
00221 private:
00222 QLinkedList<QByteArray> buffers;
00223 int head, tail;
00224 int totalSize;
00225 };
00226
00228
00230
00231
00232
00233 static void qt_ignore_sigpipe()
00234 {
00235 static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
00236 if (atom.testAndSetRelaxed(0, 1)) {
00237 struct sigaction noaction;
00238 memset(&noaction, 0, sizeof(noaction));
00239 noaction.sa_handler = SIG_IGN;
00240 sigaction(SIGPIPE, &noaction, 0);
00241 }
00242 }
00243
00244 #define NO_INTR(ret,func) do { ret = func; } while (ret < 0 && errno == EINTR)
00245
00246 struct KPtyDevicePrivate : public KPtyPrivate {
00247 Q_DECLARE_PUBLIC(KPtyDevice)
00248
00249 KPtyDevicePrivate(KPty* parent) :
00250 KPtyPrivate(parent),
00251 emittedReadyRead(false), emittedBytesWritten(false),
00252 readNotifier(0), writeNotifier(0)
00253 {
00254 }
00255
00256 bool _k_canRead();
00257 bool _k_canWrite();
00258
00259 bool doWait(int msecs, bool reading);
00260 void finishOpen(QIODevice::OpenMode mode);
00261
00262 bool emittedReadyRead;
00263 bool emittedBytesWritten;
00264 QSocketNotifier *readNotifier;
00265 QSocketNotifier *writeNotifier;
00266 KRingBuffer readBuffer;
00267 KRingBuffer writeBuffer;
00268 };
00269
00270 bool KPtyDevicePrivate::_k_canRead()
00271 {
00272 Q_Q(KPtyDevice);
00273 qint64 readBytes = 0;
00274
00275 #ifdef Q_OS_IRIX // this should use a config define, but how to check it?
00276 size_t available;
00277 #else
00278 int available;
00279 #endif
00280 if (!::ioctl(q->masterFd(), PTY_BYTES_AVAILABLE, (char *) &available)) {
00281 #ifdef Q_OS_SOLARIS
00282
00283
00284
00285
00286
00287
00288 if (!available) {
00289 char c;
00290
00291 NO_INTR(readBytes, read(q->masterFd(), &c, 0));
00292
00293 if (readBytes < 0) {
00294 readNotifier->setEnabled(false);
00295 emit q->readEof();
00296 return false;
00297 }
00298 return true;
00299 }
00300 #endif
00301
00302 char *ptr = readBuffer.reserve(available);
00303 NO_INTR(readBytes, read(q->masterFd(), ptr, available));
00304 if (readBytes < 0) {
00305 readBuffer.unreserve(available);
00306 q->setErrorString(i18n("Error reading from PTY"));
00307 return false;
00308 }
00309 readBuffer.unreserve(available - readBytes);
00310 }
00311
00312 if (!readBytes) {
00313 readNotifier->setEnabled(false);
00314 emit q->readEof();
00315 return false;
00316 } else {
00317 if (!emittedReadyRead) {
00318 emittedReadyRead = true;
00319 emit q->readyRead();
00320 emittedReadyRead = false;
00321 }
00322 return true;
00323 }
00324 }
00325
00326 bool KPtyDevicePrivate::_k_canWrite()
00327 {
00328 Q_Q(KPtyDevice);
00329
00330 writeNotifier->setEnabled(false);
00331 if (writeBuffer.isEmpty())
00332 return false;
00333
00334 qt_ignore_sigpipe();
00335 int wroteBytes;
00336 NO_INTR(wroteBytes,
00337 write(q->masterFd(),
00338 writeBuffer.readPointer(), writeBuffer.readSize()));
00339 if (wroteBytes < 0) {
00340 q->setErrorString(i18n("Error writing to PTY"));
00341 return false;
00342 }
00343 writeBuffer.free(wroteBytes);
00344
00345 if (!emittedBytesWritten) {
00346 emittedBytesWritten = true;
00347 emit q->bytesWritten(wroteBytes);
00348 emittedBytesWritten = false;
00349 }
00350
00351 if (!writeBuffer.isEmpty())
00352 writeNotifier->setEnabled(true);
00353 return true;
00354 }
00355
00356 #ifndef timeradd
00357
00358 # define timeradd(a, b, result) \
00359 do { \
00360 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
00361 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
00362 if ((result)->tv_usec >= 1000000) { \
00363 ++(result)->tv_sec; \
00364 (result)->tv_usec -= 1000000; \
00365 } \
00366 } while (0)
00367 # define timersub(a, b, result) \
00368 do { \
00369 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
00370 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
00371 if ((result)->tv_usec < 0) { \
00372 --(result)->tv_sec; \
00373 (result)->tv_usec += 1000000; \
00374 } \
00375 } while (0)
00376 #endif
00377
00378 bool KPtyDevicePrivate::doWait(int msecs, bool reading)
00379 {
00380 Q_Q(KPtyDevice);
00381 #ifndef __linux__
00382 struct timeval etv;
00383 #endif
00384 struct timeval tv, *tvp;
00385
00386 if (msecs < 0)
00387 tvp = 0;
00388 else {
00389 tv.tv_sec = msecs / 1000;
00390 tv.tv_usec = (msecs % 1000) * 1000;
00391 #ifndef __linux__
00392 gettimeofday(&etv, 0);
00393 timeradd(&tv, &etv, &etv);
00394 #endif
00395 tvp = &tv;
00396 }
00397
00398 while (reading ? readNotifier->isEnabled() : !writeBuffer.isEmpty()) {
00399 fd_set rfds;
00400 fd_set wfds;
00401
00402 FD_ZERO(&rfds);
00403 FD_ZERO(&wfds);
00404
00405 if (readNotifier->isEnabled())
00406 FD_SET(q->masterFd(), &rfds);
00407 if (!writeBuffer.isEmpty())
00408 FD_SET(q->masterFd(), &wfds);
00409
00410 #ifndef __linux__
00411 if (tvp) {
00412 gettimeofday(&tv, 0);
00413 timersub(&etv, &tv, &tv);
00414 if (tv.tv_sec < 0)
00415 tv.tv_sec = tv.tv_usec = 0;
00416 }
00417 #endif
00418
00419 switch (select(q->masterFd() + 1, &rfds, &wfds, 0, tvp)) {
00420 case -1:
00421 if (errno == EINTR)
00422 break;
00423 return false;
00424 case 0:
00425 q->setErrorString(i18n("PTY operation timed out"));
00426 return false;
00427 default:
00428 if (FD_ISSET(q->masterFd(), &rfds)) {
00429 bool canRead = _k_canRead();
00430 if (reading && canRead)
00431 return true;
00432 }
00433 if (FD_ISSET(q->masterFd(), &wfds)) {
00434 bool canWrite = _k_canWrite();
00435 if (!reading)
00436 return canWrite;
00437 }
00438 break;
00439 }
00440 }
00441 return false;
00442 }
00443
00444 void KPtyDevicePrivate::finishOpen(QIODevice::OpenMode mode)
00445 {
00446 Q_Q(KPtyDevice);
00447
00448 q->QIODevice::open(mode);
00449 fcntl(q->masterFd(), F_SETFL, O_NONBLOCK);
00450 readBuffer.clear();
00451 readNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Read, q);
00452 writeNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Write, q);
00453 QObject::connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_k_canRead()));
00454 QObject::connect(writeNotifier, SIGNAL(activated(int)), q, SLOT(_k_canWrite()));
00455 readNotifier->setEnabled(true);
00456 }
00457
00459
00461
00462 KPtyDevice::KPtyDevice(QObject *parent) :
00463 QIODevice(parent),
00464 KPty(new KPtyDevicePrivate(this))
00465 {
00466 }
00467
00468 KPtyDevice::~KPtyDevice()
00469 {
00470 close();
00471 }
00472
00473 bool KPtyDevice::open(OpenMode mode)
00474 {
00475 Q_D(KPtyDevice);
00476
00477 if (masterFd() >= 0)
00478 return true;
00479
00480 if (!KPty::open()) {
00481 setErrorString(i18n("Error opening PTY"));
00482 return false;
00483 }
00484
00485 d->finishOpen(mode);
00486
00487 return true;
00488 }
00489
00490 bool KPtyDevice::open(int fd, OpenMode mode)
00491 {
00492 Q_D(KPtyDevice);
00493
00494 if (!KPty::open(fd)) {
00495 setErrorString(i18n("Error opening PTY"));
00496 return false;
00497 }
00498
00499 d->finishOpen(mode);
00500
00501 return true;
00502 }
00503
00504 void KPtyDevice::close()
00505 {
00506 Q_D(KPtyDevice);
00507
00508 if (masterFd() < 0)
00509 return;
00510
00511 delete d->readNotifier;
00512 delete d->writeNotifier;
00513
00514 QIODevice::close();
00515
00516 KPty::close();
00517 }
00518
00519 bool KPtyDevice::isSequential() const
00520 {
00521 return true;
00522 }
00523
00524 bool KPtyDevice::canReadLine() const
00525 {
00526 Q_D(const KPtyDevice);
00527 return QIODevice::canReadLine() || d->readBuffer.canReadLine();
00528 }
00529
00530 bool KPtyDevice::atEnd() const
00531 {
00532 Q_D(const KPtyDevice);
00533 return QIODevice::atEnd() && d->readBuffer.isEmpty();
00534 }
00535
00536 qint64 KPtyDevice::bytesAvailable() const
00537 {
00538 Q_D(const KPtyDevice);
00539 return QIODevice::bytesAvailable() + d->readBuffer.size();
00540 }
00541
00542 qint64 KPtyDevice::bytesToWrite() const
00543 {
00544 Q_D(const KPtyDevice);
00545 return d->writeBuffer.size();
00546 }
00547
00548 bool KPtyDevice::waitForReadyRead(int msecs)
00549 {
00550 Q_D(KPtyDevice);
00551 return d->doWait(msecs, true);
00552 }
00553
00554 bool KPtyDevice::waitForBytesWritten(int msecs)
00555 {
00556 Q_D(KPtyDevice);
00557 return d->doWait(msecs, false);
00558 }
00559
00560 void KPtyDevice::setSuspended(bool suspended)
00561 {
00562 Q_D(KPtyDevice);
00563 d->readNotifier->setEnabled(!suspended);
00564 }
00565
00566 bool KPtyDevice::isSuspended() const
00567 {
00568 Q_D(const KPtyDevice);
00569 return !d->readNotifier->isEnabled();
00570 }
00571
00572
00573 qint64 KPtyDevice::readData(char *data, qint64 maxlen)
00574 {
00575 Q_D(KPtyDevice);
00576 return d->readBuffer.read(data, (int)qMin<qint64>(maxlen, KMAXINT));
00577 }
00578
00579
00580 qint64 KPtyDevice::readLineData(char *data, qint64 maxlen)
00581 {
00582 Q_D(KPtyDevice);
00583 return d->readBuffer.readLine(data, (int)qMin<qint64>(maxlen, KMAXINT));
00584 }
00585
00586
00587 qint64 KPtyDevice::writeData(const char *data, qint64 len)
00588 {
00589 Q_D(KPtyDevice);
00590 Q_ASSERT(len <= KMAXINT);
00591
00592 d->writeBuffer.write(data, len);
00593 d->writeNotifier->setEnabled(true);
00594 return len;
00595 }
00596
00597 #include "kptydevice.moc"