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