00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00080
00081
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
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);
00097 }
00098 if (pid > 0) {
00099 int w;
00100
00101 int rc = waitpid (pid, &w, 0);
00102 if (rc != pid)
00103 ::exit(1);
00104
00105
00106
00107
00108
00109
00110
00111 signal(SIGCHLD,tmp);
00112 return (rc != -1 && WIFEXITED(w) && WEXITSTATUS(w) == 0);
00113 }
00114 signal(SIGCHLD,tmp);
00115 return 0;
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
00152
00153
00154
00155
00156 }
00157
00158
00159
00160 int STTY::findTTY()
00161 {
00162 int ptyfd = -1;
00163 bool needGrantPty = TRUE;
00164
00165
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
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) {
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__)
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);
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
00259
00260 while ((n = ::read(f, buf, sizeof(buf)-1)) > 0) {
00261 *(buf+n) = 0;
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
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) {
00295 ::unlink(fifo);
00296 return false;
00297 }
00298
00299 if (pid == 0) {
00300
00301
00302
00303
00304
00305 const char* prog = appName.latin1();
00306 QString script = QString("tty>") + QString(fifo) +
00307 QString(";"
00308 "trap \"\" INT QUIT TSTP;"
00309 "exec<&-;exec>&-;"
00310 "while :;do sleep 3600;done");
00311 const char* scriptStr = script.latin1();
00312 const char* end = 0;
00313
00314 ::execlp( prog, prog,
00315
00316
00317 "-caption", i18n("kdevelop: Debug application console").local8Bit().data(),
00318 "-e", "sh",
00319 "-c", scriptStr,
00320 end);
00321
00322
00323 ::exit(1);
00324 }
00325
00326
00327 if (pid <= 0)
00328 ::exit(1);
00329
00330
00331
00332 fifo_fd = ::open(fifo, O_RDONLY);
00333 if (fifo_fd < 0)
00334 return false;
00335
00336
00337
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
00345 if (n <= 0)
00346 return false;
00347
00348
00349 ttyname[n] = 0;
00350 if (char* newline = strchr(ttyname, '\n'))
00351 *newline = 0;
00352
00353 ttySlave = ttyname;
00354 pid_ = pid;
00355
00356 return true;
00357 }
00358
00359 }
00360
00361
00362 #include "stty.moc"