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
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
00083
00084
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
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);
00100 }
00101 if (pid > 0) {
00102 int w;
00103
00104 int rc = waitpid (pid, &w, 0);
00105 if (rc != pid)
00106 ::exit(1);
00107
00108
00109
00110
00111
00112
00113
00114 signal(SIGCHLD,tmp);
00115 return (rc != -1 && WIFEXITED(w) && WEXITSTATUS(w) == 0);
00116 }
00117 signal(SIGCHLD,tmp);
00118 return 0;
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
00155
00156
00157
00158
00159 }
00160
00161
00162
00163 int STTY::findTTY()
00164 {
00165 int ptyfd = -1;
00166 bool needGrantPty = TRUE;
00167
00168
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
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) {
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__)
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);
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
00262
00263 while ((n = ::read(f, buf, sizeof(buf)-1)) > 0) {
00264 *(buf+n) = 0;
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
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) {
00298 ::unlink(fifo);
00299 return false;
00300 }
00301
00302 if (pid == 0) {
00303
00304
00305
00306
00307
00308 const char* prog = appName.latin1();
00309 QString script = QString("tty>") + QString(fifo) +
00310 QString(";"
00311 "trap \"\" INT QUIT TSTP;"
00312 "exec<&-;exec>&-;"
00313 "while :;do sleep 3600;done");
00314 const char* scriptStr = script.latin1();
00315 const char* end = 0;
00316
00317 ::execlp( prog, prog,
00318
00319
00320 "-caption", i18n("kdevelop: Debug application console").local8Bit().data(),
00321 "-e", "sh",
00322 "-c", scriptStr,
00323 end);
00324
00325
00326 ::exit(1);
00327 }
00328
00329
00330 if (pid <= 0)
00331 ::exit(1);
00332
00333
00334
00335 fifo_fd = ::open(fifo, O_RDONLY);
00336 if (fifo_fd < 0)
00337 return false;
00338
00339
00340
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
00348 if (n <= 0)
00349 return false;
00350
00351
00352 ttyname[n] = 0;
00353 if (char* newline = strchr(ttyname, '\n'))
00354 *newline = 0;
00355
00356 ttySlave = ttyname;
00357 pid_ = pid;
00358
00359 return true;
00360 }
00361
00362 }
00363
00364
00365 #include "stty.moc"