]> git.saurik.com Git - apt.git/blame - apt-pkg/contrib/error.cc
Merge branch 'debian/sid' into debian/experimental
[apt.git] / apt-pkg / contrib / error.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
578bfd0a 3/* ######################################################################
98ee7cd3
DK
4
5 Global Error Class - Global error mechanism
578bfd0a
AL
6
7 We use a simple STL vector to store each error record. A PendingFlag
8 is kept which indicates when the vector contains a Sever error.
98ee7cd3 9
578bfd0a
AL
10 This source is placed in the Public Domain, do with it what you will
11 It was originally written by Jason Gunthorpe.
98ee7cd3 12
578bfd0a
AL
13 ##################################################################### */
14 /*}}}*/
15// Include Files /*{{{*/
ea542140
DK
16#include <config.h>
17
6f27a7fc
AL
18#include <apt-pkg/error.h>
19
90f057fd 20#include <iostream>
578bfd0a
AL
21#include <errno.h>
22#include <stdio.h>
8f3853ba 23#include <stdlib.h>
6f27a7fc 24#include <unistd.h>
578bfd0a 25
4f333a8b
MV
26#include <string>
27#include <cstring>
28
ea542140 29 /*}}}*/
578bfd0a 30
6f27a7fc
AL
31// Global Error Object /*{{{*/
32/* If the implementation supports posix threads then the accessor function
33 is compiled to be thread safe otherwise a non-safe version is used. A
34 Per-Thread error object is maintained in much the same manner as libc
35 manages errno */
b2e465d6 36#if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
98ee7cd3
DK
37 #include <pthread.h>
38
39 static pthread_key_t ErrorKey;
40 static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
41 static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
42
43 GlobalError *_GetErrorObj() {
44 static pthread_once_t Once = PTHREAD_ONCE_INIT;
45 pthread_once(&Once,KeyAlloc);
46
47 void *Res = pthread_getspecific(ErrorKey);
48 if (Res == 0)
49 pthread_setspecific(ErrorKey,Res = new GlobalError);
50 return (GlobalError *)Res;
51 }
6f27a7fc 52#else
98ee7cd3
DK
53 GlobalError *_GetErrorObj() {
54 static GlobalError *Obj = new GlobalError;
55 return Obj;
56 }
6f27a7fc
AL
57#endif
58 /*}}}*/
578bfd0a 59// GlobalError::GlobalError - Constructor /*{{{*/
98ee7cd3
DK
60GlobalError::GlobalError() : PendingFlag(false) {}
61 /*}}}*/
38f29703
DK
62// GlobalError::FatalE, Errno, WarningE, NoticeE and DebugE - Add to the list/*{{{*/
63#define GEMessage(NAME, TYPE) \
64bool GlobalError::NAME (const char *Function, const char *Description,...) { \
65 va_list args; \
66 size_t msgSize = 400; \
67 int const errsv = errno; \
68 while (true) { \
69 va_start(args,Description); \
9ca0d581 70 bool const retry = InsertErrno(TYPE, Function, Description, args, errsv, msgSize); \
38f29703 71 va_end(args); \
9ca0d581
DK
72 if (retry == false) \
73 break; \
38f29703
DK
74 } \
75 return false; \
98ee7cd3 76}
38f29703
DK
77GEMessage(FatalE, FATAL)
78GEMessage(Errno, ERROR)
79GEMessage(WarningE, WARNING)
80GEMessage(NoticeE, NOTICE)
81GEMessage(DebugE, DEBUG)
82#undef GEMessage
98ee7cd3 83 /*}}}*/
cd7bbc47
DK
84// GlobalError::InsertErrno - Get part of the errortype string from errno/*{{{*/
85bool GlobalError::InsertErrno(MsgType const &type, const char *Function,
86 const char *Description,...) {
87 va_list args;
38f29703
DK
88 size_t msgSize = 400;
89 int const errsv = errno;
90 while (true) {
91 va_start(args,Description);
9ca0d581 92 bool const retry = InsertErrno(type, Function, Description, args, errsv, msgSize);
38f29703 93 va_end(args);
9ca0d581
DK
94 if (retry == false)
95 break;
38f29703
DK
96 }
97 return false;
cd7bbc47
DK
98}
99 /*}}}*/
98ee7cd3
DK
100// GlobalError::InsertErrno - formats an error message with the errno /*{{{*/
101bool GlobalError::InsertErrno(MsgType type, const char* Function,
38f29703
DK
102 const char* Description, va_list &args,
103 int const errsv, size_t &msgSize) {
104 char* S = (char*) malloc(msgSize);
105 int const n = snprintf(S, msgSize, "%s - %s (%i: %s)", Description,
106 Function, errsv, strerror(errsv));
107 if (n > -1 && ((unsigned int) n) < msgSize);
108 else {
109 if (n > -1)
110 msgSize = n + 1;
111 else
112 msgSize *= 2;
6070a346 113 free(S);
38f29703 114 return true;
8f3853ba
DK
115 }
116
38f29703 117 bool const geins = Insert(type, S, args, msgSize);
8f3853ba
DK
118 free(S);
119 return geins;
98ee7cd3
DK
120}
121 /*}}}*/
38f29703
DK
122// GlobalError::Fatal, Error, Warning, Notice and Debug - Add to the list/*{{{*/
123#define GEMessage(NAME, TYPE) \
124bool GlobalError::NAME (const char *Description,...) { \
125 va_list args; \
126 size_t msgSize = 400; \
127 while (true) { \
128 va_start(args,Description); \
129 if (Insert(TYPE, Description, args, msgSize) == false) \
130 break; \
131 va_end(args); \
132 } \
133 return false; \
98ee7cd3 134}
38f29703
DK
135GEMessage(Fatal, FATAL)
136GEMessage(Error, ERROR)
137GEMessage(Warning, WARNING)
138GEMessage(Notice, NOTICE)
139GEMessage(Debug, DEBUG)
140#undef GEMessage
98ee7cd3 141 /*}}}*/
cd7bbc47
DK
142// GlobalError::Insert - Add a errotype message to the list /*{{{*/
143bool GlobalError::Insert(MsgType const &type, const char *Description,...)
144{
145 va_list args;
38f29703
DK
146 size_t msgSize = 400;
147 while (true) {
148 va_start(args,Description);
149 if (Insert(type, Description, args, msgSize) == false)
150 break;
151 va_end(args);
152 }
153 return false;
cd7bbc47
DK
154}
155 /*}}}*/
98ee7cd3
DK
156// GlobalError::Insert - Insert a new item at the end /*{{{*/
157bool GlobalError::Insert(MsgType type, const char* Description,
38f29703
DK
158 va_list &args, size_t &msgSize) {
159 char* S = (char*) malloc(msgSize);
160 int const n = vsnprintf(S, msgSize, Description, args);
161 if (n > -1 && ((unsigned int) n) < msgSize);
162 else {
163 if (n > -1)
164 msgSize = n + 1;
165 else
166 msgSize *= 2;
6070a346 167 free(S);
38f29703 168 return true;
8f3853ba 169 }
98ee7cd3
DK
170
171 Item const m(S, type);
172 Messages.push_back(m);
173
174 if (type == ERROR || type == FATAL)
175 PendingFlag = true;
176
177 if (type == FATAL || type == DEBUG)
178 std::clog << m << std::endl;
179
8f3853ba 180 free(S);
98ee7cd3
DK
181 return false;
182}
183 /*}}}*/
184// GlobalError::PopMessage - Pulls a single message out /*{{{*/
185bool GlobalError::PopMessage(std::string &Text) {
186 if (Messages.empty() == true)
187 return false;
188
189 Item const msg = Messages.front();
190 Messages.pop_front();
191
192 bool const Ret = (msg.Type == ERROR || msg.Type == FATAL);
193 Text = msg.Text;
194 if (PendingFlag == false || Ret == false)
195 return Ret;
196
197 // check if another error message is pending
198 for (std::list<Item>::const_iterator m = Messages.begin();
f7f0d6c7 199 m != Messages.end(); ++m)
98ee7cd3
DK
200 if (m->Type == ERROR || m->Type == FATAL)
201 return Ret;
202
203 PendingFlag = false;
204 return Ret;
578bfd0a
AL
205}
206 /*}}}*/
207// GlobalError::DumpErrors - Dump all of the errors/warns to cerr /*{{{*/
12be8a62 208void GlobalError::DumpErrors(std::ostream &out, MsgType const &threshold,
c4ba7c44
DK
209 bool const &mergeStack) {
210 if (mergeStack == true)
211 for (std::list<MsgStack>::const_reverse_iterator s = Stacks.rbegin();
212 s != Stacks.rend(); ++s)
213 Messages.insert(Messages.begin(), s->Messages.begin(), s->Messages.end());
214
98ee7cd3 215 for (std::list<Item>::const_iterator m = Messages.begin();
f7f0d6c7 216 m != Messages.end(); ++m)
12be8a62 217 if (m->Type >= threshold)
98ee7cd3
DK
218 out << (*m) << std::endl;
219 Discard();
578bfd0a
AL
220}
221 /*}}}*/
98ee7cd3
DK
222// GlobalError::Discard - Discard /*{{{*/
223void GlobalError::Discard() {
224 Messages.clear();
225 PendingFlag = false;
6c139d6e
AL
226};
227 /*}}}*/
98ee7cd3
DK
228// GlobalError::empty - does our error list include anything? /*{{{*/
229bool GlobalError::empty(MsgType const &trashhold) const {
230 if (PendingFlag == true)
231 return false;
232
233 if (Messages.empty() == true)
234 return true;
235
236 for (std::list<Item>::const_iterator m = Messages.begin();
f7f0d6c7 237 m != Messages.end(); ++m)
98ee7cd3
DK
238 if (m->Type >= trashhold)
239 return false;
240
241 return true;
6c139d6e
AL
242}
243 /*}}}*/
c4ba7c44
DK
244// GlobalError::PushToStack /*{{{*/
245void GlobalError::PushToStack() {
246 MsgStack pack(Messages, PendingFlag);
247 Stacks.push_back(pack);
248 Discard();
249}
250 /*}}}*/
251// GlobalError::RevertToStack /*{{{*/
252void GlobalError::RevertToStack() {
253 Discard();
254 MsgStack pack = Stacks.back();
255 Messages = pack.Messages;
256 PendingFlag = pack.PendingFlag;
257 Stacks.pop_back();
258}
259 /*}}}*/
260// GlobalError::MergeWithStack /*{{{*/
261void GlobalError::MergeWithStack() {
262 MsgStack pack = Stacks.back();
263 Messages.insert(Messages.begin(), pack.Messages.begin(), pack.Messages.end());
264 PendingFlag = PendingFlag || pack.PendingFlag;
265 Stacks.pop_back();
266}
267 /*}}}*/