Mercurial > hg > octave-thorsten
changeset 13662:32f4713142d8
Reverted KPty to work with MacOS again.
author | Jacob Dawid <jacob.dawid@googlemail.com> |
---|---|
date | Fri, 09 Sep 2011 20:58:52 +0200 |
parents | 8a1896fb82d4 |
children | 746c99f44c4b |
files | gui/src/terminal/KPty.cpp |
diffstat | 1 files changed, 444 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/gui/src/terminal/KPty.cpp +++ b/gui/src/terminal/KPty.cpp @@ -23,21 +23,109 @@ */ #include "KPty.h" + +#if defined(Q_OS_MAC) +#define HAVE_UTIL_H +#define HAVE_UTMPX +#define _UTMPX_COMPAT +#define HAVE_PTSNAME +#define HAVE_SYS_TIME_H +#else +#define HAVE_PTY_H +#endif + +#define HAVE_OPENPTY + +#include <QtCore/QByteArray> + +#ifdef __sgi +#define __svr4__ +#endif + +#ifdef __osf__ +#define _OSF_SOURCE +#include <float.h> +#endif + +#ifdef _AIX +#define _ALL_SOURCE +#endif + +// __USE_XOPEN isn't defined by default in ICC +// (needed for ptsname(), grantpt() and unlockpt()) +#ifdef __INTEL_COMPILER +#ifndef __USE_XOPEN +#define __USE_XOPEN +#endif +#endif + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/param.h> + +#include <errno.h> #include <fcntl.h> +#include <time.h> +#include <stdlib.h> #include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <grp.h> +#if defined(HAVE_PTY_H) #include <pty.h> -#include <utmp.h> +#endif + +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#elif defined(HAVE_UTIL_H) +#include <util.h> +#endif + +#define HAVE_UTMPX +#define _UTMPX_COMPAT -#define PATH_MAX 1024 +#ifdef HAVE_UTEMPTER +extern "C" +{ +#include <utempter.h> +} +#else +#include <utmp.h> +#ifdef HAVE_UTMPX +#include <utmpx.h> +#endif +#if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE) +#define _PATH_UTMPX _UTMPX_FILE +#endif +#if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE) +#define _PATH_WTMPX _WTMPX_FILE +#endif +#endif /* for HP-UX (some versions) the extern C is needed, and for other platforms it doesn't hurt */ extern "C" { #include <termios.h> +#if defined(HAVE_TERMIO_H) +#include <termio.h> // struct winsize on some systems +#endif } +#if defined (_HPUX_SOURCE) +#define _TERMIOS_INCLUDED +#include <bsdtty.h> +#endif + +#ifdef HAVE_SYS_STROPTS_H +#include <sys/stropts.h> // Defines I_PUSH +#define _NEW_TTY_CTRL +#endif + #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__) #define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode) #else @@ -62,6 +150,22 @@ #define TTY_GROUP "tty" +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +/////////////////////// +// private functions // +/////////////////////// + +////////////////// +// private data // +////////////////// + KPtyPrivate::KPtyPrivate (KPty * parent): masterFd (-1), slaveFd (-1), @@ -74,6 +178,21 @@ { } +#ifndef HAVE_OPENPTY +bool +KPtyPrivate::chownpty (bool grant) +{ + return !QProcess::execute (KStandardDirs::findExe ("kgrantpty"), + QStringList () << (grant ? "--grant" : + "--revoke") << QString:: + number (masterFd)); +} +#endif + +///////////////////////////// +// public member functions // +///////////////////////////// + KPty::KPty (): d_ptr (new KPtyPrivate (this)) { @@ -101,6 +220,8 @@ d->ownMaster = true; + QByteArray ptyName; + // Find a master pty that we can open //////////////////////////////// // Because not all the pty animals are created equal, they want to @@ -108,15 +229,174 @@ // We try, as we know them, one by one. +#ifdef HAVE_OPENPTY + char ptsn[PATH_MAX]; if (::openpty (&d->masterFd, &d->slaveFd, ptsn, 0, 0)) { d->masterFd = -1; d->slaveFd = -1; + //kWarning(175) << "Can't open a pseudo teletype"; return false; } d->ttyName = ptsn; +#else + +#ifdef HAVE__GETPTY // irix + + char *ptsn = + _getpty (&d->masterFd, O_RDWR | O_NOCTTY, S_IRUSR | S_IWUSR, 0); + if (ptsn) + { + d->ttyName = ptsn; + goto grantedpt; + } + +#elif defined(HAVE_PTSNAME) || defined(TIOCGPTN) + +#ifdef HAVE_POSIX_OPENPT + d->masterFd =::posix_openpt (O_RDWR | O_NOCTTY); +#elif defined(HAVE_GETPT) + d->masterFd =::getpt (); +#elif defined(PTM_DEVICE) + //d->masterFd = KDE_open(PTM_DEVICE, O_RDWR|O_NOCTTY); + d->masterFd =::open (PTM_DEVICE, O_RDWR | O_NOCTTY); +#else +#error No method to open a PTY master detected. +#endif + if (d->masterFd >= 0) + { +#ifdef HAVE_PTSNAME + char *ptsn = ptsname (d->masterFd); + if (ptsn) + { + d->ttyName = ptsn; +#else + int ptyno; + if (!ioctl (d->masterFd, TIOCGPTN, &ptyno)) + { + char buf[32]; + sprintf (buf, "/dev/pts/%d", ptyno); + d->ttyName = buf; +#endif +#ifdef HAVE_GRANTPT + if (!grantpt (d->masterFd)) + goto grantedpt; +#else + goto gotpty; +#endif + } + ::close (d->masterFd); + d->masterFd = -1; + } +#endif // HAVE_PTSNAME || TIOCGPTN + + // Linux device names, FIXME: Trouble on other systems? + for (const char *s3 = "pqrstuvwxyzabcde"; *s3; s3++) + { + for (const char *s4 = "0123456789abcdef"; *s4; s4++) + { + ptyName = QString ().sprintf ("/dev/pty%c%c", *s3, *s4).toAscii (); + d->ttyName = + QString ().sprintf ("/dev/tty%c%c", *s3, *s4).toAscii (); + + d->masterFd =::open (ptyName.data (), O_RDWR); + if (d->masterFd >= 0) + { +#ifdef Q_OS_SOLARIS + /* Need to check the process group of the pty. + * If it exists, then the slave pty is in use, + * and we need to get another one. + */ + int pgrp_rtn; + if (ioctl (d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 + || errno != EIO) + { + ::close (d->masterFd); + d->masterFd = -1; + continue; + } +#endif /* Q_OS_SOLARIS */ + if (!access (d->ttyName.data (), R_OK | W_OK)) // checks availability based on permission bits + { + if (!geteuid ()) + { + struct group *p = getgrnam (TTY_GROUP); + if (!p) + p = getgrnam ("wheel"); + gid_t gid = p ? p->gr_gid : getgid (); + + chown (d->ttyName.data (), getuid (), gid); + chmod (d->ttyName.data (), S_IRUSR | S_IWUSR | S_IWGRP); + } + goto gotpty; + } + ::close (d->masterFd); + d->masterFd = -1; + } + } + } + + //kWarning(175) << "Can't open a pseudo teletype"; + return false; + +gotpty: + KDE_struct_stat st; + if (KDE_stat (d->ttyName.data (), &st)) + return false; // this just cannot happen ... *cough* Yeah right, I just + // had it happen when pty #349 was allocated. I guess + // there was some sort of leak? I only had a few open. + if (((st.st_uid != getuid ()) || + (st.st_mode & (S_IRGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH))) && + !d->chownpty (true)) + { + + /*kWarning(175) + << "chownpty failed for device " << ptyName << "::" << d->ttyName + << "\nThis means the communication can be eavesdropped." << endl; + */ + } + +grantedpt: + +#ifdef HAVE_REVOKE + revoke (d->ttyName.data ()); +#endif + +#ifdef HAVE_UNLOCKPT + unlockpt (d->masterFd); +#elif defined(TIOCSPTLCK) + int flag = 0; + ioctl (d->masterFd, TIOCSPTLCK, &flag); +#endif + + d->slaveFd =::open (d->ttyName.data (), O_RDWR | O_NOCTTY); + if (d->slaveFd < 0) + { + //kWarning(175) << "Can't open slave pseudo teletype"; + ::close (d->masterFd); + d->masterFd = -1; + return false; + } + +#if (defined(__svr4__) || defined(__sgi__) || defined(Q_OS_SOLARIS)) + // Solaris uses STREAMS for terminal handling. It is possible + // for the pty handling modules to be left off the stream; in that + // case push them on. ioctl(fd, I_FIND, ...) is documented to return + // 1 if the module is on the stream already. + { + static const char *pt = "ptem"; + static const char *ld = "ldterm"; + if (ioctl (d->slaveFd, I_FIND, pt) == 0) + ioctl (d->slaveFd, I_PUSH, pt); + if (ioctl (d->slaveFd, I_FIND, ld) == 0) + ioctl (d->slaveFd, I_PUSH, ld); + } +#endif + +#endif /* HAVE_OPENPTY */ + fcntl (d->masterFd, F_SETFD, FD_CLOEXEC); fcntl (d->slaveFd, F_SETFD, FD_CLOEXEC); @@ -126,25 +406,38 @@ bool KPty::open (int fd) { +#if !defined(HAVE_PTSNAME) && !defined(TIOCGPTN) + //kWarning(175) << "Unsupported attempt to open pty with fd" << fd; + return false; +#else Q_D (KPty); if (d->masterFd >= 0) { + //kWarning(175) << "Attempting to open an already open pty"; return false; } d->ownMaster = false; +#ifdef HAVE_PTSNAME + char *ptsn = ptsname (fd); + if (ptsn) + { + d->ttyName = ptsn; +#else int ptyno; if (!ioctl (fd, TIOCGPTN, &ptyno)) { char buf[32]; sprintf (buf, "/dev/pts/%d", ptyno); d->ttyName = buf; +#endif } else { - return false; + //kWarning(175) << "Failed to determine pty slave device for fd" << fd; + return false; } d->masterFd = fd; @@ -155,6 +448,7 @@ } return true; +#endif } void @@ -177,11 +471,13 @@ return true; if (d->masterFd < 0) { + //kWarning(175) << "Attempting to open pty slave while master is closed"; return false; } d->slaveFd =::open (d->ttyName.data (), O_RDWR | O_NOCTTY); if (d->slaveFd < 0) { + //kWarning(175) << "Can't open slave pseudo teletype"; return false; } fcntl (d->slaveFd, F_SETFD, FD_CLOEXEC); @@ -198,6 +494,29 @@ closeSlave (); if (d->ownMaster) { +#ifndef HAVE_OPENPTY + // don't bother resetting unix98 pty, it will go away after closing master anyway. + if (memcmp (d->ttyName.data (), "/dev/pts/", 9)) + { + if (!geteuid ()) + { + struct stat st; + if (!stat (d->ttyName.data (), &st)) + { + chown (d->ttyName.data (), 0, + st.st_gid == getgid ()? 0 : -1); + chmod (d->ttyName.data (), + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | + S_IWOTH); + } + } + else + { + fcntl (d->masterFd, F_SETFD, 0); + d->chownpty (false); + } + } +#endif ::close (d->masterFd); } d->masterFd = -1; @@ -215,18 +534,36 @@ setsid (); // make our slave pty the new controlling terminal. +#ifdef TIOCSCTTY ioctl (d->slaveFd, TIOCSCTTY, 0); +#else + // __svr4__ hack: the first tty opened after setsid() becomes controlling tty + ::close (open (d->ttyName, O_WRONLY, 0)); +#endif // make our new process group the foreground group on the pty int pgrp = getpid (); +#if defined(_POSIX_VERSION) || defined(__svr4__) tcsetpgrp (d->slaveFd, pgrp); +#elif defined(TIOCSPGRP) + ioctl (d->slaveFd, TIOCSPGRP, (char *) &pgrp); +#endif } void KPty::login (const char *user, const char *remotehost) { +#ifdef HAVE_UTEMPTER + Q_D (KPty); + + addToUtmp (d->ttyName, remotehost, d->masterFd); + Q_UNUSED (user); +#else +#ifdef HAVE_UTMPX + struct utmpx l_struct; +#else struct utmp l_struct; - +#endif memset (&l_struct, 0, sizeof (l_struct)); // note: strncpy without terminators _is_ correct here. man 4 utmp @@ -236,51 +573,146 @@ if (remotehost) { strncpy (l_struct.ut_host, remotehost, sizeof (l_struct.ut_host)); +#ifdef HAVE_STRUCT_UTMP_UT_SYSLEN + l_struct.ut_syslen = + qMin (strlen (remotehost), sizeof (l_struct.ut_host)); +#endif } +#ifndef __GLIBC__ + Q_D (KPty); + const char *str_ptr = d->ttyName.data (); + if (!memcmp (str_ptr, "/dev/", 5)) + str_ptr += 5; + strncpy (l_struct.ut_line, str_ptr, sizeof (l_struct.ut_line)); +#ifdef HAVE_STRUCT_UTMP_UT_ID + strncpy (l_struct.ut_id, + str_ptr + strlen (str_ptr) - sizeof (l_struct.ut_id), + sizeof (l_struct.ut_id)); +#endif +#endif + +#ifdef HAVE_UTMPX + //gettimeofday(&l_struct.ut_tv, 0); + gettimeofday ((struct timeval *) &l_struct.ut_tv, 0); +#else l_struct.ut_time = time (0); +#endif + +#ifdef HAVE_LOGIN +#ifdef HAVE_LOGINX + ::loginx (&l_struct); +#else + ::login (&l_struct); +#endif +#else +#ifdef HAVE_STRUCT_UTMP_UT_TYPE + l_struct.ut_type = USER_PROCESS; +#endif +#ifdef HAVE_STRUCT_UTMP_UT_PID + l_struct.ut_pid = getpid (); +#ifdef HAVE_STRUCT_UTMP_UT_SESSION + l_struct.ut_session = getsid (0); +#endif +#endif +#ifdef HAVE_UTMPX + utmpxname (_PATH_UTMPX); + setutxent (); + pututxline (&l_struct); + endutxent (); + //updwtmpx(_PATH_WTMPX, &l_struct); +#else utmpname (_PATH_UTMP); setutent (); pututline (&l_struct); endutent (); updwtmp (_PATH_WTMP, &l_struct); +#endif +#endif +#endif } void KPty::logout () { +#ifdef HAVE_UTEMPTER + Q_D (KPty); + + removeLineFromUtmp (d->ttyName, d->masterFd); +#else Q_D (KPty); const char *str_ptr = d->ttyName.data (); if (!memcmp (str_ptr, "/dev/", 5)) str_ptr += 5; +#ifdef __GLIBC__ else { const char *sl_ptr = strrchr (str_ptr, '/'); if (sl_ptr) - str_ptr = sl_ptr + 1; + str_ptr = sl_ptr + 1; } - +#endif +#ifdef HAVE_LOGIN +#ifdef HAVE_LOGINX + ::logoutx (str_ptr, 0, DEAD_PROCESS); +#else + ::logout (str_ptr); +#endif +#else +#ifdef HAVE_UTMPX + struct utmpx l_struct, *ut; +#else struct utmp l_struct, *ut; - +#endif memset (&l_struct, 0, sizeof (l_struct)); + strncpy (l_struct.ut_line, str_ptr, sizeof (l_struct.ut_line)); + +#ifdef HAVE_UTMPX + utmpxname (_PATH_UTMPX); + setutxent (); + if ((ut = getutxline (&l_struct))) + { +#else utmpname (_PATH_UTMP); setutent (); if ((ut = getutline (&l_struct))) { +#endif memset (ut->ut_name, 0, sizeof (*ut->ut_name)); memset (ut->ut_host, 0, sizeof (*ut->ut_host)); +#ifdef HAVE_STRUCT_UTMP_UT_SYSLEN + ut->ut_syslen = 0; +#endif +#ifdef HAVE_STRUCT_UTMP_UT_TYPE + ut->ut_type = DEAD_PROCESS; +#endif +#ifdef HAVE_UTMPX + //gettimeofday(&(ut->ut_tv), 0); + gettimeofday ((struct timeval *) &(ut->ut_tv), 0); + pututxline (ut); + } + endutxent (); +#else ut->ut_time = time (0); pututline (ut); } endutent (); +#endif +#endif +#endif } bool KPty::tcGetAttr (struct::termios * ttmode) const { Q_D (const KPty); + +#ifdef Q_OS_SOLARIS + if (_tcgetattr (d->slaveFd, ttmode) == 0) + return true; +#endif return _tcgetattr (d->masterFd, ttmode) == 0; } @@ -288,6 +720,11 @@ KPty::tcSetAttr (struct::termios * ttmode) { Q_D (KPty); + +#ifdef Q_OS_SOLARIS + if (_tcsetattr (d->slaveFd, ttmode) == 0) + return true; +#endif return _tcsetattr (d->masterFd, ttmode) == 0; }