KDevelop API Documentation

stty.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002     begin                : Mon Sep 13 1999
00003     copyright            : (C) 1999 by John Birch
00004     email                : jbb@kdevelop.org
00005 
00006   This code was originally written by Judin Maxim, from the
00007     KDEStudio project.
00008 
00009   It was then updated with later code from konsole (KDE).
00010 
00011     It has also been enhanced with an idea from the code in kdbg
00012     written by Johannes Sixt<Johannes.Sixt@telecom.at>
00013 
00014  ***************************************************************************/
00015 
00016 /***************************************************************************
00017  *                                                                         *
00018  *   This program is free software; you can redistribute it and/or modify  *
00019  *   it under the terms of the GNU General Public License as published by  *
00020  *   the Free Software Foundation; either version 2 of the License, or     *
00021  *   (at your option) any later version.                                   *
00022  *                                                                         *
00023  ***************************************************************************/
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028 
00029 #ifdef __osf__
00030 #define _XOPEN_SOURCE_EXTENDED
00031 #define O_NDELAY O_NONBLOCK
00032 #endif
00033 
00034 #include <sys/types.h>
00035 #include <sys/ioctl.h>
00036 #include <sys/stat.h>
00037 #include <sys/wait.h>
00038 #include <sys/time.h>
00039 #include <sys/resource.h>
00040 
00041 #ifdef HAVE_SYS_STROPTS_H
00042 #include <sys/stropts.h>
00043 #define _NEW_TTY_CTRL
00044 #endif
00045 
00046 #include <assert.h>
00047 #include <fcntl.h>
00048 #include <grp.h>
00049 #include <stdio.h>
00050 #include <stdlib.h>
00051 #include <signal.h>
00052 #include <termios.h>
00053 #include <time.h>
00054 #include <unistd.h>
00055 
00056 #if defined (_HPUX_SOURCE)
00057 #define _TERMIOS_INCLUDED
00058 #include <bsdtty.h>
00059 #endif
00060 
00061 #include <qintdict.h>
00062 #include <qsocketnotifier.h>
00063 #include <qstring.h>
00064 #include <qfile.h>
00065 
00066 #include <klocale.h>
00067 #include <kstandarddirs.h>
00068 #include <kapplication.h>
00069 
00070 #include "stty.h"
00071 
00072 #define PTY_FILENO 3
00073 #define BASE_CHOWN "konsole_grantpty"
00074 
00075 namespace GDBDebugger
00076 {
00077 
00078 static int chownpty(int fd, int grant)
00079 // param fd: the fd of a master pty.
00080 // param grant: 1 to grant, 0 to revoke
00081 // returns 1 on success 0 on fail
00082 {
00083     void(*tmp)(int) = signal(SIGCHLD,SIG_DFL);
00084     pid_t pid = fork();
00085     if (pid < 0) {
00086         signal(SIGCHLD,tmp);
00087         return 0;
00088     }
00089     if (pid == 0) {
00090         /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */
00091         if (fd != PTY_FILENO && dup2(fd, PTY_FILENO) < 0)
00092             ::exit(1);
00093 
00094         QString path = locate("exe", BASE_CHOWN);
00095         execle(QFile::encodeName(path), BASE_CHOWN, grant?"--grant":"--revoke", (void *)0, NULL);
00096         ::exit(1); // should not be reached
00097     }
00098     if (pid > 0) {
00099         int w;
00100         //  retry:
00101         int rc = waitpid (pid, &w, 0);
00102         if (rc != pid)
00103             ::exit(1);
00104 
00105         //    { // signal from other child, behave like catchChild.
00106         //      // guess this gives quite some control chaos...
00107         //      Shell* sh = shells.find(rc);
00108         //      if (sh) { shells.remove(rc); sh->doneShell(w); }
00109         //      goto retry;
00110         //    }
00111         signal(SIGCHLD,tmp);
00112         return (rc != -1 && WIFEXITED(w) && WEXITSTATUS(w) == 0);
00113     }
00114     signal(SIGCHLD,tmp);
00115     return 0; //dummy.
00116 }
00117 
00118 // **************************************************************************
00119 
00120 STTY::STTY(bool ext, const QString &termAppName)
00121     : QObject(),
00122       out(0),
00123       err(0),
00124       ttySlave(""),
00125       pid_(0)
00126 {
00127     if (ext) {
00128         findExternalTTY(termAppName);
00129     } else {
00130         fout = findTTY();
00131         if (fout >= 0) {
00132             ttySlave = QString(tty_slave);
00133             out = new QSocketNotifier(fout, QSocketNotifier::Read, this);
00134             connect( out, SIGNAL(activated(int)), this, SLOT(OutReceived(int)) );
00135         }
00136     }
00137 }
00138 
00139 // **************************************************************************
00140 
00141 STTY::~STTY()
00142 {
00143     if (pid_)
00144         ::kill(pid_, SIGTERM);
00145 
00146     if (out) {
00147         ::close(fout);
00148         delete out;
00149     }
00150 
00151     //  if ( err )
00152     //  {
00153     //    ::close( ferr );
00154     //    delete err;
00155     //  }
00156 }
00157 
00158 // **************************************************************************
00159 
00160 int STTY::findTTY()
00161 {
00162     int ptyfd = -1;
00163     bool needGrantPty = TRUE;
00164 
00165     // Find a master pty that we can open ////////////////////////////////
00166 
00167 #ifdef __sgi__
00168     ptyfd = open("/dev/ptmx",O_RDWR);
00169     if (ptyfd < 0) {
00170         perror("Can't open a pseudo teletype");
00171         return(-1);
00172     }
00173     strncpy(tty_slave, ptsname(ptyfd), 50);
00174     grantpt(ptyfd);
00175     unlockpt(ptyfd);
00176     needGrantPty = FALSE;
00177 #endif
00178 
00179     // first we try UNIX PTY's
00180 #ifdef TIOCGPTN
00181     strcpy(pty_master,"/dev/ptmx");
00182     strcpy(tty_slave,"/dev/pts/");
00183     ptyfd = open(pty_master,O_RDWR);
00184     if (ptyfd >= 0) { // got the master pty
00185         int ptyno;
00186         if (ioctl(ptyfd, TIOCGPTN, &ptyno) == 0) {
00187             struct stat sbuf;
00188             sprintf(tty_slave,"/dev/pts/%d",ptyno);
00189             if (stat(tty_slave,&sbuf) == 0 && S_ISCHR(sbuf.st_mode))
00190                 needGrantPty = FALSE;
00191             else {
00192                 close(ptyfd);
00193                 ptyfd = -1;
00194             }
00195         } else {
00196             close(ptyfd);
00197             ptyfd = -1;
00198         }
00199     }
00200 #endif
00201 
00202 #if defined(_SCO_DS) || defined(__USLC__) /* SCO OSr5 and UnixWare */
00203     if (ptyfd < 0) {
00204         for (int idx = 0; idx < 256; idx++)
00205             { sprintf(pty_master, "/dev/ptyp%d", idx);
00206             sprintf(tty_slave, "/dev/ttyp%d", idx);
00207             if (access(tty_slave, F_OK) < 0) { idx = 256; break; }
00208             if ((ptyfd = open (pty_master, O_RDWR)) >= 0)
00209                 { if (access (tty_slave, R_OK|W_OK) == 0) break;
00210                 close(ptyfd); ptyfd = -1;
00211                 }
00212             }
00213     }
00214 #endif
00215     if (ptyfd < 0) { 
00216         for (const char* s3 = "pqrstuvwxyzabcde"; *s3 != 0; s3++) {
00217             for (const char* s4 = "0123456789abcdef"; *s4 != 0; s4++) {
00218                 sprintf(pty_master,"/dev/pty%c%c",*s3,*s4);
00219                 sprintf(tty_slave,"/dev/tty%c%c",*s3,*s4);
00220                 if ((ptyfd = open(pty_master, O_RDWR)) >= 0) {
00221                     if (geteuid() == 0 || access(tty_slave, R_OK|W_OK) == 0)
00222                         break;
00223 
00224                     close(ptyfd);
00225                     ptyfd = -1;
00226                 }
00227             }
00228 
00229             if (ptyfd >= 0)
00230                 break;
00231         }
00232     }
00233 
00234     if (ptyfd >= 0) {
00235         if (needGrantPty && !chownpty(ptyfd, TRUE)) {
00236             fprintf(stderr,"kdevelop: chownpty failed for device %s::%s.\n",pty_master,tty_slave);
00237             fprintf(stderr,"        : This means the session can be eavesdroped.\n");
00238             fprintf(stderr,"        : Make sure konsole_grantpty is installed and setuid root.\n");
00239         }
00240 
00241         ::fcntl(ptyfd, F_SETFL, O_NDELAY);
00242 #ifdef TIOCSPTLCK
00243         int flag = 0;
00244         ioctl(ptyfd, TIOCSPTLCK, &flag); // unlock pty
00245 #endif
00246     }
00247 
00248     return ptyfd;
00249 }
00250 
00251 // **************************************************************************
00252 
00253 void STTY::OutReceived(int f)
00254 {
00255     char buf[1024];
00256     int n;
00257 
00258     // read until socket is empty. We shouldn't be receiving a continuous
00259     // stream of data, so the loop is unlikely to cause problems.
00260     while ((n = ::read(f, buf, sizeof(buf)-1)) > 0) {
00261         *(buf+n) = 0;         // a standard string
00262         if ( f == fout )
00263             emit OutOutput(buf);
00264         else
00265             emit ErrOutput(buf);
00266     }
00267 }
00268 
00269 // **************************************************************************
00270 
00271 #define FIFO_FILE "/tmp/debug_tty.XXXXXX"
00272 
00273 bool STTY::findExternalTTY(const QString &termApp)
00274 {
00275     QString appName(termApp.isEmpty() ? QString("xterm") : termApp);
00276 
00277     char fifo[] = FIFO_FILE;
00278     int fifo_fd;
00279     if ((fifo_fd = mkstemp(fifo)) == -1)
00280         return false;
00281 
00282     ::close(fifo_fd);
00283     ::unlink(fifo);
00284 
00285     // create a fifo that will pass in the tty name
00286 #ifdef HAVE_MKFIFO
00287     if (::mkfifo(fifo, S_IRUSR|S_IWUSR) < 0)
00288 #else
00289         if (::mknod(fifo, S_IFIFO | S_IRUSR|S_IWUSR, 0) < 0)
00290 #endif
00291             return false;
00292 
00293     int pid = ::fork();
00294     if (pid < 0) {             // No process
00295         ::unlink(fifo);
00296         return false;
00297     }
00298 
00299     if (pid == 0) {            // child process
00300         /*
00301          * Spawn a console that in turn runs a shell script that passes us
00302          * back the terminal name and then only sits and waits.
00303          */
00304 
00305         const char* prog      = appName.latin1();
00306         QString script = QString("tty>") + QString(fifo) +
00307             QString(";"                  // fifo name
00308                     "trap \"\" INT QUIT TSTP;"    // ignore various signals
00309                     "exec<&-;exec>&-;"              // close stdin and stdout
00310                     "while :;do sleep 3600;done");
00311         const char* scriptStr = script.latin1();
00312         const char* end       = 0;
00313 
00314         ::execlp( prog,       prog,
00315                   //              "-name",    "debugio",
00316                   //              "-title",   "kdevelop: Program output",
00317                   "-caption", i18n("kdevelop: Debug application console").local8Bit().data(),
00318                   "-e",       "sh",
00319                   "-c",       scriptStr,
00320                   end);
00321 
00322         // Should not get here, as above should always work
00323         ::exit(1);
00324     }
00325 
00326     // parent process
00327     if (pid <= 0)
00328         ::exit(1);
00329 
00330     // Open the communication between us (the parent) and the
00331     // child (the process running on a tty console)
00332     fifo_fd = ::open(fifo, O_RDONLY);
00333     if (fifo_fd < 0)
00334         return false;
00335 
00336     // Get the ttyname from the fifo buffer that the child process
00337     // has sent.
00338     char ttyname[50];
00339     int n = ::read(fifo_fd, ttyname, sizeof(ttyname)-sizeof(char));
00340 
00341     ::close(fifo_fd);
00342     ::unlink(fifo);
00343 
00344     // No name??
00345     if (n <= 0)
00346         return false;
00347 
00348     // remove whitespace
00349     ttyname[n] = 0;
00350     if (char* newline = strchr(ttyname, '\n'))
00351         *newline = 0;      // clobber the new line
00352 
00353     ttySlave = ttyname;
00354     pid_ = pid;
00355 
00356     return true;
00357 }
00358 
00359 }
00360 
00361 // **************************************************************************
00362 #include "stty.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 00:03:46 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003