]> git.saurik.com Git - apt.git/blob - apt-pkg/acquire-method.cc
RPM version compare test program
[apt.git] / apt-pkg / acquire-method.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: acquire-method.cc,v 1.26 2001/03/13 06:51:46 jgg Exp $
4 /* ######################################################################
5
6 Acquire Method
7
8 This is a skeleton class that implements most of the functionality
9 of a method and some useful functions to make method implementation
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
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>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/fileutl.h>
26 #include <apt-pkg/hashes.h>
27
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 /*}}}*/
32
33 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
34 // ---------------------------------------------------------------------
35 /* This constructs the initialization text */
36 pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
37 {
38 char S[300] = "";
39 char *End = S;
40 strcat(End,"100 Capabilities\n");
41 sprintf(End+strlen(End),"Version: %s\n",Ver);
42
43 if ((Flags & SingleInstance) == SingleInstance)
44 strcat(End,"Single-Instance: true\n");
45
46 if ((Flags & Pipeline) == Pipeline)
47 strcat(End,"Pipeline: true\n");
48
49 if ((Flags & SendConfig) == SendConfig)
50 strcat(End,"Send-Config: true\n");
51
52 if ((Flags & LocalOnly) == LocalOnly)
53 strcat(End,"Local-Only: true\n");
54
55 if ((Flags & NeedsCleanup) == NeedsCleanup)
56 strcat(End,"Needs-Cleanup: true\n");
57
58 if ((Flags & Removable) == Removable)
59 strcat(End,"Removable: true\n");
60 strcat(End,"\n");
61
62 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
63 exit(100);
64
65 SetNonBlock(STDIN_FILENO,true);
66
67 Queue = 0;
68 QueueBack = 0;
69 }
70 /*}}}*/
71 // AcqMethod::Fail - A fetch has failed /*{{{*/
72 // ---------------------------------------------------------------------
73 /* */
74 void pkgAcqMethod::Fail(bool Transient)
75 {
76 string Err = "Undetermined Error";
77 if (_error->empty() == false)
78 _error->PopMessage(Err);
79 _error->Discard();
80 Fail(Err,Transient);
81 }
82 /*}}}*/
83 // AcqMethod::Fail - A fetch has failed /*{{{*/
84 // ---------------------------------------------------------------------
85 /* */
86 void pkgAcqMethod::Fail(string Err,bool Transient)
87 {
88 // Strip out junk from the error messages
89 for (char *I = Err.begin(); I != Err.end(); I++)
90 {
91 if (*I == '\r')
92 *I = ' ';
93 if (*I == '\n')
94 *I = ' ';
95 }
96
97 char S[1024];
98 if (Queue != 0)
99 {
100 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
101 "Message: %s %s\n",Queue->Uri.c_str(),Err.c_str(),
102 FailExtra.c_str());
103
104 // Dequeue
105 FetchItem *Tmp = Queue;
106 Queue = Queue->Next;
107 delete Tmp;
108 if (Tmp == QueueBack)
109 QueueBack = Queue;
110 }
111 else
112 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
113 "Message: %s %s\n",Err.c_str(),
114 FailExtra.c_str());
115
116 // Set the transient flag
117 if (Transient == true)
118 strcat(S,"Transient-Failure: true\n\n");
119 else
120 strcat(S,"\n");
121
122 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
123 exit(100);
124 }
125 /*}}}*/
126 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
127 // ---------------------------------------------------------------------
128 /* */
129 void pkgAcqMethod::URIStart(FetchResult &Res)
130 {
131 if (Queue == 0)
132 abort();
133
134 char S[1024] = "";
135 char *End = S;
136
137 End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
138 if (Res.Size != 0)
139 End += snprintf(End,sizeof(S)-4 - (End - S),"Size: %lu\n",Res.Size);
140
141 if (Res.LastModified != 0)
142 End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified: %s\n",
143 TimeRFC1123(Res.LastModified).c_str());
144
145 if (Res.ResumePoint != 0)
146 End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point: %lu\n",
147 Res.ResumePoint);
148
149 strcat(End,"\n");
150 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
151 exit(100);
152 }
153 /*}}}*/
154 // AcqMethod::URIDone - A URI is finished /*{{{*/
155 // ---------------------------------------------------------------------
156 /* */
157 void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
158 {
159 if (Queue == 0)
160 abort();
161
162 char S[1024] = "";
163 char *End = S;
164
165 End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
166
167 if (Res.Filename.empty() == false)
168 End += snprintf(End,sizeof(S)-50 - (End - S),"Filename: %s\n",Res.Filename.c_str());
169
170 if (Res.Size != 0)
171 End += snprintf(End,sizeof(S)-50 - (End - S),"Size: %lu\n",Res.Size);
172
173 if (Res.LastModified != 0)
174 End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified: %s\n",
175 TimeRFC1123(Res.LastModified).c_str());
176
177 if (Res.MD5Sum.empty() == false)
178 End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash: %s\n",Res.MD5Sum.c_str());
179 if (Res.SHA1Sum.empty() == false)
180 End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str());
181
182 if (Res.ResumePoint != 0)
183 End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point: %lu\n",
184 Res.ResumePoint);
185
186 if (Res.IMSHit == true)
187 strcat(End,"IMS-Hit: true\n");
188 End = S + strlen(S);
189
190 if (Alt != 0)
191 {
192 if (Alt->Filename.empty() == false)
193 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
194
195 if (Alt->Size != 0)
196 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size: %lu\n",Alt->Size);
197
198 if (Alt->LastModified != 0)
199 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified: %s\n",
200 TimeRFC1123(Alt->LastModified).c_str());
201
202 if (Alt->MD5Sum.empty() == false)
203 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
204 Alt->MD5Sum.c_str());
205 if (Alt->SHA1Sum.empty() == false)
206 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA1-Hash: %s\n",
207 Alt->SHA1Sum.c_str());
208
209 if (Alt->IMSHit == true)
210 strcat(End,"Alt-IMS-Hit: true\n");
211 }
212
213 strcat(End,"\n");
214 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
215 exit(100);
216
217 // Dequeue
218 FetchItem *Tmp = Queue;
219 Queue = Queue->Next;
220 delete Tmp;
221 if (Tmp == QueueBack)
222 QueueBack = Queue;
223 }
224 /*}}}*/
225 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
226 // ---------------------------------------------------------------------
227 /* This sends a 403 Media Failure message to the APT and waits for it
228 to be ackd */
229 bool pkgAcqMethod::MediaFail(string Required,string Drive)
230 {
231 char S[1024];
232 snprintf(S,sizeof(S),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
233 Required.c_str(),Drive.c_str());
234
235 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
236 exit(100);
237
238 vector<string> MyMessages;
239
240 /* Here we read messages until we find a 603, each non 603 message is
241 appended to the main message list for later processing */
242 while (1)
243 {
244 if (WaitFd(STDIN_FILENO) == false)
245 return false;
246
247 if (ReadMessages(STDIN_FILENO,MyMessages) == false)
248 return false;
249
250 string Message = MyMessages.front();
251 MyMessages.erase(MyMessages.begin());
252
253 // Fetch the message number
254 char *End;
255 int Number = strtol(Message.c_str(),&End,10);
256 if (End == Message.c_str())
257 {
258 cerr << "Malformed message!" << endl;
259 exit(100);
260 }
261
262 // Change ack
263 if (Number == 603)
264 {
265 while (MyMessages.empty() == false)
266 {
267 Messages.push_back(MyMessages.front());
268 MyMessages.erase(MyMessages.begin());
269 }
270
271 return !StringToBool(LookupTag(Message,"Fail"),false);
272 }
273
274 Messages.push_back(Message);
275 }
276 }
277 /*}}}*/
278 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
279 // ---------------------------------------------------------------------
280 /* This parses each configuration entry and puts it into the _config
281 Configuration class. */
282 bool pkgAcqMethod::Configuration(string Message)
283 {
284 ::Configuration &Cnf = *_config;
285
286 const char *I = Message.begin();
287
288 unsigned int Length = strlen("Config-Item");
289 for (; I + Length < Message.end(); I++)
290 {
291 // Not a config item
292 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
293 continue;
294
295 I += Length + 1;
296
297 for (; I < Message.end() && *I == ' '; I++);
298 const char *Equals = I;
299 for (; Equals < Message.end() && *Equals != '='; Equals++);
300 const char *End = Equals;
301 for (; End < Message.end() && *End != '\n'; End++);
302 if (End == Equals)
303 return false;
304
305 Cnf.Set(DeQuoteString(string(I,Equals-I)),
306 DeQuoteString(string(Equals+1,End-Equals-1)));
307 I = End;
308 }
309
310 return true;
311 }
312 /*}}}*/
313 // AcqMethod::Run - Run the message engine /*{{{*/
314 // ---------------------------------------------------------------------
315 /* Fetch any messages and execute them. In single mode it returns 1 if
316 there are no more available messages - any other result is a
317 fatal failure code! */
318 int pkgAcqMethod::Run(bool Single)
319 {
320 while (1)
321 {
322 // Block if the message queue is empty
323 if (Messages.empty() == true)
324 {
325 if (Single == false)
326 if (WaitFd(STDIN_FILENO) == false)
327 break;
328 if (ReadMessages(STDIN_FILENO,Messages) == false)
329 break;
330 }
331
332 // Single mode exits if the message queue is empty
333 if (Single == true && Messages.empty() == true)
334 return -1;
335
336 string Message = Messages.front();
337 Messages.erase(Messages.begin());
338
339 // Fetch the message number
340 char *End;
341 int Number = strtol(Message.c_str(),&End,10);
342 if (End == Message.c_str())
343 {
344 cerr << "Malformed message!" << endl;
345 return 100;
346 }
347
348 switch (Number)
349 {
350 case 601:
351 if (Configuration(Message) == false)
352 return 100;
353 break;
354
355 case 600:
356 {
357 FetchItem *Tmp = new FetchItem;
358
359 Tmp->Uri = LookupTag(Message,"URI");
360 Tmp->DestFile = LookupTag(Message,"FileName");
361 if (StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified) == false)
362 Tmp->LastModified = 0;
363 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
364 Tmp->Next = 0;
365
366 // Append it to the list
367 FetchItem **I = &Queue;
368 for (; *I != 0; I = &(*I)->Next);
369 *I = Tmp;
370 if (QueueBack == 0)
371 QueueBack = Tmp;
372
373 // Notify that this item is to be fetched.
374 if (Fetch(Tmp) == false)
375 Fail();
376
377 break;
378 }
379 }
380 }
381
382 Exit();
383 return 0;
384 }
385 /*}}}*/
386 // AcqMethod::Log - Send a log message /*{{{*/
387 // ---------------------------------------------------------------------
388 /* */
389 void pkgAcqMethod::Log(const char *Format,...)
390 {
391 string CurrentURI = "<UNKNOWN>";
392 if (Queue != 0)
393 CurrentURI = Queue->Uri;
394
395 va_list args;
396 va_start(args,Format);
397
398 // sprintf the description
399 char S[1024];
400 unsigned int Len = snprintf(S,sizeof(S)-4,"101 Log\nURI: %s\n"
401 "Message: ",CurrentURI.c_str());
402
403 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
404 strcat(S,"\n\n");
405
406 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
407 exit(100);
408 }
409 /*}}}*/
410 // AcqMethod::Status - Send a status message /*{{{*/
411 // ---------------------------------------------------------------------
412 /* */
413 void pkgAcqMethod::Status(const char *Format,...)
414 {
415 string CurrentURI = "<UNKNOWN>";
416 if (Queue != 0)
417 CurrentURI = Queue->Uri;
418
419 va_list args;
420 va_start(args,Format);
421
422 // sprintf the description
423 char S[1024];
424 unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\nURI: %s\n"
425 "Message: ",CurrentURI.c_str());
426
427 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
428 strcat(S,"\n\n");
429
430 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
431 exit(100);
432 }
433 /*}}}*/
434
435 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
436 // ---------------------------------------------------------------------
437 /* */
438 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
439 IMSHit(false), Size(0), ResumePoint(0)
440 {
441 }
442 /*}}}*/
443 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
444 // ---------------------------------------------------------------------
445 /* This hides the number of hashes we are supporting from the caller.
446 It just deals with the hash class. */
447 void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
448 {
449 MD5Sum = Hash.MD5.Result();
450 SHA1Sum = Hash.SHA1.Result();
451 }
452 /*}}}*/