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
00028
00029
00030
00031 #include "oipkg.h"
00032
00033 #include <qdir.h>
00034 #include <qfile.h>
00035 #include <qtextstream.h>
00036
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039
00040 extern "C" {
00041 #include <libipkg.h>
00042 };
00043 args_t m_ipkgArgs;
00044
00045 const QString IPKG_CONF = "/etc/ipkg.conf";
00046 const QString IPKG_CONF_DIR = "/etc/ipkg";
00047 const QString IPKG_PKG_PATH = "/usr/lib/ipkg/lists";
00048 const QString IPKG_STATUS_PATH = "usr/lib/ipkg/status";
00049 const QString IPKG_INFO_PATH = "usr/lib/ipkg/info";
00050
00051 OIpkg *oipkg;
00052
00053
00054
00055 int fsignalIpkgMessage( ipkg_conf_t *conf, message_level_t level, char *msg )
00056 {
00057
00058 if ( conf && ( conf->verbosity < level ) )
00059 return 0;
00060 else
00061 oipkg->ipkgMessage( msg );
00062
00063 return 0;
00064 }
00065
00066 char *fIpkgResponse( char * )
00067 {
00068 return 0l;
00069 }
00070
00071 int fIpkgStatus( char *, int , char *desc, void * )
00072 {
00073 oipkg->ipkgStatus( desc );
00074 return 0;
00075 }
00076
00077 int fIpkgFiles( char *, char *desc, char *, pkg_state_status_t ,
00078 void * )
00079 {
00080 oipkg->ipkgList( desc );
00081 return 0;
00082 }
00083
00084 OIpkg::OIpkg( Config *config, QObject *parent, const char *name )
00085 : QObject( parent, name )
00086 , m_config( config )
00087 , m_confInfo( NULL )
00088 , m_ipkgExecOptions( 0 )
00089 , m_ipkgExecVerbosity( 1 )
00090 {
00091
00092 oipkg = this;
00093
00094
00095 ipkg_init( &fsignalIpkgMessage, &fIpkgResponse, &m_ipkgArgs );
00096
00097
00098 m_ipkgArgs.noaction = false;
00099 m_ipkgArgs.force_defaults = true;
00100 }
00101
00102 OIpkg::~OIpkg()
00103 {
00104
00105 if ( m_confInfo )
00106 m_confInfo->setAutoDelete( true );
00107
00108
00109 ipkg_deinit( &m_ipkgArgs );
00110 }
00111
00112 OConfItemList *OIpkg::configItems()
00113 {
00114
00115 return filterConfItems();
00116 }
00117
00118 OConfItemList *OIpkg::servers()
00119 {
00120
00121 return filterConfItems( OConfItem::Source );
00122 }
00123
00124 OConfItemList *OIpkg::destinations()
00125 {
00126
00127 return filterConfItems( OConfItem::Destination );
00128 }
00129
00130 OConfItemList *OIpkg::options()
00131 {
00132
00133 return filterConfItems( OConfItem::Option );
00134 }
00135
00136 void OIpkg::setConfigItems( OConfItemList *configList )
00137 {
00138 if ( m_confInfo )
00139 delete m_confInfo;
00140
00141 m_confInfo = configList;
00142
00143
00144 QFile confFile( IPKG_CONF );
00145 if ( confFile.open( IO_WriteOnly ) )
00146 {
00147 QTextStream confStream( &confFile );
00148 confStream << "# Generated by Opie Package Manager\n\n";
00149
00150 OConfItemListIterator it( *m_confInfo );
00151 for ( ; it.current(); ++it )
00152 {
00153 OConfItem *item = it.current();
00154
00155
00156 if ( item->type() != OConfItem::NotDefined )
00157 {
00158 QString confLine;
00159 QString name = item->name();
00160 if ( !item->active() )
00161 confLine = "#";
00162
00163 switch ( item->type() )
00164 {
00165 case OConfItem::Source :
00166 {
00167 if ( item->features().contains( "Compressed" ) )
00168 confLine.append( "src/gz" );
00169 else
00170 confLine.append( "src" );
00171 }
00172 break;
00173 case OConfItem::Destination : confLine.append( "dest" ); break;
00174 case OConfItem::Option : confLine.append( "option" ); break;
00175 case OConfItem::Arch : confLine.append( "arch" ); break;
00176 case OConfItem::Other :
00177 {
00178
00179
00180
00181
00182 confLine.append( item->name() );
00183 name = item->features();
00184 }
00185 break;
00186 default : break;
00187 };
00188
00189 confStream << confLine << " " << name << " " << item->value() << "\n";
00190 }
00191 }
00192
00193 confFile.close();
00194 }
00195 else
00196 {
00197
00198 return;
00199 }
00200
00201
00202 QStringList confFiles;
00203 QDir confDir( IPKG_CONF_DIR );
00204 if ( confDir.exists() )
00205 {
00206 confDir.setNameFilter( "*.conf" );
00207 confDir.setFilter( QDir::Files );
00208 confFiles = confDir.entryList( "*.conf", QDir::Files );
00209
00210 QStringList::Iterator lastFile = confFiles.end();
00211 for ( QStringList::Iterator it = confFiles.begin(); it != lastFile; ++it )
00212 {
00213
00214 QString absFile = (*it);
00215 if ( !absFile.startsWith( "/" ) )
00216 absFile.prepend( QString( IPKG_CONF_DIR ) + "/" );
00217
00218
00219 QFile::remove( absFile );
00220 }
00221 }
00222
00223
00224 ipkg_deinit( &m_ipkgArgs );
00225 ipkg_init( &fsignalIpkgMessage, &fIpkgResponse, &m_ipkgArgs );
00226 m_ipkgArgs.noaction = false;
00227 m_ipkgArgs.force_defaults = true;
00228 }
00229
00230 void OIpkg::saveSettings()
00231 {
00232
00233 if ( m_config )
00234 {
00235 m_config->setGroup( "Ipkg" );
00236 m_config->writeEntry( "ExecOptions", m_ipkgExecOptions );
00237 m_config->writeEntry( "Verbosity", m_ipkgExecVerbosity );
00238 }
00239 }
00240
00241 OPackageList *OIpkg::availablePackages( const QString &server )
00242 {
00243
00244 if ( !m_confInfo )
00245 loadConfiguration();
00246
00247
00248 OPackageList *pl = new OPackageList;
00249
00250
00251 QString listsDir;
00252 OConfItem *confItem = findConfItem( OConfItem::Other, "lists_dir" );
00253 if ( confItem )
00254 listsDir = confItem->value();
00255 else
00256 listsDir = IPKG_PKG_PATH;
00257
00258
00259 QFile f( listsDir + "/" + server );
00260 if ( !f.open( IO_ReadOnly ) )
00261 return NULL;
00262 QTextStream t( &f );
00263
00264
00265 OPackage *package = NULL;
00266 QString line = t.readLine();
00267 while ( !t.eof() )
00268 {
00269
00270 int pos = line.find( ':', 0 );
00271 QString key;
00272 if ( pos > -1 )
00273 key = line.mid( 0, pos );
00274 else
00275 key = QString::null;
00276 QString value = line.mid( pos+2, line.length()-pos );
00277
00278
00279 if ( package == NULL && !key.isEmpty() )
00280 {
00281 package = new OPackage( value );
00282 package->setSource( server );
00283 pl->append( package );
00284 }
00285
00286
00287 if ( key == "Package" )
00288 package->setName( value );
00289 else if ( key == "Version" )
00290 package->setVersion( value );
00291 else if ( key == "Section" )
00292 package->setCategory( value );
00293
00294 else if ( key.isEmpty() && value.isEmpty() )
00295 package = NULL;
00296
00297
00298 if ( key == "Description" )
00299 {
00300 line = t.readLine();
00301 while ( !line.isEmpty() && line.find( ':', 0 ) == -1 && !t.eof() )
00302 line = t.readLine();
00303 }
00304 else
00305 line = t.readLine();
00306 }
00307
00308 f.close();
00309
00310 return pl;
00311 }
00312
00313 OPackageList *OIpkg::installedPackages( const QString &destName, const QString &destPath )
00314 {
00315
00316 if ( !m_confInfo )
00317 loadConfiguration();
00318
00319
00320 OPackageList *pl = new OPackageList;
00321
00322
00323 QString path = destPath;
00324 if ( path.right( 1 ) != "/" )
00325 path.append( "/" );
00326 path.append( IPKG_STATUS_PATH );
00327
00328 QFile f( path );
00329 if ( !f.open( IO_ReadOnly ) )
00330 return NULL;
00331 QTextStream t( &f );
00332
00333
00334 bool newPackage = false;
00335 QString line = t.readLine();
00336 QString name;
00337 QString version;
00338 QString status;
00339
00340 while ( !t.eof() )
00341 {
00342
00343 int pos = line.find( ':', 0 );
00344 QString key;
00345 if ( pos > -1 )
00346 key = line.mid( 0, pos );
00347 else
00348 key = QString::null;
00349 QString value = line.mid( pos+2, line.length()-pos );
00350
00351
00352 if ( newPackage && !key.isEmpty() )
00353 {
00354
00355 if ( !name.isNull() && status.contains( " installed" ) )
00356 {
00357 pl->append( new OPackage( name, QString::null, version, QString::null, destName ) );
00358 name = QString::null;
00359 version = QString::null;
00360 status = QString::null;
00361
00362 newPackage = false;
00363 }
00364 }
00365
00366
00367 if ( key == "Package" )
00368 name = value;
00369 else if ( key == "Version" )
00370 version = value;
00371 else if ( key == "Status" )
00372 status = value;
00373 else if ( key.isEmpty() && value.isEmpty() )
00374 newPackage = true;
00375
00376
00377 if ( key == "Description" )
00378 {
00379 line = t.readLine();
00380 while ( !line.isEmpty() && line.find( ':', 0 ) == -1 && !t.eof() )
00381 line = t.readLine();
00382 }
00383 else
00384 line = t.readLine();
00385 }
00386
00387 f.close();
00388
00389
00390 if ( !name.isNull() && status.contains( " installed" ) )
00391 pl->append( new OPackage( name, QString::null, version, QString::null, destName ) );
00392
00393 return pl;
00394 }
00395
00396 OConfItem *OIpkg::findConfItem( OConfItem::Type type, const QString &name )
00397 {
00398
00399 OConfItemListIterator configIt( *m_confInfo );
00400 OConfItem *config = 0l;
00401 for ( ; configIt.current(); ++configIt )
00402 {
00403 config = configIt.current();
00404 if ( config->type() == type && config->name() == name )
00405 break;
00406 }
00407
00408 if ( config && config->type() == type && config->name() == name )
00409 return config;
00410
00411 return 0l;
00412 }
00413
00414 bool OIpkg::executeCommand( OPackage::Command command, const QStringList ¶meters, const QString &destination,
00415 const QObject *receiver, const char *slotOutput, bool rawOutput )
00416 {
00417 if ( command == OPackage::NotDefined )
00418 return false;
00419
00420
00421 m_ipkgArgs.force_depends = ( m_ipkgExecOptions & FORCE_DEPENDS );
00422 m_ipkgArgs.force_reinstall = ( m_ipkgExecOptions & FORCE_REINSTALL );
00423
00424 m_ipkgArgs.force_overwrite = ( m_ipkgExecOptions & FORCE_OVERWRITE );
00425 m_ipkgArgs.verbosity = m_ipkgExecVerbosity;
00426 if ( m_ipkgArgs.dest )
00427 free( m_ipkgArgs.dest );
00428 if ( !destination.isNull() )
00429 {
00430 int len = destination.length() + 1;
00431 m_ipkgArgs.dest = (char *)malloc( len );
00432 strncpy( m_ipkgArgs.dest, destination, destination.length() );
00433 m_ipkgArgs.dest[ len - 1 ] = '\0';
00434 }
00435 else
00436 m_ipkgArgs.dest = 0l;
00437
00438
00439
00440 if ( !rawOutput )
00441 {
00442
00443 }
00444
00445 switch( command )
00446 {
00447 case OPackage::Update : {
00448 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00449 ipkg_lists_update( &m_ipkgArgs );
00450 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00451 };
00452 break;
00453 case OPackage::Upgrade : {
00454 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00455 ipkg_packages_upgrade( &m_ipkgArgs );
00456
00457
00458 OConfItemList *destList = destinations();
00459 OConfItemListIterator it( *destList );
00460 for ( ; it.current(); ++it )
00461 {
00462 OConfItem *dest = it.current();
00463 if ( dest->name() != "root" )
00464 linkPackageDir( dest->name() );
00465 }
00466 delete destList;
00467 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00468 };
00469 break;
00470 case OPackage::Install : {
00471 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00472 for ( QStringList::ConstIterator it = parameters.begin(); it != parameters.end(); ++it )
00473 {
00474 ipkg_packages_install( &m_ipkgArgs, (*it) );
00475 }
00476 if ( destination != "root" )
00477 linkPackageDir( destination );
00478 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00479 };
00480 break;
00481 case OPackage::Remove : {
00482 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00483
00484
00485 OConfItemList *destList = destinations();
00486
00487 for ( QStringList::ConstIterator it = parameters.begin(); it != parameters.end(); ++it )
00488 {
00489 unlinkPackage( (*it), destList );
00490 ipkg_packages_remove( &m_ipkgArgs, (*it), true );
00491 }
00492
00493 delete destList;
00494 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00495 };
00496 break;
00497 case OPackage::Download : {
00498 connect( this, SIGNAL(signalIpkgMessage(const QString &)), receiver, slotOutput );
00499 for ( QStringList::ConstIterator it = parameters.begin(); it != parameters.end(); ++it )
00500 {
00501 ipkg_packages_download( &m_ipkgArgs, (*it) );
00502 }
00503 disconnect( this, SIGNAL(signalIpkgMessage(const QString &)), 0, 0 );
00504 };
00505 break;
00506 case OPackage::Info : {
00507 connect( this, SIGNAL(signalIpkgStatus(const QString &)), receiver, slotOutput );
00508 ipkg_packages_info( &m_ipkgArgs, (*parameters.begin()), &fIpkgStatus, 0l );
00509 disconnect( this, SIGNAL(signalIpkgStatus(const QString &)), 0, 0 );
00510 };
00511 break;
00512 case OPackage::Files : {
00513 connect( this, SIGNAL(signalIpkgList(const QString &)), receiver, slotOutput );
00514 ipkg_package_files( &m_ipkgArgs, (*parameters.begin()), &fIpkgFiles, 0l );
00515 disconnect( this, SIGNAL(signalIpkgList(const QString &)), 0, 0 );
00516 };
00517 break;
00518 default : break;
00519 };
00520
00521 return true;
00522 }
00523
00524 void OIpkg::ipkgMessage( char *msg )
00525 {
00526 emit signalIpkgMessage( msg );
00527 }
00528
00529 void OIpkg::ipkgStatus( char *status )
00530 {
00531 emit signalIpkgStatus( status );
00532 }
00533
00534 void OIpkg::ipkgList( char *filelist )
00535 {
00536 emit signalIpkgList( filelist );
00537 }
00538
00539 void OIpkg::loadConfiguration()
00540 {
00541 if ( m_confInfo )
00542 delete m_confInfo;
00543
00544
00545 m_confInfo = new OConfItemList();
00546
00547 QStringList confFiles;
00548 QDir confDir( IPKG_CONF_DIR );
00549 if ( confDir.exists() )
00550 {
00551 confDir.setNameFilter( "*.conf" );
00552 confDir.setFilter( QDir::Files );
00553 confFiles = confDir.entryList( "*.conf", QDir::Files );
00554 }
00555 confFiles << IPKG_CONF;
00556
00557 QStringList::Iterator lastFile = confFiles.end();
00558 for ( QStringList::Iterator it = confFiles.begin(); it != lastFile; ++it )
00559 {
00560
00561 QString absFile = (*it);
00562 if ( !absFile.startsWith( "/" ) )
00563 absFile.prepend( QString( IPKG_CONF_DIR ) + "/" );
00564
00565
00566 QFile f( absFile );
00567 if ( f.open( IO_ReadOnly ) )
00568 {
00569 QTextStream s( &f );
00570 while ( !s.eof() )
00571 {
00572
00573 QString line = s.readLine().simplifyWhiteSpace();
00574
00575
00576 if ( !line.isEmpty() )
00577 {
00578
00579 bool comment = false;
00580 if ( line.startsWith( "#" ) )
00581 {
00582 line.remove( 0, 1 );
00583 line = line.simplifyWhiteSpace();
00584 comment = true;
00585 }
00586
00587 bool recognizedOption = true;
00588 int pos = line.find( ' ', 1 ) + 1;
00589 int endpos = line.find( ' ', pos );
00590
00591
00592 QString name = line.mid( pos, endpos - pos );
00593
00594
00595 QString value = "";
00596 if ( endpos > -1 )
00597 value = line.right( line.length() - endpos - 1 );
00598
00599
00600 bool active = !comment;
00601
00602
00603
00604
00605
00606
00607
00608 QString typeStr = line.left( pos - 1 );
00609 OConfItem::Type type;
00610 QString features;
00611 if ( typeStr == "src" )
00612 type = OConfItem::Source;
00613 else if ( typeStr == "src/gz" )
00614 {
00615 type = OConfItem::Source;
00616 features = "Compressed";
00617 }
00618 else if ( typeStr == "dest" )
00619 type = OConfItem::Destination;
00620 else if ( typeStr == "option" )
00621 type = OConfItem::Option;
00622 else if ( typeStr == "arch" )
00623 type = OConfItem::Arch;
00624 else if ( typeStr == "lists_dir" )
00625 {
00626 type = OConfItem::Other;
00627 features = name;
00628 name = typeStr;
00629
00630
00631 if ( value == QString::null || value == "" )
00632 value = IPKG_PKG_PATH;
00633 }
00634 else
00635 recognizedOption = false;
00636
00637
00638 if ( recognizedOption )
00639 m_confInfo->append( new OConfItem( type, name, value, features, active ) );
00640 }
00641 }
00642
00643 f.close();
00644 }
00645 }
00646
00647
00648 if ( m_config )
00649 {
00650 m_config->setGroup( "Ipkg" );
00651 m_ipkgExecOptions = m_config->readNumEntry( "ExecOptions", m_ipkgExecOptions );
00652 m_ipkgExecVerbosity = m_config->readNumEntry( "Verbosity", m_ipkgExecVerbosity );
00653 }
00654 }
00655
00656 OConfItemList *OIpkg::filterConfItems( OConfItem::Type typefilter )
00657 {
00658
00659 if ( !m_confInfo )
00660 loadConfiguration();
00661
00662
00663 OConfItemList *sl = new OConfItemList;
00664
00665
00666 bool retrieveAll = ( typefilter == OConfItem::NotDefined );
00667
00668
00669 OConfItemListIterator it( *m_confInfo );
00670 for ( ; it.current(); ++it )
00671 {
00672 OConfItem *item = it.current();
00673 if ( retrieveAll || item->type() == typefilter )
00674 {
00675 sl->append( item );
00676 }
00677 }
00678
00679 return sl;
00680 }
00681
00682 const QString &OIpkg::rootPath()
00683 {
00684 if ( m_rootPath.isEmpty() )
00685 {
00686 OConfItem *rootDest = findConfItem( OConfItem::Destination, "root" );
00687 rootDest ? m_rootPath = rootDest->value()
00688 : m_rootPath = '/';
00689 if ( m_rootPath.right( 1 ) == '/' )
00690 m_rootPath.truncate( m_rootPath.length() - 1 );
00691 }
00692 return m_rootPath;
00693 }
00694
00695 void OIpkg::linkPackageDir( const QString &dest )
00696 {
00697 if ( !dest.isNull() )
00698 {
00699 OConfItem *destConfItem = findConfItem( OConfItem::Destination, dest );
00700
00701 emit signalIpkgMessage( tr( "Linking packages installed in: %1" ).arg( dest ) );
00702
00703
00704 QString destDir = destConfItem->value();
00705 QString destInfoDir = destDir;
00706 if ( destInfoDir.right( 1 ) != '/' )
00707 destInfoDir.append( '/' );
00708 destInfoDir.append( IPKG_INFO_PATH );
00709
00710
00711 QDir packageDir( destInfoDir );
00712 QStringList packageFiles;
00713 if ( packageDir.exists() )
00714 {
00715 packageDir.setNameFilter( "*.list" );
00716 packageDir.setFilter( QDir::Files );
00717 packageFiles = packageDir.entryList( "*.list", QDir::Files );
00718 }
00719
00720
00721 QStringList::Iterator lastFile = packageFiles.end();
00722 for ( QStringList::Iterator it = packageFiles.begin(); it != lastFile; ++it )
00723 {
00724
00725 QString packageFileName = destInfoDir;
00726 packageFileName.append( '/' );
00727 packageFileName.append( (*it) );
00728 QFile packageFile( packageFileName );
00729 if ( packageFile.open( IO_ReadOnly ) )
00730 {
00731 QTextStream t( &packageFile );
00732 QString linkFile;
00733 while ( !t.eof() )
00734 {
00735
00736 linkFile = t.readLine();
00737 QString linkDest( linkFile.right( linkFile.length() - destDir.length() ) );
00738 linkDest.prepend( rootPath() );
00739
00740
00741 QFileInfo fileInfo( linkFile );
00742 if ( fileInfo.isSymLink() && !fileInfo.readLink().isEmpty() )
00743 linkFile = fileInfo.readLink();
00744
00745
00746 fileInfo.setFile( linkDest );
00747 QString linkDestDirName = fileInfo.dirPath( true );
00748 QDir linkDestDir( linkDestDirName );
00749 if ( !linkDestDir.exists() )
00750 {
00751 linkDestDir.mkdir( linkDestDirName );
00752 }
00753 else
00754 {
00755
00756 if ( QFile::exists( linkDest ) )
00757 QFile::remove( linkDest );
00758 }
00759
00760
00761
00762 if ( symlink( linkFile, linkDest ) == -1 )
00763 emit signalIpkgMessage( tr( "Error linkling '%1' to '%2'" )
00764 .arg( linkFile )
00765 .arg( linkDest ) );
00766 }
00767 packageFile.close();
00768 }
00769 }
00770 }
00771 }
00772
00773 void OIpkg::unlinkPackage( const QString &package, OConfItemList *destList )
00774 {
00775 if ( !package.isNull() )
00776 {
00777
00778 if ( destList )
00779 {
00780 OConfItemListIterator it( *destList );
00781 for ( ; it.current(); ++it )
00782 {
00783 OConfItem *dest = it.current();
00784 QString destInfoFileName = QString( "%1/%2/%3.list" ).arg( dest->value() )
00785 .arg( IPKG_INFO_PATH )
00786 .arg( package );
00787
00788
00789
00790 if ( QFile::exists( destInfoFileName ) && dest->name() != "root" )
00791 {
00792 QFile destInfoFile( destInfoFileName );
00793 if ( destInfoFile.open( IO_ReadOnly ) )
00794 {
00795 QTextStream t( &destInfoFile );
00796 QString linkFile;
00797 while ( !t.eof() )
00798 {
00799
00800 linkFile = t.readLine();
00801 QString linkDest( linkFile.right( linkFile.length() -
00802 dest->value().length() ) );
00803 linkDest.prepend( rootPath() );
00804
00805
00806 QFile::remove( linkDest );
00807 }
00808 destInfoFile.close();
00809 }
00810
00811 emit signalIpkgMessage( tr( "Links removed for: %1" ).arg( package ) );
00812 return;
00813 }
00814 }
00815 }
00816 }
00817 }