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