* apt-pkg/acquire-item.cc:
[ntk/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];
be4401bf
AL
99 if (Queue != 0)
100 {
8b067c22 101 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
b2e465d6
AL
102 "Message: %s %s\n",Queue->Uri.c_str(),Err.c_str(),
103 FailExtra.c_str());
a72ace20 104
be4401bf
AL
105 // Dequeue
106 FetchItem *Tmp = Queue;
107 Queue = Queue->Next;
108 delete Tmp;
5cb5d8dc
AL
109 if (Tmp == QueueBack)
110 QueueBack = Queue;
be4401bf
AL
111 }
112 else
8b067c22 113 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
b2e465d6
AL
114 "Message: %s %s\n",Err.c_str(),
115 FailExtra.c_str());
be4401bf 116
a72ace20
AL
117 // Set the transient flag
118 if (Transient == true)
119 strcat(S,"Transient-Failure: true\n\n");
120 else
121 strcat(S,"\n");
122
93bf083d
AL
123 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
124 exit(100);
125}
126 /*}}}*/
127// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
128// ---------------------------------------------------------------------
129/* */
be4401bf 130void pkgAcqMethod::URIStart(FetchResult &Res)
93bf083d 131{
be4401bf
AL
132 if (Queue == 0)
133 abort();
134
93bf083d
AL
135 char S[1024] = "";
136 char *End = S;
137
be4401bf 138 End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
93bf083d 139 if (Res.Size != 0)
8b067c22 140 End += snprintf(End,sizeof(S)-4 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
141
142 if (Res.LastModified != 0)
8b067c22 143 End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
144 TimeRFC1123(Res.LastModified).c_str());
145
be4401bf 146 if (Res.ResumePoint != 0)
8b067c22 147 End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point: %lu\n",
be4401bf 148 Res.ResumePoint);
93bf083d
AL
149
150 strcat(End,"\n");
151 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
152 exit(100);
153}
154 /*}}}*/
155// AcqMethod::URIDone - A URI is finished /*{{{*/
156// ---------------------------------------------------------------------
157/* */
158void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
159{
be4401bf
AL
160 if (Queue == 0)
161 abort();
162
93bf083d
AL
163 char S[1024] = "";
164 char *End = S;
165
be4401bf 166 End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
93bf083d
AL
167
168 if (Res.Filename.empty() == false)
8b067c22 169 End += snprintf(End,sizeof(S)-50 - (End - S),"Filename: %s\n",Res.Filename.c_str());
93bf083d
AL
170
171 if (Res.Size != 0)
8b067c22 172 End += snprintf(End,sizeof(S)-50 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
173
174 if (Res.LastModified != 0)
8b067c22 175 End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
176 TimeRFC1123(Res.LastModified).c_str());
177
178 if (Res.MD5Sum.empty() == false)
8b067c22 179 End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash: %s\n",Res.MD5Sum.c_str());
a7c835af
AL
180 if (Res.SHA1Sum.empty() == false)
181 End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str());
5d0d7fae
MV
182 if (Res.SHA256Sum.empty() == false)
183 End += snprintf(End,sizeof(S)-50 - (End - S),"SHA256-Hash: %s\n",Res.SHA256Sum.c_str());
b3d44315
MV
184 if (Res.GPGVOutput.size() > 0)
185 End += snprintf(End,sizeof(S)-50 - (End - S),"GPGVOutput:\n");
186 for (vector<string>::iterator I = Res.GPGVOutput.begin();
187 I != Res.GPGVOutput.end(); I++)
188 End += snprintf(End,sizeof(S)-50 - (End - S), " %s\n", (*I).c_str());
93bf083d 189
b98f2859 190 if (Res.ResumePoint != 0)
8b067c22 191 End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point: %lu\n",
b98f2859
AL
192 Res.ResumePoint);
193
93bf083d
AL
194 if (Res.IMSHit == true)
195 strcat(End,"IMS-Hit: true\n");
196 End = S + strlen(S);
197
198 if (Alt != 0)
199 {
200 if (Alt->Filename.empty() == false)
8b067c22 201 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
93bf083d
AL
202
203 if (Alt->Size != 0)
8b067c22 204 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size: %lu\n",Alt->Size);
93bf083d
AL
205
206 if (Alt->LastModified != 0)
8b067c22 207 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified: %s\n",
93bf083d
AL
208 TimeRFC1123(Alt->LastModified).c_str());
209
210 if (Alt->MD5Sum.empty() == false)
8b067c22 211 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
93bf083d 212 Alt->MD5Sum.c_str());
a7c835af
AL
213 if (Alt->SHA1Sum.empty() == false)
214 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA1-Hash: %s\n",
215 Alt->SHA1Sum.c_str());
5d0d7fae
MV
216 if (Alt->SHA256Sum.empty() == false)
217 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA256-Hash: %s\n",
218 Alt->SHA256Sum.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();
5d0d7fae 463 SHA256Sum = Hash.SHA256.Result();
a7c835af
AL
464}
465 /*}}}*/