]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire.cc
Document Acquire{MaxReleaseFileSize,AllowInsecureRepositories,AllowDowngradeToInsecur...
[apt.git] / apt-pkg / acquire.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
1b480911 3// $Id: acquire.cc,v 1.50 2004/03/17 05:17:11 mdz Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire - File Acquiration
7
1e3f4083 8 The core element for the schedule system is the concept of a named
0a8a80e5 9 queue. Each queue is unique and each queue has a name derived from the
1e3f4083 10 URI. The degree of paralization can be controlled by how the queue
0a8a80e5
AL
11 name is derived from the URI.
12
0118833a
AL
13 ##################################################################### */
14 /*}}}*/
15// Include Files /*{{{*/
ea542140
DK
16#include <config.h>
17
0118833a
AL
18#include <apt-pkg/acquire.h>
19#include <apt-pkg/acquire-item.h>
20#include <apt-pkg/acquire-worker.h>
0a8a80e5
AL
21#include <apt-pkg/configuration.h>
22#include <apt-pkg/error.h>
cdcc6d34 23#include <apt-pkg/strutl.h>
1cd1c398 24#include <apt-pkg/fileutl.h>
8267fe24 25
453b82a3
DK
26#include <string>
27#include <vector>
b4fc9b6f 28#include <iostream>
75ef8f14 29#include <sstream>
04a54261
DK
30#include <iomanip>
31
526334a0 32#include <stdio.h>
453b82a3
DK
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
04a54261
DK
36#include <pwd.h>
37#include <grp.h>
7a7fa5f0 38#include <dirent.h>
8267fe24 39#include <sys/time.h>
453b82a3 40#include <sys/select.h>
524f8105 41#include <errno.h>
56472095 42#include <sys/stat.h>
04a54261 43#include <sys/types.h>
ea542140
DK
44
45#include <apti18n.h>
0118833a
AL
46 /*}}}*/
47
b4fc9b6f
AL
48using namespace std;
49
0118833a
AL
50// Acquire::pkgAcquire - Constructor /*{{{*/
51// ---------------------------------------------------------------------
93bf083d 52/* We grab some runtime state from the configuration space */
5efbd596 53pkgAcquire::pkgAcquire() : LockFD(-1), Queues(0), Workers(0), Configs(0), Log(NULL), ToFetch(0),
1cd1c398 54 Debug(_config->FindB("Debug::pkgAcquire",false)),
5efbd596 55 Running(false)
0118833a 56{
1cd1c398 57 string const Mode = _config->Find("Acquire::Queue-Mode","host");
0a8a80e5
AL
58 if (strcasecmp(Mode.c_str(),"host") == 0)
59 QueueMode = QueueHost;
60 if (strcasecmp(Mode.c_str(),"access") == 0)
1cd1c398
DK
61 QueueMode = QueueAccess;
62}
04a54261
DK
63pkgAcquire::pkgAcquire(pkgAcquireStatus *Progress) : LockFD(-1), Queues(0), Workers(0),
64 Configs(0), Log(NULL), ToFetch(0),
1cd1c398 65 Debug(_config->FindB("Debug::pkgAcquire",false)),
5efbd596 66 Running(false)
1cd1c398
DK
67{
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;
04a54261 73 SetLog(Progress);
1cd1c398
DK
74}
75 /*}}}*/
04a54261
DK
76// Acquire::GetLock - lock directory and prepare for action /*{{{*/
77static bool SetupAPTPartialDirectory(std::string const &grand, std::string const &parent)
1cd1c398 78{
04a54261
DK
79 std::string const partial = parent + "partial";
80 if (CreateAPTDirectoryIfNeeded(grand, partial) == false &&
81 CreateAPTDirectoryIfNeeded(parent, partial) == false)
82 return false;
0a8a80e5 83
04a54261
DK
84 if (getuid() == 0) // if we aren't root, we can't chown, so don't try it
85 {
86 struct passwd *pw = getpwnam("_apt");
87 struct group *gr = getgrnam("root");
88 if (pw != NULL && gr != NULL && chown(partial.c_str(), pw->pw_uid, gr->gr_gid) != 0)
89 _error->WarningE("SetupAPTPartialDirectory", "chown to _apt:root of directory %s failed", partial.c_str());
90 }
91 if (chmod(partial.c_str(), 0700) != 0)
92 _error->WarningE("SetupAPTPartialDirectory", "chmod 0700 of directory %s failed", partial.c_str());
93
94 return true;
95}
96bool pkgAcquire::Setup(pkgAcquireStatus *Progress, string const &Lock)
97{
98 Log = Progress;
99 if (Lock.empty())
43acd019
DK
100 {
101 string const listDir = _config->FindDir("Dir::State::lists");
04a54261
DK
102 if (SetupAPTPartialDirectory(_config->FindDir("Dir::State"), listDir) == false)
103 return _error->Errno("Acquire", _("List directory %spartial is missing."), listDir.c_str());
43acd019 104 string const archivesDir = _config->FindDir("Dir::Cache::Archives");
04a54261
DK
105 if (SetupAPTPartialDirectory(_config->FindDir("Dir::Cache"), archivesDir) == false)
106 return _error->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir.c_str());
107 return true;
108 }
109 return GetLock(Lock);
110}
111bool pkgAcquire::GetLock(std::string const &Lock)
112{
113 if (Lock.empty() == true)
114 return false;
9c2c9c24 115
04a54261
DK
116 // check for existence and possibly create auxiliary directories
117 string const listDir = _config->FindDir("Dir::State::lists");
118 string const archivesDir = _config->FindDir("Dir::Cache::Archives");
9c2c9c24 119
04a54261
DK
120 if (Lock == listDir)
121 {
122 if (SetupAPTPartialDirectory(_config->FindDir("Dir::State"), listDir) == false)
123 return _error->Errno("Acquire", _("List directory %spartial is missing."), listDir.c_str());
124 }
125 if (Lock == archivesDir)
126 {
127 if (SetupAPTPartialDirectory(_config->FindDir("Dir::Cache"), archivesDir) == false)
43acd019
DK
128 return _error->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir.c_str());
129 }
1cd1c398 130
04a54261 131 if (_config->FindB("Debug::NoLocking", false) == true)
1cd1c398
DK
132 return true;
133
134 // Lock the directory this acquire object will work in
04a54261 135 LockFD = ::GetLock(flCombine(Lock, "lock"));
1cd1c398
DK
136 if (LockFD == -1)
137 return _error->Error(_("Unable to lock directory %s"), Lock.c_str());
138
139 return true;
140}
141 /*}}}*/
0118833a
AL
142// Acquire::~pkgAcquire - Destructor /*{{{*/
143// ---------------------------------------------------------------------
93bf083d 144/* Free our memory, clean up the queues (destroy the workers) */
0118833a
AL
145pkgAcquire::~pkgAcquire()
146{
459681d3 147 Shutdown();
1cd1c398
DK
148
149 if (LockFD != -1)
150 close(LockFD);
151
3b5421b4
AL
152 while (Configs != 0)
153 {
154 MethodConfig *Jnk = Configs;
155 Configs = Configs->Next;
156 delete Jnk;
157 }
281daf46
AL
158}
159 /*}}}*/
8e5fc8f5 160// Acquire::Shutdown - Clean out the acquire object /*{{{*/
281daf46
AL
161// ---------------------------------------------------------------------
162/* */
163void pkgAcquire::Shutdown()
164{
f7f0d6c7 165 while (Items.empty() == false)
1b480911
AL
166 {
167 if (Items[0]->Status == Item::StatFetching)
168 Items[0]->Status = Item::StatError;
281daf46 169 delete Items[0];
1b480911 170 }
0a8a80e5
AL
171
172 while (Queues != 0)
173 {
174 Queue *Jnk = Queues;
175 Queues = Queues->Next;
176 delete Jnk;
177 }
0118833a
AL
178}
179 /*}}}*/
180// Acquire::Add - Add a new item /*{{{*/
181// ---------------------------------------------------------------------
93bf083d
AL
182/* This puts an item on the acquire list. This list is mainly for tracking
183 item status */
0118833a
AL
184void pkgAcquire::Add(Item *Itm)
185{
186 Items.push_back(Itm);
187}
188 /*}}}*/
189// Acquire::Remove - Remove a item /*{{{*/
190// ---------------------------------------------------------------------
93bf083d 191/* Remove an item from the acquire list. This is usually not used.. */
0118833a
AL
192void pkgAcquire::Remove(Item *Itm)
193{
a3eaf954
AL
194 Dequeue(Itm);
195
753b3525 196 for (ItemIterator I = Items.begin(); I != Items.end();)
0118833a
AL
197 {
198 if (*I == Itm)
b4fc9b6f 199 {
0118833a 200 Items.erase(I);
b4fc9b6f
AL
201 I = Items.begin();
202 }
753b3525 203 else
f7f0d6c7 204 ++I;
8267fe24 205 }
0118833a
AL
206}
207 /*}}}*/
0a8a80e5
AL
208// Acquire::Add - Add a worker /*{{{*/
209// ---------------------------------------------------------------------
93bf083d
AL
210/* A list of workers is kept so that the select loop can direct their FD
211 usage. */
0a8a80e5
AL
212void pkgAcquire::Add(Worker *Work)
213{
214 Work->NextAcquire = Workers;
215 Workers = Work;
216}
217 /*}}}*/
218// Acquire::Remove - Remove a worker /*{{{*/
219// ---------------------------------------------------------------------
93bf083d
AL
220/* A worker has died. This can not be done while the select loop is running
221 as it would require that RunFds could handling a changing list state and
1e3f4083 222 it can't.. */
0a8a80e5
AL
223void pkgAcquire::Remove(Worker *Work)
224{
93bf083d
AL
225 if (Running == true)
226 abort();
227
0a8a80e5
AL
228 Worker **I = &Workers;
229 for (; *I != 0;)
230 {
231 if (*I == Work)
232 *I = (*I)->NextAcquire;
233 else
234 I = &(*I)->NextAcquire;
235 }
236}
237 /*}}}*/
0118833a
AL
238// Acquire::Enqueue - Queue an URI for fetching /*{{{*/
239// ---------------------------------------------------------------------
93bf083d 240/* This is the entry point for an item. An item calls this function when
281daf46 241 it is constructed which creates a queue (based on the current queue
93bf083d
AL
242 mode) and puts the item in that queue. If the system is running then
243 the queue might be started. */
8267fe24 244void pkgAcquire::Enqueue(ItemDesc &Item)
0118833a 245{
0a8a80e5 246 // Determine which queue to put the item in
e331f6ed
AL
247 const MethodConfig *Config;
248 string Name = QueueName(Item.URI,Config);
0a8a80e5
AL
249 if (Name.empty() == true)
250 return;
251
252 // Find the queue structure
253 Queue *I = Queues;
254 for (; I != 0 && I->Name != Name; I = I->Next);
255 if (I == 0)
256 {
257 I = new Queue(Name,this);
258 I->Next = Queues;
259 Queues = I;
93bf083d
AL
260
261 if (Running == true)
262 I->Startup();
0a8a80e5 263 }
bfd22fc0 264
e331f6ed
AL
265 // See if this is a local only URI
266 if (Config->LocalOnly == true && Item.Owner->Complete == false)
267 Item.Owner->Local = true;
8267fe24 268 Item.Owner->Status = Item::StatIdle;
0a8a80e5
AL
269
270 // Queue it into the named queue
c03462c6
MV
271 if(I->Enqueue(Item))
272 ToFetch++;
273
0a8a80e5
AL
274 // Some trace stuff
275 if (Debug == true)
276 {
8267fe24
AL
277 clog << "Fetching " << Item.URI << endl;
278 clog << " to " << Item.Owner->DestFile << endl;
e331f6ed 279 clog << " Queue is: " << Name << endl;
0a8a80e5 280 }
3b5421b4
AL
281}
282 /*}}}*/
0a8a80e5 283// Acquire::Dequeue - Remove an item from all queues /*{{{*/
3b5421b4 284// ---------------------------------------------------------------------
93bf083d
AL
285/* This is called when an item is finished being fetched. It removes it
286 from all the queues */
0a8a80e5
AL
287void pkgAcquire::Dequeue(Item *Itm)
288{
289 Queue *I = Queues;
bfd22fc0 290 bool Res = false;
93bf083d
AL
291 if (Debug == true)
292 clog << "Dequeuing " << Itm->DestFile << endl;
5674f6b3
RG
293
294 for (; I != 0; I = I->Next)
295 {
296 if (I->Dequeue(Itm))
297 {
298 Res = true;
299 if (Debug == true)
300 clog << "Dequeued from " << I->Name << endl;
301 }
302 }
303
bfd22fc0
AL
304 if (Res == true)
305 ToFetch--;
0a8a80e5
AL
306}
307 /*}}}*/
308// Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
309// ---------------------------------------------------------------------
310/* The string returned depends on the configuration settings and the
311 method parameters. Given something like http://foo.org/bar it can
312 return http://foo.org or http */
e331f6ed 313string pkgAcquire::QueueName(string Uri,MethodConfig const *&Config)
3b5421b4 314{
93bf083d
AL
315 URI U(Uri);
316
e331f6ed 317 Config = GetConfig(U.Access);
0a8a80e5
AL
318 if (Config == 0)
319 return string();
320
321 /* Single-Instance methods get exactly one queue per URI. This is
322 also used for the Access queue method */
323 if (Config->SingleInstance == true || QueueMode == QueueAccess)
5674f6b3
RG
324 return U.Access;
325
326 string AccessSchema = U.Access + ':',
327 FullQueueName = AccessSchema + U.Host;
328 unsigned int Instances = 0, SchemaLength = AccessSchema.length();
329
330 Queue *I = Queues;
331 for (; I != 0; I = I->Next) {
332 // if the queue already exists, re-use it
333 if (I->Name == FullQueueName)
334 return FullQueueName;
335
336 if (I->Name.compare(0, SchemaLength, AccessSchema) == 0)
337 Instances++;
338 }
339
340 if (Debug) {
341 clog << "Found " << Instances << " instances of " << U.Access << endl;
342 }
343
344 if (Instances >= (unsigned int)_config->FindI("Acquire::QueueHost::Limit",10))
345 return U.Access;
93bf083d 346
5674f6b3 347 return FullQueueName;
0118833a
AL
348}
349 /*}}}*/
3b5421b4
AL
350// Acquire::GetConfig - Fetch the configuration information /*{{{*/
351// ---------------------------------------------------------------------
352/* This locates the configuration structure for an access method. If
353 a config structure cannot be found a Worker will be created to
354 retrieve it */
0a8a80e5 355pkgAcquire::MethodConfig *pkgAcquire::GetConfig(string Access)
3b5421b4
AL
356{
357 // Search for an existing config
358 MethodConfig *Conf;
359 for (Conf = Configs; Conf != 0; Conf = Conf->Next)
360 if (Conf->Access == Access)
361 return Conf;
362
363 // Create the new config class
364 Conf = new MethodConfig;
365 Conf->Access = Access;
366 Conf->Next = Configs;
367 Configs = Conf;
0118833a 368
3b5421b4
AL
369 // Create the worker to fetch the configuration
370 Worker Work(Conf);
371 if (Work.Start() == false)
372 return 0;
7c6e2dc7
MV
373
374 /* if a method uses DownloadLimit, we switch to SingleInstance mode */
4b65cc13 375 if(_config->FindI("Acquire::"+Access+"::Dl-Limit",0) > 0)
7c6e2dc7
MV
376 Conf->SingleInstance = true;
377
3b5421b4
AL
378 return Conf;
379}
380 /*}}}*/
0a8a80e5
AL
381// Acquire::SetFds - Deal with readable FDs /*{{{*/
382// ---------------------------------------------------------------------
383/* Collect FDs that have activity monitors into the fd sets */
384void pkgAcquire::SetFds(int &Fd,fd_set *RSet,fd_set *WSet)
385{
386 for (Worker *I = Workers; I != 0; I = I->NextAcquire)
387 {
388 if (I->InReady == true && I->InFd >= 0)
389 {
390 if (Fd < I->InFd)
391 Fd = I->InFd;
392 FD_SET(I->InFd,RSet);
393 }
394 if (I->OutReady == true && I->OutFd >= 0)
395 {
396 if (Fd < I->OutFd)
397 Fd = I->OutFd;
398 FD_SET(I->OutFd,WSet);
399 }
400 }
401}
402 /*}}}*/
403// Acquire::RunFds - Deal with active FDs /*{{{*/
404// ---------------------------------------------------------------------
93bf083d
AL
405/* Dispatch active FDs over to the proper workers. It is very important
406 that a worker never be erased while this is running! The queue class
407 should never erase a worker except during shutdown processing. */
0a8a80e5
AL
408void pkgAcquire::RunFds(fd_set *RSet,fd_set *WSet)
409{
410 for (Worker *I = Workers; I != 0; I = I->NextAcquire)
411 {
412 if (I->InFd >= 0 && FD_ISSET(I->InFd,RSet) != 0)
413 I->InFdReady();
414 if (I->OutFd >= 0 && FD_ISSET(I->OutFd,WSet) != 0)
415 I->OutFdReady();
416 }
417}
418 /*}}}*/
419// Acquire::Run - Run the fetch sequence /*{{{*/
420// ---------------------------------------------------------------------
421/* This runs the queues. It manages a select loop for all of the
422 Worker tasks. The workers interact with the queues and items to
423 manage the actual fetch. */
1c5f7e5f 424pkgAcquire::RunResult pkgAcquire::Run(int PulseIntervall)
0a8a80e5 425{
8b89e57f
AL
426 Running = true;
427
0a8a80e5
AL
428 for (Queue *I = Queues; I != 0; I = I->Next)
429 I->Startup();
430
b98f2859
AL
431 if (Log != 0)
432 Log->Start();
433
024d1123
AL
434 bool WasCancelled = false;
435
0a8a80e5 436 // Run till all things have been acquired
8267fe24
AL
437 struct timeval tv;
438 tv.tv_sec = 0;
1c5f7e5f 439 tv.tv_usec = PulseIntervall;
0a8a80e5
AL
440 while (ToFetch > 0)
441 {
442 fd_set RFds;
443 fd_set WFds;
444 int Highest = 0;
445 FD_ZERO(&RFds);
446 FD_ZERO(&WFds);
447 SetFds(Highest,&RFds,&WFds);
448
b0db36b1
AL
449 int Res;
450 do
451 {
452 Res = select(Highest+1,&RFds,&WFds,0,&tv);
453 }
454 while (Res < 0 && errno == EINTR);
455
8267fe24 456 if (Res < 0)
8b89e57f 457 {
8267fe24
AL
458 _error->Errno("select","Select has failed");
459 break;
8b89e57f 460 }
93bf083d 461
0a8a80e5 462 RunFds(&RFds,&WFds);
93bf083d
AL
463 if (_error->PendingError() == true)
464 break;
8267fe24
AL
465
466 // Timeout, notify the log class
467 if (Res == 0 || (Log != 0 && Log->Update == true))
468 {
1c5f7e5f 469 tv.tv_usec = PulseIntervall;
8267fe24
AL
470 for (Worker *I = Workers; I != 0; I = I->NextAcquire)
471 I->Pulse();
024d1123
AL
472 if (Log != 0 && Log->Pulse(this) == false)
473 {
474 WasCancelled = true;
475 break;
476 }
8267fe24 477 }
0a8a80e5 478 }
be4401bf 479
b98f2859
AL
480 if (Log != 0)
481 Log->Stop();
482
be4401bf
AL
483 // Shut down the acquire bits
484 Running = false;
0a8a80e5 485 for (Queue *I = Queues; I != 0; I = I->Next)
8e5fc8f5 486 I->Shutdown(false);
0a8a80e5 487
ab559b35 488 // Shut down the items
f7f0d6c7 489 for (ItemIterator I = Items.begin(); I != Items.end(); ++I)
8e5fc8f5 490 (*I)->Finished();
ab559b35 491
024d1123
AL
492 if (_error->PendingError())
493 return Failed;
494 if (WasCancelled)
495 return Cancelled;
496 return Continue;
93bf083d
AL
497}
498 /*}}}*/
be4401bf 499// Acquire::Bump - Called when an item is dequeued /*{{{*/
93bf083d
AL
500// ---------------------------------------------------------------------
501/* This routine bumps idle queues in hopes that they will be able to fetch
502 the dequeued item */
503void pkgAcquire::Bump()
504{
be4401bf
AL
505 for (Queue *I = Queues; I != 0; I = I->Next)
506 I->Bump();
0a8a80e5
AL
507}
508 /*}}}*/
8267fe24
AL
509// Acquire::WorkerStep - Step to the next worker /*{{{*/
510// ---------------------------------------------------------------------
511/* Not inlined to advoid including acquire-worker.h */
512pkgAcquire::Worker *pkgAcquire::WorkerStep(Worker *I)
513{
514 return I->NextAcquire;
d3e8fbb3 515}
8267fe24 516 /*}}}*/
a6568219 517// Acquire::Clean - Cleans a directory /*{{{*/
7a7fa5f0
AL
518// ---------------------------------------------------------------------
519/* This is a bit simplistic, it looks at every file in the dir and sees
520 if it is part of the download set. */
521bool pkgAcquire::Clean(string Dir)
522{
95b5f6c1
DK
523 // non-existing directories are by definition clean…
524 if (DirectoryExists(Dir) == false)
525 return true;
526
10ecfe4f
MV
527 if(Dir == "/")
528 return _error->Error(_("Clean of %s is not supported"), Dir.c_str());
529
7a7fa5f0
AL
530 DIR *D = opendir(Dir.c_str());
531 if (D == 0)
b2e465d6 532 return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
7a7fa5f0
AL
533
534 string StartDir = SafeGetCWD();
535 if (chdir(Dir.c_str()) != 0)
536 {
537 closedir(D);
b2e465d6 538 return _error->Errno("chdir",_("Unable to change to %s"),Dir.c_str());
7a7fa5f0
AL
539 }
540
541 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
542 {
543 // Skip some files..
544 if (strcmp(Dir->d_name,"lock") == 0 ||
545 strcmp(Dir->d_name,"partial") == 0 ||
546 strcmp(Dir->d_name,".") == 0 ||
547 strcmp(Dir->d_name,"..") == 0)
548 continue;
549
550 // Look in the get list
b4fc9b6f 551 ItemCIterator I = Items.begin();
f7f0d6c7 552 for (; I != Items.end(); ++I)
7a7fa5f0
AL
553 if (flNotDir((*I)->DestFile) == Dir->d_name)
554 break;
555
556 // Nothing found, nuke it
557 if (I == Items.end())
558 unlink(Dir->d_name);
559 };
560
7a7fa5f0 561 closedir(D);
3c8cda8b
MV
562 if (chdir(StartDir.c_str()) != 0)
563 return _error->Errno("chdir",_("Unable to change to %s"),StartDir.c_str());
7a7fa5f0
AL
564 return true;
565}
566 /*}}}*/
a6568219
AL
567// Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
568// ---------------------------------------------------------------------
569/* This is the total number of bytes needed */
a02db58f 570APT_PURE unsigned long long pkgAcquire::TotalNeeded()
a6568219 571{
a3c4c81a 572 unsigned long long Total = 0;
f7f0d6c7 573 for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); ++I)
a6568219
AL
574 Total += (*I)->FileSize;
575 return Total;
576}
577 /*}}}*/
578// Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
579// ---------------------------------------------------------------------
580/* This is the number of bytes that is not local */
a02db58f 581APT_PURE unsigned long long pkgAcquire::FetchNeeded()
a6568219 582{
a3c4c81a 583 unsigned long long Total = 0;
f7f0d6c7 584 for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); ++I)
a6568219
AL
585 if ((*I)->Local == false)
586 Total += (*I)->FileSize;
587 return Total;
588}
589 /*}}}*/
6b1ff003
AL
590// Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
591// ---------------------------------------------------------------------
592/* This is the number of bytes that is not local */
a02db58f 593APT_PURE unsigned long long pkgAcquire::PartialPresent()
6b1ff003 594{
a3c4c81a 595 unsigned long long Total = 0;
f7f0d6c7 596 for (ItemCIterator I = ItemsBegin(); I != ItemsEnd(); ++I)
6b1ff003
AL
597 if ((*I)->Local == false)
598 Total += (*I)->PartialSize;
599 return Total;
600}
92fcbfc1 601 /*}}}*/
8e5fc8f5 602// Acquire::UriBegin - Start iterator for the uri list /*{{{*/
f7a08e33
AL
603// ---------------------------------------------------------------------
604/* */
605pkgAcquire::UriIterator pkgAcquire::UriBegin()
606{
607 return UriIterator(Queues);
608}
609 /*}}}*/
8e5fc8f5 610// Acquire::UriEnd - End iterator for the uri list /*{{{*/
f7a08e33
AL
611// ---------------------------------------------------------------------
612/* */
613pkgAcquire::UriIterator pkgAcquire::UriEnd()
614{
615 return UriIterator(0);
616}
617 /*}}}*/
e331f6ed
AL
618// Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
619// ---------------------------------------------------------------------
620/* */
25613a61
DK
621pkgAcquire::MethodConfig::MethodConfig() : d(NULL), Next(0), SingleInstance(false),
622 Pipeline(false), SendConfig(false), LocalOnly(false), NeedsCleanup(false),
623 Removable(false)
e331f6ed 624{
e331f6ed
AL
625}
626 /*}}}*/
0a8a80e5
AL
627// Queue::Queue - Constructor /*{{{*/
628// ---------------------------------------------------------------------
629/* */
25613a61
DK
630pkgAcquire::Queue::Queue(string Name,pkgAcquire *Owner) : d(NULL), Next(0),
631 Name(Name), Items(0), Workers(0), Owner(Owner), PipeDepth(0), MaxPipeDepth(1)
0a8a80e5 632{
0a8a80e5
AL
633}
634 /*}}}*/
635// Queue::~Queue - Destructor /*{{{*/
636// ---------------------------------------------------------------------
637/* */
638pkgAcquire::Queue::~Queue()
639{
8e5fc8f5 640 Shutdown(true);
0a8a80e5
AL
641
642 while (Items != 0)
643 {
644 QItem *Jnk = Items;
645 Items = Items->Next;
646 delete Jnk;
647 }
648}
649 /*}}}*/
650// Queue::Enqueue - Queue an item to the queue /*{{{*/
651// ---------------------------------------------------------------------
652/* */
c03462c6 653bool pkgAcquire::Queue::Enqueue(ItemDesc &Item)
0a8a80e5 654{
7a1b1f8b 655 QItem **I = &Items;
c03462c6
MV
656 // move to the end of the queue and check for duplicates here
657 for (; *I != 0; I = &(*I)->Next)
658 if (Item.URI == (*I)->URI)
659 {
660 Item.Owner->Status = Item::StatDone;
661 return false;
662 }
663
0a8a80e5 664 // Create a new item
7a1b1f8b
AL
665 QItem *Itm = new QItem;
666 *Itm = Item;
667 Itm->Next = 0;
668 *I = Itm;
0a8a80e5 669
8267fe24 670 Item.Owner->QueueCounter++;
93bf083d
AL
671 if (Items->Next == 0)
672 Cycle();
c03462c6 673 return true;
0a8a80e5
AL
674}
675 /*}}}*/
c88edf1d 676// Queue::Dequeue - Remove an item from the queue /*{{{*/
0a8a80e5 677// ---------------------------------------------------------------------
b185acc2 678/* We return true if we hit something */
bfd22fc0 679bool pkgAcquire::Queue::Dequeue(Item *Owner)
0a8a80e5 680{
b185acc2
AL
681 if (Owner->Status == pkgAcquire::Item::StatFetching)
682 return _error->Error("Tried to dequeue a fetching object");
683
bfd22fc0
AL
684 bool Res = false;
685
0a8a80e5
AL
686 QItem **I = &Items;
687 for (; *I != 0;)
688 {
689 if ((*I)->Owner == Owner)
690 {
691 QItem *Jnk= *I;
692 *I = (*I)->Next;
693 Owner->QueueCounter--;
694 delete Jnk;
bfd22fc0 695 Res = true;
0a8a80e5
AL
696 }
697 else
698 I = &(*I)->Next;
699 }
bfd22fc0
AL
700
701 return Res;
0a8a80e5
AL
702}
703 /*}}}*/
704// Queue::Startup - Start the worker processes /*{{{*/
705// ---------------------------------------------------------------------
8e5fc8f5
AL
706/* It is possible for this to be called with a pre-existing set of
707 workers. */
0a8a80e5
AL
708bool pkgAcquire::Queue::Startup()
709{
8e5fc8f5
AL
710 if (Workers == 0)
711 {
712 URI U(Name);
713 pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(U.Access);
714 if (Cnf == 0)
715 return false;
716
717 Workers = new Worker(this,Cnf,Owner->Log);
718 Owner->Add(Workers);
719 if (Workers->Start() == false)
720 return false;
721
722 /* When pipelining we commit 10 items. This needs to change when we
723 added other source retry to have cycle maintain a pipeline depth
724 on its own. */
725 if (Cnf->Pipeline == true)
6ce72612 726 MaxPipeDepth = _config->FindI("Acquire::Max-Pipeline-Depth",10);
8e5fc8f5
AL
727 else
728 MaxPipeDepth = 1;
729 }
5cb5d8dc 730
93bf083d 731 return Cycle();
0a8a80e5
AL
732}
733 /*}}}*/
734// Queue::Shutdown - Shutdown the worker processes /*{{{*/
735// ---------------------------------------------------------------------
8e5fc8f5
AL
736/* If final is true then all workers are eliminated, otherwise only workers
737 that do not need cleanup are removed */
738bool pkgAcquire::Queue::Shutdown(bool Final)
0a8a80e5
AL
739{
740 // Delete all of the workers
8e5fc8f5
AL
741 pkgAcquire::Worker **Cur = &Workers;
742 while (*Cur != 0)
0a8a80e5 743 {
8e5fc8f5
AL
744 pkgAcquire::Worker *Jnk = *Cur;
745 if (Final == true || Jnk->GetConf()->NeedsCleanup == false)
746 {
747 *Cur = Jnk->NextQueue;
748 Owner->Remove(Jnk);
749 delete Jnk;
750 }
751 else
752 Cur = &(*Cur)->NextQueue;
0a8a80e5
AL
753 }
754
755 return true;
3b5421b4
AL
756}
757 /*}}}*/
7d8afa39 758// Queue::FindItem - Find a URI in the item list /*{{{*/
c88edf1d
AL
759// ---------------------------------------------------------------------
760/* */
761pkgAcquire::Queue::QItem *pkgAcquire::Queue::FindItem(string URI,pkgAcquire::Worker *Owner)
762{
763 for (QItem *I = Items; I != 0; I = I->Next)
764 if (I->URI == URI && I->Worker == Owner)
765 return I;
766 return 0;
767}
768 /*}}}*/
769// Queue::ItemDone - Item has been completed /*{{{*/
770// ---------------------------------------------------------------------
771/* The worker signals this which causes the item to be removed from the
93bf083d
AL
772 queue. If this is the last queue instance then it is removed from the
773 main queue too.*/
c88edf1d
AL
774bool pkgAcquire::Queue::ItemDone(QItem *Itm)
775{
b185acc2 776 PipeDepth--;
db890fdb
AL
777 if (Itm->Owner->Status == pkgAcquire::Item::StatFetching)
778 Itm->Owner->Status = pkgAcquire::Item::StatDone;
779
93bf083d
AL
780 if (Itm->Owner->QueueCounter <= 1)
781 Owner->Dequeue(Itm->Owner);
782 else
783 {
784 Dequeue(Itm->Owner);
785 Owner->Bump();
786 }
c88edf1d 787
93bf083d
AL
788 return Cycle();
789}
790 /*}}}*/
791// Queue::Cycle - Queue new items into the method /*{{{*/
792// ---------------------------------------------------------------------
b185acc2
AL
793/* This locates a new idle item and sends it to the worker. If pipelining
794 is enabled then it keeps the pipe full. */
93bf083d
AL
795bool pkgAcquire::Queue::Cycle()
796{
797 if (Items == 0 || Workers == 0)
c88edf1d
AL
798 return true;
799
e7432370
AL
800 if (PipeDepth < 0)
801 return _error->Error("Pipedepth failure");
802
93bf083d
AL
803 // Look for a queable item
804 QItem *I = Items;
e7432370 805 while (PipeDepth < (signed)MaxPipeDepth)
b185acc2
AL
806 {
807 for (; I != 0; I = I->Next)
808 if (I->Owner->Status == pkgAcquire::Item::StatIdle)
809 break;
810
811 // Nothing to do, queue is idle.
812 if (I == 0)
813 return true;
814
815 I->Worker = Workers;
816 I->Owner->Status = pkgAcquire::Item::StatFetching;
e7432370 817 PipeDepth++;
b185acc2
AL
818 if (Workers->QueueItem(I) == false)
819 return false;
820 }
93bf083d 821
b185acc2 822 return true;
c88edf1d
AL
823}
824 /*}}}*/
be4401bf
AL
825// Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
826// ---------------------------------------------------------------------
b185acc2 827/* This is called when an item in multiple queues is dequeued */
be4401bf
AL
828void pkgAcquire::Queue::Bump()
829{
b185acc2 830 Cycle();
be4401bf
AL
831}
832 /*}}}*/
b98f2859
AL
833// AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
834// ---------------------------------------------------------------------
835/* */
25613a61 836pkgAcquireStatus::pkgAcquireStatus() : d(NULL), Percent(0), Update(true), MorePulses(false)
b98f2859
AL
837{
838 Start();
839}
840 /*}}}*/
841// AcquireStatus::Pulse - Called periodically /*{{{*/
842// ---------------------------------------------------------------------
843/* This computes some internal state variables for the derived classes to
844 use. It generates the current downloaded bytes and total bytes to download
845 as well as the current CPS estimate. */
024d1123 846bool pkgAcquireStatus::Pulse(pkgAcquire *Owner)
b98f2859
AL
847{
848 TotalBytes = 0;
849 CurrentBytes = 0;
d568ed2d
AL
850 TotalItems = 0;
851 CurrentItems = 0;
b98f2859
AL
852
853 // Compute the total number of bytes to fetch
854 unsigned int Unknown = 0;
855 unsigned int Count = 0;
c6e9cc58
MV
856 bool UnfetchedReleaseFiles = false;
857 for (pkgAcquire::ItemCIterator I = Owner->ItemsBegin();
858 I != Owner->ItemsEnd();
f7f0d6c7 859 ++I, ++Count)
b98f2859 860 {
d568ed2d
AL
861 TotalItems++;
862 if ((*I)->Status == pkgAcquire::Item::StatDone)
f7f0d6c7 863 ++CurrentItems;
d568ed2d 864
a6568219
AL
865 // Totally ignore local items
866 if ((*I)->Local == true)
867 continue;
b2e465d6 868
d0cfa8ad
MV
869 // see if the method tells us to expect more
870 TotalItems += (*I)->ExpectedAdditionalItems;
871
c6e9cc58
MV
872 // check if there are unfetched Release files
873 if ((*I)->Complete == false && (*I)->ExpectedAdditionalItems > 0)
874 UnfetchedReleaseFiles = true;
875
b98f2859
AL
876 TotalBytes += (*I)->FileSize;
877 if ((*I)->Complete == true)
878 CurrentBytes += (*I)->FileSize;
879 if ((*I)->FileSize == 0 && (*I)->Complete == false)
f7f0d6c7 880 ++Unknown;
b98f2859
AL
881 }
882
883 // Compute the current completion
dbbc5494 884 unsigned long long ResumeSize = 0;
b98f2859
AL
885 for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
886 I = Owner->WorkerStep(I))
c62f7898 887 {
b98f2859 888 if (I->CurrentItem != 0 && I->CurrentItem->Owner->Complete == false)
aa0e1101
AL
889 {
890 CurrentBytes += I->CurrentSize;
891 ResumeSize += I->ResumePoint;
892
893 // Files with unknown size always have 100% completion
894 if (I->CurrentItem->Owner->FileSize == 0 &&
895 I->CurrentItem->Owner->Complete == false)
896 TotalBytes += I->CurrentSize;
897 }
c62f7898 898 }
aa0e1101 899
b98f2859
AL
900 // Normalize the figures and account for unknown size downloads
901 if (TotalBytes <= 0)
902 TotalBytes = 1;
903 if (Unknown == Count)
904 TotalBytes = Unknown;
18ef0a78
AL
905
906 // Wha?! Is not supposed to happen.
907 if (CurrentBytes > TotalBytes)
908 CurrentBytes = TotalBytes;
96c6cab1
MV
909
910 // debug
911 if (_config->FindB("Debug::acquire::progress", false) == true)
912 std::clog << " Bytes: "
913 << SizeToStr(CurrentBytes) << " / " << SizeToStr(TotalBytes)
914 << std::endl;
b98f2859
AL
915
916 // Compute the CPS
917 struct timeval NewTime;
918 gettimeofday(&NewTime,0);
2ec1674d 919 if ((NewTime.tv_sec - Time.tv_sec == 6 && NewTime.tv_usec > Time.tv_usec) ||
b98f2859
AL
920 NewTime.tv_sec - Time.tv_sec > 6)
921 {
f17ac097
AL
922 double Delta = NewTime.tv_sec - Time.tv_sec +
923 (NewTime.tv_usec - Time.tv_usec)/1000000.0;
b98f2859 924
b98f2859 925 // Compute the CPS value
f17ac097 926 if (Delta < 0.01)
e331f6ed
AL
927 CurrentCPS = 0;
928 else
aa0e1101
AL
929 CurrentCPS = ((CurrentBytes - ResumeSize) - LastBytes)/Delta;
930 LastBytes = CurrentBytes - ResumeSize;
dbbc5494 931 ElapsedTime = (unsigned long long)Delta;
b98f2859
AL
932 Time = NewTime;
933 }
024d1123 934
c6e9cc58
MV
935 // calculate the percentage, if we have too little data assume 1%
936 if (TotalBytes > 0 && UnfetchedReleaseFiles)
96c6cab1
MV
937 Percent = 0;
938 else
939 // use both files and bytes because bytes can be unreliable
940 Percent = (0.8 * (CurrentBytes/float(TotalBytes)*100.0) +
941 0.2 * (CurrentItems/float(TotalItems)*100.0));
942
75ef8f14
MV
943 int fd = _config->FindI("APT::Status-Fd",-1);
944 if(fd > 0)
945 {
946 ostringstream status;
947
948 char msg[200];
949 long i = CurrentItems < TotalItems ? CurrentItems + 1 : CurrentItems;
c033d415
MV
950 unsigned long long ETA = 0;
951 if(CurrentCPS > 0)
952 ETA = (TotalBytes - CurrentBytes) / CurrentCPS;
75ef8f14 953
1e8b4c0f
MV
954 // only show the ETA if it makes sense
955 if (ETA > 0 && ETA < 172800 /* two days */ )
0c508b03 956 snprintf(msg,sizeof(msg), _("Retrieving file %li of %li (%s remaining)"), i, TotalItems, TimeToStr(ETA).c_str());
1e8b4c0f 957 else
0c508b03 958 snprintf(msg,sizeof(msg), _("Retrieving file %li of %li"), i, TotalItems);
1e8b4c0f 959
75ef8f14
MV
960 // build the status str
961 status << "dlstatus:" << i
96c6cab1 962 << ":" << std::setprecision(3) << Percent
d0cfa8ad
MV
963 << ":" << msg
964 << endl;
31bda500
DK
965
966 std::string const dlstatus = status.str();
d68d65ad 967 FileFd::Write(fd, dlstatus.c_str(), dlstatus.size());
75ef8f14
MV
968 }
969
024d1123 970 return true;
b98f2859
AL
971}
972 /*}}}*/
973// AcquireStatus::Start - Called when the download is started /*{{{*/
974// ---------------------------------------------------------------------
975/* We just reset the counters */
976void pkgAcquireStatus::Start()
977{
978 gettimeofday(&Time,0);
979 gettimeofday(&StartTime,0);
980 LastBytes = 0;
981 CurrentCPS = 0;
982 CurrentBytes = 0;
983 TotalBytes = 0;
984 FetchedBytes = 0;
985 ElapsedTime = 0;
d568ed2d
AL
986 TotalItems = 0;
987 CurrentItems = 0;
b98f2859
AL
988}
989 /*}}}*/
a6568219 990// AcquireStatus::Stop - Finished downloading /*{{{*/
b98f2859
AL
991// ---------------------------------------------------------------------
992/* This accurately computes the elapsed time and the total overall CPS. */
993void pkgAcquireStatus::Stop()
994{
995 // Compute the CPS and elapsed time
996 struct timeval NewTime;
997 gettimeofday(&NewTime,0);
998
31a0531d
AL
999 double Delta = NewTime.tv_sec - StartTime.tv_sec +
1000 (NewTime.tv_usec - StartTime.tv_usec)/1000000.0;
b98f2859 1001
b98f2859 1002 // Compute the CPS value
31a0531d 1003 if (Delta < 0.01)
e331f6ed
AL
1004 CurrentCPS = 0;
1005 else
31a0531d 1006 CurrentCPS = FetchedBytes/Delta;
b98f2859 1007 LastBytes = CurrentBytes;
dbbc5494 1008 ElapsedTime = (unsigned long long)Delta;
b98f2859
AL
1009}
1010 /*}}}*/
1011// AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
1012// ---------------------------------------------------------------------
1013/* This is used to get accurate final transfer rate reporting. */
73da43e9 1014void pkgAcquireStatus::Fetched(unsigned long long Size,unsigned long long Resume)
93274b8d 1015{
b98f2859
AL
1016 FetchedBytes += Size - Resume;
1017}
1018 /*}}}*/
862bafea
DK
1019
1020pkgAcquire::UriIterator::~UriIterator() {}
1021pkgAcquire::MethodConfig::~MethodConfig() {}
1022pkgAcquireStatus::~pkgAcquireStatus() {}