]>
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)),
57 string
const Mode
= _config
->Find("Acquire::Queue-Mode","host");
58 if (strcasecmp(Mode
.c_str(),"host") == 0)
59 QueueMode
= QueueHost
;
60 if (strcasecmp(Mode
.c_str(),"access") == 0)
61 QueueMode
= QueueAccess
;
63 pkgAcquire::pkgAcquire(pkgAcquireStatus
*Progress
) : LockFD(-1), Queues(0), Workers(0),
64 Configs(0), Log(NULL
), ToFetch(0),
65 Debug(_config
->FindB("Debug::pkgAcquire",false)),
68 string
const Mode
= _config
->Find("Acquire::Queue-Mode","host");
69 if (strcasecmp(Mode
.c_str(),"host") == 0)
70 QueueMode
= QueueHost
;
71 if (strcasecmp(Mode
.c_str(),"access") == 0)
72 QueueMode
= QueueAccess
;
76 // Acquire::GetLock - lock directory and prepare for action /*{{{*/
77 static bool SetupAPTPartialDirectory(std::string
const &grand
, std::string
const &parent
)
79 std::string
const partial
= parent
+ "partial";
80 if (CreateAPTDirectoryIfNeeded(grand
, partial
) == false &&
81 CreateAPTDirectoryIfNeeded(parent
, partial
) == false)
84 if (getuid() == 0) // if we aren't root, we can't chown, so don't try it
86 std::string SandboxUser
= _config
->Find("APT::Sandbox::User");
87 struct passwd
*pw
= getpwnam(SandboxUser
.c_str());
88 struct group
*gr
= getgrnam("root");
89 if (pw
!= NULL
&& gr
!= NULL
)
91 // chown the partial dir
92 if(chown(partial
.c_str(), pw
->pw_uid
, gr
->gr_gid
) != 0)
93 _error
->WarningE("SetupAPTPartialDirectory", "chown to %s:root of directory %s failed", SandboxUser
.c_str(), partial
.c_str());
94 // chown the auth.conf file
95 std::string AuthConf
= _config
->FindFile("Dir::Etc::netrc");
96 if(chown(AuthConf
.c_str(), pw
->pw_uid
, gr
->gr_gid
) != 0)
97 _error
->WarningE("SetupAPTPartialDirectory", "chown to %s:root of file %s failed", SandboxUser
.c_str(), AuthConf
.c_str());
100 if (chmod(partial
.c_str(), 0700) != 0)
101 _error
->WarningE("SetupAPTPartialDirectory", "chmod 0700 of directory %s failed", partial
.c_str());
105 bool pkgAcquire::Setup(pkgAcquireStatus
*Progress
, string
const &Lock
)
110 string
const listDir
= _config
->FindDir("Dir::State::lists");
111 if (SetupAPTPartialDirectory(_config
->FindDir("Dir::State"), listDir
) == false)
112 return _error
->Errno("Acquire", _("List directory %spartial is missing."), listDir
.c_str());
113 string
const archivesDir
= _config
->FindDir("Dir::Cache::Archives");
114 if (SetupAPTPartialDirectory(_config
->FindDir("Dir::Cache"), archivesDir
) == false)
115 return _error
->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir
.c_str());
118 return GetLock(Lock
);
120 bool pkgAcquire::GetLock(std::string
const &Lock
)
122 if (Lock
.empty() == true)
125 // check for existence and possibly create auxiliary directories
126 string
const listDir
= _config
->FindDir("Dir::State::lists");
127 string
const archivesDir
= _config
->FindDir("Dir::Cache::Archives");
131 if (SetupAPTPartialDirectory(_config
->FindDir("Dir::State"), listDir
) == false)
132 return _error
->Errno("Acquire", _("List directory %spartial is missing."), listDir
.c_str());
134 if (Lock
== archivesDir
)
136 if (SetupAPTPartialDirectory(_config
->FindDir("Dir::Cache"), archivesDir
) == false)
137 return _error
->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir
.c_str());
140 if (_config
->FindB("Debug::NoLocking", false) == true)
143 // Lock the directory this acquire object will work in
144 LockFD
= ::GetLock(flCombine(Lock
, "lock"));
146 return _error
->Error(_("Unable to lock directory %s"), Lock
.c_str());
151 // Acquire::~pkgAcquire - Destructor /*{{{*/
152 // ---------------------------------------------------------------------
153 /* Free our memory, clean up the queues (destroy the workers) */
154 pkgAcquire::~pkgAcquire()
163 MethodConfig
*Jnk
= Configs
;
164 Configs
= Configs
->Next
;
169 // Acquire::Shutdown - Clean out the acquire object /*{{{*/
170 // ---------------------------------------------------------------------
172 void pkgAcquire::Shutdown()
174 while (Items
.empty() == false)
176 if (Items
[0]->Status
== Item::StatFetching
)
177 Items
[0]->Status
= Item::StatError
;
184 Queues
= Queues
->Next
;
189 // Acquire::Add - Add a new item /*{{{*/
190 // ---------------------------------------------------------------------
191 /* This puts an item on the acquire list. This list is mainly for tracking
193 void pkgAcquire::Add(Item
*Itm
)
195 Items
.push_back(Itm
);
198 // Acquire::Remove - Remove a item /*{{{*/
199 // ---------------------------------------------------------------------
200 /* Remove an item from the acquire list. This is usually not used.. */
201 void pkgAcquire::Remove(Item
*Itm
)
205 for (ItemIterator I
= Items
.begin(); I
!= Items
.end();)
217 // Acquire::Add - Add a worker /*{{{*/
218 // ---------------------------------------------------------------------
219 /* A list of workers is kept so that the select loop can direct their FD
221 void pkgAcquire::Add(Worker
*Work
)
223 Work
->NextAcquire
= Workers
;
227 // Acquire::Remove - Remove a worker /*{{{*/
228 // ---------------------------------------------------------------------
229 /* A worker has died. This can not be done while the select loop is running
230 as it would require that RunFds could handling a changing list state and
232 void pkgAcquire::Remove(Worker
*Work
)
237 Worker
**I
= &Workers
;
241 *I
= (*I
)->NextAcquire
;
243 I
= &(*I
)->NextAcquire
;
247 // Acquire::Enqueue - Queue an URI for fetching /*{{{*/
248 // ---------------------------------------------------------------------
249 /* This is the entry point for an item. An item calls this function when
250 it is constructed which creates a queue (based on the current queue
251 mode) and puts the item in that queue. If the system is running then
252 the queue might be started. */
253 void pkgAcquire::Enqueue(ItemDesc
&Item
)
255 // Determine which queue to put the item in
256 const MethodConfig
*Config
;
257 string Name
= QueueName(Item
.URI
,Config
);
258 if (Name
.empty() == true)
261 // Find the queue structure
263 for (; I
!= 0 && I
->Name
!= Name
; I
= I
->Next
);
266 I
= new Queue(Name
,this);
274 // See if this is a local only URI
275 if (Config
->LocalOnly
== true && Item
.Owner
->Complete
== false)
276 Item
.Owner
->Local
= true;
277 Item
.Owner
->Status
= Item::StatIdle
;
279 // Queue it into the named queue
286 clog
<< "Fetching " << Item
.URI
<< endl
;
287 clog
<< " to " << Item
.Owner
->DestFile
<< endl
;
288 clog
<< " Queue is: " << Name
<< endl
;
292 // Acquire::Dequeue - Remove an item from all queues /*{{{*/
293 // ---------------------------------------------------------------------
294 /* This is called when an item is finished being fetched. It removes it
295 from all the queues */
296 void pkgAcquire::Dequeue(Item
*Itm
)
301 clog
<< "Dequeuing " << Itm
->DestFile
<< endl
;
303 for (; I
!= 0; I
= I
->Next
)
309 clog
<< "Dequeued from " << I
->Name
<< endl
;
317 // Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
318 // ---------------------------------------------------------------------
319 /* The string returned depends on the configuration settings and the
320 method parameters. Given something like http://foo.org/bar it can
321 return http://foo.org or http */
322 string
pkgAcquire::QueueName(string Uri
,MethodConfig
const *&Config
)
326 Config
= GetConfig(U
.Access
);
330 /* Single-Instance methods get exactly one queue per URI. This is
331 also used for the Access queue method */
332 if (Config
->SingleInstance
== true || QueueMode
== QueueAccess
)
335 string AccessSchema
= U
.Access
+ ':',
336 FullQueueName
= AccessSchema
+ U
.Host
;
337 unsigned int Instances
= 0, SchemaLength
= AccessSchema
.length();
340 for (; I
!= 0; I
= I
->Next
) {
341 // if the queue already exists, re-use it
342 if (I
->Name
== FullQueueName
)
343 return FullQueueName
;
345 if (I
->Name
.compare(0, SchemaLength
, AccessSchema
) == 0)
350 clog
<< "Found " << Instances
<< " instances of " << U
.Access
<< endl
;
353 if (Instances
>= (unsigned int)_config
->FindI("Acquire::QueueHost::Limit",10))
356 return FullQueueName
;
359 // Acquire::GetConfig - Fetch the configuration information /*{{{*/
360 // ---------------------------------------------------------------------
361 /* This locates the configuration structure for an access method. If
362 a config structure cannot be found a Worker will be created to
364 pkgAcquire::MethodConfig
*pkgAcquire::GetConfig(string Access
)
366 // Search for an existing config
368 for (Conf
= Configs
; Conf
!= 0; Conf
= Conf
->Next
)
369 if (Conf
->Access
== Access
)
372 // Create the new config class
373 Conf
= new MethodConfig
;
374 Conf
->Access
= Access
;
375 Conf
->Next
= Configs
;
378 // Create the worker to fetch the configuration
380 if (Work
.Start() == false)
383 /* if a method uses DownloadLimit, we switch to SingleInstance mode */
384 if(_config
->FindI("Acquire::"+Access
+"::Dl-Limit",0) > 0)
385 Conf
->SingleInstance
= true;
390 // Acquire::SetFds - Deal with readable FDs /*{{{*/
391 // ---------------------------------------------------------------------
392 /* Collect FDs that have activity monitors into the fd sets */
393 void pkgAcquire::SetFds(int &Fd
,fd_set
*RSet
,fd_set
*WSet
)
395 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
397 if (I
->InReady
== true && I
->InFd
>= 0)
401 FD_SET(I
->InFd
,RSet
);
403 if (I
->OutReady
== true && I
->OutFd
>= 0)
407 FD_SET(I
->OutFd
,WSet
);
412 // Acquire::RunFds - Deal with active FDs /*{{{*/
413 // ---------------------------------------------------------------------
414 /* Dispatch active FDs over to the proper workers. It is very important
415 that a worker never be erased while this is running! The queue class
416 should never erase a worker except during shutdown processing. */
417 void pkgAcquire::RunFds(fd_set
*RSet
,fd_set
*WSet
)
419 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
421 if (I
->InFd
>= 0 && FD_ISSET(I
->InFd
,RSet
) != 0)
423 if (I
->OutFd
>= 0 && FD_ISSET(I
->OutFd
,WSet
) != 0)
428 // Acquire::Run - Run the fetch sequence /*{{{*/
429 // ---------------------------------------------------------------------
430 /* This runs the queues. It manages a select loop for all of the
431 Worker tasks. The workers interact with the queues and items to
432 manage the actual fetch. */
433 pkgAcquire::RunResult
pkgAcquire::Run(int PulseIntervall
)
437 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
443 bool WasCancelled
= false;
445 // Run till all things have been acquired
448 tv
.tv_usec
= PulseIntervall
;
456 SetFds(Highest
,&RFds
,&WFds
);
461 Res
= select(Highest
+1,&RFds
,&WFds
,0,&tv
);
463 while (Res
< 0 && errno
== EINTR
);
467 _error
->Errno("select","Select has failed");
472 if (_error
->PendingError() == true)
475 // Timeout, notify the log class
476 if (Res
== 0 || (Log
!= 0 && Log
->Update
== true))
478 tv
.tv_usec
= PulseIntervall
;
479 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
481 if (Log
!= 0 && Log
->Pulse(this) == false)
492 // Shut down the acquire bits
494 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
497 // Shut down the items
498 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
501 if (_error
->PendingError())
508 // Acquire::Bump - Called when an item is dequeued /*{{{*/
509 // ---------------------------------------------------------------------
510 /* This routine bumps idle queues in hopes that they will be able to fetch
512 void pkgAcquire::Bump()
514 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
518 // Acquire::WorkerStep - Step to the next worker /*{{{*/
519 // ---------------------------------------------------------------------
520 /* Not inlined to advoid including acquire-worker.h */
521 pkgAcquire::Worker
*pkgAcquire::WorkerStep(Worker
*I
)
523 return I
->NextAcquire
;
526 // Acquire::Clean - Cleans a directory /*{{{*/
527 // ---------------------------------------------------------------------
528 /* This is a bit simplistic, it looks at every file in the dir and sees
529 if it is part of the download set. */
530 bool pkgAcquire::Clean(string Dir
)
532 // non-existing directories are by definition clean…
533 if (DirectoryExists(Dir
) == false)
537 return _error
->Error(_("Clean of %s is not supported"), Dir
.c_str());
539 DIR *D
= opendir(Dir
.c_str());
541 return _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
543 string StartDir
= SafeGetCWD();
544 if (chdir(Dir
.c_str()) != 0)
547 return _error
->Errno("chdir",_("Unable to change to %s"),Dir
.c_str());
550 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
553 if (strcmp(Dir
->d_name
,"lock") == 0 ||
554 strcmp(Dir
->d_name
,"partial") == 0 ||
555 strcmp(Dir
->d_name
,".") == 0 ||
556 strcmp(Dir
->d_name
,"..") == 0)
559 // Look in the get list
560 ItemCIterator I
= Items
.begin();
561 for (; I
!= Items
.end(); ++I
)
562 if (flNotDir((*I
)->DestFile
) == Dir
->d_name
)
565 // Nothing found, nuke it
566 if (I
== Items
.end())
571 if (chdir(StartDir
.c_str()) != 0)
572 return _error
->Errno("chdir",_("Unable to change to %s"),StartDir
.c_str());
576 // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
577 // ---------------------------------------------------------------------
578 /* This is the total number of bytes needed */
579 APT_PURE
unsigned long long pkgAcquire::TotalNeeded()
581 unsigned long long Total
= 0;
582 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
583 Total
+= (*I
)->FileSize
;
587 // Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
588 // ---------------------------------------------------------------------
589 /* This is the number of bytes that is not local */
590 APT_PURE
unsigned long long pkgAcquire::FetchNeeded()
592 unsigned long long Total
= 0;
593 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
594 if ((*I
)->Local
== false)
595 Total
+= (*I
)->FileSize
;
599 // Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
600 // ---------------------------------------------------------------------
601 /* This is the number of bytes that is not local */
602 APT_PURE
unsigned long long pkgAcquire::PartialPresent()
604 unsigned long long Total
= 0;
605 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
606 if ((*I
)->Local
== false)
607 Total
+= (*I
)->PartialSize
;
611 // Acquire::UriBegin - Start iterator for the uri list /*{{{*/
612 // ---------------------------------------------------------------------
614 pkgAcquire::UriIterator
pkgAcquire::UriBegin()
616 return UriIterator(Queues
);
619 // Acquire::UriEnd - End iterator for the uri list /*{{{*/
620 // ---------------------------------------------------------------------
622 pkgAcquire::UriIterator
pkgAcquire::UriEnd()
624 return UriIterator(0);
627 // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
628 // ---------------------------------------------------------------------
630 pkgAcquire::MethodConfig::MethodConfig() : d(NULL
), Next(0), SingleInstance(false),
631 Pipeline(false), SendConfig(false), LocalOnly(false), NeedsCleanup(false),
636 // Queue::Queue - Constructor /*{{{*/
637 // ---------------------------------------------------------------------
639 pkgAcquire::Queue::Queue(string Name
,pkgAcquire
*Owner
) : d(NULL
), Next(0),
640 Name(Name
), Items(0), Workers(0), Owner(Owner
), PipeDepth(0), MaxPipeDepth(1)
644 // Queue::~Queue - Destructor /*{{{*/
645 // ---------------------------------------------------------------------
647 pkgAcquire::Queue::~Queue()
659 // Queue::Enqueue - Queue an item to the queue /*{{{*/
660 // ---------------------------------------------------------------------
662 bool pkgAcquire::Queue::Enqueue(ItemDesc
&Item
)
665 // move to the end of the queue and check for duplicates here
666 for (; *I
!= 0; I
= &(*I
)->Next
)
667 if (Item
.URI
== (*I
)->URI
)
669 Item
.Owner
->Status
= Item::StatDone
;
674 QItem
*Itm
= new QItem
;
679 Item
.Owner
->QueueCounter
++;
680 if (Items
->Next
== 0)
685 // Queue::Dequeue - Remove an item from the queue /*{{{*/
686 // ---------------------------------------------------------------------
687 /* We return true if we hit something */
688 bool pkgAcquire::Queue::Dequeue(Item
*Owner
)
690 if (Owner
->Status
== pkgAcquire::Item::StatFetching
)
691 return _error
->Error("Tried to dequeue a fetching object");
698 if ((*I
)->Owner
== Owner
)
702 Owner
->QueueCounter
--;
713 // Queue::Startup - Start the worker processes /*{{{*/
714 // ---------------------------------------------------------------------
715 /* It is possible for this to be called with a pre-existing set of
717 bool pkgAcquire::Queue::Startup()
722 pkgAcquire::MethodConfig
*Cnf
= Owner
->GetConfig(U
.Access
);
726 Workers
= new Worker(this,Cnf
,Owner
->Log
);
728 if (Workers
->Start() == false)
731 /* When pipelining we commit 10 items. This needs to change when we
732 added other source retry to have cycle maintain a pipeline depth
734 if (Cnf
->Pipeline
== true)
735 MaxPipeDepth
= _config
->FindI("Acquire::Max-Pipeline-Depth",10);
743 // Queue::Shutdown - Shutdown the worker processes /*{{{*/
744 // ---------------------------------------------------------------------
745 /* If final is true then all workers are eliminated, otherwise only workers
746 that do not need cleanup are removed */
747 bool pkgAcquire::Queue::Shutdown(bool Final
)
749 // Delete all of the workers
750 pkgAcquire::Worker
**Cur
= &Workers
;
753 pkgAcquire::Worker
*Jnk
= *Cur
;
754 if (Final
== true || Jnk
->GetConf()->NeedsCleanup
== false)
756 *Cur
= Jnk
->NextQueue
;
761 Cur
= &(*Cur
)->NextQueue
;
767 // Queue::FindItem - Find a URI in the item list /*{{{*/
768 // ---------------------------------------------------------------------
770 pkgAcquire::Queue::QItem
*pkgAcquire::Queue::FindItem(string URI
,pkgAcquire::Worker
*Owner
)
772 for (QItem
*I
= Items
; I
!= 0; I
= I
->Next
)
773 if (I
->URI
== URI
&& I
->Worker
== Owner
)
778 // Queue::ItemDone - Item has been completed /*{{{*/
779 // ---------------------------------------------------------------------
780 /* The worker signals this which causes the item to be removed from the
781 queue. If this is the last queue instance then it is removed from the
783 bool pkgAcquire::Queue::ItemDone(QItem
*Itm
)
786 if (Itm
->Owner
->Status
== pkgAcquire::Item::StatFetching
)
787 Itm
->Owner
->Status
= pkgAcquire::Item::StatDone
;
789 if (Itm
->Owner
->QueueCounter
<= 1)
790 Owner
->Dequeue(Itm
->Owner
);
800 // Queue::Cycle - Queue new items into the method /*{{{*/
801 // ---------------------------------------------------------------------
802 /* This locates a new idle item and sends it to the worker. If pipelining
803 is enabled then it keeps the pipe full. */
804 bool pkgAcquire::Queue::Cycle()
806 if (Items
== 0 || Workers
== 0)
810 return _error
->Error("Pipedepth failure");
812 // Look for a queable item
814 while (PipeDepth
< (signed)MaxPipeDepth
)
816 for (; I
!= 0; I
= I
->Next
)
817 if (I
->Owner
->Status
== pkgAcquire::Item::StatIdle
)
820 // Nothing to do, queue is idle.
825 I
->Owner
->Status
= pkgAcquire::Item::StatFetching
;
827 if (Workers
->QueueItem(I
) == false)
834 // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
835 // ---------------------------------------------------------------------
836 /* This is called when an item in multiple queues is dequeued */
837 void pkgAcquire::Queue::Bump()
842 // AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
843 // ---------------------------------------------------------------------
845 pkgAcquireStatus::pkgAcquireStatus() : d(NULL
), Percent(0), Update(true), MorePulses(false)
850 // AcquireStatus::Pulse - Called periodically /*{{{*/
851 // ---------------------------------------------------------------------
852 /* This computes some internal state variables for the derived classes to
853 use. It generates the current downloaded bytes and total bytes to download
854 as well as the current CPS estimate. */
855 bool pkgAcquireStatus::Pulse(pkgAcquire
*Owner
)
862 // Compute the total number of bytes to fetch
863 unsigned int Unknown
= 0;
864 unsigned int Count
= 0;
865 bool UnfetchedReleaseFiles
= false;
866 for (pkgAcquire::ItemCIterator I
= Owner
->ItemsBegin();
867 I
!= Owner
->ItemsEnd();
871 if ((*I
)->Status
== pkgAcquire::Item::StatDone
)
874 // Totally ignore local items
875 if ((*I
)->Local
== true)
878 // see if the method tells us to expect more
879 TotalItems
+= (*I
)->ExpectedAdditionalItems
;
881 // check if there are unfetched Release files
882 if ((*I
)->Complete
== false && (*I
)->ExpectedAdditionalItems
> 0)
883 UnfetchedReleaseFiles
= true;
885 TotalBytes
+= (*I
)->FileSize
;
886 if ((*I
)->Complete
== true)
887 CurrentBytes
+= (*I
)->FileSize
;
888 if ((*I
)->FileSize
== 0 && (*I
)->Complete
== false)
892 // Compute the current completion
893 unsigned long long ResumeSize
= 0;
894 for (pkgAcquire::Worker
*I
= Owner
->WorkersBegin(); I
!= 0;
895 I
= Owner
->WorkerStep(I
))
897 if (I
->CurrentItem
!= 0 && I
->CurrentItem
->Owner
->Complete
== false)
899 CurrentBytes
+= I
->CurrentSize
;
900 ResumeSize
+= I
->ResumePoint
;
902 // Files with unknown size always have 100% completion
903 if (I
->CurrentItem
->Owner
->FileSize
== 0 &&
904 I
->CurrentItem
->Owner
->Complete
== false)
905 TotalBytes
+= I
->CurrentSize
;
909 // Normalize the figures and account for unknown size downloads
912 if (Unknown
== Count
)
913 TotalBytes
= Unknown
;
915 // Wha?! Is not supposed to happen.
916 if (CurrentBytes
> TotalBytes
)
917 CurrentBytes
= TotalBytes
;
920 if (_config
->FindB("Debug::acquire::progress", false) == true)
921 std::clog
<< " Bytes: "
922 << SizeToStr(CurrentBytes
) << " / " << SizeToStr(TotalBytes
)
926 struct timeval NewTime
;
927 gettimeofday(&NewTime
,0);
928 if ((NewTime
.tv_sec
- Time
.tv_sec
== 6 && NewTime
.tv_usec
> Time
.tv_usec
) ||
929 NewTime
.tv_sec
- Time
.tv_sec
> 6)
931 double Delta
= NewTime
.tv_sec
- Time
.tv_sec
+
932 (NewTime
.tv_usec
- Time
.tv_usec
)/1000000.0;
934 // Compute the CPS value
938 CurrentCPS
= ((CurrentBytes
- ResumeSize
) - LastBytes
)/Delta
;
939 LastBytes
= CurrentBytes
- ResumeSize
;
940 ElapsedTime
= (unsigned long long)Delta
;
944 // calculate the percentage, if we have too little data assume 1%
945 if (TotalBytes
> 0 && UnfetchedReleaseFiles
)
948 // use both files and bytes because bytes can be unreliable
949 Percent
= (0.8 * (CurrentBytes
/float(TotalBytes
)*100.0) +
950 0.2 * (CurrentItems
/float(TotalItems
)*100.0));
952 int fd
= _config
->FindI("APT::Status-Fd",-1);
955 ostringstream status
;
958 long i
= CurrentItems
< TotalItems
? CurrentItems
+ 1 : CurrentItems
;
959 unsigned long long ETA
= 0;
961 ETA
= (TotalBytes
- CurrentBytes
) / CurrentCPS
;
963 // only show the ETA if it makes sense
964 if (ETA
> 0 && ETA
< 172800 /* two days */ )
965 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li (%s remaining)"), i
, TotalItems
, TimeToStr(ETA
).c_str());
967 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li"), i
, TotalItems
);
969 // build the status str
970 status
<< "dlstatus:" << i
971 << ":" << std::setprecision(3) << Percent
975 std::string
const dlstatus
= status
.str();
976 FileFd::Write(fd
, dlstatus
.c_str(), dlstatus
.size());
982 // AcquireStatus::Start - Called when the download is started /*{{{*/
983 // ---------------------------------------------------------------------
984 /* We just reset the counters */
985 void pkgAcquireStatus::Start()
987 gettimeofday(&Time
,0);
988 gettimeofday(&StartTime
,0);
999 // AcquireStatus::Stop - Finished downloading /*{{{*/
1000 // ---------------------------------------------------------------------
1001 /* This accurately computes the elapsed time and the total overall CPS. */
1002 void pkgAcquireStatus::Stop()
1004 // Compute the CPS and elapsed time
1005 struct timeval NewTime
;
1006 gettimeofday(&NewTime
,0);
1008 double Delta
= NewTime
.tv_sec
- StartTime
.tv_sec
+
1009 (NewTime
.tv_usec
- StartTime
.tv_usec
)/1000000.0;
1011 // Compute the CPS value
1015 CurrentCPS
= FetchedBytes
/Delta
;
1016 LastBytes
= CurrentBytes
;
1017 ElapsedTime
= (unsigned long long)Delta
;
1020 // AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
1021 // ---------------------------------------------------------------------
1022 /* This is used to get accurate final transfer rate reporting. */
1023 void pkgAcquireStatus::Fetched(unsigned long long Size
,unsigned long long Resume
)
1025 FetchedBytes
+= Size
- Resume
;
1029 APT_CONST
pkgAcquire::UriIterator::~UriIterator() {}
1030 APT_CONST
pkgAcquire::MethodConfig::~MethodConfig() {}
1031 APT_CONST
pkgAcquireStatus::~pkgAcquireStatus() {}