00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00066 #include "procctl.h"
00067 #include "MyPty.h"
00068
00069
00070 #include <qsocketnotifier.h>
00071 #include <qfile.h>
00072
00073
00074 #include <stdlib.h>
00075 #include <stdio.h>
00076 #include <signal.h>
00077 #include <fcntl.h>
00078 #include <unistd.h>
00079 #include <termios.h>
00080 #include <sys/types.h>
00081 #include <sys/ioctl.h>
00082 #include <sys/wait.h>
00083
00084
00085 #ifdef HAVE_OPENPTY
00086 #include <pty.h>
00087 #endif
00088
00089 #undef VERBOSE_DEBUG
00090
00091
00092
00093
00099 void MyPty::setSize(int lines, int columns)
00100 {
00101 struct winsize wsize;
00102 wsize.ws_row = (unsigned short)lines;
00103 wsize.ws_col = (unsigned short)columns;
00104 if(m_fd < 0) return;
00105 ioctl(m_fd,TIOCSWINSZ,(char *)&wsize);
00106 }
00107
00108
00109 void MyPty::donePty()
00110 {
00111
00112
00113 ::close(m_fd);
00114
00115 if (m_cpid) {
00116 kill(m_cpid, SIGHUP);
00117
00118 delete m_sn_e;
00119 delete m_sn_r;
00120 m_sn_e = 0l;
00121 m_sn_r = 0l;
00122 }
00123
00124 m_cpid = 0;
00125 m_fd = -1;
00126
00127 }
00128
00129
00130 const char* MyPty::deviceName()
00131 {
00132 return m_ttynam;
00133 }
00134
00135
00136 void MyPty::error()
00137 {
00138
00139 donePty();
00140 }
00141
00142 void MyPty::start() {
00143 QStrList lis;
00144 int r =run(m_cmd.latin1(), lis, 0, 0);
00145 r = r;
00146 }
00150 int MyPty::run(const char* cmd, QStrList &, const char*, int)
00151 {
00152
00153 m_cpid = fork();
00154
00155 if ( !m_cpid ) {
00156
00157 for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL);
00158 int ttyfd = ::open(m_ttynam, O_RDWR);
00159 dup2(ttyfd, STDIN_FILENO);
00160 dup2(ttyfd, STDOUT_FILENO);
00161 dup2(ttyfd, STDERR_FILENO);
00162
00163 ::close(ttyfd);
00164 static struct termios ttmode;
00165 if ( setsid() < 0 )
00166 perror( "failed to set process group" );
00167 #if defined (TIOCSCTTY)
00168
00169 ioctl(STDIN_FILENO, TIOCSCTTY, 0);
00170 #endif
00171 tcgetattr( STDIN_FILENO, &ttmode );
00172 ttmode.c_cc[VINTR] = 3;
00173 ttmode.c_cc[VERASE] = 8;
00174 tcsetattr( STDIN_FILENO, TCSANOW, &ttmode );
00175 setenv("TERM",m_term,1);
00176 setenv("COLORTERM","0",1);
00177 EnvironmentMap::Iterator it;
00178 for (it = m_env.begin(); it != m_env.end(); it++) {
00179 setenv(it.key().latin1(), it.data().latin1(), 1);
00180 }
00181 if (getuid() == 0) {
00182 char msg[] = "WARNING: You are running this shell as root!\n";
00183 write(ttyfd, msg, sizeof(msg));
00184 }
00185 execl(cmd, cmd, 0);
00186
00187 donePty();
00188 exit(-1);
00189 }
00190
00191
00192 delete m_sn_r;
00193 m_sn_r = new QSocketNotifier(m_fd,QSocketNotifier::Read,this);
00194 delete m_sn_e;
00195 m_sn_e = new QSocketNotifier(m_fd,QSocketNotifier::Exception,this);
00196 connect(m_sn_r,SIGNAL(activated(int)),this,SLOT(readPty()));
00197 connect(m_sn_e,SIGNAL(activated(int)),this,SLOT(error()));
00198
00199 return 0;
00200 }
00201
00202 int MyPty::openPty()
00203 {
00204
00205 int ptyfd = -1;
00206
00207 #ifdef HAVE_OPENPTY
00208 int ttyfd;
00209 if ( openpty(&ptyfd,&ttyfd,m_ttynam,0,0) )
00210 ptyfd = -1;
00211 else
00212 ::close(ttyfd);
00213 #else
00214 for (const char* c0 = "pqrstuvwxyzabcde"; ptyfd < 0 && *c0 != 0; c0++) {
00215 for (const char* c1 = "0123456789abcdef"; ptyfd < 0 && *c1 != 0; c1++) {
00216 sprintf(m_ptynam,"/dev/pty%c%c",*c0,*c1);
00217 sprintf(m_ttynam,"/dev/tty%c%c",*c0,*c1);
00218 if ((ptyfd = ::open(m_ptynam,O_RDWR)) >= 0) {
00219 if (geteuid() != 0 && !access(m_ttynam,R_OK|W_OK) == 0) {
00220 ::close(ptyfd);
00221 ptyfd = -1;
00222 }
00223 }
00224 }
00225 }
00226 #endif
00227
00228 if ( ptyfd < 0 ) {
00229
00230 return -1;
00231 }
00232
00233 return ptyfd;
00234 }
00235
00239 MyPty::MyPty(const Profile& prof) : m_cpid(0)
00240 {
00241
00242 int term = prof.readNumEntry("Terminal", Profile::VT100 );
00243 switch( term ) {
00244 default:
00245 case Profile::VT100:
00246 case Profile::VT102:
00247 m_term = "vt100";
00248 break;
00249 case Profile::Linux:
00250 m_term = "linux";
00251 break;
00252 case Profile::XTerm:
00253 m_term = "xterm";
00254 break;
00255 }
00256 m_sn_e = 0l;
00257 m_sn_r = 0l;
00258 m_fd = openPty();
00259 ProcCtl* ctl = ProcCtl::self();
00260 Q_UNUSED(ctl);
00261 reload(prof);
00262 }
00263
00269 MyPty::~MyPty()
00270 {
00271 donePty();
00272 }
00273 QString MyPty::identifier()const {
00274 return QString::fromLatin1("term");
00275 }
00276 QString MyPty::name()const{
00277 return identifier();
00278 }
00279 bool MyPty::open() {
00280 if (m_fd < 0)
00281 m_fd = openPty();
00282
00283 start();
00284 return true;
00285 }
00286 void MyPty::close() {
00287 donePty();
00288 m_fd = openPty();
00289 }
00290 void MyPty::reload( const Profile& prof) {
00291 m_env.clear();
00292 m_cmd = prof.readEntry("Command", "/bin/sh");
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 if ( m_cmd.stripWhiteSpace() == "/bin/bash" && !QFile::exists(QFile::encodeName(m_cmd) ) )
00303 m_cmd = "/bin/sh";
00304
00305
00306 int envcount = prof.readNumEntry("EnvVars", 0);
00307 for (int i=0; i<envcount; i++) {
00308 QString name = prof.readEntry("Env_Name_" + QString::number(i), "");
00309 QString value = prof.readEntry("Env_Value_" + QString::number(i), "");
00310 if (!(name.isEmpty() || value.isEmpty())) {
00311 m_env.insert(name, value);
00312 }
00313 }
00314 }
00316 void MyPty::send(const QByteArray& ar)
00317 {
00318 #ifdef VERBOSE_DEBUG
00319
00320 printf("sending bytes:\n");
00321 for (uint i = 0; i < ar.count(); i++)
00322 printf("%c", ar[i]);
00323 printf("\n");
00324 #endif
00325
00326 ::write(m_fd, ar.data(), ar.count());
00327 }
00328
00330 void MyPty::readPty()
00331 {
00332 QByteArray buf(4096);
00333
00334 int len = ::read( m_fd, buf.data(), 4096 );
00335
00336 if (len == -1 || len == 0) {
00337 donePty();
00338 return;
00339 }
00340
00341 if (len < 0)
00342 return;
00343
00344
00345 buf.resize(len);
00346 emit received(buf);
00347
00348 #ifdef VERBOSE_DEBUG
00349
00350 printf("read bytes:\n");
00351 for (uint i = 0; i < buf.count(); i++)
00352 printf("%c", buf[i]);
00353 printf("\n");
00354 #endif
00355
00356 }
00357 QBitArray MyPty::supports()const {
00358 QBitArray ar(3);
00359
00360 ar[0] = 1;
00361
00362 ar[1] = 0;
00363 ar[2] = 0;
00364
00365 return ar;
00366 }