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

ipkg.cpp

Go to the documentation of this file.
00001 /*
00002                              This file is part of the OPIE Project
00003 
00004                =.            Copyright (c)  2002 Andy Qua <andy.qua@blueyonder.co.uk>
00005              .=l.                                Dan Williams <drw@handhelds.org>
00006            .>+-=
00007  _;:,     .>    :=|.         This file is free software; you can
00008 .> <`_,   >  .   <=          redistribute it and/or modify it under
00009 :`=1 )Y*s>-.--   :           the terms of the GNU General Public
00010 .="- .-=="i,     .._         License as published by the Free Software
00011  - .   .-<_>     .<>         Foundation; either version 2 of the License,
00012      ._= =}       :          or (at your option) any later version.
00013     .%`+i>       _;_.
00014     .i_,=:_.      -<s.       This file is distributed in the hope that
00015      +  .  -:.       =       it will be useful, but WITHOUT ANY WARRANTY;
00016     : ..    .:,     . . .    without even the implied warranty of
00017     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00018   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU General
00019 ..}^=.=       =       ;      Public License for more details.
00020 ++=   -.     .`     .:
00021  :     =  ...= . :.=-        You should have received a copy of the GNU
00022  -.   .:....=;==+<;          General Public License along with this file;
00023   -_. . .   )=.  =           see the file COPYING. If not, write to the
00024     --        :-=`           Free Software Foundation, Inc.,
00025                              59 Temple Place - Suite 330,
00026                              Boston, MA 02111-1307, USA.
00027 
00028 */
00029 
00030 #include <opie2/oprocess.h>
00031 
00032 #ifdef QWS
00033 #include <qpe/qpeapplication.h>
00034 #else
00035 #include <qapplication.h>
00036 #endif
00037 #include <qdir.h>
00038 #include <qfile.h>
00039 #include <qtextstream.h>
00040 
00041 #include "utils.h"
00042 #include "ipkg.h"
00043 #include "global.h"
00044 
00045 using namespace Opie::Core;
00046 Ipkg :: Ipkg()
00047 {
00048     proc = 0;
00049 }
00050 
00051 Ipkg :: ~Ipkg()
00052 {
00053 }
00054 
00055 // Option is what we are going to do - install, upgrade, download, reinstall
00056 // package is the package name to install - either a fully qualified path and ipk
00057 //   file (if stored locally) or just the name of the package (for a network package)
00058 // packageName is the package name - (for a network package this will be the same as
00059 //    package parameter)
00060 // dest is the destination alias (from ipk.conf)
00061 // destDir is the dir that the destination alias points to (used to link to root)
00062 // flags is the ipkg options flags
00063 // dir is the directory to run ipkg in (defaults to "")
00064 void Ipkg :: runIpkg()
00065 {
00066     error = false;
00067     QStringList commands;
00068 
00069     QDir::setCurrent( "/tmp" );
00070 
00071     if ( runtimeDir != "" )
00072     {
00073         commands << "cd ";
00074         commands << runtimeDir;
00075         commands << ";";
00076     }
00077     commands << "ipkg" << "-V" << QString::number( infoLevel ) << "-force-defaults";
00078 
00079     // only set the destination for an install operation
00080     if ( option == "install" )
00081         commands << "-dest" << destination;
00082 
00083 
00084     if ( option != "update" && option != "download" )
00085     {
00086         if ( flags & FORCE_DEPENDS )
00087             commands << "-force-depends";
00088         if ( flags & FORCE_REINSTALL  )
00089             commands << "-force-reinstall";
00090         if ( flags & FORCE_REMOVE )
00091             commands << "-force-removal-of-essential-packages";
00092         if ( flags & FORCE_OVERWRITE )
00093             commands << "-force-overwrite";
00094         if ( infoLevel == 3 )
00095             commands << "-verbose_wget";
00096 
00097         // Handle make links
00098         // Rules - If make links is switched on, create links to root
00099         // if destDir is NOT /
00100         if ( flags & MAKE_LINKS )
00101         {
00102             // If destDir == / turn off make links as package is being insalled
00103             // to root already.
00104             if ( destDir == "/" )
00105                 flags ^= MAKE_LINKS;
00106         }
00107     }
00108 
00109 #ifdef X86
00110     commands << "-f";
00111     commands << IPKG_CONF;
00112 #endif
00113 
00114 
00115     if ( option == "reinstall" )
00116         commands << "install";
00117     else
00118         commands << option;
00119     if ( package != "" )
00120         commands << package;
00121 
00122 
00123     if ( package != "" )
00124         emit outputText( tr( "Dealing with package %1" ).arg( package) );
00125 
00126     qApp->processEvents();
00127 
00128     // If we are removing, reinstalling or upgrading packages and make links option is selected
00129     // create the links
00130     if ( option == "remove" || option == "reinstall" || option == "upgrade" )
00131     {
00132         createLinks = false;
00133         if ( flags & MAKE_LINKS )
00134         {
00135             emit outputText( tr( "Removing symbolic links...\n" ) );
00136             linkPackage( Utils::getPackageNameFromIpkFilename( package ), destination, destDir );
00137             emit outputText( QString( " " ) );
00138         }
00139     }
00140 
00141     // Execute command
00142     dependantPackages = new QList<QString>;
00143     dependantPackages->setAutoDelete( true );
00144 
00145     executeIpkgCommand( commands, option );
00146 }
00147 
00148 void Ipkg :: createSymLinks()
00149 {
00150     if ( option == "install" || option == "reinstall" || option == "upgrade" )
00151     {
00152         // If we are not removing packages and make links option is selected
00153         // create the links
00154         createLinks = true;
00155         if ( flags & MAKE_LINKS )
00156         {
00157             emit outputText( " " );
00158             emit outputText( tr( "Creating symbolic links for %1." ).arg( package) );
00159 
00160             linkPackage( Utils::getPackageNameFromIpkFilename( package ), destination, destDir );
00161 
00162             // link dependant packages that were installed with this release
00163             QString *pkg;
00164             for ( pkg = dependantPackages->first(); pkg != 0; pkg = dependantPackages->next() )
00165             {
00166                 if ( *pkg == package )
00167                     continue;
00168                 emit outputText( " " );
00169                 emit outputText( tr( "Creating symbolic links for %1" ).arg( *pkg ) );
00170                 linkPackage( Utils::getPackageNameFromIpkFilename( *pkg ), destination, destDir );
00171             }
00172         }
00173     }
00174 
00175     delete dependantPackages;
00176 
00177     emit outputText( tr("Finished") );
00178     emit outputText( "" );
00179 }
00180 
00181 void Ipkg :: removeStatusEntry()
00182 {
00183     QString statusFile = destDir;
00184     if ( statusFile.right( 1 ) != "/" )
00185         statusFile.append( "/" );
00186     statusFile.append( "usr/lib/ipkg/status" );
00187     QString outStatusFile = statusFile;
00188     outStatusFile.append( ".tmp" );
00189 
00190     emit outputText( "" );
00191     emit outputText( tr("Removing status entry...") );
00192     QString tempstr = tr("status file - ");
00193     tempstr.append( statusFile );
00194     emit outputText( tempstr );
00195     tempstr = tr("package - ");
00196     tempstr.append( package );
00197     emit outputText( tempstr );
00198 
00199     QFile readFile( statusFile );
00200     QFile writeFile( outStatusFile );
00201 
00202     if ( !readFile.open( IO_ReadOnly ) )
00203     {
00204         tempstr = tr("Couldn't open status file - ");
00205         tempstr.append( statusFile );
00206         emit outputText( tempstr );
00207         return;
00208     }
00209 
00210     if ( !writeFile.open( IO_WriteOnly ) )
00211     {
00212         tempstr = tr("Couldn't create tempory status file - ");
00213         tempstr.append( outStatusFile );
00214         emit outputText( tempstr );
00215         return;
00216     }
00217 
00218     int i = 0;
00219 
00220     QTextStream readStream( &readFile );
00221     QTextStream writeStream( &writeFile );
00222     QString line;
00223 
00224     char k[21];
00225     char v[1001];
00226     QString key;
00227     QString value;
00228 
00229     while ( !readStream.atEnd() )
00230     {
00231         //read new line
00232         line = readStream.readLine();
00233 
00234         if ( line.contains( ":", TRUE ) )
00235         {
00236             //grep key and value from line
00237             k[0] = '\0';
00238             v[0] = '\0';
00239             sscanf( line, "%[^:]: %[^\n]", k, v );
00240             key = k;
00241             value = v;
00242             key = key.stripWhiteSpace();
00243             value = value.stripWhiteSpace();
00244         } else {
00245             key = "";
00246             value = "";
00247         }
00248 
00249         if ( key == "Package" && value == package )
00250         {
00251             //skip lines from the deleted package
00252             while ( ( !readStream.atEnd() ) && ( line.stripWhiteSpace() != "" ) )
00253             {
00254                 line = readStream.readLine();
00255             }
00256         } else {
00257 
00258             //write other lines into the tempfile
00259             writeStream << line << "\n";
00260 
00261             // Improve UI responsiveness
00262             i++;
00263             if ( ( i % 50 ) == 0 )
00264                 qApp->processEvents();
00265         }
00266     }
00267 
00268     readFile.close();
00269     writeFile.close();
00270 
00271     // Remove old status file and put tmp stats file in its place
00272     remove( statusFile );
00273     rename( outStatusFile, statusFile );
00274  }
00275 
00276 int Ipkg :: executeIpkgLinkCommand( QStringList *cmd )
00277 {
00278     // If one is already running - should never be but just to be safe
00279     if ( proc )
00280     {
00281         delete proc;
00282         proc = 0;
00283     }
00284 
00285     // OK we're gonna use OProcess to run this thing
00286     proc = new OProcess();
00287     aborted = false;
00288 
00289     // Connect up our slots
00290     connect(proc, SIGNAL(processExited(Opie::Core::OProcess*)),
00291             this, SLOT( linkProcessFinished()));
00292     connect(proc, SIGNAL(receivedStdout(Opie::Core::OProcess*,char*,int)),
00293             this, SLOT(linkCommandStdout(Opie::Core::OProcess*,char*,int)));
00294 
00295      *proc << *cmd;
00296 
00297     if(!proc->start(OProcess::NotifyOnExit, OProcess::All))
00298     {
00299         emit outputText( tr("Couldn't start ipkg-link process" ) );
00300     }
00301 
00302     return 0;
00303 }
00304 
00305 void Ipkg::linkProcessFinished()
00306 {
00307     // Report that the link process succeeded/failed
00308 
00309     if ( error )
00310         emit outputText( tr("Symbolic linking failed!\n") );
00311     else
00312         emit outputText( tr("Symbolic linking succeeded.\n") );
00313 
00314     delete proc;
00315     proc = 0;
00316     finished = true;
00317 }
00318 
00319 void Ipkg::linkCommandStdout(OProcess*, char *buffer, int buflen)
00320 {
00321     QString lineStr = buffer;
00322     if ( lineStr[buflen-1] == '\n' )
00323         buflen --;
00324     lineStr = lineStr.left( buflen );
00325     emit outputText( lineStr );
00326 
00327     if ( lineStr.find( " not found." ) != -1 )
00328     {
00329         // Capture ipkg-link errors
00330         error = true;
00331     }
00332 
00333     buffer[0] = '\0';
00334 }
00335 
00336 int Ipkg :: executeIpkgCommand( QStringList &cmd, const QString /*option*/ )
00337 {
00338     // If one is already running - should never be but just to be safe
00339     if ( proc )
00340     {
00341         delete proc;
00342         proc = 0;
00343     }
00344 
00345     // OK we're gonna use OProcess to run this thing
00346     proc = new OProcess();
00347     aborted = false;
00348 
00349 
00350     // Connect up our slots
00351     connect(proc, SIGNAL(processExited(Opie::Core::OProcess*)),
00352             this, SLOT( processFinished()));
00353 
00354     connect(proc, SIGNAL(receivedStdout(Opie::Core::OProcess*,char*,int)),
00355             this, SLOT(commandStdout(Opie::Core::OProcess*,char*,int)));
00356 
00357     connect(proc, SIGNAL(receivedStderr(Opie::Core::OProcess*,char*,int)),
00358             this, SLOT(commandStderr(Opie::Core::OProcess*,char*,int)));
00359 
00360     for ( QStringList::Iterator it = cmd.begin(); it != cmd.end(); ++it )
00361     {
00362          *proc << (*it).latin1();
00363     }
00364 
00365     // Start the process going
00366     finished = false;
00367     if(!proc->start(OProcess::NotifyOnExit, OProcess::All))
00368     {
00369         emit outputText( tr("Couldn't start ipkg process" ) );
00370     }
00371 
00372     return 0;
00373 }
00374 
00375 void Ipkg::commandStdout(OProcess*, char *buffer, int buflen)
00376 {
00377     QString lineStr = buffer;
00378     if ( lineStr[buflen-1] == '\n' )
00379         buflen --;
00380     lineStr = lineStr.left( buflen );
00381     emit outputText( lineStr );
00382 
00383     // check if we are installing dependant packages
00384     if ( option == "install" || option == "reinstall" )
00385     {
00386         // Need to keep track of any dependant packages that get installed
00387         // so that we can create links to them as necessary
00388         if ( lineStr.startsWith( "Installing " ) )
00389         {
00390             int start = lineStr.find( " " ) + 1;
00391             int end = lineStr.find( " ", start );
00392             QString *package = new QString( lineStr.mid( start, end-start ) );
00393             dependantPackages->append( package );
00394         }
00395     }
00396     else if ( option == "remove" && !( flags & FORCE_DEPENDS ) &&
00397               lineStr.find( "is depended upon by packages:" ) != -1 )
00398     {
00399         // Ipkg should send this to STDERR, but doesn't - so trap here
00400         error = true;
00401     }
00402 
00403     buffer[0] = '\0';
00404 }
00405 
00406 void Ipkg::commandStderr(OProcess*, char *buffer, int buflen)
00407 {
00408     QString lineStr = buffer;
00409     if ( lineStr[buflen-1] == '\n' )
00410         buflen --;
00411     lineStr=lineStr.left( buflen );
00412     emit outputText( lineStr );
00413     buffer[0] = '\0';
00414     error = true;
00415 }
00416 
00417 void Ipkg::processFinished()
00418 {
00419     // Finally, if we are removing a package, remove its entry from the <destdir>/usr/lib/ipkg/status file
00420     // to workaround an ipkg bug which stops reinstall to a different location
00421 
00422     if ( !error && option == "remove" )
00423         removeStatusEntry();
00424 
00425     delete proc;
00426     proc = 0;
00427     finished = true;
00428 
00429     emit ipkgFinished();
00430 }
00431 
00432 
00433 void Ipkg :: abort()
00434 {
00435     if ( proc )
00436     {
00437         proc->kill();
00438         aborted = true;
00439     }
00440 }
00441 
00442 void Ipkg :: linkPackage( const QString &packFileName, const QString &dest, const QString &destDir )
00443 {
00444     Q_CONST_UNUSED( destDir )
00445     if ( dest == "root" || dest == "/" )
00446         return;
00447 
00448     if( option == "remove" || option == "reinstall" || option == "upgrade" )
00449     {
00450         QStringList commands;
00451 
00452         if ( runtimeDir != "" )
00453         {
00454             commands << "cd ";
00455             commands << runtimeDir;
00456             commands << ";";
00457         }
00458         commands << "ipkg-link" << "remove" << packFileName;
00459         executeIpkgLinkCommand( &commands );
00460     }
00461 
00462     if( option == "install" || option == "reinstall" || option == "upgrade" )
00463     {
00464         QStringList commands;
00465         if ( runtimeDir != "" )
00466         {
00467             commands << "cd ";
00468             commands << runtimeDir;
00469             commands << ";";
00470         }
00471         commands << "ipkg-link" << "add" << packFileName;
00472         executeIpkgLinkCommand( &commands );
00473     }
00474 /*
00475     qApp->processEvents();
00476     QStringList *fileList = getList( packFileName, destDir );
00477     qApp->processEvents();
00478     processFileList( fileList, destDir );
00479     delete fileList;*/
00480 }
00481 /*
00482 QStringList* Ipkg :: getList( const QString &packageFilename, const QString &destDir )
00483 {
00484     QString packageFileDir = destDir;
00485     packageFileDir.append( "/usr/lib/ipkg/info/" );
00486     packageFileDir.append( packageFilename );
00487     packageFileDir.append( ".list" );
00488     QFile f( packageFileDir );
00489 
00490     if ( !f.open(IO_ReadOnly) )
00491     {
00492         // Couldn't open from dest, try from /
00493         f.close();
00494 
00495         packageFileDir = "/usr/lib/ipkg/info/";
00496         packageFileDir.append( packageFilename );
00497         packageFileDir.append( ".list" );
00498         f.setName( packageFileDir );
00499         if ( ! f.open(IO_ReadOnly) )
00500         {
00501             QString tempstr = tr("Could not open :");
00502             tempstr.append( packageFileDir );
00503             emit outputText( tempstr );
00504             return (QStringList*)0;
00505         }
00506     }
00507     QStringList *fileList = new QStringList();
00508     QTextStream t( &f );
00509     while ( !t.eof() )
00510         *fileList += t.readLine();
00511 
00512     f.close();
00513     return fileList;
00514 }
00515 
00516 void Ipkg :: processFileList( const QStringList *fileList, const QString &destDir )
00517 {
00518     if ( !fileList || fileList->isEmpty() )
00519         return;
00520 
00521     QString baseDir = ROOT;
00522 
00523     if ( createLinks == true )
00524     {
00525         for ( uint i=0; i < fileList->count(); i++ )
00526         {
00527             processLinkDir( (*fileList)[i], baseDir, destDir );
00528             qApp->processEvents();
00529         }
00530     }
00531     else
00532     {
00533         for ( int i = fileList->count()-1; i >= 0 ; i-- )
00534         {
00535             processLinkDir( (*fileList)[i], baseDir, destDir );
00536             qApp->processEvents();
00537         }
00538     }
00539 }
00540 
00541 void Ipkg :: processLinkDir( const QString &file, const QString &destDir, const QString &baseDir )
00542 {
00543 
00544     QString sourceFile = baseDir;
00545     sourceFile.append( file );
00546 
00547     QString linkFile = destDir;
00548     if ( file.startsWith( "/" ) && destDir.right( 1 ) == "/" )
00549     {
00550         linkFile.append( file.mid( 1 ) );
00551     }
00552     else
00553     {
00554         linkFile.append( file );
00555     }
00556     QString text;
00557     if ( createLinks )
00558     {
00559         // If this file is a directory (ends with a /) and it doesn't exist,
00560         // we need to create it
00561         if ( file.right(1) == "/" )
00562         {
00563             QFileInfo f( linkFile );
00564             if ( !f.exists() )
00565             {
00566                 QString tempstr = tr("Creating directory ");
00567                 tempstr.append( linkFile );
00568                 emit outputText( tempstr );
00569                 QDir d;
00570                 d.mkdir( linkFile, true );
00571             }
00572 //            else
00573 //                emit outputText( QString( "Directory " ) + linkFile + " already exists" );
00574 
00575         }
00576         else
00577         {
00578             int rc = symlink( sourceFile, linkFile );
00579             text = ( rc == 0 ? tr( "Linked %1 to %2" ) : tr( "Failed to link %1 to %2" ) ).
00580                     arg( sourceFile ).
00581                     arg( linkFile );
00582             emit outputText( text );
00583         }
00584     }
00585     else
00586     {
00587         QFileInfo f( linkFile );
00588         if ( f.exists() )
00589         {
00590             if ( f.isFile() )
00591             {
00592                 QFile f( linkFile );
00593                 bool rc = f.remove();
00594 
00595                 text = ( rc ? tr( "Removed %1" ) : tr( "Failed to remove %1" ) ).arg( linkFile );
00596                 emit outputText( text );
00597             }
00598             else if ( f.isDir() )
00599             {
00600                 QDir d;
00601                 bool rc = d.rmdir( linkFile, true );
00602                 if ( rc )
00603                 {
00604                     text = ( rc ? tr( "Removed " ) : tr( "Failed to remove " ) ).arg( linkFile );
00605                     emit outputText( text );
00606                 }
00607             }
00608         }
00609     }
00610 }
00611 */

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