Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

system.cpp

Go to the documentation of this file.
00001 #include <sys/types.h>
00002 #include <sys/wait.h>
00003 
00004 #include <net/if.h>
00005 #include <net/if_arp.h>
00006 #include <netinet/in.h>
00007 #include <arpa/inet.h>
00008 #include <sys/ioctl.h>
00009 #include <sys/socket.h>
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <fcntl.h>
00013 #include <errno.h>
00014 #include <unistd.h>
00015 
00016 #include <opie2/oprocess.h>
00017 
00018 #include <qdir.h>
00019 #include <qregexp.h>
00020 #include <qstringlist.h>
00021 #include <qfile.h>
00022 #include <qtextstream.h>
00023 #include <qapplication.h>
00024 
00025 #include "resources.h"
00026 #include "system.h"
00027 
00028 #define PROCNETDEV "/proc/net/dev"
00029 
00030 #ifndef ARPHRD_IEEE80211
00031 #define ARPHRD_IEEE80211 801
00032 #endif
00033 
00034 static char Dig2Hex[] = { 
00035   '0', '1', '2', '3', 
00036   '4', '5', '6', '7', 
00037   '8', '9', 'A', 'B', 
00038   'C', 'D', 'E', 'F'
00039 };
00040 
00041 // get HIGH nibble of byte
00042 #define HN(x)           Dig2Hex[(((x)&0xf0)>>4)]
00043 // get LOW nibble of byte
00044 #define LN(x)           Dig2Hex[((x)&0x0f)]
00045 
00046 System::System( void ) : QObject(), ProbedInterfaces() {
00047     ProcDevNet = 0;
00048 }
00049 
00050 System::~System( void ) {
00051     if( ProcDevNet )
00052       delete ProcDevNet;
00053 }
00054 
00055 QDict<InterfaceInfo> & System::interfaces( void ) {
00056     if( ProbedInterfaces.count() == 0 ) {
00057       probeInterfaces();
00058     }
00059     return ProbedInterfaces;
00060 }
00061 
00062 int System::runAsRoot( QStringList & S, MyProcess * Prc ) {
00063     char * usr = getenv("USER");
00064 
00065     if( S.count() == 0 ) {
00066       // close loophole to start shell
00067       return 8888;
00068     }
00069     if( usr == 0 || strcmp( usr, "root" ) ) {
00070       // unknown or non-root user -> use SUDO
00071       S.prepend( "sudo" );
00072     }
00073 
00074     if( getenv( "NS2TESTMODE" ) ) {
00075       odebug << "TESTMODE !!! execute " 
00076             << S.join( " ") 
00077             << oendl;
00078     } else {
00079       MyProcess * P;
00080 
00081       if( Prc ) {
00082         P = Prc;
00083       } else {
00084         P = new MyProcess();
00085         emit processEvent( tr("Command : ") + S.join( " " ) );
00086 
00087         connect( P, 
00088                  SIGNAL( stdoutLine( const QString & ) ),
00089                  this, 
00090                  SIGNAL( stdoutLine( const QString & ) ) );
00091 
00092         connect( P, 
00093                  SIGNAL( stderrLine( const QString & ) ),
00094                  this, 
00095                  SIGNAL( stderrLine( const QString & ) ) );
00096 
00097         connect( P, 
00098                  SIGNAL(processExited(MyProcess*) ),
00099                  this, SLOT
00100                  (SLOT_ProcessExited(MyProcess*) ) );
00101       }
00102 
00103       P->process() << S;
00104 
00105       Log(("Executing %s\n", S.join( " " ).latin1() ));
00106 
00107       if( ! P->process().start( OProcess::DontCare, 
00108                       OProcess::AllOutput ) ) {
00109         odebug << "Error starting " << S << oendl;
00110         if( ! Prc )
00111           delete P;
00112         // error starting app
00113         return 0;
00114       }
00115       odebug << "Started " << S << oendl;
00116     }
00117 
00118     // all is fine
00119     return 1;
00120 }
00121 
00122 int System::execAsUser( QStringList & SL, bool Synchronous ) {
00123       MyProcess * P = new MyProcess();
00124       CurrentQPEUser CU = NSResources->currentUser();
00125       char * usr = getenv("USER");
00126 
00127       if( usr == 0 ||
00128           strcmp( usr, "root" ) == 0 ) {
00129         // find user running qpe
00130         if( CU.UserName.isEmpty() ) {
00131           // if we come here, the exec was not successfull
00132           Log(("User not known \n" ));
00133           return 0;
00134         }
00135       }
00136 
00137       // now we are ready to exec the requested command
00138       setuid( CU.Uid );
00139       setgid( CU.Gid );
00140 
00141       for( unsigned int i = 0 ; i < CU.EnvList.count() ; i ++ ) {
00142         QString X;
00143         QStringList SL;
00144         X = CU.EnvList[i];
00145         SL = QStringList::split( "=", X );
00146         P->process().setEnvironment( SL[0], SL[1] );
00147       }
00148 
00149       P->process() << SL;
00150 
00151       emit processEvent( tr("Command : ") + SL.join( " " ) );
00152 
00153       Log(("Executing as user %s : %s\n", 
00154             CU.UserName.latin1(),
00155             SL.join( " " ).latin1() ));
00156 
00157       P->setEchoMode( Synchronous );
00158 
00159       bool rv = P->process().start( 
00160             (Synchronous) ? OProcess::Block : 
00161                             OProcess::DontCare,  
00162             (Synchronous) ? OProcess::AllOutput : 
00163                             OProcess::NoCommunication );
00164       delete P;
00165 
00166       if( ! rv ) {
00167         // if we come here, the exec was not successfull
00168         Log(("Could not exec : %d\n", errno ));
00169       }
00170 
00171       return rv;
00172 }
00173 
00174 void System::SLOT_ProcessExited( MyProcess * P ) {
00175       QString R;
00176 
00177       for( QValueListConstIterator<QCString> it = P->process().args().begin();
00178            it != P->process().args().end(); 
00179            ++it ) {
00180         R += (*it); 
00181         R += " ";
00182       }
00183 
00184       R += "Returned with " + QString().setNum( P->process().exitStatus() );
00185       emit processEvent( R );
00186       delete P;
00187 }
00188 
00189 void System::refreshStatistics( InterfaceInfo & I ) {
00190     if( ! ProcDevNet ) {
00191       return;
00192     }
00193     // cannot seek on dev
00194     ProcDevNet->close();
00195     ProcDevNet->open( IO_ReadOnly );
00196 
00197     QString line;
00198     QTextStream procTs(ProcDevNet);
00199     QStringList SL;
00200     int loc = -1;
00201     int version;
00202 
00203     procTs.readLine();
00204     line = procTs.readLine();
00205     // get version
00206     if( line.find("compressed") )
00207       version = 3;
00208     else if( line.find( "bytes" ) )
00209       version = 2;
00210     else 
00211       version = 1;
00212     while((line = procTs.readLine().simplifyWhiteSpace()) != QString::null) {
00213       if( (loc = line.find(":") ) == -1) {
00214         continue;
00215       }
00216 
00217       if( I.Name != line.left(loc) ) 
00218         continue;
00219 
00220       // tokenize
00221       SL = QStringList::split( ' ', line.mid(loc+1), FALSE );
00222 
00223       // update data
00224       switch( version ) {
00225         case 1 :
00226           I.RcvBytes = "";
00227           I.RcvPackets = SL[0];
00228           I.RcvErrors = SL[1];
00229           I.RcvDropped = SL[2];
00230 
00231           I.SndBytes = "";
00232           I.SndPackets = SL[5];
00233           I.SndErrors = SL[6];
00234           I.SndDropped = SL[7];
00235 
00236           I.Collisions = SL[9];
00237           break;
00238         case 2 :
00239           I.RcvBytes = SL[0];
00240           I.RcvPackets = SL[1];
00241           I.RcvErrors = SL[2];
00242           I.RcvDropped = SL[3];
00243 
00244           I.SndBytes = SL[6];
00245           I.SndPackets = SL[7];
00246           I.SndErrors = SL[8];
00247           I.SndDropped = SL[9];
00248 
00249           I.Collisions = SL[11];
00250           break;
00251         case 3 :
00252           I.RcvBytes = SL[0];
00253           I.RcvPackets = SL[1];
00254           I.RcvErrors = SL[2];
00255           I.RcvDropped = SL[3];
00256 
00257           I.SndBytes = SL[8];
00258           I.SndPackets = SL[9];
00259           I.SndErrors = SL[10];
00260           I.SndDropped = SL[11];
00261 
00262           I.Collisions = SL[13];
00263           break;
00264       }
00265       break;
00266     }
00267 }
00268 
00269 //
00270 // THIS UPDATES THE LIST -> INTERFACES ARE NOT DELETED BUT
00271 // FLAGGED AS ! 'IsUp' IF NO LONGER PRESENT
00272 //
00273 
00274 void System::probeInterfaces( void ) {
00275 
00276     // probe interfaces
00277     int sockfd;
00278     // get list of all interfaces
00279     struct ifreq ifrs;
00280     InterfaceInfo * IFI;
00281 
00282     // flag all as 'down'
00283     for( QDictIterator<InterfaceInfo> it( ProbedInterfaces ); 
00284          it.current();
00285          ++it ) {
00286       it.current()->IsUp = 0;
00287     }
00288 
00289     sockfd = socket(PF_INET, SOCK_DGRAM, 0);
00290     if(sockfd == -1) {
00291       odebug << "Cannot open INET socket "
00292             << errno 
00293             << " "
00294             << strerror( errno )
00295             << oendl;
00296       return;
00297     }
00298 
00299     // read interfaces from /proc/dev/net
00300     // SIOCGIFCONF does not return ALL interfaces ???!?
00301     ProcDevNet = new QFile(PROCNETDEV);
00302     if( ! ProcDevNet->open(IO_ReadOnly) ) {
00303       odebug << "Cannot open " 
00304             << PROCNETDEV
00305             << " "
00306             << errno 
00307             << " "
00308             << strerror( errno )
00309             << oendl;
00310       delete ProcDevNet;
00311       ProcDevNet =0;
00312       ::close( sockfd );
00313       return;
00314     }
00315 
00316     QString line;
00317     QString NicName;
00318     QTextStream procTs(ProcDevNet);
00319     int loc = -1;
00320 
00321     procTs.readLine(); // eat a line
00322     procTs.readLine(); // eat a line
00323     while((line = procTs.readLine().simplifyWhiteSpace()) != QString::null) {
00324       if((loc = line.find(":")) == -1) {
00325         continue;
00326       }
00327 
00328       NicName = line.left(loc);
00329 
00330       // set name for ioctl
00331       strcpy( ifrs.ifr_name, NicName.latin1() );
00332 
00333       if ( ! ( IFI = ProbedInterfaces.find( NicName ) ) ) {
00334         // new nic
00335         Log(("New NIC found : %s\n", NicName.latin1()));
00336         IFI = new InterfaceInfo;
00337         IFI->Name = line.left(loc);
00338         IFI->Collection = 0;
00339         ProbedInterfaces.insert( IFI->Name, IFI );
00340 
00341         // get dynamic info
00342         if( ioctl(sockfd, SIOCGIFFLAGS, &ifrs) >= 0 ) {
00343           IFI->IsPointToPoint = ((ifrs.ifr_flags & IFF_POINTOPOINT) == IFF_POINTOPOINT);
00344         } else {
00345           IFI->IsPointToPoint = 0;
00346         }
00347 
00348         // settings that never change
00349         IFI->DstAddress = "";
00350 
00351         if( IFI->IsPointToPoint ) {
00352           if( ioctl(sockfd, SIOCGIFDSTADDR, &ifrs) >= 0 ) {
00353             IFI->DstAddress = 
00354              inet_ntoa(((struct sockaddr_in*)&ifrs.ifr_dstaddr)->sin_addr);
00355           }
00356         }
00357 
00358         IFI->CardType = 999999;
00359         IFI->MACAddress = "";
00360 
00361         if( ioctl(sockfd, SIOCGIFHWADDR, &ifrs) >= 0 ) {
00362           Log(("Family for NIC %s : %d\n", IFI->Name.latin1(), 
00363               ifrs.ifr_hwaddr.sa_family ));
00364 
00365           IFI->CardType = ifrs.ifr_hwaddr.sa_family;
00366           switch( ifrs.ifr_hwaddr.sa_family ) {
00367             case ARPHRD_ETHER : // regular MAC address
00368               // valid address -> convert to regular ::: format
00369               // length = 6 bytes = 12 DIGITS -> 6 :
00370               IFI->MACAddress.sprintf(
00371                 "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
00372                 HN( ifrs.ifr_hwaddr.sa_data[0] ),
00373                 LN( ifrs.ifr_hwaddr.sa_data[0] ),
00374                 HN( ifrs.ifr_hwaddr.sa_data[1] ),
00375                 LN( ifrs.ifr_hwaddr.sa_data[1] ),
00376                 HN( ifrs.ifr_hwaddr.sa_data[2] ),
00377                 LN( ifrs.ifr_hwaddr.sa_data[2] ),
00378                 HN( ifrs.ifr_hwaddr.sa_data[3] ),
00379                 LN( ifrs.ifr_hwaddr.sa_data[3] ),
00380                 HN( ifrs.ifr_hwaddr.sa_data[4] ),
00381                 LN( ifrs.ifr_hwaddr.sa_data[4] ),
00382                 HN( ifrs.ifr_hwaddr.sa_data[5] ),
00383                 LN( ifrs.ifr_hwaddr.sa_data[5] )
00384               );
00385               break;
00386 #ifdef ARPHRD_IEEE1394
00387             case ARPHRD_IEEE1394 : // Firewire Eth address
00388               IFI->MACAddress.sprintf(
00389                 "%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-00-00",
00390                 HN( ifrs.ifr_hwaddr.sa_data[0] ),
00391                 LN( ifrs.ifr_hwaddr.sa_data[0] ),
00392                 HN( ifrs.ifr_hwaddr.sa_data[1] ),
00393                 LN( ifrs.ifr_hwaddr.sa_data[1] ),
00394                 HN( ifrs.ifr_hwaddr.sa_data[2] ),
00395                 LN( ifrs.ifr_hwaddr.sa_data[2] ),
00396                 HN( ifrs.ifr_hwaddr.sa_data[3] ),
00397                 LN( ifrs.ifr_hwaddr.sa_data[3] ),
00398                 HN( ifrs.ifr_hwaddr.sa_data[4] ),
00399                 LN( ifrs.ifr_hwaddr.sa_data[4] ),
00400                 HN( ifrs.ifr_hwaddr.sa_data[5] ),
00401                 LN( ifrs.ifr_hwaddr.sa_data[5] ),
00402                 HN( ifrs.ifr_hwaddr.sa_data[6] ),
00403                 LN( ifrs.ifr_hwaddr.sa_data[6] ),
00404                 HN( ifrs.ifr_hwaddr.sa_data[7] ),
00405                 LN( ifrs.ifr_hwaddr.sa_data[7] ),
00406                 HN( ifrs.ifr_hwaddr.sa_data[8] ),
00407                 LN( ifrs.ifr_hwaddr.sa_data[8] ),
00408                 HN( ifrs.ifr_hwaddr.sa_data[9] ),
00409                 LN( ifrs.ifr_hwaddr.sa_data[9] ),
00410                 HN( ifrs.ifr_hwaddr.sa_data[10] ),
00411                 LN( ifrs.ifr_hwaddr.sa_data[10] ),
00412                 HN( ifrs.ifr_hwaddr.sa_data[11] ),
00413                 LN( ifrs.ifr_hwaddr.sa_data[11] ),
00414                 HN( ifrs.ifr_hwaddr.sa_data[12] ),
00415                 LN( ifrs.ifr_hwaddr.sa_data[12] ),
00416                 HN( ifrs.ifr_hwaddr.sa_data[13] ),
00417                 LN( ifrs.ifr_hwaddr.sa_data[13] )
00418               );
00419               break;
00420 #endif
00421             case ARPHRD_PPP : // PPP
00422               break;
00423             case ARPHRD_IEEE80211 : // WLAN
00424               break;
00425             case ARPHRD_IRDA : // IRDA
00426               break;
00427           }
00428         }
00429       } else // else already probed before -> just update
00430         Log(("Redetected NIC %s\n", NicName.latin1()));
00431 
00432       // get dynamic info
00433       if( ioctl(sockfd, SIOCGIFFLAGS, &ifrs) >= 0 ) {
00434         IFI->IsUp = ((ifrs.ifr_flags & IFF_UP) == IFF_UP);
00435         IFI->HasMulticast = ((ifrs.ifr_flags & IFF_MULTICAST) == IFF_MULTICAST);
00436       } else {
00437         IFI->IsUp = 0;
00438         IFI->HasMulticast = 0;
00439       }
00440 
00441       if( ioctl(sockfd, SIOCGIFADDR, &ifrs) >= 0 ) {
00442         IFI->Address = 
00443            inet_ntoa(((struct sockaddr_in*)&ifrs.ifr_addr)->sin_addr);
00444       } else {
00445         IFI->Address = "";
00446         IFI->IsUp = 0;
00447       }
00448       if( ioctl(sockfd, SIOCGIFBRDADDR, &ifrs) >= 0 ) {
00449         IFI->BCastAddress = 
00450            inet_ntoa(((struct sockaddr_in*)&ifrs.ifr_broadaddr)->sin_addr);
00451       } else {
00452         IFI->BCastAddress = "";
00453       }
00454       if( ioctl(sockfd, SIOCGIFNETMASK, &ifrs) >= 0 ) {
00455         IFI->Netmask = 
00456            inet_ntoa(((struct sockaddr_in*)&ifrs.ifr_netmask)->sin_addr);
00457       } else {
00458         IFI->Netmask = "";
00459       }
00460       Log(("NIC %s UP ? %d\n", NicName.latin1(), IFI->IsUp ));
00461     }
00462 
00463     ::close( sockfd );
00464 }
00465 
00466 InterfaceInfo * System::findInterface( const QString & N ) {
00467       InterfaceInfo * Run;
00468       // has PAN NetworkSetup UP interface ?
00469       for( QDictIterator<InterfaceInfo> It(ProbedInterfaces);
00470            It.current();
00471            ++It ) {
00472         Run = It.current();
00473         if( N == Run->Name ) {
00474           // this PAN NetworkSetup is up
00475           return Run;
00476         }
00477       }
00478       return 0;
00479 }
00480 
00481 #include <stdarg.h>
00482 static FILE * logf = 0;
00483 
00484 void VLog( char * Format, ... ) {
00485       va_list l;
00486 
00487       va_start(l, Format );
00488 
00489       if( logf == (FILE *)0 ) {
00490         QString S = getenv("NS2LOG");
00491         if( S == "stderr" ) {
00492           logf = stderr;
00493         } else if( S.isEmpty() ) {
00494           logf = fopen( "/tmp/ns2log", "a" );
00495         } else {
00496           logf = fopen( S, "a" );
00497         }
00498 
00499         if( ! logf ) {
00500           fprintf( stderr, "Cannot open logfile %s : %d\n", 
00501               S.latin1(), errno );
00502           logf = (FILE *)1;
00503         } else {
00504           fprintf( logf, "____ OPEN LOGFILE ____\n");
00505         }
00506       }
00507 
00508       if( (unsigned long)logf > 1 ) {
00509         vfprintf( logf, Format, l );
00510       }
00511       va_end( l );
00512       fflush( logf );
00513 
00514 }
00515 
00516 void LogClose( void ) {
00517       if( (long)logf > 1 ) {
00518         fprintf( logf, "____ CLOSE LOGFILE ____\n");
00519         if( logf != stderr ) {
00520           fclose( logf );
00521         }
00522         logf = 0;
00523       }
00524 }
00525 
00526 QString removeSpaces( const QString & X ) {
00527       QString Y;
00528       Y = X.simplifyWhiteSpace(); 
00529       Y.replace( QRegExp(" "), "_" );
00530       odebug << X <<  " **" << Y << "**" << oendl;
00531       return Y;
00532 }
00533 
00534 //
00535 //
00536 //
00537 //
00538 //
00539 
00540 MyProcess::MyProcess() : QObject(), StdoutBuffer(), StderrBuffer() {
00541       P = new OProcess();
00542       connect( P, 
00543                SIGNAL( receivedStdout(Opie::Core::OProcess*, char*, int ) ),
00544                this, 
00545                SLOT( SLOT_Stdout(Opie::Core::OProcess*,char*,int) ) );
00546 
00547       connect( P, 
00548                SIGNAL( receivedStderr(Opie::Core::OProcess*, char*, int ) ),
00549                this, 
00550                SLOT( SLOT_Stderr(Opie::Core::OProcess*,char*,int) ) );
00551       connect( P, 
00552                SIGNAL( processExited(Opie::Core::OProcess*) ),
00553                this,
00554                SLOT( SLOT_ProcessExited(Opie::Core::OProcess*) ) );
00555 }
00556 
00557 MyProcess::~MyProcess() {
00558       delete P;
00559 }
00560 
00561 void MyProcess::SLOT_Stdout( Opie::Core::OProcess * , char * Buf, int len ) {
00562       if( EchoMode ) {
00563         write( 1, Buf, len );
00564         return;
00565       }
00566 
00567       char * LB = (char *)alloca( len + 1 );
00568       memcpy( LB, Buf, len );
00569       LB[len] = '\0';
00570 
00571       // now input is zero terminated
00572       StdoutBuffer += LB;
00573 
00574       odebug << "Received " << len << " bytes on stdout" << oendl;
00575       // see if we have some lines (allow empty lines)
00576       QStringList SL = QStringList::split( "\n", StdoutBuffer, TRUE );
00577 
00578       for( unsigned int i = 0; i < SL.count()-1; i ++ ) {
00579         Log(( "Stdout : \"%s\"\n", SL[i].latin1() ) );
00580         emit stdoutLine( SL[i] );
00581       }
00582 
00583       // last line is rest
00584       StdoutBuffer = SL[ SL.count()-1 ];
00585 }
00586 
00587 void MyProcess::SLOT_Stderr( Opie::Core::OProcess * , char * Buf, int len ) {
00588       if( EchoMode ) {
00589         write( 2, Buf, len );
00590         return;
00591       }
00592 
00593       char * LB = (char *)alloca( len + 1 );
00594       memcpy( LB, Buf, len );
00595       LB[len] = '\0';
00596 
00597       // now input is zero terminated
00598       StderrBuffer += LB;
00599 
00600       odebug << "Received " << len << " bytes on stderr" << oendl;
00601       // see if we have some lines (allow empty lines)
00602       QStringList SL = QStringList::split( "\n", StderrBuffer, TRUE );
00603 
00604       for( unsigned int i = 0; i < SL.count()-1; i ++ ) {
00605         Log(( "Stderr : \"%s\"\n", SL[i].latin1() ) );
00606         emit stderrLine( SL[i] );
00607       }
00608 
00609       // last line is rest
00610       StderrBuffer = SL[ SL.count()-1 ];
00611 }
00612 
00613 void MyProcess::SLOT_ProcessExited( Opie::Core::OProcess * ) {
00614       emit processExited( this );
00615 }

Generated on Sat Nov 5 16:17:54 2005 for OPIE by  doxygen 1.4.2