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