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