3 This file is part of the KDE libraries
4 Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
5 Copyright (C) 2002-2003,2007-2008 Oswald Buddenhagen <ossi@kde.org>
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
40 // __USE_XOPEN isn't defined by default in ICC
41 // (needed for ptsname(), grantpt() and unlockpt())
42 #ifdef __INTEL_COMPILER
48 #include <sys/types.h>
49 #include <sys/ioctl.h>
51 #include <sys/resource.h>
53 #include <sys/param.h>
64 #if defined(HAVE_PTY_H)
70 #elif defined(HAVE_UTIL_H)
76 # include <utempter.h>
83 # if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
84 # define _PATH_UTMPX _UTMPX_FILE
86 # if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
87 # define _PATH_WTMPX _WTMPX_FILE
91 /* for HP-UX (some versions) the extern C is needed, and for other
92 platforms it doesn't hurt */
95 #if defined(HAVE_TERMIO_H)
96 # include <termio.h> // struct winsize on some systems
100 #if defined (_HPUX_SOURCE)
101 # define _TERMIOS_INCLUDED
105 #ifdef HAVE_SYS_STROPTS_H
106 # include <sys/stropts.h> // Defines I_PUSH
107 # define _NEW_TTY_CTRL
110 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
111 # define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
113 # if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
114 # define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
116 # define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
120 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
121 # define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
123 # if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
124 # define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
126 # define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
131 #include <kstandarddirs.h> // findExe
132 #include <kde_file.h>
134 #include <QtCore/Q_PID>
136 #define TTY_GROUP "tty"
138 ///////////////////////
139 // private functions //
140 ///////////////////////
146 KPtyPrivate::KPtyPrivate(KPty
* parent
) :
147 masterFd(-1), slaveFd(-1), ownMaster(true), q_ptr(parent
)
151 KPtyPrivate::~KPtyPrivate()
156 bool KPtyPrivate::chownpty(bool grant
)
158 return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
159 QStringList() << (grant
?"--grant":"--revoke") << QString::number(masterFd
));
163 /////////////////////////////
164 // public member functions //
165 /////////////////////////////
168 d_ptr(new KPtyPrivate(this))
172 KPty::KPty(KPtyPrivate
*d
) :
188 if (d
->masterFd
>= 0)
195 // Find a master pty that we can open ////////////////////////////////
197 // Because not all the pty animals are created equal, they want to
198 // be opened by several different methods.
200 // We try, as we know them, one by one.
205 if (::openpty( &d
->masterFd
, &d
->slaveFd
, ptsn
, 0, 0))
209 kWarning(175) << "Can't open a pseudo teletype";
216 #ifdef HAVE__GETPTY // irix
218 char *ptsn
= _getpty(&d
->masterFd
, O_RDWR
|O_NOCTTY
, S_IRUSR
|S_IWUSR
, 0);
224 #elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
226 #ifdef HAVE_POSIX_OPENPT
227 d
->masterFd
= ::posix_openpt(O_RDWR
|O_NOCTTY
);
228 #elif defined(HAVE_GETPT)
229 d
->masterFd
= ::getpt();
230 #elif defined(PTM_DEVICE)
231 d
->masterFd
= KDE_open(PTM_DEVICE
, O_RDWR
|O_NOCTTY
);
233 # error No method to open a PTY master detected.
235 if (d
->masterFd
>= 0)
238 char *ptsn
= ptsname(d
->masterFd
);
243 if (!ioctl(d
->masterFd
, TIOCGPTN
, &ptyno
)) {
245 sprintf(buf
, "/dev/pts/%d", ptyno
);
249 if (!grantpt(d
->masterFd
))
255 ::close(d
->masterFd
);
258 #endif // HAVE_PTSNAME || TIOCGPTN
260 // Linux device names, FIXME: Trouble on other systems?
261 for (const char* s3
= "pqrstuvwxyzabcde"; *s3
; s3
++)
263 for (const char* s4
= "0123456789abcdef"; *s4
; s4
++)
265 ptyName
= QString().sprintf("/dev/pty%c%c", *s3
, *s4
).toAscii();
266 d
->ttyName
= QString().sprintf("/dev/tty%c%c", *s3
, *s4
).toAscii();
268 d
->masterFd
= KDE_open(ptyName
.data(), O_RDWR
);
269 if (d
->masterFd
>= 0)
272 /* Need to check the process group of the pty.
273 * If it exists, then the slave pty is in use,
274 * and we need to get another one.
277 if (ioctl(d
->masterFd
, TIOCGPGRP
, &pgrp_rtn
) == 0 || errno
!= EIO
) {
278 ::close(d
->masterFd
);
282 #endif /* Q_OS_SOLARIS */
283 if (!access(d
->ttyName
.data(),R_OK
|W_OK
)) // checks availability based on permission bits
287 struct group
* p
= getgrnam(TTY_GROUP
);
289 p
= getgrnam("wheel");
290 gid_t gid
= p
? p
->gr_gid
: getgid ();
292 chown(d
->ttyName
.data(), getuid(), gid
);
293 chmod(d
->ttyName
.data(), S_IRUSR
|S_IWUSR
|S_IWGRP
);
297 ::close(d
->masterFd
);
303 kWarning(175) << "Can't open a pseudo teletype";
308 if (KDE_stat(d
->ttyName
.data(), &st
))
309 return false; // this just cannot happen ... *cough* Yeah right, I just
310 // had it happen when pty #349 was allocated. I guess
311 // there was some sort of leak? I only had a few open.
312 if (((st
.st_uid
!= getuid()) ||
313 (st
.st_mode
& (S_IRGRP
|S_IXGRP
|S_IROTH
|S_IWOTH
|S_IXOTH
))) &&
317 << "chownpty failed for device " << ptyName
<< "::" << d
->ttyName
318 << "\nThis means the communication can be eavesdropped." << endl
;
324 revoke(d
->ttyName
.data());
328 unlockpt(d
->masterFd
);
329 #elif defined(TIOCSPTLCK)
331 ioctl(d
->masterFd
, TIOCSPTLCK
, &flag
);
334 d
->slaveFd
= KDE_open(d
->ttyName
.data(), O_RDWR
| O_NOCTTY
);
337 kWarning(175) << "Can't open slave pseudo teletype";
338 ::close(d
->masterFd
);
343 #if (defined(__svr4__) || defined(__sgi__))
345 ioctl(d
->slaveFd
, I_PUSH
, "ptem");
346 ioctl(d
->slaveFd
, I_PUSH
, "ldterm");
349 #endif /* HAVE_OPENPTY */
351 fcntl(d
->masterFd
, F_SETFD
, FD_CLOEXEC
);
352 fcntl(d
->slaveFd
, F_SETFD
, FD_CLOEXEC
);
357 bool KPty::open(int fd
)
359 #if !defined(HAVE_PTSNAME) && !defined(TIOCGPTN)
360 kWarning(175) << "Unsupported attempt to open pty with fd" << fd
;
365 if (d
->masterFd
>= 0) {
366 kWarning(175) << "Attempting to open an already open pty";
370 d
->ownMaster
= false;
373 char *ptsn
= ptsname(fd
);
378 if (!ioctl(fd
, TIOCGPTN
, &ptyno
)) {
380 sprintf(buf
, "/dev/pts/%d", ptyno
);
384 kWarning(175) << "Failed to determine pty slave device for fd" << fd
;
398 void KPty::closeSlave()
408 bool KPty::openSlave()
414 if (d
->masterFd
< 0) {
415 kWarning(175) << "Attempting to open pty slave while master is closed";
418 d
->slaveFd
= KDE_open(d
->ttyName
.data(), O_RDWR
| O_NOCTTY
);
419 if (d
->slaveFd
< 0) {
420 kWarning(175) << "Can't open slave pseudo teletype";
423 fcntl(d
->slaveFd
, F_SETFD
, FD_CLOEXEC
);
436 // don't bother resetting unix98 pty, it will go away after closing master anyway.
437 if (memcmp(d
->ttyName
.data(), "/dev/pts/", 9)) {
440 if (!stat(d
->ttyName
.data(), &st
)) {
441 chown(d
->ttyName
.data(), 0, st
.st_gid
== getgid() ? 0 : -1);
442 chmod(d
->ttyName
.data(), S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
);
445 fcntl(d
->masterFd
, F_SETFD
, 0);
450 ::close(d
->masterFd
);
459 // Setup job control //////////////////////////////////
461 // Become session leader, process group leader,
462 // and get rid of the old controlling terminal.
465 // make our slave pty the new controlling terminal.
467 ioctl(d
->slaveFd
, TIOCSCTTY
, 0);
469 // __svr4__ hack: the first tty opened after setsid() becomes controlling tty
470 ::close(KDE_open(d
->ttyName
, O_WRONLY
, 0));
473 // make our new process group the foreground group on the pty
475 #if defined(_POSIX_VERSION) || defined(__svr4__)
476 tcsetpgrp(d
->slaveFd
, pgrp
);
477 #elif defined(TIOCSPGRP)
478 ioctl(d
->slaveFd
, TIOCSPGRP
, (char *)&pgrp
);
482 void KPty::login(const char *user
, const char *remotehost
)
487 addToUtmp(d
->ttyName
, remotehost
, d
->masterFd
);
491 struct utmpx l_struct
;
493 struct utmp l_struct
;
495 memset(&l_struct
, 0, sizeof(l_struct
));
496 // note: strncpy without terminators _is_ correct here. man 4 utmp
499 strncpy(l_struct
.ut_name
, user
, sizeof(l_struct
.ut_name
));
502 strncpy(l_struct
.ut_host
, remotehost
, sizeof(l_struct
.ut_host
));
503 # ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
504 l_struct
.ut_syslen
= qMin(strlen(remotehost
), sizeof(l_struct
.ut_host
));
510 const char *str_ptr
= d
->ttyName
.data();
511 if (!memcmp(str_ptr
, "/dev/", 5))
513 strncpy(l_struct
.ut_line
, str_ptr
, sizeof(l_struct
.ut_line
));
514 # ifdef HAVE_STRUCT_UTMP_UT_ID
515 strncpy(l_struct
.ut_id
,
516 str_ptr
+ strlen(str_ptr
) - sizeof(l_struct
.ut_id
),
517 sizeof(l_struct
.ut_id
));
522 gettimeofday(&l_struct
.ut_tv
, 0);
524 l_struct
.ut_time
= time(0);
534 # ifdef HAVE_STRUCT_UTMP_UT_TYPE
535 l_struct
.ut_type
= USER_PROCESS
;
537 # ifdef HAVE_STRUCT_UTMP_UT_PID
538 l_struct
.ut_pid
= getpid();
539 # ifdef HAVE_STRUCT_UTMP_UT_SESSION
540 l_struct
.ut_session
= getsid(0);
544 utmpxname(_PATH_UTMPX
);
546 pututxline(&l_struct
);
548 updwtmpx(_PATH_WTMPX
, &l_struct
);
550 utmpname(_PATH_UTMP
);
552 pututline(&l_struct
);
554 updwtmp(_PATH_WTMP
, &l_struct
);
565 removeLineFromUtmp(d
->ttyName
, d
->masterFd
);
569 const char *str_ptr
= d
->ttyName
.data();
570 if (!memcmp(str_ptr
, "/dev/", 5))
574 const char *sl_ptr
= strrchr(str_ptr
, '/');
576 str_ptr
= sl_ptr
+ 1;
581 ::logoutx(str_ptr
, 0, DEAD_PROCESS
);
587 struct utmpx l_struct
, *ut
;
589 struct utmp l_struct
, *ut
;
591 memset(&l_struct
, 0, sizeof(l_struct
));
593 strncpy(l_struct
.ut_line
, str_ptr
, sizeof(l_struct
.ut_line
));
596 utmpxname(_PATH_UTMPX
);
598 if ((ut
= getutxline(&l_struct
))) {
600 utmpname(_PATH_UTMP
);
602 if ((ut
= getutline(&l_struct
))) {
604 memset(ut
->ut_name
, 0, sizeof(*ut
->ut_name
));
605 memset(ut
->ut_host
, 0, sizeof(*ut
->ut_host
));
606 # ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
609 # ifdef HAVE_STRUCT_UTMP_UT_TYPE
610 ut
->ut_type
= DEAD_PROCESS
;
613 gettimeofday(&(ut
->ut_tv
), 0);
618 ut
->ut_time
= time(0);
627 // XXX Supposedly, tc[gs]etattr do not work with the master on Solaris.
630 bool KPty::tcGetAttr(struct ::termios
*ttmode
) const
634 return _tcgetattr(d
->masterFd
, ttmode
) == 0;
637 bool KPty::tcSetAttr(struct ::termios
*ttmode
)
641 return _tcsetattr(d
->masterFd
, ttmode
) == 0;
644 bool KPty::setWinSize(int lines
, int columns
)
648 struct winsize winSize
;
649 memset(&winSize
, 0, sizeof(winSize
));
650 winSize
.ws_row
= (unsigned short)lines
;
651 winSize
.ws_col
= (unsigned short)columns
;
652 return ioctl(d
->masterFd
, TIOCSWINSZ
, (char *)&winSize
) == 0;
655 bool KPty::setEcho(bool echo
)
657 struct ::termios ttmode
;
658 if (!tcGetAttr(&ttmode
))
661 ttmode
.c_lflag
&= ~ECHO
;
663 ttmode
.c_lflag
|= ECHO
;
664 return tcSetAttr(&ttmode
);
667 const char *KPty::ttyName() const
671 return d
->ttyName
.data();
674 int KPty::masterFd() const
681 int KPty::slaveFd() const