]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-worker.cc
dpkgpm: Convert users of localtime() to localtime_r()
[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
ae732225
DK
257 for (auto const &O: Itm->Owners)
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
20801f61 338 HashStringList ReceivedHashes;
8a8feb29 339 {
b6a0018e
DK
340 std::string const givenfilename = LookupTag(Message, "Filename");
341 std::string const filename = givenfilename.empty() ? Itm->Owner->DestFile : givenfilename;
08ea7806
DK
342 // see if we got hashes to verify
343 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
448c38bd 344 {
08ea7806
DK
345 std::string const tagname = std::string(*type) + "-Hash";
346 std::string const hashsum = LookupTag(Message, tagname.c_str());
347 if (hashsum.empty() == false)
348 ReceivedHashes.push_back(HashString(*type, hashsum));
349 }
350 // not all methods always sent Hashes our way
351 if (ReceivedHashes.usable() == false)
352 {
353 HashStringList const ExpectedHashes = Itm->GetExpectedHashes();
354 if (ExpectedHashes.usable() == true && RealFileExists(filename))
355 {
356 Hashes calc(ExpectedHashes);
357 FileFd file(filename, FileFd::ReadOnly, FileFd::None);
358 calc.AddFD(file);
359 ReceivedHashes = calc.GetHashStringList();
360 }
448c38bd 361 }
b3501edb 362
b6a0018e
DK
363 // only local files can refer other filenames and counting them as fetched would be unfair
364 if (Log != NULL && Itm->Owner->Complete == false && Itm->Owner->Local == false && givenfilename == filename)
365 Log->Fetched(ReceivedHashes.FileSize(),atoi(LookupTag(Message,"Resume-Point","0").c_str()));
366 }
08ea7806
DK
367
368 std::vector<Item*> const ItmOwners = Itm->Owners;
369 OwnerQ->ItemDone(Itm);
370 Itm = NULL;
b3501edb 371
448c38bd
DK
372 bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
373 StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
08ea7806 374 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
8267fe24 375 {
08ea7806
DK
376 pkgAcquire::Item * const Owner = *O;
377 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
378 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
c46824ce 379 {
08ea7806
DK
380 std::clog << "201 URI Done: " << Owner->DescURI() << endl
381 << "ReceivedHash:" << endl;
382 for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
383 std::clog << "\t- " << hs->toStr() << std::endl;
384 std::clog << "ExpectedHash:" << endl;
385 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
386 std::clog << "\t- " << hs->toStr() << std::endl;
387 std::clog << endl;
448c38bd 388 }
448c38bd 389
08ea7806
DK
390 // decide if what we got is what we expected
391 bool consideredOkay = false;
392 if (ExpectedHashes.usable())
393 {
394 if (ReceivedHashes.usable() == false)
395 {
396 /* IMS-Hits can't be checked here as we will have uncompressed file,
397 but the hashes for the compressed file. What we have was good through
398 so all we have to ensure later is that we are not stalled. */
399 consideredOkay = isIMSHit;
400 }
401 else if (ReceivedHashes == ExpectedHashes)
402 consideredOkay = true;
403 else
404 consideredOkay = false;
448c38bd 405
08ea7806
DK
406 }
407 else if (Owner->HashesRequired() == true)
408 consideredOkay = false;
409 else
63d60998 410 {
08ea7806 411 consideredOkay = true;
63d60998
DK
412 // even if the hashes aren't usable to declare something secure
413 // we can at least use them to declare it an integrity failure
414 if (ExpectedHashes.empty() == false && ReceivedHashes != ExpectedHashes && _config->Find("Acquire::ForceHash").empty())
415 consideredOkay = false;
416 }
448c38bd 417
dd676dc7
DK
418 if (consideredOkay == true)
419 consideredOkay = Owner->VerifyDone(Message, Config);
420 else // hashsum mismatch
421 Owner->Status = pkgAcquire::Item::StatAuthError;
422
08ea7806 423 if (consideredOkay == true)
448c38bd 424 {
08ea7806 425 Owner->Done(Message, ReceivedHashes, Config);
08ea7806 426 if (Log != 0)
448c38bd 427 {
08ea7806
DK
428 if (isIMSHit)
429 Log->IMSHit(Owner->GetItemDesc());
430 else
431 Log->Done(Owner->GetItemDesc());
448c38bd 432 }
448c38bd 433 }
08ea7806
DK
434 else
435 {
08ea7806 436 Owner->Failed(Message,Config);
08ea7806
DK
437 if (Log != 0)
438 Log->Fail(Owner->GetItemDesc());
439 }
18ef0a78 440 }
08ea7806 441 ItemDone();
c88edf1d 442 break;
448c38bd
DK
443 }
444
0a8a80e5
AL
445 // 400 URI Failure
446 case 400:
c88edf1d
AL
447 {
448 if (Itm == 0)
449 {
5684f71f
DK
450 std::string const msg = LookupTag(Message,"Message");
451 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
c88edf1d
AL
452 break;
453 }
454
08ea7806
DK
455 PrepareFiles("400::URIFailure", Itm);
456
c5ccf175
AL
457 // Display update before completion
458 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
459 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
460 Log->Pulse((*O)->GetOwner());
359e1c4f 461
08ea7806 462 std::vector<Item*> const ItmOwners = Itm->Owners;
c88edf1d 463 OwnerQ->ItemDone(Itm);
08ea7806 464 Itm = NULL;
7e5f33eb 465
08ea7806
DK
466 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
467 {
468 // set some status
469 if(LookupTag(Message,"FailReason") == "Timeout" ||
470 LookupTag(Message,"FailReason") == "TmpResolveFailure" ||
471 LookupTag(Message,"FailReason") == "ResolveFailure" ||
472 LookupTag(Message,"FailReason") == "ConnectionRefused")
473 (*O)->Status = pkgAcquire::Item::StatTransientNetworkError;
7e5f33eb 474
08ea7806 475 (*O)->Failed(Message,Config);
7d8afa39 476
08ea7806
DK
477 if (Log != 0)
478 Log->Fail((*O)->GetItemDesc());
479 }
480 ItemDone();
7d8afa39 481
c88edf1d 482 break;
448c38bd
DK
483 }
484
0a8a80e5
AL
485 // 401 General Failure
486 case 401:
b2e465d6 487 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
0a8a80e5 488 break;
448c38bd 489
542ec555
AL
490 // 403 Media Change
491 case 403:
448c38bd 492 MediaChange(Message);
542ec555 493 break;
448c38bd 494 }
3b5421b4
AL
495 }
496 return true;
497}
498 /*}}}*/
499// Worker::Capabilities - 100 Capabilities handler /*{{{*/
500// ---------------------------------------------------------------------
501/* This parses the capabilities message and dumps it into the configuration
502 structure. */
503bool pkgAcquire::Worker::Capabilities(string Message)
504{
505 if (Config == 0)
506 return true;
448c38bd 507
3b5421b4
AL
508 Config->Version = LookupTag(Message,"Version");
509 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
0a8a80e5
AL
510 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
511 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
e331f6ed 512 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
8e5fc8f5 513 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
459681d3 514 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
3b5421b4
AL
515
516 // Some debug text
517 if (Debug == true)
518 {
519 clog << "Configured access method " << Config->Access << endl;
459681d3
AL
520 clog << "Version:" << Config->Version <<
521 " SingleInstance:" << Config->SingleInstance <<
448c38bd
DK
522 " Pipeline:" << Config->Pipeline <<
523 " SendConfig:" << Config->SendConfig <<
524 " LocalOnly: " << Config->LocalOnly <<
525 " NeedsCleanup: " << Config->NeedsCleanup <<
459681d3 526 " Removable: " << Config->Removable << endl;
3b5421b4 527 }
448c38bd 528
542ec555
AL
529 return true;
530}
531 /*}}}*/
532// Worker::MediaChange - Request a media change /*{{{*/
533// ---------------------------------------------------------------------
534/* */
535bool pkgAcquire::Worker::MediaChange(string Message)
536{
80a26ed1 537 int status_fd = _config->FindI("APT::Status-Fd",-1);
448c38bd 538 if(status_fd > 0)
80a26ed1
MV
539 {
540 string Media = LookupTag(Message,"Media");
448c38bd 541 string Drive = LookupTag(Message,"Drive");
80a26ed1 542 ostringstream msg,status;
1a82c63e
MV
543 ioprintf(msg,_("Please insert the disc labeled: "
544 "'%s' "
94171725 545 "in the drive '%s' and press [Enter]."),
1a82c63e 546 Media.c_str(),Drive.c_str());
80a26ed1 547 status << "media-change: " // message
1a82c63e
MV
548 << Media << ":" // media
549 << Drive << ":" // drive
550 << msg.str() // l10n message
80a26ed1 551 << endl;
31bda500
DK
552
553 std::string const dlstatus = status.str();
d68d65ad 554 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
80a26ed1
MV
555 }
556
542ec555
AL
557 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
558 LookupTag(Message,"Drive")) == false)
559 {
560 char S[300];
96bc43c4 561 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
542ec555
AL
562 if (Debug == true)
563 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
564 OutQueue += S;
565 OutReady = true;
566 return true;
567 }
568
569 char S[300];
96bc43c4 570 snprintf(S,sizeof(S),"603 Media Changed\n\n");
542ec555
AL
571 if (Debug == true)
572 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
573 OutQueue += S;
574 OutReady = true;
3b5421b4
AL
575 return true;
576}
0118833a 577 /*}}}*/
0a8a80e5
AL
578// Worker::SendConfiguration - Send the config to the method /*{{{*/
579// ---------------------------------------------------------------------
580/* */
581bool pkgAcquire::Worker::SendConfiguration()
582{
583 if (Config->SendConfig == false)
584 return true;
585
586 if (OutFd == -1)
587 return false;
0a8a80e5 588
d280d03a 589 /* Write out all of the configuration directives by walking the
0a8a80e5 590 configuration tree */
d280d03a
DK
591 std::ostringstream Message;
592 Message << "601 Configuration\n";
593 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
594 Message << '\n';
0a8a80e5
AL
595
596 if (Debug == true)
d280d03a
DK
597 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
598 OutQueue += Message.str();
599 OutReady = true;
600
0a8a80e5
AL
601 return true;
602}
603 /*}}}*/
604// Worker::QueueItem - Add an item to the outbound queue /*{{{*/
605// ---------------------------------------------------------------------
606/* Send a URI Acquire message to the method */
607bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
608{
609 if (OutFd == -1)
610 return false;
448c38bd 611
0a8a80e5
AL
612 string Message = "600 URI Acquire\n";
613 Message.reserve(300);
614 Message += "URI: " + Item->URI;
615 Message += "\nFilename: " + Item->Owner->DestFile;
08ea7806
DK
616
617 HashStringList const hsl = Item->GetExpectedHashes();
d003a557
DK
618 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
619 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
08ea7806
DK
620
621 if (hsl.FileSize() == 0)
c48eea97 622 {
08ea7806
DK
623 unsigned long long FileSize = Item->GetMaximumSize();
624 if(FileSize > 0)
625 {
626 string MaximumSize;
627 strprintf(MaximumSize, "%llu", FileSize);
628 Message += "\nMaximum-Size: " + MaximumSize;
629 }
c48eea97 630 }
08ea7806
DK
631
632 Item->SyncDestinationFiles();
633 Message += Item->Custom600Headers();
0a8a80e5 634 Message += "\n\n";
359e1c4f
DK
635
636 if (RealFileExists(Item->Owner->DestFile))
637 {
638 std::string SandboxUser = _config->Find("APT::Sandbox::User");
639 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
640 SandboxUser.c_str(), "root", 0600);
641 }
642
0a8a80e5
AL
643 if (Debug == true)
644 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
645 OutQueue += Message;
646 OutReady = true;
448c38bd 647
0a8a80e5
AL
648 return true;
649}
650 /*}}}*/
651// Worker::OutFdRead - Out bound FD is ready /*{{{*/
652// ---------------------------------------------------------------------
653/* */
654bool pkgAcquire::Worker::OutFdReady()
655{
ee7af1bd
YY
656 int Res;
657 do
658 {
659 Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
660 }
661 while (Res < 0 && errno == EINTR);
662
663 if (Res <= 0)
0a8a80e5 664 return MethodFailure();
ee7af1bd
YY
665
666 OutQueue.erase(0,Res);
0a8a80e5
AL
667 if (OutQueue.empty() == true)
668 OutReady = false;
448c38bd 669
0a8a80e5
AL
670 return true;
671}
672 /*}}}*/
673// Worker::InFdRead - In bound FD is ready /*{{{*/
674// ---------------------------------------------------------------------
675/* */
676bool pkgAcquire::Worker::InFdReady()
677{
678 if (ReadMessages() == false)
679 return false;
680 RunMessages();
681 return true;
682}
683 /*}}}*/
684// Worker::MethodFailure - Called when the method fails /*{{{*/
685// ---------------------------------------------------------------------
1e3f4083 686/* This is called when the method is believed to have failed, probably because
0a8a80e5
AL
687 read returned -1. */
688bool pkgAcquire::Worker::MethodFailure()
689{
76d97c26 690 _error->Error("Method %s has died unexpectedly!",Access.c_str());
448c38bd 691
ab7f4d7c
MV
692 // do not reap the child here to show meaningfull error to the user
693 ExecWait(Process,Access.c_str(),false);
0a8a80e5
AL
694 Process = -1;
695 close(InFd);
696 close(OutFd);
697 InFd = -1;
698 OutFd = -1;
699 OutReady = false;
700 InReady = false;
701 OutQueue = string();
702 MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
448c38bd 703
0a8a80e5
AL
704 return false;
705}
706 /*}}}*/
448c38bd 707// Worker::Pulse - Called periodically /*{{{*/
8267fe24
AL
708// ---------------------------------------------------------------------
709/* */
710void pkgAcquire::Worker::Pulse()
711{
712 if (CurrentItem == 0)
713 return;
448c38bd 714
8267fe24
AL
715 struct stat Buf;
716 if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
717 return;
718 CurrentSize = Buf.st_size;
719}
720 /*}}}*/
721// Worker::ItemDone - Called when the current item is finished /*{{{*/
722// ---------------------------------------------------------------------
723/* */
724void pkgAcquire::Worker::ItemDone()
725{
726 CurrentItem = 0;
727 CurrentSize = 0;
728 TotalSize = 0;
729 Status = string();
730}
731 /*}}}*/
08ea7806
DK
732void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
733{
734 if (RealFileExists(Itm->Owner->DestFile))
735 {
736 ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
737 std::string const filename = Itm->Owner->DestFile;
738 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
739 {
740 pkgAcquire::Item const * const Owner = *O;
741 if (Owner->DestFile == filename)
742 continue;
743 unlink(Owner->DestFile.c_str());
744 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
745 {
3d8232bf 746 // different mounts can't happen for us as we download to lists/ by default,
08ea7806
DK
747 // but if the system is reused by others the locations can potentially be on
748 // different disks, so use symlink as poor-men replacement.
749 // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
750 if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
751 _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
752 }
753 }
754 }
755 else
756 {
757 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
758 unlink((*O)->DestFile.c_str());
759 }
760}
761 /*}}}*/