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