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"