KDevelop API Documentation

languages/java/debugger/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.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Oct 19 08:01:43 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003