]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-worker.cc
deal better with acquiring the same URI multiple times
[apt.git] / apt-pkg / acquire-worker.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
24a0d63a 3// $Id: acquire-worker.cc,v 1.34 2001/05/22 04:42:54 jgg Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire Worker
7
3b5421b4
AL
8 The worker process can startup either as a Configuration prober
9 or as a queue runner. As a configuration prober it only reads the
10 configuration message and
11
0118833a
AL
12 ##################################################################### */
13 /*}}}*/
14// Include Files /*{{{*/
ea542140
DK
15#include <config.h>
16
453b82a3 17#include <apt-pkg/acquire.h>
0118833a 18#include <apt-pkg/acquire-worker.h>
0a8a80e5 19#include <apt-pkg/acquire-item.h>
3b5421b4
AL
20#include <apt-pkg/configuration.h>
21#include <apt-pkg/error.h>
22#include <apt-pkg/fileutl.h>
cdcc6d34 23#include <apt-pkg/strutl.h>
453b82a3 24#include <apt-pkg/hashes.h>
3b5421b4 25
453b82a3
DK
26#include <string>
27#include <vector>
24a0d63a 28#include <iostream>
80a26ed1 29#include <sstream>
ea542140 30
8267fe24 31#include <sys/stat.h>
453b82a3 32#include <stdlib.h>
3b5421b4
AL
33#include <unistd.h>
34#include <signal.h>
542ec555 35#include <stdio.h>
b0db36b1 36#include <errno.h>
359e1c4f
DK
37#include <sys/types.h>
38#include <pwd.h>
39#include <grp.h>
ea542140
DK
40
41#include <apti18n.h>
3b5421b4
AL
42 /*}}}*/
43
24a0d63a
AL
44using namespace std;
45
3b5421b4
AL
46// Worker::Worker - Constructor for Queue startup /*{{{*/
47// ---------------------------------------------------------------------
48/* */
8267fe24
AL
49pkgAcquire::Worker::Worker(Queue *Q,MethodConfig *Cnf,
50 pkgAcquireStatus *Log) : Log(Log)
3b5421b4
AL
51{
52 OwnerQ = Q;
0a8a80e5
AL
53 Config = Cnf;
54 Access = Cnf->Access;
55 CurrentItem = 0;
18ef0a78
AL
56 TotalSize = 0;
57 CurrentSize = 0;
448c38bd
DK
58
59 Construct();
3b5421b4
AL
60}
61 /*}}}*/
62// Worker::Worker - Constructor for method config startup /*{{{*/
63// ---------------------------------------------------------------------
64/* */
65pkgAcquire::Worker::Worker(MethodConfig *Cnf)
66{
67 OwnerQ = 0;
68 Config = Cnf;
69 Access = Cnf->Access;
0a8a80e5 70 CurrentItem = 0;
18ef0a78
AL
71 TotalSize = 0;
72 CurrentSize = 0;
448c38bd
DK
73
74 Construct();
3b5421b4
AL
75}
76 /*}}}*/
77// Worker::Construct - Constructor helper /*{{{*/
78// ---------------------------------------------------------------------
79/* */
80void pkgAcquire::Worker::Construct()
81{
0a8a80e5
AL
82 NextQueue = 0;
83 NextAcquire = 0;
3b5421b4
AL
84 Process = -1;
85 InFd = -1;
86 OutFd = -1;
0a8a80e5
AL
87 OutReady = false;
88 InReady = false;
3b5421b4
AL
89 Debug = _config->FindB("Debug::pkgAcquire::Worker",false);
90}
91 /*}}}*/
92// Worker::~Worker - Destructor /*{{{*/
93// ---------------------------------------------------------------------
94/* */
95pkgAcquire::Worker::~Worker()
96{
97 close(InFd);
98 close(OutFd);
99
100 if (Process > 0)
0a8a80e5 101 {
8e5fc8f5
AL
102 /* Closing of stdin is the signal to exit and die when the process
103 indicates it needs cleanup */
104 if (Config->NeedsCleanup == false)
105 kill(Process,SIGINT);
ddc1d8d0 106 ExecWait(Process,Access.c_str(),true);
0a8a80e5 107 }
3b5421b4
AL
108}
109 /*}}}*/
110// Worker::Start - Start the worker process /*{{{*/
111// ---------------------------------------------------------------------
112/* This forks the method and inits the communication channel */
113bool pkgAcquire::Worker::Start()
114{
115 // Get the method path
116 string Method = _config->FindDir("Dir::Bin::Methods") + Access;
117 if (FileExists(Method) == false)
9082a1fc
DK
118 {
119 _error->Error(_("The method driver %s could not be found."),Method.c_str());
120 if (Access == "https")
121 _error->Notice(_("Is the package %s installed?"), "apt-transport-https");
122 return false;
123 }
3b5421b4
AL
124
125 if (Debug == true)
126 clog << "Starting method '" << Method << '\'' << endl;
127
128 // Create the pipes
129 int Pipes[4] = {-1,-1,-1,-1};
130 if (pipe(Pipes) != 0 || pipe(Pipes+2) != 0)
131 {
132 _error->Errno("pipe","Failed to create IPC pipe to subprocess");
133 for (int I = 0; I != 4; I++)
134 close(Pipes[I]);
135 return false;
136 }
8b89e57f 137 for (int I = 0; I != 4; I++)
4490f2de 138 SetCloseExec(Pipes[I],true);
448c38bd 139
3b5421b4 140 // Fork off the process
54676e1a 141 Process = ExecFork();
3b5421b4
AL
142 if (Process == 0)
143 {
144 // Setup the FDs
145 dup2(Pipes[1],STDOUT_FILENO);
146 dup2(Pipes[2],STDIN_FILENO);
3b5421b4 147 SetCloseExec(STDOUT_FILENO,false);
448c38bd 148 SetCloseExec(STDIN_FILENO,false);
3b5421b4 149 SetCloseExec(STDERR_FILENO,false);
448c38bd 150
3b5421b4
AL
151 const char *Args[2];
152 Args[0] = Method.c_str();
153 Args[1] = 0;
154 execv(Args[0],(char **)Args);
155 cerr << "Failed to exec method " << Args[0] << endl;
0dbb95d8 156 _exit(100);
3b5421b4
AL
157 }
158
159 // Fix up our FDs
160 InFd = Pipes[0];
161 OutFd = Pipes[3];
162 SetNonBlock(Pipes[0],true);
163 SetNonBlock(Pipes[3],true);
164 close(Pipes[1]);
165 close(Pipes[2]);
0a8a80e5
AL
166 OutReady = false;
167 InReady = true;
448c38bd 168
3b5421b4
AL
169 // Read the configuration data
170 if (WaitFd(InFd) == false ||
171 ReadMessages() == false)
b2e465d6 172 return _error->Error(_("Method %s did not start correctly"),Method.c_str());
3b5421b4
AL
173
174 RunMessages();
8b89e57f
AL
175 if (OwnerQ != 0)
176 SendConfiguration();
448c38bd 177
3b5421b4
AL
178 return true;
179}
180 /*}}}*/
181// Worker::ReadMessages - Read all pending messages into the list /*{{{*/
182// ---------------------------------------------------------------------
0a8a80e5 183/* */
3b5421b4
AL
184bool pkgAcquire::Worker::ReadMessages()
185{
0a8a80e5
AL
186 if (::ReadMessages(InFd,MessageQueue) == false)
187 return MethodFailure();
3b5421b4
AL
188 return true;
189}
190 /*}}}*/
3b5421b4
AL
191// Worker::RunMessage - Empty the message queue /*{{{*/
192// ---------------------------------------------------------------------
193/* This takes the messages from the message queue and runs them through
194 the parsers in order. */
195bool pkgAcquire::Worker::RunMessages()
196{
197 while (MessageQueue.empty() == false)
198 {
199 string Message = MessageQueue.front();
200 MessageQueue.erase(MessageQueue.begin());
0a8a80e5
AL
201
202 if (Debug == true)
203 clog << " <- " << Access << ':' << QuoteString(Message,"\n") << endl;
448c38bd 204
3b5421b4
AL
205 // Fetch the message number
206 char *End;
207 int Number = strtol(Message.c_str(),&End,10);
208 if (End == Message.c_str())
209 return _error->Error("Invalid message from method %s: %s",Access.c_str(),Message.c_str());
210
c88edf1d
AL
211 string URI = LookupTag(Message,"URI");
212 pkgAcquire::Queue::QItem *Itm = 0;
213 if (URI.empty() == false)
214 Itm = OwnerQ->FindItem(URI,this);
196fd136
MV
215
216 // update used mirror
217 string UsedMirror = LookupTag(Message,"UsedMirror", "");
448c38bd 218 if (!UsedMirror.empty() &&
196fd136 219 Itm &&
448c38bd 220 Itm->Description.find(" ") != string::npos)
196fd136
MV
221 {
222 Itm->Description.replace(0, Itm->Description.find(" "), UsedMirror);
223 // FIXME: will we need this as well?
224 //Itm->ShortDesc = UsedMirror;
225 }
448c38bd 226
3b5421b4
AL
227 // Determine the message number and dispatch
228 switch (Number)
229 {
0a8a80e5 230 // 100 Capabilities
3b5421b4
AL
231 case 100:
232 if (Capabilities(Message) == false)
233 return _error->Error("Unable to process Capabilities message from %s",Access.c_str());
234 break;
448c38bd 235
0a8a80e5
AL
236 // 101 Log
237 case 101:
238 if (Debug == true)
239 clog << " <- (log) " << LookupTag(Message,"Message") << endl;
240 break;
448c38bd 241
0a8a80e5
AL
242 // 102 Status
243 case 102:
244 Status = LookupTag(Message,"Message");
245 break;
448c38bd 246
15d7e515
MV
247 // 103 Redirect
248 case 103:
249 {
250 if (Itm == 0)
251 {
252 _error->Error("Method gave invalid 103 Redirect message");
253 break;
254 }
448c38bd 255
15d7e515
MV
256 string NewURI = LookupTag(Message,"New-URI",URI.c_str());
257 Itm->URI = NewURI;
5674f6b3
RG
258
259 ItemDone();
260
5674f6b3 261 // Change the status so that it can be dequeued
08ea7806
DK
262 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
263 {
264 pkgAcquire::Item *Owner = *O;
265 Owner->Status = pkgAcquire::Item::StatIdle;
266 }
5674f6b3
RG
267 // Mark the item as done (taking care of all queues)
268 // and then put it in the main queue again
08ea7806 269 std::vector<Item*> const ItmOwners = Itm->Owners;
5674f6b3 270 OwnerQ->ItemDone(Itm);
08ea7806
DK
271 Itm = NULL;
272 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
273 {
274 pkgAcquire::Item *Owner = *O;
275 pkgAcquire::ItemDesc desc = Owner->GetItemDesc();
276 desc.URI = NewURI;
277 OwnerQ->Owner->Enqueue(desc);
5674f6b3 278
08ea7806
DK
279 if (Log != 0)
280 Log->Done(Owner->GetItemDesc());
281 }
15d7e515
MV
282 break;
283 }
448c38bd 284
0a8a80e5
AL
285 // 200 URI Start
286 case 200:
c88edf1d
AL
287 {
288 if (Itm == 0)
289 {
93bf083d 290 _error->Error("Method gave invalid 200 URI Start message");
c88edf1d
AL
291 break;
292 }
448c38bd 293
c88edf1d
AL
294 CurrentItem = Itm;
295 CurrentSize = 0;
650faab0
DK
296 TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
297 ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
08ea7806
DK
298 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
299 {
300 (*O)->Start(Message, TotalSize);
448c38bd 301
08ea7806
DK
302 // Display update before completion
303 if (Log != 0)
304 {
305 if (Log->MorePulses == true)
306 Log->Pulse((*O)->GetOwner());
307 Log->Fetch((*O)->GetItemDesc());
308 }
309 }
8267fe24 310
c88edf1d
AL
311 break;
312 }
448c38bd 313
0a8a80e5
AL
314 // 201 URI Done
315 case 201:
c88edf1d
AL
316 {
317 if (Itm == 0)
318 {
93bf083d 319 _error->Error("Method gave invalid 201 URI Done message");
c88edf1d
AL
320 break;
321 }
448c38bd 322
08ea7806 323 PrepareFiles("201::URIDone", Itm);
359e1c4f 324
c5ccf175
AL
325 // Display update before completion
326 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
327 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
328 Log->Pulse((*O)->GetOwner());
448c38bd 329
08ea7806 330 std::string const filename = LookupTag(Message, "Filename", Itm->Owner->DestFile.c_str());
20801f61 331 HashStringList ReceivedHashes;
8a8feb29 332 {
08ea7806
DK
333 // see if we got hashes to verify
334 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
448c38bd 335 {
08ea7806
DK
336 std::string const tagname = std::string(*type) + "-Hash";
337 std::string const hashsum = LookupTag(Message, tagname.c_str());
338 if (hashsum.empty() == false)
339 ReceivedHashes.push_back(HashString(*type, hashsum));
340 }
341 // not all methods always sent Hashes our way
342 if (ReceivedHashes.usable() == false)
343 {
344 HashStringList const ExpectedHashes = Itm->GetExpectedHashes();
345 if (ExpectedHashes.usable() == true && RealFileExists(filename))
346 {
347 Hashes calc(ExpectedHashes);
348 FileFd file(filename, FileFd::ReadOnly, FileFd::None);
349 calc.AddFD(file);
350 ReceivedHashes = calc.GetHashStringList();
351 }
448c38bd
DK
352 }
353 }
b3501edb 354
08ea7806
DK
355 // only local files can refer other filenames and counting them as fetched would be unfair
356 if (Log != NULL && filename != Itm->Owner->DestFile)
357 Log->Fetched(ReceivedHashes.FileSize(),atoi(LookupTag(Message,"Resume-Point","0").c_str()));
358
359 std::vector<Item*> const ItmOwners = Itm->Owners;
360 OwnerQ->ItemDone(Itm);
361 Itm = NULL;
b3501edb 362
448c38bd
DK
363 bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
364 StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
08ea7806
DK
365
366 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
8267fe24 367 {
08ea7806
DK
368 pkgAcquire::Item * const Owner = *O;
369 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
370 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
c46824ce 371 {
08ea7806
DK
372 std::clog << "201 URI Done: " << Owner->DescURI() << endl
373 << "ReceivedHash:" << endl;
374 for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
375 std::clog << "\t- " << hs->toStr() << std::endl;
376 std::clog << "ExpectedHash:" << endl;
377 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
378 std::clog << "\t- " << hs->toStr() << std::endl;
379 std::clog << endl;
448c38bd 380 }
448c38bd 381
08ea7806
DK
382 // decide if what we got is what we expected
383 bool consideredOkay = false;
384 if (ExpectedHashes.usable())
385 {
386 if (ReceivedHashes.usable() == false)
387 {
388 /* IMS-Hits can't be checked here as we will have uncompressed file,
389 but the hashes for the compressed file. What we have was good through
390 so all we have to ensure later is that we are not stalled. */
391 consideredOkay = isIMSHit;
392 }
393 else if (ReceivedHashes == ExpectedHashes)
394 consideredOkay = true;
395 else
396 consideredOkay = false;
448c38bd 397
08ea7806
DK
398 }
399 else if (Owner->HashesRequired() == true)
400 consideredOkay = false;
401 else
402 consideredOkay = true;
448c38bd 403
08ea7806 404 if (consideredOkay == true)
448c38bd 405 {
08ea7806
DK
406 Owner->Done(Message, ReceivedHashes, Config);
407
408 // Log that we are done
409 if (Log != 0)
448c38bd 410 {
08ea7806
DK
411 if (isIMSHit)
412 Log->IMSHit(Owner->GetItemDesc());
413 else
414 Log->Done(Owner->GetItemDesc());
448c38bd 415 }
448c38bd 416 }
08ea7806
DK
417 else
418 {
419 Owner->Status = pkgAcquire::Item::StatAuthError;
420 Owner->Failed(Message,Config);
448c38bd 421
08ea7806
DK
422 if (Log != 0)
423 Log->Fail(Owner->GetItemDesc());
424 }
18ef0a78 425 }
08ea7806 426 ItemDone();
c88edf1d 427 break;
448c38bd
DK
428 }
429
0a8a80e5
AL
430 // 400 URI Failure
431 case 400:
c88edf1d
AL
432 {
433 if (Itm == 0)
434 {
5684f71f
DK
435 std::string const msg = LookupTag(Message,"Message");
436 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
c88edf1d
AL
437 break;
438 }
439
08ea7806
DK
440 PrepareFiles("400::URIFailure", Itm);
441
c5ccf175
AL
442 // Display update before completion
443 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
444 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
445 Log->Pulse((*O)->GetOwner());
359e1c4f 446
08ea7806 447 std::vector<Item*> const ItmOwners = Itm->Owners;
c88edf1d 448 OwnerQ->ItemDone(Itm);
08ea7806 449 Itm = NULL;
7e5f33eb 450
08ea7806
DK
451 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
452 {
453 // set some status
454 if(LookupTag(Message,"FailReason") == "Timeout" ||
455 LookupTag(Message,"FailReason") == "TmpResolveFailure" ||
456 LookupTag(Message,"FailReason") == "ResolveFailure" ||
457 LookupTag(Message,"FailReason") == "ConnectionRefused")
458 (*O)->Status = pkgAcquire::Item::StatTransientNetworkError;
7e5f33eb 459
08ea7806 460 (*O)->Failed(Message,Config);
7d8afa39 461
08ea7806
DK
462 if (Log != 0)
463 Log->Fail((*O)->GetItemDesc());
464 }
465 ItemDone();
7d8afa39 466
c88edf1d 467 break;
448c38bd
DK
468 }
469
0a8a80e5
AL
470 // 401 General Failure
471 case 401:
b2e465d6 472 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
0a8a80e5 473 break;
448c38bd 474
542ec555
AL
475 // 403 Media Change
476 case 403:
448c38bd 477 MediaChange(Message);
542ec555 478 break;
448c38bd 479 }
3b5421b4
AL
480 }
481 return true;
482}
483 /*}}}*/
484// Worker::Capabilities - 100 Capabilities handler /*{{{*/
485// ---------------------------------------------------------------------
486/* This parses the capabilities message and dumps it into the configuration
487 structure. */
488bool pkgAcquire::Worker::Capabilities(string Message)
489{
490 if (Config == 0)
491 return true;
448c38bd 492
3b5421b4
AL
493 Config->Version = LookupTag(Message,"Version");
494 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
0a8a80e5
AL
495 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
496 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
e331f6ed 497 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
8e5fc8f5 498 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
459681d3 499 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
3b5421b4
AL
500
501 // Some debug text
502 if (Debug == true)
503 {
504 clog << "Configured access method " << Config->Access << endl;
459681d3
AL
505 clog << "Version:" << Config->Version <<
506 " SingleInstance:" << Config->SingleInstance <<
448c38bd
DK
507 " Pipeline:" << Config->Pipeline <<
508 " SendConfig:" << Config->SendConfig <<
509 " LocalOnly: " << Config->LocalOnly <<
510 " NeedsCleanup: " << Config->NeedsCleanup <<
459681d3 511 " Removable: " << Config->Removable << endl;
3b5421b4 512 }
448c38bd 513
542ec555
AL
514 return true;
515}
516 /*}}}*/
517// Worker::MediaChange - Request a media change /*{{{*/
518// ---------------------------------------------------------------------
519/* */
520bool pkgAcquire::Worker::MediaChange(string Message)
521{
80a26ed1 522 int status_fd = _config->FindI("APT::Status-Fd",-1);
448c38bd 523 if(status_fd > 0)
80a26ed1
MV
524 {
525 string Media = LookupTag(Message,"Media");
448c38bd 526 string Drive = LookupTag(Message,"Drive");
80a26ed1 527 ostringstream msg,status;
1a82c63e
MV
528 ioprintf(msg,_("Please insert the disc labeled: "
529 "'%s' "
530 "in the drive '%s' and press enter."),
531 Media.c_str(),Drive.c_str());
80a26ed1 532 status << "media-change: " // message
1a82c63e
MV
533 << Media << ":" // media
534 << Drive << ":" // drive
535 << msg.str() // l10n message
80a26ed1 536 << endl;
31bda500
DK
537
538 std::string const dlstatus = status.str();
d68d65ad 539 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
80a26ed1
MV
540 }
541
542ec555
AL
542 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
543 LookupTag(Message,"Drive")) == false)
544 {
545 char S[300];
96bc43c4 546 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
542ec555
AL
547 if (Debug == true)
548 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
549 OutQueue += S;
550 OutReady = true;
551 return true;
552 }
553
554 char S[300];
96bc43c4 555 snprintf(S,sizeof(S),"603 Media Changed\n\n");
542ec555
AL
556 if (Debug == true)
557 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
558 OutQueue += S;
559 OutReady = true;
3b5421b4
AL
560 return true;
561}
0118833a 562 /*}}}*/
0a8a80e5
AL
563// Worker::SendConfiguration - Send the config to the method /*{{{*/
564// ---------------------------------------------------------------------
565/* */
566bool pkgAcquire::Worker::SendConfiguration()
567{
568 if (Config->SendConfig == false)
569 return true;
570
571 if (OutFd == -1)
572 return false;
0a8a80e5 573
d280d03a 574 /* Write out all of the configuration directives by walking the
0a8a80e5 575 configuration tree */
d280d03a
DK
576 std::ostringstream Message;
577 Message << "601 Configuration\n";
578 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
579 Message << '\n';
0a8a80e5
AL
580
581 if (Debug == true)
d280d03a
DK
582 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
583 OutQueue += Message.str();
584 OutReady = true;
585
0a8a80e5
AL
586 return true;
587}
588 /*}}}*/
589// Worker::QueueItem - Add an item to the outbound queue /*{{{*/
590// ---------------------------------------------------------------------
591/* Send a URI Acquire message to the method */
592bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
593{
594 if (OutFd == -1)
595 return false;
448c38bd 596
0a8a80e5
AL
597 string Message = "600 URI Acquire\n";
598 Message.reserve(300);
599 Message += "URI: " + Item->URI;
600 Message += "\nFilename: " + Item->Owner->DestFile;
08ea7806
DK
601
602 HashStringList const hsl = Item->GetExpectedHashes();
d003a557
DK
603 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
604 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
08ea7806
DK
605
606 if (hsl.FileSize() == 0)
c48eea97 607 {
08ea7806
DK
608 unsigned long long FileSize = Item->GetMaximumSize();
609 if(FileSize > 0)
610 {
611 string MaximumSize;
612 strprintf(MaximumSize, "%llu", FileSize);
613 Message += "\nMaximum-Size: " + MaximumSize;
614 }
c48eea97 615 }
08ea7806
DK
616
617 Item->SyncDestinationFiles();
618 Message += Item->Custom600Headers();
0a8a80e5 619 Message += "\n\n";
359e1c4f
DK
620
621 if (RealFileExists(Item->Owner->DestFile))
622 {
623 std::string SandboxUser = _config->Find("APT::Sandbox::User");
624 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
625 SandboxUser.c_str(), "root", 0600);
626 }
627
0a8a80e5
AL
628 if (Debug == true)
629 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
630 OutQueue += Message;
631 OutReady = true;
448c38bd 632
0a8a80e5
AL
633 return true;
634}
635 /*}}}*/
636// Worker::OutFdRead - Out bound FD is ready /*{{{*/
637// ---------------------------------------------------------------------
638/* */
639bool pkgAcquire::Worker::OutFdReady()
640{
ee7af1bd
YY
641 int Res;
642 do
643 {
644 Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
645 }
646 while (Res < 0 && errno == EINTR);
647
648 if (Res <= 0)
0a8a80e5 649 return MethodFailure();
ee7af1bd
YY
650
651 OutQueue.erase(0,Res);
0a8a80e5
AL
652 if (OutQueue.empty() == true)
653 OutReady = false;
448c38bd 654
0a8a80e5
AL
655 return true;
656}
657 /*}}}*/
658// Worker::InFdRead - In bound FD is ready /*{{{*/
659// ---------------------------------------------------------------------
660/* */
661bool pkgAcquire::Worker::InFdReady()
662{
663 if (ReadMessages() == false)
664 return false;
665 RunMessages();
666 return true;
667}
668 /*}}}*/
669// Worker::MethodFailure - Called when the method fails /*{{{*/
670// ---------------------------------------------------------------------
1e3f4083 671/* This is called when the method is believed to have failed, probably because
0a8a80e5
AL
672 read returned -1. */
673bool pkgAcquire::Worker::MethodFailure()
674{
76d97c26 675 _error->Error("Method %s has died unexpectedly!",Access.c_str());
448c38bd 676
ab7f4d7c
MV
677 // do not reap the child here to show meaningfull error to the user
678 ExecWait(Process,Access.c_str(),false);
0a8a80e5
AL
679 Process = -1;
680 close(InFd);
681 close(OutFd);
682 InFd = -1;
683 OutFd = -1;
684 OutReady = false;
685 InReady = false;
686 OutQueue = string();
687 MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
448c38bd 688
0a8a80e5
AL
689 return false;
690}
691 /*}}}*/
448c38bd 692// Worker::Pulse - Called periodically /*{{{*/
8267fe24
AL
693// ---------------------------------------------------------------------
694/* */
695void pkgAcquire::Worker::Pulse()
696{
697 if (CurrentItem == 0)
698 return;
448c38bd 699
8267fe24
AL
700 struct stat Buf;
701 if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
702 return;
703 CurrentSize = Buf.st_size;
704}
705 /*}}}*/
706// Worker::ItemDone - Called when the current item is finished /*{{{*/
707// ---------------------------------------------------------------------
708/* */
709void pkgAcquire::Worker::ItemDone()
710{
711 CurrentItem = 0;
712 CurrentSize = 0;
713 TotalSize = 0;
714 Status = string();
715}
716 /*}}}*/
08ea7806
DK
717void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
718{
719 if (RealFileExists(Itm->Owner->DestFile))
720 {
721 ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
722 std::string const filename = Itm->Owner->DestFile;
723 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
724 {
725 pkgAcquire::Item const * const Owner = *O;
726 if (Owner->DestFile == filename)
727 continue;
728 unlink(Owner->DestFile.c_str());
729 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
730 {
731 // diferent mounts can't happen for us as we download to lists/ by default,
732 // but if the system is reused by others the locations can potentially be on
733 // different disks, so use symlink as poor-men replacement.
734 // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
735 if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
736 _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
737 }
738 }
739 }
740 else
741 {
742 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
743 unlink((*O)->DestFile.c_str());
744 }
745}
746 /*}}}*/