]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-method.cc
* merged changes from Kamions upload (thanks!)
[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");
b98f2859
AL
371 if (StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified) == false)
372 Tmp->LastModified = 0;
a72ace20 373 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
be4401bf
AL
374 Tmp->Next = 0;
375
376 // Append it to the list
377 FetchItem **I = &Queue;
92e889c8 378 for (; *I != 0; I = &(*I)->Next);
be4401bf 379 *I = Tmp;
5cb5d8dc
AL
380 if (QueueBack == 0)
381 QueueBack = Tmp;
382
bfd22fc0 383 // Notify that this item is to be fetched.
be4401bf 384 if (Fetch(Tmp) == false)
93bf083d 385 Fail();
bfd22fc0 386
93bf083d
AL
387 break;
388 }
389 }
390 }
391
8e5fc8f5 392 Exit();
93bf083d
AL
393 return 0;
394}
395 /*}}}*/
be4401bf
AL
396// AcqMethod::Log - Send a log message /*{{{*/
397// ---------------------------------------------------------------------
398/* */
399void pkgAcqMethod::Log(const char *Format,...)
400{
401 string CurrentURI = "<UNKNOWN>";
402 if (Queue != 0)
403 CurrentURI = Queue->Uri;
404
405 va_list args;
406 va_start(args,Format);
407
408 // sprintf the description
409 char S[1024];
8b067c22 410 unsigned int Len = snprintf(S,sizeof(S)-4,"101 Log\nURI: %s\n"
be4401bf
AL
411 "Message: ",CurrentURI.c_str());
412
8b067c22 413 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
414 strcat(S,"\n\n");
415
416 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
417 exit(100);
418}
419 /*}}}*/
420// AcqMethod::Status - Send a status message /*{{{*/
421// ---------------------------------------------------------------------
422/* */
423void pkgAcqMethod::Status(const char *Format,...)
424{
425 string CurrentURI = "<UNKNOWN>";
426 if (Queue != 0)
427 CurrentURI = Queue->Uri;
428
429 va_list args;
430 va_start(args,Format);
431
432 // sprintf the description
433 char S[1024];
8b067c22 434 unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\nURI: %s\n"
be4401bf
AL
435 "Message: ",CurrentURI.c_str());
436
8b067c22 437 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
438 strcat(S,"\n\n");
439
440 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
441 exit(100);
442}
443 /*}}}*/
444
93bf083d
AL
445// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
446// ---------------------------------------------------------------------
447/* */
93274b8d
AL
448pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
449 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
450{
451}
452 /*}}}*/
a7c835af
AL
453// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
454// ---------------------------------------------------------------------
455/* This hides the number of hashes we are supporting from the caller.
456 It just deals with the hash class. */
457void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
458{
459 MD5Sum = Hash.MD5.Result();
460 SHA1Sum = Hash.SHA1.Result();
461}
462 /*}}}*/