27#include "tdeprocess.h"
39#ifdef __INTEL_COMPILER
48#include <sys/resource.h>
52#ifdef HAVE_SYS_STROPTS_H
53# include <sys/stropts.h>
66#if defined(HAVE_LIBUTIL_H)
68# if (!defined(__FreeBSD__) || __FreeBSD_version < 900007)
72#if defined(HAVE_UTIL_H)
94#if defined(HAVE_TCGETATTR)
95# define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
96#elif defined(TIOCGETA)
97# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
99# define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
104#if defined(HAVE_TCSETATTR) && defined(TCSANOW)
105# define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
106#elif defined(TIOCSETA)
107# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
109# define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
114#if defined (_HPUX_SOURCE)
115# define _TERMIOS_INCLUDED
119#if defined(HAVE_PTY_H)
124#include <tdestandarddirs.h>
136#define TTY_GROUP "tty"
157#define BASE_CHOWN "kgrantpty"
169 masterFd(-1), slaveFd(-1)
171 memset(&winSize, 0,
sizeof(winSize));
180 struct winsize winSize;
203 if(d->masterFd >= 0) {
204 kdWarning(175) <<
"KPty::setPty(): " <<
"d->masterFd >= 0" <<
endl;
207 d->masterFd = pty_master;
208 return _attachPty(pty_master);
211bool KPty::_attachPty(
int pty_master)
213 if (d->slaveFd < 0 ) {
215 kdDebug(175) <<
"KPty::_attachPty(): " << pty_master <<
endl;
216#if defined(HAVE_PTSNAME)
217 char *ptsn = ptsname(d->masterFd);
227#if defined(HAVE_GRANTPT)
228 if (grantpt(d->masterFd)) {
233 if (stat(d->ttyName.data(), &st))
237 if (((st.st_uid != getuid()) ||
238 (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
242 <<
"KPty::_attachPty(): " <<
"chownpty failed for device " << d->ttyName <<
endl
243 <<
"KPty::_attachPty(): " <<
"This means the communication can be eavesdropped." <<
endl;
248 revoke(d->ttyName.data());
252 unlockpt(d->masterFd);
255 d->slaveFd =
::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
258 kdWarning(175) <<
"KPty::_attachPty(): " <<
"Can't open slave pseudo teletype" <<
endl;
265 ioctl(d->slaveFd, TIOCSWINSZ, (
char *)&d->winSize);
269#if (defined(__svr4__) || defined(__sgi__))
271 ioctl(d->slaveFd, I_PUSH,
"ptem");
272 ioctl(d->slaveFd, I_PUSH,
"ldterm");
279 struct ::termios ttmode;
281 _tcgetattr(d->slaveFd, &ttmode);
284 ttmode.c_iflag &= ~(IXOFF | IXON);
286 ttmode.c_iflag |= (IXOFF | IXON);
290 ttmode.c_iflag &= ~IUTF8;
292 ttmode.c_iflag |= IUTF8;
295 ttmode.c_cc[VINTR] = CINTR;
296 ttmode.c_cc[VQUIT] = CQUIT;
297 ttmode.c_cc[VERASE] = CERASE;
299 _tcsetattr(d->slaveFd, &ttmode);
303 ioctl(d->slaveFd, TIOCSWINSZ, (
char *)&d->winSize);
306 fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
307 fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
314 if (d->masterFd >= 0)
317#if defined(HAVE_OPENPTY)
320 if (openpty(&d->masterFd, &d->slaveFd, cpty, NULL, &d->winSize) == 0) {
323 kdWarning(175) <<
"Can't open slave pseudo teletype" <<
endl;
337#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT)
338#if defined(HAVE_GETPT)
339 d->masterFd = ::getpt();
340#elif defined(HAVE_POSIX_OPENPT)
341 d->masterFd = ::posix_openpt(O_RDWR);
343 d->masterFd =
::open(
"/dev/ptc",O_RDWR);
345 d->masterFd =
::open(
"/dev/ptmx",O_RDWR);
347 if (d->masterFd >= 0)
349 char *ptsn = ptsname(d->masterFd);
351 grantpt(d->masterFd);
362 for (
const char* s3 =
"pqrstuvwxyzabcdefghijklmno"; *s3; s3++)
364 for (
const char* s4 =
"0123456789abcdefghijklmnopqrstuvwxyz"; *s4; s4++)
366 ptyName.sprintf(
"/dev/pty%c%c", *s3, *s4);
367 d->ttyName.sprintf(
"/dev/tty%c%c", *s3, *s4);
369 d->masterFd =
::open(ptyName.data(), O_RDWR);
370 if (d->masterFd >= 0)
378 if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
384 if (!access(d->ttyName.data(),R_OK|W_OK))
388 struct group* p = getgrnam(TTY_GROUP);
390 p = getgrnam(
"wheel");
391 gid_t gid = p ? p->gr_gid : getgid ();
393 chown(d->ttyName.data(), getuid(), gid);
394 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
404 kdWarning(175) <<
"KPty::open(): " <<
"Can't open a pseudo teletype" <<
endl;
409 return _attachPty(d->masterFd);
419 if (memcmp(d->ttyName.data(),
"/dev/pts/", 9)) {
422 if (!stat(d->ttyName.data(), &st)) {
423 chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
424 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
427 fcntl(d->masterFd, F_SETFD, 0);
433 d->masterFd = d->slaveFd = -1;
446 ioctl(d->slaveFd, TIOCSCTTY, 0);
454#if defined(_POSIX_VERSION) || defined(__svr4__)
455 tcsetpgrp (d->slaveFd, pgrp);
456#elif defined(TIOCSPGRP)
457 ioctl(d->slaveFd, TIOCSPGRP, (
char *)&pgrp);
464 TDEProcess_Utmp utmp;
465 utmp.cmdFd = d->masterFd;
466 utmp << UTEMPTER_HELPER <<
"add";
471 Q_UNUSED(remotehost);
472#elif defined(USE_LOGIN)
474 struct utmp l_struct;
475 memset(&l_struct, 0,
sizeof(
struct utmp));
479 strncpy(l_struct.ut_name, user, UT_NAMESIZE);
482 strncpy(l_struct.ut_host, remotehost, UT_HOSTSIZE);
485 str_ptr = d->ttyName.data();
486 if (!memcmp(str_ptr,
"/dev/", 5))
488 strncpy(l_struct.ut_line, str_ptr, UT_LINESIZE);
496 l_struct.ut_time=ut_time_temp;
502 Q_UNUSED(remotehost);
509 TDEProcess_Utmp utmp;
510 utmp.cmdFd = d->masterFd;
511 utmp << UTEMPTER_HELPER <<
"del";
513#elif defined(USE_LOGIN)
514 const char *str_ptr = d->ttyName.data();
515 if (!memcmp(str_ptr,
"/dev/", 5))
519 const char *sl_ptr = strrchr(str_ptr,
'/');
521 str_ptr = sl_ptr + 1;
530 d->winSize.ws_row = (
unsigned short)lines;
531 d->winSize.ws_col = (
unsigned short)columns;
532 if (d->masterFd >= 0)
533 ioctl( d->masterFd, TIOCSWINSZ, (
char *)&d->winSize );
538 d->xonXoff = useXonXoff;
539 if (d->masterFd >= 0) {
543 struct ::termios ttmode;
545 _tcgetattr(d->masterFd, &ttmode);
548 ttmode.c_iflag &= ~(IXOFF | IXON);
550 ttmode.c_iflag |= (IXOFF | IXON);
552 _tcsetattr(d->masterFd, &ttmode);
560 if (d->masterFd >= 0) {
564 struct ::termios ttmode;
566 _tcgetattr(d->masterFd, &ttmode);
569 ttmode.c_iflag &= ~IUTF8;
571 ttmode.c_iflag |= IUTF8;
573 _tcsetattr(d->masterFd, &ttmode);
580 return d->ttyName.data();
594bool KPty::chownpty(
bool grant)
596#if !defined(__OpenBSD__) && !defined(__FreeBSD__)
598 proc << locate(
"exe", BASE_CHOWN) << (grant?
"--grant":
"--revoke") << TQString::number(d->masterFd);
bool setPty(int pty_master)
Attach a existing pty master.
void setXonXoff(bool useXonXoff)
Set whether the pty should honor Xon/Xoff flow control.
void setCTty()
Creates a new session and process group and makes this pty the controlling tty.
void setWinSize(int lines, int columns)
Change the logical (screen) size of the pty.
void login(const char *user=0, const char *remotehost=0)
Creates an utmp entry for the tty.
bool open()
Create a pty master/slave pair.
void setUtf8Mode(bool useUtf8)
Set the pty in utf8 mode on systems that support it.
void logout()
Removes the utmp entry for this tty.
const char * ttyName() const
void close()
Close the pty master/slave pair.
Child process invocation, monitoring and control.
virtual int commSetupDoneC()
Called right after a (successful) fork(), but before an exec() on the child process' side.
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
int exitStatus() const
Returns the exit status of the process.
@ Block
The application is suspended until the started process is finished.
bool normalExit() const
Checks whether the process exited cleanly.
kndbgstream & endl(kndbgstream &s)
Does nothing.