KDevelop API Documentation

languages/cpp/debugger/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.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:01 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003