]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-method.cc
* apt-pkg/indexfile.cc:
[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];
36280399 102 char *End = S;
be4401bf
AL
103 if (Queue != 0)
104 {
36280399
MV
105 End += snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
106 "Message: %s %s\n",Queue->Uri.c_str(), Err.c_str(), IP.c_str());
be4401bf
AL
107 // Dequeue
108 FetchItem *Tmp = Queue;
109 Queue = Queue->Next;
110 delete Tmp;
5cb5d8dc
AL
111 if (Tmp == QueueBack)
112 QueueBack = Queue;
be4401bf
AL
113 }
114 else
36280399
MV
115 {
116 End += snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
117 "Message: %s\n",Err.c_str());
118 }
119 if(FailReason.empty() == false)
120 End += snprintf(End,sizeof(S)-50 - (End - S),"FailReason: %s\n",FailReason.c_str());
121 if (UsedMirror.empty() == false)
122 End += snprintf(End,sizeof(S)-50 - (End - S),"UsedMirror: %s\n",UsedMirror.c_str());
a72ace20
AL
123 // Set the transient flag
124 if (Transient == true)
125 strcat(S,"Transient-Failure: true\n\n");
126 else
127 strcat(S,"\n");
128
93bf083d
AL
129 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
130 exit(100);
131}
132 /*}}}*/
133// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
134// ---------------------------------------------------------------------
135/* */
be4401bf 136void pkgAcqMethod::URIStart(FetchResult &Res)
93bf083d 137{
be4401bf
AL
138 if (Queue == 0)
139 abort();
140
93bf083d
AL
141 char S[1024] = "";
142 char *End = S;
143
be4401bf 144 End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
93bf083d 145 if (Res.Size != 0)
8b067c22 146 End += snprintf(End,sizeof(S)-4 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
147
148 if (Res.LastModified != 0)
8b067c22 149 End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
150 TimeRFC1123(Res.LastModified).c_str());
151
be4401bf 152 if (Res.ResumePoint != 0)
8b067c22 153 End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point: %lu\n",
be4401bf 154 Res.ResumePoint);
93bf083d
AL
155
156 strcat(End,"\n");
157 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
158 exit(100);
159}
160 /*}}}*/
161// AcqMethod::URIDone - A URI is finished /*{{{*/
162// ---------------------------------------------------------------------
163/* */
164void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
165{
be4401bf
AL
166 if (Queue == 0)
167 abort();
168
93bf083d
AL
169 char S[1024] = "";
170 char *End = S;
171
be4401bf 172 End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
93bf083d
AL
173
174 if (Res.Filename.empty() == false)
8b067c22 175 End += snprintf(End,sizeof(S)-50 - (End - S),"Filename: %s\n",Res.Filename.c_str());
93bf083d
AL
176
177 if (Res.Size != 0)
8b067c22 178 End += snprintf(End,sizeof(S)-50 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
179
180 if (Res.LastModified != 0)
8b067c22 181 End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
182 TimeRFC1123(Res.LastModified).c_str());
183
184 if (Res.MD5Sum.empty() == false)
8b067c22 185 End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash: %s\n",Res.MD5Sum.c_str());
a7c835af
AL
186 if (Res.SHA1Sum.empty() == false)
187 End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str());
36280399
MV
188 if (UsedMirror.empty() == false)
189 End += snprintf(End,sizeof(S)-50 - (End - S),"UsedMirror: %s\n",UsedMirror.c_str());
b3d44315
MV
190 if (Res.GPGVOutput.size() > 0)
191 End += snprintf(End,sizeof(S)-50 - (End - S),"GPGVOutput:\n");
192 for (vector<string>::iterator I = Res.GPGVOutput.begin();
193 I != Res.GPGVOutput.end(); I++)
194 End += snprintf(End,sizeof(S)-50 - (End - S), " %s\n", (*I).c_str());
93bf083d 195
b98f2859 196 if (Res.ResumePoint != 0)
8b067c22 197 End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point: %lu\n",
b98f2859
AL
198 Res.ResumePoint);
199
93bf083d
AL
200 if (Res.IMSHit == true)
201 strcat(End,"IMS-Hit: true\n");
202 End = S + strlen(S);
203
204 if (Alt != 0)
205 {
206 if (Alt->Filename.empty() == false)
8b067c22 207 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
93bf083d
AL
208
209 if (Alt->Size != 0)
8b067c22 210 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size: %lu\n",Alt->Size);
93bf083d
AL
211
212 if (Alt->LastModified != 0)
8b067c22 213 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified: %s\n",
93bf083d
AL
214 TimeRFC1123(Alt->LastModified).c_str());
215
216 if (Alt->MD5Sum.empty() == false)
8b067c22 217 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
93bf083d 218 Alt->MD5Sum.c_str());
a7c835af
AL
219 if (Alt->SHA1Sum.empty() == false)
220 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA1-Hash: %s\n",
221 Alt->SHA1Sum.c_str());
93bf083d
AL
222
223 if (Alt->IMSHit == true)
224 strcat(End,"Alt-IMS-Hit: true\n");
225 }
226
227 strcat(End,"\n");
228 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
229 exit(100);
be4401bf
AL
230
231 // Dequeue
232 FetchItem *Tmp = Queue;
233 Queue = Queue->Next;
234 delete Tmp;
5cb5d8dc
AL
235 if (Tmp == QueueBack)
236 QueueBack = Queue;
93bf083d
AL
237}
238 /*}}}*/
f46e7681
AL
239// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
240// ---------------------------------------------------------------------
241/* This sends a 403 Media Failure message to the APT and waits for it
242 to be ackd */
018f1533 243bool pkgAcqMethod::MediaFail(string Required,string Drive)
f46e7681
AL
244{
245 char S[1024];
246 snprintf(S,sizeof(S),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
247 Required.c_str(),Drive.c_str());
248
249 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
250 exit(100);
251
252 vector<string> MyMessages;
253
254 /* Here we read messages until we find a 603, each non 603 message is
255 appended to the main message list for later processing */
256 while (1)
257 {
258 if (WaitFd(STDIN_FILENO) == false)
76d97c26 259 return false;
f46e7681
AL
260
261 if (ReadMessages(STDIN_FILENO,MyMessages) == false)
76d97c26
AL
262 return false;
263
f46e7681
AL
264 string Message = MyMessages.front();
265 MyMessages.erase(MyMessages.begin());
266
267 // Fetch the message number
268 char *End;
269 int Number = strtol(Message.c_str(),&End,10);
270 if (End == Message.c_str())
271 {
272 cerr << "Malformed message!" << endl;
273 exit(100);
274 }
275
276 // Change ack
277 if (Number == 603)
278 {
76d97c26 279 while (MyMessages.empty() == false)
f46e7681
AL
280 {
281 Messages.push_back(MyMessages.front());
282 MyMessages.erase(MyMessages.begin());
283 }
542ec555 284
2a749770 285 return !StringToBool(LookupTag(Message,"Failed"),false);
f46e7681
AL
286 }
287
288 Messages.push_back(Message);
289 }
290}
291 /*}}}*/
93bf083d
AL
292// AcqMethod::Configuration - Handle the configuration message /*{{{*/
293// ---------------------------------------------------------------------
294/* This parses each configuration entry and puts it into the _config
295 Configuration class. */
296bool pkgAcqMethod::Configuration(string Message)
297{
298 ::Configuration &Cnf = *_config;
299
b4fc9b6f
AL
300 const char *I = Message.c_str();
301 const char *MsgEnd = I + Message.length();
93bf083d
AL
302
303 unsigned int Length = strlen("Config-Item");
b4fc9b6f 304 for (; I + Length < MsgEnd; I++)
93bf083d
AL
305 {
306 // Not a config item
307 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
308 continue;
309
310 I += Length + 1;
311
b4fc9b6f 312 for (; I < MsgEnd && *I == ' '; I++);
93bf083d 313 const char *Equals = I;
b4fc9b6f 314 for (; Equals < MsgEnd && *Equals != '='; Equals++);
93bf083d 315 const char *End = Equals;
b4fc9b6f 316 for (; End < MsgEnd && *End != '\n'; End++);
93bf083d
AL
317 if (End == Equals)
318 return false;
319
6d5dd02a
AL
320 Cnf.Set(DeQuoteString(string(I,Equals-I)),
321 DeQuoteString(string(Equals+1,End-Equals-1)));
93bf083d
AL
322 I = End;
323 }
324
325 return true;
326}
327 /*}}}*/
328// AcqMethod::Run - Run the message engine /*{{{*/
329// ---------------------------------------------------------------------
8384ebdf
AL
330/* Fetch any messages and execute them. In single mode it returns 1 if
331 there are no more available messages - any other result is a
332 fatal failure code! */
be4401bf 333int pkgAcqMethod::Run(bool Single)
93bf083d 334{
93bf083d
AL
335 while (1)
336 {
be4401bf 337 // Block if the message queue is empty
93bf083d 338 if (Messages.empty() == true)
be4401bf
AL
339 {
340 if (Single == false)
341 if (WaitFd(STDIN_FILENO) == false)
8e5fc8f5 342 break;
92e889c8 343 if (ReadMessages(STDIN_FILENO,Messages) == false)
8e5fc8f5 344 break;
92e889c8
AL
345 }
346
be4401bf
AL
347 // Single mode exits if the message queue is empty
348 if (Single == true && Messages.empty() == true)
8384ebdf 349 return -1;
be4401bf 350
93bf083d
AL
351 string Message = Messages.front();
352 Messages.erase(Messages.begin());
353
354 // Fetch the message number
355 char *End;
356 int Number = strtol(Message.c_str(),&End,10);
357 if (End == Message.c_str())
358 {
359 cerr << "Malformed message!" << endl;
360 return 100;
361 }
362
363 switch (Number)
8e5fc8f5 364 {
93bf083d
AL
365 case 601:
366 if (Configuration(Message) == false)
367 return 100;
368 break;
369
370 case 600:
be4401bf
AL
371 {
372 FetchItem *Tmp = new FetchItem;
373
374 Tmp->Uri = LookupTag(Message,"URI");
375 Tmp->DestFile = LookupTag(Message,"FileName");
b98f2859
AL
376 if (StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified) == false)
377 Tmp->LastModified = 0;
a72ace20 378 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
be4401bf
AL
379 Tmp->Next = 0;
380
381 // Append it to the list
382 FetchItem **I = &Queue;
92e889c8 383 for (; *I != 0; I = &(*I)->Next);
be4401bf 384 *I = Tmp;
5cb5d8dc
AL
385 if (QueueBack == 0)
386 QueueBack = Tmp;
387
bfd22fc0 388 // Notify that this item is to be fetched.
be4401bf 389 if (Fetch(Tmp) == false)
93bf083d 390 Fail();
bfd22fc0 391
93bf083d
AL
392 break;
393 }
394 }
395 }
396
8e5fc8f5 397 Exit();
93bf083d
AL
398 return 0;
399}
400 /*}}}*/
be4401bf
AL
401// AcqMethod::Log - Send a log message /*{{{*/
402// ---------------------------------------------------------------------
403/* */
404void pkgAcqMethod::Log(const char *Format,...)
405{
406 string CurrentURI = "<UNKNOWN>";
407 if (Queue != 0)
408 CurrentURI = Queue->Uri;
409
410 va_list args;
411 va_start(args,Format);
412
413 // sprintf the description
414 char S[1024];
8b067c22 415 unsigned int Len = snprintf(S,sizeof(S)-4,"101 Log\nURI: %s\n"
be4401bf
AL
416 "Message: ",CurrentURI.c_str());
417
8b067c22 418 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
419 strcat(S,"\n\n");
420
421 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
422 exit(100);
423}
424 /*}}}*/
425// AcqMethod::Status - Send a status message /*{{{*/
426// ---------------------------------------------------------------------
427/* */
428void pkgAcqMethod::Status(const char *Format,...)
429{
430 string CurrentURI = "<UNKNOWN>";
431 if (Queue != 0)
432 CurrentURI = Queue->Uri;
433
434 va_list args;
435 va_start(args,Format);
436
437 // sprintf the description
438 char S[1024];
8b067c22 439 unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\nURI: %s\n"
be4401bf
AL
440 "Message: ",CurrentURI.c_str());
441
8b067c22 442 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
443 strcat(S,"\n\n");
444
445 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
446 exit(100);
447}
448 /*}}}*/
449
93bf083d
AL
450// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
451// ---------------------------------------------------------------------
452/* */
93274b8d
AL
453pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
454 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
455{
456}
457 /*}}}*/
a7c835af
AL
458// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
459// ---------------------------------------------------------------------
460/* This hides the number of hashes we are supporting from the caller.
461 It just deals with the hash class. */
462void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
463{
464 MD5Sum = Hash.MD5.Result();
465 SHA1Sum = Hash.SHA1.Result();
466}
467 /*}}}*/