]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire.cc
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: acquire.cc,v 1.50 2004/03/17 05:17:11 mdz Exp $ 
   4 /* ###################################################################### 
   6    Acquire - File Acquiration 
   8    The core element for the schedule system is the concept of a named 
   9    queue. Each queue is unique and each queue has a name derived from the 
  10    URI. The degree of paralization can be controlled by how the queue 
  11    name is derived from the URI. 
  13    ##################################################################### */ 
  15 // Include Files                                                        /*{{{*/ 
  18 #include <apt-pkg/acquire.h> 
  19 #include <apt-pkg/acquire-item.h> 
  20 #include <apt-pkg/acquire-worker.h> 
  21 #include <apt-pkg/configuration.h> 
  22 #include <apt-pkg/error.h> 
  23 #include <apt-pkg/strutl.h> 
  24 #include <apt-pkg/fileutl.h> 
  40 #include <sys/select.h> 
  43 #include <sys/types.h> 
  50 // Acquire::pkgAcquire - Constructor                                    /*{{{*/ 
  51 // --------------------------------------------------------------------- 
  52 /* We grab some runtime state from the configuration space */ 
  53 pkgAcquire::pkgAcquire() : LockFD(-1), Queues(0), Workers(0), Configs(0), Log(NULL
), ToFetch(0), 
  54                            Debug(_config
->FindB("Debug::pkgAcquire",false)), 
  59 pkgAcquire::pkgAcquire(pkgAcquireStatus 
*Progress
) : LockFD(-1), Queues(0), Workers(0), 
  60                            Configs(0), Log(NULL
), ToFetch(0), 
  61                            Debug(_config
->FindB("Debug::pkgAcquire",false)), 
  67 void pkgAcquire::Initialize() 
  69    string 
const Mode 
= _config
->Find("Acquire::Queue-Mode","host"); 
  70    if (strcasecmp(Mode
.c_str(),"host") == 0) 
  71       QueueMode 
= QueueHost
; 
  72    if (strcasecmp(Mode
.c_str(),"access") == 0) 
  73       QueueMode 
= QueueAccess
; 
  75    // chown the auth.conf file as it will be accessed by our methods 
  76    std::string 
const SandboxUser 
= _config
->Find("APT::Sandbox::User"); 
  77    if (getuid() == 0 && SandboxUser
.empty() == false) // if we aren't root, we can't chown, so don't try it 
  79       struct passwd 
const * const pw 
= getpwnam(SandboxUser
.c_str()); 
  80       struct group 
const * const gr 
= getgrnam("root"); 
  81       if (pw 
!= NULL 
&& gr 
!= NULL
) 
  83          std::string 
const AuthConf 
= _config
->FindFile("Dir::Etc::netrc"); 
  84          if(AuthConf
.empty() == false && RealFileExists(AuthConf
) && 
  85                chown(AuthConf
.c_str(), pw
->pw_uid
, gr
->gr_gid
) != 0) 
  86             _error
->WarningE("SetupAPTPartialDirectory", "chown to %s:root of file %s failed", SandboxUser
.c_str(), AuthConf
.c_str()); 
  91 // Acquire::GetLock - lock directory and prepare for action             /*{{{*/ 
  92 static bool SetupAPTPartialDirectory(std::string 
const &grand
, std::string 
const &parent
) 
  94    std::string 
const partial 
= parent 
+ "partial"; 
  95    if (CreateAPTDirectoryIfNeeded(grand
, partial
) == false && 
  96          CreateAPTDirectoryIfNeeded(parent
, partial
) == false) 
  99    std::string 
const SandboxUser 
= _config
->Find("APT::Sandbox::User"); 
 100    if (getuid() == 0 && SandboxUser
.empty() == false) // if we aren't root, we can't chown, so don't try it 
 102       struct passwd 
const * const pw 
= getpwnam(SandboxUser
.c_str()); 
 103       struct group 
const * const gr 
= getgrnam("root"); 
 104       if (pw 
!= NULL 
&& gr 
!= NULL
) 
 106          // chown the partial dir 
 107          if(chown(partial
.c_str(), pw
->pw_uid
, gr
->gr_gid
) != 0) 
 108             _error
->WarningE("SetupAPTPartialDirectory", "chown to %s:root of directory %s failed", SandboxUser
.c_str(), partial
.c_str()); 
 111    if (chmod(partial
.c_str(), 0700) != 0) 
 112       _error
->WarningE("SetupAPTPartialDirectory", "chmod 0700 of directory %s failed", partial
.c_str()); 
 116 bool pkgAcquire::Setup(pkgAcquireStatus 
*Progress
, string 
const &Lock
) 
 121       string 
const listDir 
= _config
->FindDir("Dir::State::lists"); 
 122       if (SetupAPTPartialDirectory(_config
->FindDir("Dir::State"), listDir
) == false) 
 123          return _error
->Errno("Acquire", _("List directory %spartial is missing."), listDir
.c_str()); 
 124       string 
const archivesDir 
= _config
->FindDir("Dir::Cache::Archives"); 
 125       if (SetupAPTPartialDirectory(_config
->FindDir("Dir::Cache"), archivesDir
) == false) 
 126          return _error
->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir
.c_str()); 
 129    return GetLock(Lock
); 
 131 bool pkgAcquire::GetLock(std::string 
const &Lock
) 
 133    if (Lock
.empty() == true) 
 136    // check for existence and possibly create auxiliary directories 
 137    string 
const listDir 
= _config
->FindDir("Dir::State::lists"); 
 138    string 
const archivesDir 
= _config
->FindDir("Dir::Cache::Archives"); 
 142       if (SetupAPTPartialDirectory(_config
->FindDir("Dir::State"), listDir
) == false) 
 143          return _error
->Errno("Acquire", _("List directory %spartial is missing."), listDir
.c_str()); 
 145    if (Lock 
== archivesDir
) 
 147       if (SetupAPTPartialDirectory(_config
->FindDir("Dir::Cache"), archivesDir
) == false) 
 148          return _error
->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir
.c_str()); 
 151    if (_config
->FindB("Debug::NoLocking", false) == true) 
 154    // Lock the directory this acquire object will work in 
 155    LockFD 
= ::GetLock(flCombine(Lock
, "lock")); 
 157       return _error
->Error(_("Unable to lock directory %s"), Lock
.c_str()); 
 162 // Acquire::~pkgAcquire - Destructor                                    /*{{{*/ 
 163 // --------------------------------------------------------------------- 
 164 /* Free our memory, clean up the queues (destroy the workers) */ 
 165 pkgAcquire::~pkgAcquire() 
 174       MethodConfig 
*Jnk 
= Configs
; 
 175       Configs 
= Configs
->Next
; 
 180 // Acquire::Shutdown - Clean out the acquire object                     /*{{{*/ 
 181 // --------------------------------------------------------------------- 
 183 void pkgAcquire::Shutdown() 
 185    while (Items
.empty() == false) 
 187       if (Items
[0]->Status 
== Item::StatFetching
) 
 188          Items
[0]->Status 
= Item::StatError
; 
 195       Queues 
= Queues
->Next
; 
 200 // Acquire::Add - Add a new item                                        /*{{{*/ 
 201 // --------------------------------------------------------------------- 
 202 /* This puts an item on the acquire list. This list is mainly for tracking 
 204 void pkgAcquire::Add(Item 
*Itm
) 
 206    Items
.push_back(Itm
); 
 209 // Acquire::Remove - Remove a item                                      /*{{{*/ 
 210 // --------------------------------------------------------------------- 
 211 /* Remove an item from the acquire list. This is usually not used.. */ 
 212 void pkgAcquire::Remove(Item 
*Itm
) 
 216    for (ItemIterator I 
= Items
.begin(); I 
!= Items
.end();) 
 228 // Acquire::Add - Add a worker                                          /*{{{*/ 
 229 // --------------------------------------------------------------------- 
 230 /* A list of workers is kept so that the select loop can direct their FD 
 232 void pkgAcquire::Add(Worker 
*Work
) 
 234    Work
->NextAcquire 
= Workers
; 
 238 // Acquire::Remove - Remove a worker                                    /*{{{*/ 
 239 // --------------------------------------------------------------------- 
 240 /* A worker has died. This can not be done while the select loop is running 
 241    as it would require that RunFds could handling a changing list state and 
 243 void pkgAcquire::Remove(Worker 
*Work
) 
 248    Worker 
**I 
= &Workers
; 
 252          *I 
= (*I
)->NextAcquire
; 
 254          I 
= &(*I
)->NextAcquire
; 
 258 // Acquire::Enqueue - Queue an URI for fetching                         /*{{{*/ 
 259 // --------------------------------------------------------------------- 
 260 /* This is the entry point for an item. An item calls this function when 
 261    it is constructed which creates a queue (based on the current queue 
 262    mode) and puts the item in that queue. If the system is running then 
 263    the queue might be started. */ 
 264 void pkgAcquire::Enqueue(ItemDesc 
&Item
) 
 266    // Determine which queue to put the item in 
 267    const MethodConfig 
*Config
; 
 268    string Name 
= QueueName(Item
.URI
,Config
); 
 269    if (Name
.empty() == true) 
 272    // Find the queue structure 
 274    for (; I 
!= 0 && I
->Name 
!= Name
; I 
= I
->Next
); 
 277       I 
= new Queue(Name
,this); 
 285    // See if this is a local only URI 
 286    if (Config
->LocalOnly 
== true && Item
.Owner
->Complete 
== false) 
 287       Item
.Owner
->Local 
= true; 
 288    Item
.Owner
->Status 
= Item::StatIdle
; 
 290    // Queue it into the named queue 
 297       clog 
<< "Fetching " << Item
.URI 
<< endl
; 
 298       clog 
<< " to " << Item
.Owner
->DestFile 
<< endl
; 
 299       clog 
<< " Queue is: " << Name 
<< endl
; 
 303 // Acquire::Dequeue - Remove an item from all queues                    /*{{{*/ 
 304 // --------------------------------------------------------------------- 
 305 /* This is called when an item is finished being fetched. It removes it 
 306    from all the queues */ 
 307 void pkgAcquire::Dequeue(Item 
*Itm
) 
 312       clog 
<< "Dequeuing " << Itm
->DestFile 
<< endl
; 
 314    for (; I 
!= 0; I 
= I
->Next
) 
 320             clog 
<< "Dequeued from " << I
->Name 
<< endl
; 
 328 // Acquire::QueueName - Return the name of the queue for this URI       /*{{{*/ 
 329 // --------------------------------------------------------------------- 
 330 /* The string returned depends on the configuration settings and the 
 331    method parameters. Given something like http://foo.org/bar it can 
 332    return http://foo.org or http */ 
 333 string 
pkgAcquire::QueueName(string Uri
,MethodConfig 
const *&Config
) 
 337    Config 
= GetConfig(U
.Access
); 
 341    /* Single-Instance methods get exactly one queue per URI. This is 
 342       also used for the Access queue method  */ 
 343    if (Config
->SingleInstance 
== true || QueueMode 
== QueueAccess
) 
 346    string AccessSchema 
= U
.Access 
+ ':', 
 347         FullQueueName 
= AccessSchema 
+ U
.Host
; 
 348    unsigned int Instances 
= 0, SchemaLength 
= AccessSchema
.length(); 
 351    for (; I 
!= 0; I 
= I
->Next
) { 
 352       // if the queue already exists, re-use it 
 353       if (I
->Name 
== FullQueueName
) 
 354          return FullQueueName
; 
 356       if (I
->Name
.compare(0, SchemaLength
, AccessSchema
) == 0) 
 361       clog 
<< "Found " << Instances 
<< " instances of " << U
.Access 
<< endl
; 
 364    if (Instances 
>= (unsigned int)_config
->FindI("Acquire::QueueHost::Limit",10)) 
 367    return FullQueueName
; 
 370 // Acquire::GetConfig - Fetch the configuration information             /*{{{*/ 
 371 // --------------------------------------------------------------------- 
 372 /* This locates the configuration structure for an access method. If  
 373    a config structure cannot be found a Worker will be created to 
 375 pkgAcquire::MethodConfig 
*pkgAcquire::GetConfig(string Access
) 
 377    // Search for an existing config 
 379    for (Conf 
= Configs
; Conf 
!= 0; Conf 
= Conf
->Next
) 
 380       if (Conf
->Access 
== Access
) 
 383    // Create the new config class 
 384    Conf 
= new MethodConfig
; 
 385    Conf
->Access 
= Access
; 
 386    Conf
->Next 
= Configs
; 
 389    // Create the worker to fetch the configuration 
 391    if (Work
.Start() == false) 
 394    /* if a method uses DownloadLimit, we switch to SingleInstance mode */ 
 395    if(_config
->FindI("Acquire::"+Access
+"::Dl-Limit",0) > 0) 
 396       Conf
->SingleInstance 
= true; 
 401 // Acquire::SetFds - Deal with readable FDs                             /*{{{*/ 
 402 // --------------------------------------------------------------------- 
 403 /* Collect FDs that have activity monitors into the fd sets */ 
 404 void pkgAcquire::SetFds(int &Fd
,fd_set 
*RSet
,fd_set 
*WSet
) 
 406    for (Worker 
*I 
= Workers
; I 
!= 0; I 
= I
->NextAcquire
) 
 408       if (I
->InReady 
== true && I
->InFd 
>= 0) 
 412          FD_SET(I
->InFd
,RSet
); 
 414       if (I
->OutReady 
== true && I
->OutFd 
>= 0) 
 418          FD_SET(I
->OutFd
,WSet
); 
 423 // Acquire::RunFds - Deal with active FDs                               /*{{{*/ 
 424 // --------------------------------------------------------------------- 
 425 /* Dispatch active FDs over to the proper workers. It is very important 
 426    that a worker never be erased while this is running! The queue class 
 427    should never erase a worker except during shutdown processing. */ 
 428 void pkgAcquire::RunFds(fd_set 
*RSet
,fd_set 
*WSet
) 
 430    for (Worker 
*I 
= Workers
; I 
!= 0; I 
= I
->NextAcquire
) 
 432       if (I
->InFd 
>= 0 && FD_ISSET(I
->InFd
,RSet
) != 0) 
 434       if (I
->OutFd 
>= 0 && FD_ISSET(I
->OutFd
,WSet
) != 0) 
 439 // Acquire::Run - Run the fetch sequence                                /*{{{*/ 
 440 // --------------------------------------------------------------------- 
 441 /* This runs the queues. It manages a select loop for all of the 
 442    Worker tasks. The workers interact with the queues and items to 
 443    manage the actual fetch. */ 
 444 pkgAcquire::RunResult 
pkgAcquire::Run(int PulseIntervall
) 
 448    for (Queue 
*I 
= Queues
; I 
!= 0; I 
= I
->Next
) 
 454    bool WasCancelled 
= false; 
 456    // Run till all things have been acquired 
 459    tv
.tv_usec 
= PulseIntervall
;  
 467       SetFds(Highest
,&RFds
,&WFds
); 
 472          Res 
= select(Highest
+1,&RFds
,&WFds
,0,&tv
); 
 474       while (Res 
< 0 && errno 
== EINTR
); 
 478          _error
->Errno("select","Select has failed"); 
 483       if (_error
->PendingError() == true) 
 486       // Timeout, notify the log class 
 487       if (Res 
== 0 || (Log 
!= 0 && Log
->Update 
== true)) 
 489          tv
.tv_usec 
= PulseIntervall
; 
 490          for (Worker 
*I 
= Workers
; I 
!= 0; I 
= I
->NextAcquire
) 
 492          if (Log 
!= 0 && Log
->Pulse(this) == false) 
 503    // Shut down the acquire bits 
 505    for (Queue 
*I 
= Queues
; I 
!= 0; I 
= I
->Next
) 
 508    // Shut down the items 
 509    for (ItemIterator I 
= Items
.begin(); I 
!= Items
.end(); ++I
) 
 512    if (_error
->PendingError()) 
 519 // Acquire::Bump - Called when an item is dequeued                      /*{{{*/ 
 520 // --------------------------------------------------------------------- 
 521 /* This routine bumps idle queues in hopes that they will be able to fetch 
 523 void pkgAcquire::Bump() 
 525    for (Queue 
*I 
= Queues
; I 
!= 0; I 
= I
->Next
) 
 529 // Acquire::WorkerStep - Step to the next worker                        /*{{{*/ 
 530 // --------------------------------------------------------------------- 
 531 /* Not inlined to advoid including acquire-worker.h */ 
 532 pkgAcquire::Worker 
*pkgAcquire::WorkerStep(Worker 
*I
) 
 534    return I
->NextAcquire
; 
 537 // Acquire::Clean - Cleans a directory                                  /*{{{*/ 
 538 // --------------------------------------------------------------------- 
 539 /* This is a bit simplistic, it looks at every file in the dir and sees 
 540    if it is part of the download set. */ 
 541 bool pkgAcquire::Clean(string Dir
) 
 543    // non-existing directories are by definition clean… 
 544    if (DirectoryExists(Dir
) == false) 
 548       return _error
->Error(_("Clean of %s is not supported"), Dir
.c_str()); 
 550    DIR *D 
= opendir(Dir
.c_str());    
 552       return _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str()); 
 554    string StartDir 
= SafeGetCWD(); 
 555    if (chdir(Dir
.c_str()) != 0) 
 558       return _error
->Errno("chdir",_("Unable to change to %s"),Dir
.c_str()); 
 561    for (struct dirent 
*Dir 
= readdir(D
); Dir 
!= 0; Dir 
= readdir(D
)) 
 564       if (strcmp(Dir
->d_name
,"lock") == 0 || 
 565           strcmp(Dir
->d_name
,"partial") == 0 || 
 566           strcmp(Dir
->d_name
,".") == 0 || 
 567           strcmp(Dir
->d_name
,"..") == 0) 
 570       // Look in the get list 
 571       ItemCIterator I 
= Items
.begin(); 
 572       for (; I 
!= Items
.end(); ++I
) 
 573          if (flNotDir((*I
)->DestFile
) == Dir
->d_name
) 
 576       // Nothing found, nuke it 
 577       if (I 
== Items
.end()) 
 582    if (chdir(StartDir
.c_str()) != 0) 
 583       return _error
->Errno("chdir",_("Unable to change to %s"),StartDir
.c_str()); 
 587 // Acquire::TotalNeeded - Number of bytes to fetch                      /*{{{*/ 
 588 // --------------------------------------------------------------------- 
 589 /* This is the total number of bytes needed */ 
 590 APT_PURE 
unsigned long long pkgAcquire::TotalNeeded() 
 592    unsigned long long Total 
= 0; 
 593    for (ItemCIterator I 
= ItemsBegin(); I 
!= ItemsEnd(); ++I
) 
 594       Total 
+= (*I
)->FileSize
; 
 598 // Acquire::FetchNeeded - Number of bytes needed to get                 /*{{{*/ 
 599 // --------------------------------------------------------------------- 
 600 /* This is the number of bytes that is not local */ 
 601 APT_PURE 
unsigned long long pkgAcquire::FetchNeeded() 
 603    unsigned long long Total 
= 0; 
 604    for (ItemCIterator I 
= ItemsBegin(); I 
!= ItemsEnd(); ++I
) 
 605       if ((*I
)->Local 
== false) 
 606          Total 
+= (*I
)->FileSize
; 
 610 // Acquire::PartialPresent - Number of partial bytes we already have    /*{{{*/ 
 611 // --------------------------------------------------------------------- 
 612 /* This is the number of bytes that is not local */ 
 613 APT_PURE 
unsigned long long pkgAcquire::PartialPresent() 
 615   unsigned long long Total 
= 0; 
 616    for (ItemCIterator I 
= ItemsBegin(); I 
!= ItemsEnd(); ++I
) 
 617       if ((*I
)->Local 
== false) 
 618          Total 
+= (*I
)->PartialSize
; 
 622 // Acquire::UriBegin - Start iterator for the uri list                  /*{{{*/ 
 623 // --------------------------------------------------------------------- 
 625 pkgAcquire::UriIterator 
pkgAcquire::UriBegin() 
 627    return UriIterator(Queues
); 
 630 // Acquire::UriEnd - End iterator for the uri list                      /*{{{*/ 
 631 // --------------------------------------------------------------------- 
 633 pkgAcquire::UriIterator 
pkgAcquire::UriEnd() 
 635    return UriIterator(0); 
 638 // Acquire::MethodConfig::MethodConfig - Constructor                    /*{{{*/ 
 639 // --------------------------------------------------------------------- 
 641 pkgAcquire::MethodConfig::MethodConfig() : d(NULL
), Next(0), SingleInstance(false), 
 642    Pipeline(false), SendConfig(false), LocalOnly(false), NeedsCleanup(false), 
 647 // Queue::Queue - Constructor                                           /*{{{*/ 
 648 // --------------------------------------------------------------------- 
 650 pkgAcquire::Queue::Queue(string Name
,pkgAcquire 
*Owner
) : d(NULL
), Next(0), 
 651    Name(Name
), Items(0), Workers(0), Owner(Owner
), PipeDepth(0), MaxPipeDepth(1) 
 655 // Queue::~Queue - Destructor                                           /*{{{*/ 
 656 // --------------------------------------------------------------------- 
 658 pkgAcquire::Queue::~Queue() 
 670 // Queue::Enqueue - Queue an item to the queue                          /*{{{*/ 
 671 // --------------------------------------------------------------------- 
 673 bool pkgAcquire::Queue::Enqueue(ItemDesc 
&Item
) 
 676    // move to the end of the queue and check for duplicates here 
 677    for (; *I 
!= 0; I 
= &(*I
)->Next
) 
 678       if (Item
.URI 
== (*I
)->URI
)  
 680          Item
.Owner
->Status 
= Item::StatDone
; 
 685    QItem 
*Itm 
= new QItem
; 
 690    Item
.Owner
->QueueCounter
++;    
 691    if (Items
->Next 
== 0) 
 696 // Queue::Dequeue - Remove an item from the queue                       /*{{{*/ 
 697 // --------------------------------------------------------------------- 
 698 /* We return true if we hit something */ 
 699 bool pkgAcquire::Queue::Dequeue(Item 
*Owner
) 
 701    if (Owner
->Status 
== pkgAcquire::Item::StatFetching
) 
 702       return _error
->Error("Tried to dequeue a fetching object"); 
 709       if ((*I
)->Owner 
== Owner
) 
 713          Owner
->QueueCounter
--; 
 724 // Queue::Startup - Start the worker processes                          /*{{{*/ 
 725 // --------------------------------------------------------------------- 
 726 /* It is possible for this to be called with a pre-existing set of 
 728 bool pkgAcquire::Queue::Startup() 
 733       pkgAcquire::MethodConfig 
*Cnf 
= Owner
->GetConfig(U
.Access
); 
 737       Workers 
= new Worker(this,Cnf
,Owner
->Log
); 
 739       if (Workers
->Start() == false) 
 742       /* When pipelining we commit 10 items. This needs to change when we 
 743          added other source retry to have cycle maintain a pipeline depth 
 745       if (Cnf
->Pipeline 
== true) 
 746          MaxPipeDepth 
= _config
->FindI("Acquire::Max-Pipeline-Depth",10); 
 754 // Queue::Shutdown - Shutdown the worker processes                      /*{{{*/ 
 755 // --------------------------------------------------------------------- 
 756 /* If final is true then all workers are eliminated, otherwise only workers 
 757    that do not need cleanup are removed */ 
 758 bool pkgAcquire::Queue::Shutdown(bool Final
) 
 760    // Delete all of the workers 
 761    pkgAcquire::Worker 
**Cur 
= &Workers
; 
 764       pkgAcquire::Worker 
*Jnk 
= *Cur
; 
 765       if (Final 
== true || Jnk
->GetConf()->NeedsCleanup 
== false) 
 767          *Cur 
= Jnk
->NextQueue
; 
 772          Cur 
= &(*Cur
)->NextQueue
;       
 778 // Queue::FindItem - Find a URI in the item list                        /*{{{*/ 
 779 // --------------------------------------------------------------------- 
 781 pkgAcquire::Queue::QItem 
*pkgAcquire::Queue::FindItem(string URI
,pkgAcquire::Worker 
*Owner
) 
 783    for (QItem 
*I 
= Items
; I 
!= 0; I 
= I
->Next
) 
 784       if (I
->URI 
== URI 
&& I
->Worker 
== Owner
) 
 789 // Queue::ItemDone - Item has been completed                            /*{{{*/ 
 790 // --------------------------------------------------------------------- 
 791 /* The worker signals this which causes the item to be removed from the 
 792    queue. If this is the last queue instance then it is removed from the 
 794 bool pkgAcquire::Queue::ItemDone(QItem 
*Itm
) 
 797    if (Itm
->Owner
->Status 
== pkgAcquire::Item::StatFetching
) 
 798       Itm
->Owner
->Status 
= pkgAcquire::Item::StatDone
; 
 800    if (Itm
->Owner
->QueueCounter 
<= 1) 
 801       Owner
->Dequeue(Itm
->Owner
); 
 811 // Queue::Cycle - Queue new items into the method                       /*{{{*/ 
 812 // --------------------------------------------------------------------- 
 813 /* This locates a new idle item and sends it to the worker. If pipelining 
 814    is enabled then it keeps the pipe full. */ 
 815 bool pkgAcquire::Queue::Cycle() 
 817    if (Items 
== 0 || Workers 
== 0) 
 821       return _error
->Error("Pipedepth failure"); 
 823    // Look for a queable item 
 825    while (PipeDepth 
< (signed)MaxPipeDepth
) 
 827       for (; I 
!= 0; I 
= I
->Next
) 
 828          if (I
->Owner
->Status 
== pkgAcquire::Item::StatIdle
) 
 831       // Nothing to do, queue is idle. 
 836       I
->Owner
->Status 
= pkgAcquire::Item::StatFetching
; 
 838       if (Workers
->QueueItem(I
) == false) 
 845 // Queue::Bump - Fetch any pending objects if we are idle               /*{{{*/ 
 846 // --------------------------------------------------------------------- 
 847 /* This is called when an item in multiple queues is dequeued */ 
 848 void pkgAcquire::Queue::Bump() 
 853 // AcquireStatus::pkgAcquireStatus - Constructor                        /*{{{*/ 
 854 // --------------------------------------------------------------------- 
 856 pkgAcquireStatus::pkgAcquireStatus() : d(NULL
), Percent(0), Update(true), MorePulses(false) 
 861 // AcquireStatus::Pulse - Called periodically                           /*{{{*/ 
 862 // --------------------------------------------------------------------- 
 863 /* This computes some internal state variables for the derived classes to 
 864    use. It generates the current downloaded bytes and total bytes to download 
 865    as well as the current CPS estimate. */ 
 866 bool pkgAcquireStatus::Pulse(pkgAcquire 
*Owner
) 
 873    // Compute the total number of bytes to fetch 
 874    unsigned int Unknown 
= 0; 
 875    unsigned int Count 
= 0; 
 876    bool UnfetchedReleaseFiles 
= false; 
 877    for (pkgAcquire::ItemCIterator I 
= Owner
->ItemsBegin();  
 878         I 
!= Owner
->ItemsEnd(); 
 882       if ((*I
)->Status 
== pkgAcquire::Item::StatDone
) 
 885       // Totally ignore local items 
 886       if ((*I
)->Local 
== true) 
 889       // see if the method tells us to expect more 
 890       TotalItems 
+= (*I
)->ExpectedAdditionalItems
; 
 892       // check if there are unfetched Release files 
 893       if ((*I
)->Complete 
== false && (*I
)->ExpectedAdditionalItems 
> 0) 
 894          UnfetchedReleaseFiles 
= true; 
 896       TotalBytes 
+= (*I
)->FileSize
; 
 897       if ((*I
)->Complete 
== true) 
 898          CurrentBytes 
+= (*I
)->FileSize
; 
 899       if ((*I
)->FileSize 
== 0 && (*I
)->Complete 
== false) 
 903    // Compute the current completion 
 904    unsigned long long ResumeSize 
= 0; 
 905    for (pkgAcquire::Worker 
*I 
= Owner
->WorkersBegin(); I 
!= 0; 
 906         I 
= Owner
->WorkerStep(I
)) 
 908       if (I
->CurrentItem 
!= 0 && I
->CurrentItem
->Owner
->Complete 
== false) 
 910          CurrentBytes 
+= I
->CurrentSize
; 
 911          ResumeSize 
+= I
->ResumePoint
; 
 913          // Files with unknown size always have 100% completion 
 914          if (I
->CurrentItem
->Owner
->FileSize 
== 0 &&  
 915              I
->CurrentItem
->Owner
->Complete 
== false) 
 916             TotalBytes 
+= I
->CurrentSize
; 
 920    // Normalize the figures and account for unknown size downloads 
 923    if (Unknown 
== Count
) 
 924       TotalBytes 
= Unknown
; 
 926    // Wha?! Is not supposed to happen. 
 927    if (CurrentBytes 
> TotalBytes
) 
 928       CurrentBytes 
= TotalBytes
; 
 931    if (_config
->FindB("Debug::acquire::progress", false) == true) 
 932       std::clog 
<< " Bytes: "  
 933                 << SizeToStr(CurrentBytes
) << " / " << SizeToStr(TotalBytes
)  
 937    struct timeval NewTime
; 
 938    gettimeofday(&NewTime
,0); 
 939    if ((NewTime
.tv_sec 
- Time
.tv_sec 
== 6 && NewTime
.tv_usec 
> Time
.tv_usec
) || 
 940        NewTime
.tv_sec 
- Time
.tv_sec 
> 6) 
 942       double Delta 
= NewTime
.tv_sec 
- Time
.tv_sec 
+  
 943                      (NewTime
.tv_usec 
- Time
.tv_usec
)/1000000.0; 
 945       // Compute the CPS value 
 949          CurrentCPS 
= ((CurrentBytes 
- ResumeSize
) - LastBytes
)/Delta
; 
 950       LastBytes 
= CurrentBytes 
- ResumeSize
; 
 951       ElapsedTime 
= (unsigned long long)Delta
; 
 955    // calculate the percentage, if we have too little data assume 1% 
 956    if (TotalBytes 
> 0 && UnfetchedReleaseFiles
) 
 959       // use both files and bytes because bytes can be unreliable 
 960       Percent 
= (0.8 * (CurrentBytes
/float(TotalBytes
)*100.0) +  
 961                  0.2 * (CurrentItems
/float(TotalItems
)*100.0)); 
 963    int fd 
= _config
->FindI("APT::Status-Fd",-1); 
 966       ostringstream status
; 
 969       long i 
= CurrentItems 
< TotalItems 
? CurrentItems 
+ 1 : CurrentItems
; 
 970       unsigned long long ETA 
= 0; 
 972          ETA 
= (TotalBytes 
- CurrentBytes
) / CurrentCPS
; 
 974       // only show the ETA if it makes sense 
 975       if (ETA 
> 0 && ETA 
< 172800 /* two days */ ) 
 976          snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li (%s remaining)"), i
, TotalItems
, TimeToStr(ETA
).c_str()); 
 978          snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li"), i
, TotalItems
); 
 980       // build the status str 
 981       status 
<< "dlstatus:" << i
 
 982              << ":"  << std::setprecision(3) << Percent
 
 986       std::string 
const dlstatus 
= status
.str(); 
 987       FileFd::Write(fd
, dlstatus
.c_str(), dlstatus
.size()); 
 993 // AcquireStatus::Start - Called when the download is started           /*{{{*/ 
 994 // --------------------------------------------------------------------- 
 995 /* We just reset the counters */ 
 996 void pkgAcquireStatus::Start() 
 998    gettimeofday(&Time
,0); 
 999    gettimeofday(&StartTime
,0); 
1010 // AcquireStatus::Stop - Finished downloading                           /*{{{*/ 
1011 // --------------------------------------------------------------------- 
1012 /* This accurately computes the elapsed time and the total overall CPS. */ 
1013 void pkgAcquireStatus::Stop() 
1015    // Compute the CPS and elapsed time 
1016    struct timeval NewTime
; 
1017    gettimeofday(&NewTime
,0); 
1019    double Delta 
= NewTime
.tv_sec 
- StartTime
.tv_sec 
+  
1020                   (NewTime
.tv_usec 
- StartTime
.tv_usec
)/1000000.0; 
1022    // Compute the CPS value 
1026       CurrentCPS 
= FetchedBytes
/Delta
; 
1027    LastBytes 
= CurrentBytes
; 
1028    ElapsedTime 
= (unsigned long long)Delta
; 
1031 // AcquireStatus::Fetched - Called when a byte set has been fetched     /*{{{*/ 
1032 // --------------------------------------------------------------------- 
1033 /* This is used to get accurate final transfer rate reporting. */ 
1034 void pkgAcquireStatus::Fetched(unsigned long long Size
,unsigned long long Resume
) 
1036    FetchedBytes 
+= Size 
- Resume
; 
1040 APT_CONST 
pkgAcquire::UriIterator::~UriIterator() {} 
1041 APT_CONST 
pkgAcquire::MethodConfig::~MethodConfig() {} 
1042 APT_CONST 
pkgAcquireStatus::~pkgAcquireStatus() {}