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