]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-method.cc
* basic error reporting from apt in place now (ReportMirrorFailures())
[apt.git] / apt-pkg / acquire-method.cc
CommitLineData
93bf083d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b3d44315 3// $Id: acquire-method.cc,v 1.27.2.1 2003/12/24 23:09:17 mdz Exp $
93bf083d
AL
4/* ######################################################################
5
6 Acquire Method
7
8384ebdf 8 This is a skeleton class that implements most of the functionality
b2e465d6 9 of a method and some useful functions to make method implementation
8384ebdf
AL
10 simpler. The methods all derive this and specialize it. The most
11 complex implementation is the http method which needs to provide
12 pipelining, it runs the message engine at the same time it is
13 downloading files..
14
93bf083d
AL
15 ##################################################################### */
16 /*}}}*/
17// Include Files /*{{{*/
18#ifdef __GNUG__
19#pragma implementation "apt-pkg/acquire-method.h"
20#endif
21#include <apt-pkg/acquire-method.h>
22#include <apt-pkg/error.h>
23#include <apt-pkg/configuration.h>
cdcc6d34 24#include <apt-pkg/strutl.h>
93bf083d 25#include <apt-pkg/fileutl.h>
a7c835af 26#include <apt-pkg/hashes.h>
b4fc9b6f
AL
27
28#include <iostream>
2c206aa4 29#include <stdarg.h>
93bf083d 30#include <stdio.h>
65a1e968 31#include <unistd.h>
b3d44315 32#include <sys/signal.h>
93bf083d
AL
33 /*}}}*/
34
b4fc9b6f
AL
35using namespace std;
36
93bf083d
AL
37// AcqMethod::pkgAcqMethod - Constructor /*{{{*/
38// ---------------------------------------------------------------------
39/* This constructs the initialization text */
40pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
41{
42 char S[300] = "";
43 char *End = S;
44 strcat(End,"100 Capabilities\n");
45 sprintf(End+strlen(End),"Version: %s\n",Ver);
46
47 if ((Flags & SingleInstance) == SingleInstance)
48 strcat(End,"Single-Instance: true\n");
49
93bf083d
AL
50 if ((Flags & Pipeline) == Pipeline)
51 strcat(End,"Pipeline: true\n");
52
53 if ((Flags & SendConfig) == SendConfig)
54 strcat(End,"Send-Config: true\n");
e331f6ed
AL
55
56 if ((Flags & LocalOnly) == LocalOnly)
57 strcat(End,"Local-Only: true\n");
8e5fc8f5
AL
58
59 if ((Flags & NeedsCleanup) == NeedsCleanup)
60 strcat(End,"Needs-Cleanup: true\n");
459681d3
AL
61
62 if ((Flags & Removable) == Removable)
63 strcat(End,"Removable: true\n");
93bf083d
AL
64 strcat(End,"\n");
65
66 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
67 exit(100);
be4401bf
AL
68
69 SetNonBlock(STDIN_FILENO,true);
5cb5d8dc 70
92e889c8 71 Queue = 0;
5cb5d8dc 72 QueueBack = 0;
93bf083d
AL
73}
74 /*}}}*/
75// AcqMethod::Fail - A fetch has failed /*{{{*/
76// ---------------------------------------------------------------------
77/* */
a72ace20 78void pkgAcqMethod::Fail(bool Transient)
93bf083d
AL
79{
80 string Err = "Undetermined Error";
81 if (_error->empty() == false)
82 _error->PopMessage(Err);
83 _error->Discard();
a72ace20 84 Fail(Err,Transient);
93bf083d
AL
85}
86 /*}}}*/
87// AcqMethod::Fail - A fetch has failed /*{{{*/
88// ---------------------------------------------------------------------
89/* */
a72ace20 90void pkgAcqMethod::Fail(string Err,bool Transient)
6d5dd02a
AL
91{
92 // Strip out junk from the error messages
b4fc9b6f 93 for (string::iterator I = Err.begin(); I != Err.end(); I++)
6d5dd02a
AL
94 {
95 if (*I == '\r')
96 *I = ' ';
97 if (*I == '\n')
98 *I = ' ';
99 }
100
93bf083d 101 char S[1024];
be4401bf
AL
102 if (Queue != 0)
103 {
8b067c22 104 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
b2e465d6
AL
105 "Message: %s %s\n",Queue->Uri.c_str(),Err.c_str(),
106 FailExtra.c_str());
a72ace20 107
be4401bf
AL
108 // Dequeue
109 FetchItem *Tmp = Queue;
110 Queue = Queue->Next;
111 delete Tmp;
5cb5d8dc
AL
112 if (Tmp == QueueBack)
113 QueueBack = Queue;
be4401bf
AL
114 }
115 else
8b067c22 116 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
b2e465d6
AL
117 "Message: %s %s\n",Err.c_str(),
118 FailExtra.c_str());
be4401bf 119
a72ace20
AL
120 // Set the transient flag
121 if (Transient == true)
122 strcat(S,"Transient-Failure: true\n\n");
123 else
124 strcat(S,"\n");
125
93bf083d
AL
126 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
127 exit(100);
128}
129 /*}}}*/
130// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
131// ---------------------------------------------------------------------
132/* */
be4401bf 133void pkgAcqMethod::URIStart(FetchResult &Res)
93bf083d 134{
be4401bf
AL
135 if (Queue == 0)
136 abort();
137
93bf083d
AL
138 char S[1024] = "";
139 char *End = S;
140
be4401bf 141 End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
93bf083d 142 if (Res.Size != 0)
8b067c22 143 End += snprintf(End,sizeof(S)-4 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
144
145 if (Res.LastModified != 0)
8b067c22 146 End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
147 TimeRFC1123(Res.LastModified).c_str());
148
be4401bf 149 if (Res.ResumePoint != 0)
8b067c22 150 End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point: %lu\n",
be4401bf 151 Res.ResumePoint);
93bf083d
AL
152
153 strcat(End,"\n");
154 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
155 exit(100);
156}
157 /*}}}*/
158// AcqMethod::URIDone - A URI is finished /*{{{*/
159// ---------------------------------------------------------------------
160/* */
161void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
162{
be4401bf
AL
163 if (Queue == 0)
164 abort();
165
93bf083d
AL
166 char S[1024] = "";
167 char *End = S;
168
be4401bf 169 End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
93bf083d
AL
170
171 if (Res.Filename.empty() == false)
8b067c22 172 End += snprintf(End,sizeof(S)-50 - (End - S),"Filename: %s\n",Res.Filename.c_str());
93bf083d
AL
173
174 if (Res.Size != 0)
8b067c22 175 End += snprintf(End,sizeof(S)-50 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
176
177 if (Res.LastModified != 0)
8b067c22 178 End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
179 TimeRFC1123(Res.LastModified).c_str());
180
181 if (Res.MD5Sum.empty() == false)
8b067c22 182 End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash: %s\n",Res.MD5Sum.c_str());
a7c835af
AL
183 if (Res.SHA1Sum.empty() == false)
184 End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str());
b3d44315
MV
185 if (Res.GPGVOutput.size() > 0)
186 End += snprintf(End,sizeof(S)-50 - (End - S),"GPGVOutput:\n");
187 for (vector<string>::iterator I = Res.GPGVOutput.begin();
188 I != Res.GPGVOutput.end(); I++)
189 End += snprintf(End,sizeof(S)-50 - (End - S), " %s\n", (*I).c_str());
93bf083d 190
b98f2859 191 if (Res.ResumePoint != 0)
8b067c22 192 End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point: %lu\n",
b98f2859
AL
193 Res.ResumePoint);
194
93bf083d
AL
195 if (Res.IMSHit == true)
196 strcat(End,"IMS-Hit: true\n");
197 End = S + strlen(S);
198
199 if (Alt != 0)
200 {
201 if (Alt->Filename.empty() == false)
8b067c22 202 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
93bf083d
AL
203
204 if (Alt->Size != 0)
8b067c22 205 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size: %lu\n",Alt->Size);
93bf083d
AL
206
207 if (Alt->LastModified != 0)
8b067c22 208 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified: %s\n",
93bf083d
AL
209 TimeRFC1123(Alt->LastModified).c_str());
210
211 if (Alt->MD5Sum.empty() == false)
8b067c22 212 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
93bf083d 213 Alt->MD5Sum.c_str());
a7c835af
AL
214 if (Alt->SHA1Sum.empty() == false)
215 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA1-Hash: %s\n",
216 Alt->SHA1Sum.c_str());
93bf083d
AL
217
218 if (Alt->IMSHit == true)
219 strcat(End,"Alt-IMS-Hit: true\n");
220 }
221
222 strcat(End,"\n");
223 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
224 exit(100);
be4401bf
AL
225
226 // Dequeue
227 FetchItem *Tmp = Queue;
228 Queue = Queue->Next;
229 delete Tmp;
5cb5d8dc
AL
230 if (Tmp == QueueBack)
231 QueueBack = Queue;
93bf083d
AL
232}
233 /*}}}*/
f46e7681
AL
234// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
235// ---------------------------------------------------------------------
236/* This sends a 403 Media Failure message to the APT and waits for it
237 to be ackd */
018f1533 238bool pkgAcqMethod::MediaFail(string Required,string Drive)
f46e7681
AL
239{
240 char S[1024];
241 snprintf(S,sizeof(S),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
242 Required.c_str(),Drive.c_str());
243
244 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
245 exit(100);
246
247 vector<string> MyMessages;
248
249 /* Here we read messages until we find a 603, each non 603 message is
250 appended to the main message list for later processing */
251 while (1)
252 {
253 if (WaitFd(STDIN_FILENO) == false)
76d97c26 254 return false;
f46e7681
AL
255
256 if (ReadMessages(STDIN_FILENO,MyMessages) == false)
76d97c26
AL
257 return false;
258
f46e7681
AL
259 string Message = MyMessages.front();
260 MyMessages.erase(MyMessages.begin());
261
262 // Fetch the message number
263 char *End;
264 int Number = strtol(Message.c_str(),&End,10);
265 if (End == Message.c_str())
266 {
267 cerr << "Malformed message!" << endl;
268 exit(100);
269 }
270
271 // Change ack
272 if (Number == 603)
273 {
76d97c26 274 while (MyMessages.empty() == false)
f46e7681
AL
275 {
276 Messages.push_back(MyMessages.front());
277 MyMessages.erase(MyMessages.begin());
278 }
542ec555 279
2a749770 280 return !StringToBool(LookupTag(Message,"Failed"),false);
f46e7681
AL
281 }
282
283 Messages.push_back(Message);
284 }
285}
286 /*}}}*/
93bf083d
AL
287// AcqMethod::Configuration - Handle the configuration message /*{{{*/
288// ---------------------------------------------------------------------
289/* This parses each configuration entry and puts it into the _config
290 Configuration class. */
291bool pkgAcqMethod::Configuration(string Message)
292{
293 ::Configuration &Cnf = *_config;
294
b4fc9b6f
AL
295 const char *I = Message.c_str();
296 const char *MsgEnd = I + Message.length();
93bf083d
AL
297
298 unsigned int Length = strlen("Config-Item");
b4fc9b6f 299 for (; I + Length < MsgEnd; I++)
93bf083d
AL
300 {
301 // Not a config item
302 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
303 continue;
304
305 I += Length + 1;
306
b4fc9b6f 307 for (; I < MsgEnd && *I == ' '; I++);
93bf083d 308 const char *Equals = I;
b4fc9b6f 309 for (; Equals < MsgEnd && *Equals != '='; Equals++);
93bf083d 310 const char *End = Equals;
b4fc9b6f 311 for (; End < MsgEnd && *End != '\n'; End++);
93bf083d
AL
312 if (End == Equals)
313 return false;
314
6d5dd02a
AL
315 Cnf.Set(DeQuoteString(string(I,Equals-I)),
316 DeQuoteString(string(Equals+1,End-Equals-1)));
93bf083d
AL
317 I = End;
318 }
319
320 return true;
321}
322 /*}}}*/
323// AcqMethod::Run - Run the message engine /*{{{*/
324// ---------------------------------------------------------------------
8384ebdf
AL
325/* Fetch any messages and execute them. In single mode it returns 1 if
326 there are no more available messages - any other result is a
327 fatal failure code! */
be4401bf 328int pkgAcqMethod::Run(bool Single)
93bf083d 329{
93bf083d
AL
330 while (1)
331 {
be4401bf 332 // Block if the message queue is empty
93bf083d 333 if (Messages.empty() == true)
be4401bf
AL
334 {
335 if (Single == false)
336 if (WaitFd(STDIN_FILENO) == false)
8e5fc8f5 337 break;
92e889c8 338 if (ReadMessages(STDIN_FILENO,Messages) == false)
8e5fc8f5 339 break;
92e889c8
AL
340 }
341
be4401bf
AL
342 // Single mode exits if the message queue is empty
343 if (Single == true && Messages.empty() == true)
8384ebdf 344 return -1;
be4401bf 345
93bf083d
AL
346 string Message = Messages.front();
347 Messages.erase(Messages.begin());
348
349 // Fetch the message number
350 char *End;
351 int Number = strtol(Message.c_str(),&End,10);
352 if (End == Message.c_str())
353 {
354 cerr << "Malformed message!" << endl;
355 return 100;
356 }
357
358 switch (Number)
8e5fc8f5 359 {
93bf083d
AL
360 case 601:
361 if (Configuration(Message) == false)
362 return 100;
363 break;
364
365 case 600:
be4401bf
AL
366 {
367 FetchItem *Tmp = new FetchItem;
368
369 Tmp->Uri = LookupTag(Message,"URI");
370 Tmp->DestFile = LookupTag(Message,"FileName");
cae9cdce 371 Tmp->ExpectedMD5 = LookupTag(Message,"ExpectedMD5");
b98f2859
AL
372 if (StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified) == false)
373 Tmp->LastModified = 0;
a72ace20 374 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
be4401bf
AL
375 Tmp->Next = 0;
376
377 // Append it to the list
378 FetchItem **I = &Queue;
92e889c8 379 for (; *I != 0; I = &(*I)->Next);
be4401bf 380 *I = Tmp;
5cb5d8dc
AL
381 if (QueueBack == 0)
382 QueueBack = Tmp;
383
bfd22fc0 384 // Notify that this item is to be fetched.
be4401bf 385 if (Fetch(Tmp) == false)
93bf083d 386 Fail();
bfd22fc0 387
93bf083d
AL
388 break;
389 }
390 }
391 }
392
8e5fc8f5 393 Exit();
93bf083d
AL
394 return 0;
395}
396 /*}}}*/
be4401bf
AL
397// AcqMethod::Log - Send a log message /*{{{*/
398// ---------------------------------------------------------------------
399/* */
400void pkgAcqMethod::Log(const char *Format,...)
401{
402 string CurrentURI = "<UNKNOWN>";
403 if (Queue != 0)
404 CurrentURI = Queue->Uri;
405
406 va_list args;
407 va_start(args,Format);
408
409 // sprintf the description
410 char S[1024];
8b067c22 411 unsigned int Len = snprintf(S,sizeof(S)-4,"101 Log\nURI: %s\n"
be4401bf
AL
412 "Message: ",CurrentURI.c_str());
413
8b067c22 414 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
415 strcat(S,"\n\n");
416
417 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
418 exit(100);
419}
420 /*}}}*/
421// AcqMethod::Status - Send a status message /*{{{*/
422// ---------------------------------------------------------------------
423/* */
424void pkgAcqMethod::Status(const char *Format,...)
425{
426 string CurrentURI = "<UNKNOWN>";
427 if (Queue != 0)
428 CurrentURI = Queue->Uri;
429
430 va_list args;
431 va_start(args,Format);
432
433 // sprintf the description
434 char S[1024];
8b067c22 435 unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\nURI: %s\n"
be4401bf
AL
436 "Message: ",CurrentURI.c_str());
437
8b067c22 438 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
439 strcat(S,"\n\n");
440
441 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
442 exit(100);
443}
444 /*}}}*/
445
93bf083d
AL
446// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
447// ---------------------------------------------------------------------
448/* */
93274b8d
AL
449pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
450 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
451{
452}
453 /*}}}*/
a7c835af
AL
454// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
455// ---------------------------------------------------------------------
456/* This hides the number of hashes we are supporting from the caller.
457 It just deals with the hash class. */
458void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
459{
460 MD5Sum = Hash.MD5.Result();
461 SHA1Sum = Hash.SHA1.Result();
462}
463 /*}}}*/