KDevelop API Documentation

stty.cpp

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