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)
92#if defined(HAVE_TCGETATTR)
93# define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
94#elif defined(TIOCGETA)
95# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
97# define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
102#if defined(HAVE_TCSETATTR) && defined(TCSANOW)
103# define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
104#elif defined(TIOCSETA)
105# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
107# define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
112#if defined(HAVE_PTY_H)
117#include <tdestandarddirs.h>
129#define TTY_GROUP "tty"
150#define BASE_CHOWN "kgrantpty"
162 masterFd(-1), slaveFd(-1)
164 memset(&winSize, 0,
sizeof(winSize));
173 struct winsize winSize;
196 if(d->masterFd >= 0) {
197 kdWarning(175) <<
"KPty::setPty(): " <<
"d->masterFd >= 0" <<
endl;
200 d->masterFd = pty_master;
201 return _attachPty(pty_master);
204bool KPty::_attachPty(
int pty_master)
206 if (d->slaveFd < 0 ) {
208 kdDebug(175) <<
"KPty::_attachPty(): " << pty_master <<
endl;
209#if defined(HAVE_PTSNAME)
210 char *ptsn = ptsname(d->masterFd);
220#if defined(HAVE_GRANTPT)
221 if (grantpt(d->masterFd)) {
226 if (stat(d->ttyName.data(), &st))
230 if (((st.st_uid != getuid()) ||
231 (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
235 <<
"KPty::_attachPty(): " <<
"chownpty failed for device " << d->ttyName <<
endl
236 <<
"KPty::_attachPty(): " <<
"This means the communication can be eavesdropped." <<
endl;
241 revoke(d->ttyName.data());
245 unlockpt(d->masterFd);
248 d->slaveFd =
::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
251 kdWarning(175) <<
"KPty::_attachPty(): " <<
"Can't open slave pseudo teletype" <<
endl;
258 ioctl(d->slaveFd, TIOCSWINSZ, (
char *)&d->winSize);
262#if (defined(__svr4__) || defined(__sgi__))
264 ioctl(d->slaveFd, I_PUSH,
"ptem");
265 ioctl(d->slaveFd, I_PUSH,
"ldterm");
272 struct ::termios ttmode;
274 _tcgetattr(d->slaveFd, &ttmode);
277 ttmode.c_iflag &= ~(IXOFF | IXON);
279 ttmode.c_iflag |= (IXOFF | IXON);
283 ttmode.c_iflag &= ~IUTF8;
285 ttmode.c_iflag |= IUTF8;
288 ttmode.c_cc[VINTR] = CINTR;
289 ttmode.c_cc[VQUIT] = CQUIT;
290 ttmode.c_cc[VERASE] = CERASE;
292 _tcsetattr(d->slaveFd, &ttmode);
296 ioctl(d->slaveFd, TIOCSWINSZ, (
char *)&d->winSize);
299 fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
300 fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
307 if (d->masterFd >= 0)
310#if defined(HAVE_OPENPTY)
313 if (openpty(&d->masterFd, &d->slaveFd, cpty, NULL, &d->winSize) == 0) {
316 kdWarning(175) <<
"Can't open slave pseudo teletype" <<
endl;
330#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT)
331#if defined(HAVE_GETPT)
332 d->masterFd = ::getpt();
333#elif defined(HAVE_POSIX_OPENPT)
334 d->masterFd = ::posix_openpt(O_RDWR);
336 d->masterFd =
::open(
"/dev/ptc",O_RDWR);
338 d->masterFd =
::open(
"/dev/ptmx",O_RDWR);
340 if (d->masterFd >= 0)
342 char *ptsn = ptsname(d->masterFd);
344 grantpt(d->masterFd);
355 for (
const char* s3 =
"pqrstuvwxyzabcdefghijklmno"; *s3; s3++)
357 for (
const char* s4 =
"0123456789abcdefghijklmnopqrstuvwxyz"; *s4; s4++)
359 ptyName.sprintf(
"/dev/pty%c%c", *s3, *s4);
360 d->ttyName.sprintf(
"/dev/tty%c%c", *s3, *s4);
362 d->masterFd =
::open(ptyName.data(), O_RDWR);
363 if (d->masterFd >= 0)
371 if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
377 if (!access(d->ttyName.data(),R_OK|W_OK))
381 struct group* p = getgrnam(TTY_GROUP);
383 p = getgrnam(
"wheel");
384 gid_t gid = p ? p->gr_gid : getgid ();
386 chown(d->ttyName.data(), getuid(), gid);
387 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
397 kdWarning(175) <<
"KPty::open(): " <<
"Can't open a pseudo teletype" <<
endl;
402 return _attachPty(d->masterFd);
412 if (memcmp(d->ttyName.data(),
"/dev/pts/", 9)) {
415 if (!stat(d->ttyName.data(), &st)) {
416 chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
417 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
420 fcntl(d->masterFd, F_SETFD, 0);
426 d->masterFd = d->slaveFd = -1;
439 ioctl(d->slaveFd, TIOCSCTTY, 0);
447#if defined(_POSIX_VERSION) || defined(__svr4__)
448 tcsetpgrp (d->slaveFd, pgrp);
449#elif defined(TIOCSPGRP)
450 ioctl(d->slaveFd, TIOCSPGRP, (
char *)&pgrp);
457 TDEProcess_Utmp utmp;
458 utmp.cmdFd = d->masterFd;
459 utmp << UTEMPTER_HELPER <<
"add";
464 Q_UNUSED(remotehost);
465#elif defined(USE_LOGIN)
467 struct utmp l_struct;
468 memset(&l_struct, 0,
sizeof(
struct utmp));
472 strncpy(l_struct.ut_name, user, UT_NAMESIZE);
475 strncpy(l_struct.ut_host, remotehost, UT_HOSTSIZE);
478 str_ptr = d->ttyName.data();
479 if (!memcmp(str_ptr,
"/dev/", 5))
481 strncpy(l_struct.ut_line, str_ptr, UT_LINESIZE);
489 l_struct.ut_time=ut_time_temp;
495 Q_UNUSED(remotehost);
502 TDEProcess_Utmp utmp;
503 utmp.cmdFd = d->masterFd;
504 utmp << UTEMPTER_HELPER <<
"del";
506#elif defined(USE_LOGIN)
507 const char *str_ptr = d->ttyName.data();
508 if (!memcmp(str_ptr,
"/dev/", 5))
512 const char *sl_ptr = strrchr(str_ptr,
'/');
514 str_ptr = sl_ptr + 1;
523 d->winSize.ws_row = (
unsigned short)lines;
524 d->winSize.ws_col = (
unsigned short)columns;
525 if (d->masterFd >= 0)
526 ioctl( d->masterFd, TIOCSWINSZ, (
char *)&d->winSize );
531 d->xonXoff = useXonXoff;
532 if (d->masterFd >= 0) {
536 struct ::termios ttmode;
538 _tcgetattr(d->masterFd, &ttmode);
541 ttmode.c_iflag &= ~(IXOFF | IXON);
543 ttmode.c_iflag |= (IXOFF | IXON);
545 _tcsetattr(d->masterFd, &ttmode);
553 if (d->masterFd >= 0) {
557 struct ::termios ttmode;
559 _tcgetattr(d->masterFd, &ttmode);
562 ttmode.c_iflag &= ~IUTF8;
564 ttmode.c_iflag |= IUTF8;
566 _tcsetattr(d->masterFd, &ttmode);
573 return d->ttyName.data();
587bool KPty::chownpty(
bool grant)
589#if !defined(__OpenBSD__) && !defined(__FreeBSD__)
591 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.