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