]>
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() {}