source: ogBrowser-Git/qtermwidget/src/kpty.cpp @ 59c8a0f

jenkinsmain
Last change on this file since 59c8a0f was 050d67a, checked in by adelcastillo <adelcastillo@…>, 16 years ago

Ahora el browser tiene consola en vez del output.
Pasado todo el sistema de compilacion a cmake.

git-svn-id: https://opengnsys.es/svn/trunk@408 a21b9725-9963-47de-94b9-378ad31fedc9

  • Property mode set to 100644
File size: 14.1 KB
Line 
1/*
2
3   This file is part of the KDE libraries
4   Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
5   Copyright (C) 2002-2003,2007 Oswald Buddenhagen <ossi@kde.org>
6
7    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
8
9   This library is free software; you can redistribute it and/or
10   modify it under the terms of the GNU Library General Public
11   License as published by the Free Software Foundation; either
12   version 2 of the License, or (at your option) any later version.
13
14   This library is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   Library General Public License for more details.
18
19   You should have received a copy of the GNU Library General Public License
20   along with this library; see the file COPYING.LIB.  If not, write to
21   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22   Boston, MA 02110-1301, USA.
23*/
24
25#include "kpty_p.h"
26
27#ifdef __sgi
28#define __svr4__
29#endif
30
31#ifdef __osf__
32#define _OSF_SOURCE
33#include <float.h>
34#endif
35
36#ifdef _AIX
37#define _ALL_SOURCE
38#endif
39
40// __USE_XOPEN isn't defined by default in ICC
41// (needed for ptsname(), grantpt() and unlockpt())
42#ifdef __INTEL_COMPILER
43#  ifndef __USE_XOPEN
44#    define __USE_XOPEN
45#  endif
46#endif
47
48#include <sys/types.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <sys/resource.h>
52#include <sys/stat.h>
53#include <sys/param.h>
54
55#include <errno.h>
56#include <fcntl.h>
57#include <time.h>
58#include <stdlib.h>
59#include <stdio.h>
60#include <string.h>
61#include <unistd.h>
62#include <grp.h>
63
64#if defined(HAVE_PTY_H)
65# include <pty.h>
66#endif
67
68#ifdef HAVE_LIBUTIL_H
69# include <libutil.h>
70#elif defined(HAVE_UTIL_H)
71# include <util.h>
72#endif
73
74#ifdef HAVE_UTEMPTER
75extern "C" {
76# include <utempter.h>
77}
78#else
79# include <utmp.h>
80# ifdef HAVE_UTMPX
81#  include <utmpx.h>
82# endif
83# if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
84#  define _PATH_UTMPX _UTMPX_FILE
85# endif
86# if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
87#  define _PATH_WTMPX _WTMPX_FILE
88# endif
89#endif
90
91/* for HP-UX (some versions) the extern C is needed, and for other
92   platforms it doesn't hurt */
93extern "C" {
94#include <termios.h>
95#if defined(HAVE_TERMIO_H)
96# include <termio.h> // struct winsize on some systems
97#endif
98}
99
100#if defined (_HPUX_SOURCE)
101# define _TERMIOS_INCLUDED
102# include <bsdtty.h>
103#endif
104
105#ifdef HAVE_SYS_STROPTS_H
106# include <sys/stropts.h>       // Defines I_PUSH
107# define _NEW_TTY_CTRL
108#endif
109
110#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
111# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
112#else
113# if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
114#  define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
115# else
116#  define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
117# endif
118#endif
119
120#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
121# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
122#else
123# if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
124#  define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
125# else
126#  define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
127# endif
128#endif
129
130//#include <kdebug.h>
131//#include <kstandarddirs.h>    // findExe
132
133#include <QtCore>
134
135// not defined on HP-UX for example
136#ifndef CTRL
137# define CTRL(x) ((x) & 037)
138#endif
139
140#define TTY_GROUP "tty"
141
142///////////////////////
143// private functions //
144///////////////////////
145
146//////////////////
147// private data //
148//////////////////
149
150KPtyPrivate::KPtyPrivate() :
151    masterFd(-1), slaveFd(-1)
152{
153}
154
155bool KPtyPrivate::chownpty(bool)
156{
157//    return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
158//        QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
159    return true;
160}
161
162/////////////////////////////
163// public member functions //
164/////////////////////////////
165
166KPty::KPty() :
167    d_ptr(new KPtyPrivate)
168{
169    d_ptr->q_ptr = this;
170}
171
172KPty::KPty(KPtyPrivate *d) :
173    d_ptr(d)
174{
175    d_ptr->q_ptr = this;
176}
177
178KPty::~KPty()
179{
180    close();
181    delete d_ptr;
182}
183
184bool KPty::open()
185{
186  Q_D(KPty);
187
188  if (d->masterFd >= 0)
189    return true;
190
191  QByteArray ptyName;
192
193  // Find a master pty that we can open ////////////////////////////////
194
195  // Because not all the pty animals are created equal, they want to
196  // be opened by several different methods.
197
198  // We try, as we know them, one by one.
199
200#ifdef HAVE_OPENPTY
201
202  char ptsn[PATH_MAX];
203  if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0))
204  {
205    d->masterFd = -1;
206    d->slaveFd = -1;
207    kWarning(175) << "Can't open a pseudo teletype";
208    return false;
209  }
210  d->ttyName = ptsn;
211
212#else
213
214#ifdef HAVE__GETPTY // irix
215
216  char *ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
217  if (ptsn) {
218    d->ttyName = ptsn;
219    goto grantedpt;
220  }
221
222#elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
223
224#ifdef HAVE_POSIX_OPENPT
225  d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
226#elif defined(HAVE_GETPT)
227  d->masterFd = ::getpt();
228#elif defined(PTM_DEVICE)
229  d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
230#else
231# error No method to open a PTY master detected.
232#endif
233
234  if (d->masterFd >= 0)
235  {
236 
237#ifdef HAVE_PTSNAME
238    char *ptsn = ptsname(d->masterFd);
239    if (ptsn) {
240        d->ttyName = ptsn;
241#else
242    int ptyno;
243    if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
244        d->ttyName = QByteArray("/dev/pts/") + QByteArray::number(ptyno);
245#endif
246#ifdef HAVE_GRANTPT
247        if (!grantpt(d->masterFd))
248           goto grantedpt;
249#else
250
251        goto gotpty;
252#endif
253    }
254    ::close(d->masterFd);
255    d->masterFd = -1;
256  }
257#endif // HAVE_PTSNAME || TIOCGPTN
258
259  // Linux device names, FIXME: Trouble on other systems?
260  for (const char* s3 = "pqrstuvwxyzabcde"; *s3; s3++)
261  {
262    for (const char* s4 = "0123456789abcdef"; *s4; s4++)
263    {
264      ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
265      d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
266
267      d->masterFd = ::open(ptyName.data(), O_RDWR);
268      if (d->masterFd >= 0)
269      {
270#ifdef Q_OS_SOLARIS
271        /* Need to check the process group of the pty.
272         * If it exists, then the slave pty is in use,
273         * and we need to get another one.
274         */
275        int pgrp_rtn;
276        if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
277          ::close(d->masterFd);
278          d->masterFd = -1;
279          continue;
280        }
281#endif /* Q_OS_SOLARIS */
282        if (!access(d->ttyName.data(),R_OK|W_OK)) // checks availability based on permission bits
283        {
284          if (!geteuid())
285          {
286            struct group* p = getgrnam(TTY_GROUP);
287            if (!p)
288              p = getgrnam("wheel");
289            gid_t gid = p ? p->gr_gid : getgid ();
290
291            chown(d->ttyName.data(), getuid(), gid);
292            chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
293          }
294          goto gotpty;
295        }
296        ::close(d->masterFd);
297        d->masterFd = -1;
298      }
299    }
300  }
301
302  qWarning() << "Can't open a pseudo teletype";
303  return false;
304
305 gotpty:
306  struct stat st;
307  if (stat(d->ttyName.data(), &st)) {
308    return false; // this just cannot happen ... *cough*  Yeah right, I just
309                  // had it happen when pty #349 was allocated.  I guess
310                  // there was some sort of leak?  I only had a few open.
311    }
312  if (((st.st_uid != getuid()) ||
313       (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
314      !d->chownpty(true))
315  {
316    qWarning()
317      << "chownpty failed for device " << ptyName << "::" << d->ttyName
318      << "\nThis means the communication can be eavesdropped." << endl;
319  }
320
321#if defined (HAVE__GETPTY) || defined (HAVE_GRANTPT)
322 grantedpt:
323#endif
324
325#ifdef HAVE_REVOKE
326  revoke(d->ttyName.data());
327#endif
328
329#ifdef HAVE_UNLOCKPT
330  unlockpt(d->masterFd);
331#elif defined(TIOCSPTLCK)
332  int flag = 0;
333  ioctl(d->masterFd, TIOCSPTLCK, &flag);
334#endif
335
336  d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
337  if (d->slaveFd < 0)
338  {
339    qWarning() << "Can't open slave pseudo teletype";
340    ::close(d->masterFd);
341    d->masterFd = -1;
342    return false;
343  }
344
345#if (defined(__svr4__) || defined(__sgi__))
346  // Solaris
347  ioctl(d->slaveFd, I_PUSH, "ptem");
348  ioctl(d->slaveFd, I_PUSH, "ldterm");
349#endif
350
351#endif /* HAVE_OPENPTY */
352
353  fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
354  fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
355
356  return true;
357}
358
359void KPty::closeSlave()
360{
361    Q_D(KPty);
362
363    if (d->slaveFd < 0)
364        return;
365    ::close(d->slaveFd);
366    d->slaveFd = -1;
367}
368
369void KPty::close()
370{
371   Q_D(KPty);
372
373   if (d->masterFd < 0)
374      return;
375   closeSlave();
376   // don't bother resetting unix98 pty, it will go away after closing master anyway.
377   if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
378      if (!geteuid()) {
379         struct stat st;
380         if (!stat(d->ttyName.data(), &st)) {
381            chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
382            chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
383         }
384      } else {
385         fcntl(d->masterFd, F_SETFD, 0);
386         d->chownpty(false);
387      }
388   }
389   ::close(d->masterFd);
390   d->masterFd = -1;
391}
392
393void KPty::setCTty()
394{
395    Q_D(KPty);
396
397    // Setup job control //////////////////////////////////
398
399    // Become session leader, process group leader,
400    // and get rid of the old controlling terminal.
401    setsid();
402
403    // make our slave pty the new controlling terminal.
404#ifdef TIOCSCTTY
405    ioctl(d->slaveFd, TIOCSCTTY, 0);
406#else
407    // __svr4__ hack: the first tty opened after setsid() becomes controlling tty
408    ::close(::open(d->ttyName, O_WRONLY, 0));
409#endif
410
411    // make our new process group the foreground group on the pty
412    int pgrp = getpid();
413#if defined(_POSIX_VERSION) || defined(__svr4__)
414    tcsetpgrp(d->slaveFd, pgrp);
415#elif defined(TIOCSPGRP)
416    ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
417#endif
418}
419
420void KPty::login(const char *user, const char *remotehost)
421{
422#ifdef HAVE_UTEMPTER
423    Q_D(KPty);
424
425    addToUtmp(d->ttyName, remotehost, d->masterFd);
426    Q_UNUSED(user);
427#else
428# ifdef HAVE_UTMPX
429    struct utmpx l_struct;
430# else
431    struct utmp l_struct;
432# endif
433    memset(&l_struct, 0, sizeof(l_struct));
434    // note: strncpy without terminators _is_ correct here. man 4 utmp
435
436    if (user)
437      strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name));
438
439    if (remotehost) {
440      strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host));
441# ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
442      l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host));
443# endif
444    }
445
446# ifndef __GLIBC__
447    Q_D(KPty);
448    const char *str_ptr = d->ttyName.data();
449    if (!memcmp(str_ptr, "/dev/", 5))
450        str_ptr += 5;
451    strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
452#  ifdef HAVE_STRUCT_UTMP_UT_ID
453    strncpy(l_struct.ut_id,
454            str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id),
455            sizeof(l_struct.ut_id));
456#  endif
457# endif
458
459# ifdef HAVE_UTMPX
460    gettimeofday(&l_struct.ut_tv, 0);
461# else
462    l_struct.ut_time = time(0);
463# endif
464
465# ifdef HAVE_LOGIN
466#  ifdef HAVE_LOGINX
467    ::loginx(&l_struct);
468#  else
469    ::login(&l_struct);
470#  endif
471# else
472#  ifdef HAVE_STRUCT_UTMP_UT_TYPE
473    l_struct.ut_type = USER_PROCESS;
474#  endif
475#  ifdef HAVE_STRUCT_UTMP_UT_PID
476    l_struct.ut_pid = getpid();
477#   ifdef HAVE_STRUCT_UTMP_UT_SESSION
478    l_struct.ut_session = getsid(0);
479#   endif
480#  endif
481#  ifdef HAVE_UTMPX
482    utmpxname(_PATH_UTMPX);
483    setutxent();
484    pututxline(&l_struct);
485    endutxent();
486    updwtmpx(_PATH_WTMPX, &l_struct);
487#  else
488    utmpname(_PATH_UTMP);
489    setutent();
490    pututline(&l_struct);
491    endutent();
492    updwtmp(_PATH_WTMP, &l_struct);
493#  endif
494# endif
495#endif
496}
497
498void KPty::logout()
499{
500#ifdef HAVE_UTEMPTER
501    Q_D(KPty);
502
503    removeLineFromUtmp(d->ttyName, d->masterFd);
504#else
505    Q_D(KPty);
506
507    const char *str_ptr = d->ttyName.data();
508    if (!memcmp(str_ptr, "/dev/", 5))
509        str_ptr += 5;
510# ifdef __GLIBC__
511    else {
512        const char *sl_ptr = strrchr(str_ptr, '/');
513        if (sl_ptr)
514            str_ptr = sl_ptr + 1;
515    }
516# endif
517# ifdef HAVE_LOGIN
518#  ifdef HAVE_LOGINX
519    ::logoutx(str_ptr, 0, DEAD_PROCESS);
520#  else
521    ::logout(str_ptr);
522#  endif
523# else
524#  ifdef HAVE_UTMPX
525    struct utmpx l_struct, *ut;
526#  else
527    struct utmp l_struct, *ut;
528#  endif
529    memset(&l_struct, 0, sizeof(l_struct));
530
531    strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
532
533#  ifdef HAVE_UTMPX
534    utmpxname(_PATH_UTMPX);
535    setutxent();
536    if ((ut = getutxline(&l_struct))) {
537#  else
538    utmpname(_PATH_UTMP);
539    setutent();
540    if ((ut = getutline(&l_struct))) {
541#  endif
542        memset(ut->ut_name, 0, sizeof(*ut->ut_name));
543        memset(ut->ut_host, 0, sizeof(*ut->ut_host));
544#  ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
545        ut->ut_syslen = 0;
546#  endif
547#  ifdef HAVE_STRUCT_UTMP_UT_TYPE
548        ut->ut_type = DEAD_PROCESS;
549#  endif
550#  ifdef HAVE_UTMPX
551        gettimeofday(ut->ut_tv, 0);
552        pututxline(ut);
553    }
554    endutxent();
555#  else
556        ut->ut_time = time(0);
557        pututline(ut);
558    }
559    endutent();
560#  endif
561# endif
562#endif
563}
564
565// XXX Supposedly, tc[gs]etattr do not work with the master on Solaris.
566// Please verify.
567
568bool KPty::tcGetAttr(struct ::termios *ttmode) const
569{
570    Q_D(const KPty);
571
572    return _tcgetattr(d->masterFd, ttmode) == 0;
573}
574
575bool KPty::tcSetAttr(struct ::termios *ttmode)
576{
577    Q_D(KPty);
578
579    return _tcsetattr(d->masterFd, ttmode) == 0;
580}
581
582bool KPty::setWinSize(int lines, int columns)
583{
584    Q_D(KPty);
585
586    struct winsize winSize;
587    memset(&winSize, 0, sizeof(winSize));
588    winSize.ws_row = (unsigned short)lines;
589    winSize.ws_col = (unsigned short)columns;
590    return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
591}
592
593bool KPty::setEcho(bool echo)
594{
595    struct ::termios ttmode;
596    if (!tcGetAttr(&ttmode))
597        return false;
598    if (!echo)
599        ttmode.c_lflag &= ~ECHO;
600    else
601        ttmode.c_lflag |= ECHO;
602    return tcSetAttr(&ttmode);
603}
604
605const char *KPty::ttyName() const
606{
607    Q_D(const KPty);
608
609    return d->ttyName.data();
610}
611
612int KPty::masterFd() const
613{
614    Q_D(const KPty);
615
616    return d->masterFd;
617}
618
619int KPty::slaveFd() const
620{
621    Q_D(const KPty);
622
623    return d->slaveFd;
624}
Note: See TracBrowser for help on using the repository browser.