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