]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/error.cc
Merge branch 'debian/experimental-no-abi-break' into debian/sid
[apt.git] / apt-pkg / contrib / error.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4
5 Global Error Class - Global error mechanism
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.
9
10 This source is placed in the Public Domain, do with it what you will
11 It was originally written by Jason Gunthorpe.
12
13 ##################################################################### */
14 /*}}}*/
15 // Include Files /*{{{*/
16 #include <config.h>
17
18 #include <apt-pkg/error.h>
19
20 #include <iostream>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25
26 #include <string>
27 #include <cstring>
28
29 /*}}}*/
30
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 */
36 #if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
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 }
52 #else
53 GlobalError *_GetErrorObj() {
54 static GlobalError *Obj = new GlobalError;
55 return Obj;
56 }
57 #endif
58 /*}}}*/
59 // GlobalError::GlobalError - Constructor /*{{{*/
60 GlobalError::GlobalError() : PendingFlag(false) {}
61 /*}}}*/
62 // GlobalError::FatalE, Errno, WarningE, NoticeE and DebugE - Add to the list/*{{{*/
63 #define GEMessage(NAME, TYPE) \
64 bool 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); \
70 bool const retry = InsertErrno(TYPE, Function, Description, args, errsv, msgSize); \
71 va_end(args); \
72 if (retry == false) \
73 break; \
74 } \
75 return false; \
76 }
77 GEMessage(FatalE, FATAL)
78 GEMessage(Errno, ERROR)
79 GEMessage(WarningE, WARNING)
80 GEMessage(NoticeE, NOTICE)
81 GEMessage(DebugE, DEBUG)
82 #undef GEMessage
83 /*}}}*/
84 // GlobalError::InsertErrno - Get part of the errortype string from errno/*{{{*/
85 bool GlobalError::InsertErrno(MsgType const &type, const char *Function,
86 const char *Description,...) {
87 va_list args;
88 size_t msgSize = 400;
89 int const errsv = errno;
90 while (true) {
91 va_start(args,Description);
92 bool const retry = InsertErrno(type, Function, Description, args, errsv, msgSize);
93 va_end(args);
94 if (retry == false)
95 break;
96 }
97 return false;
98 }
99 /*}}}*/
100 // GlobalError::InsertErrno - formats an error message with the errno /*{{{*/
101 bool GlobalError::InsertErrno(MsgType type, const char* Function,
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;
113 free(S);
114 return true;
115 }
116
117 bool const geins = Insert(type, S, args, msgSize);
118 free(S);
119 return geins;
120 }
121 /*}}}*/
122 // GlobalError::Fatal, Error, Warning, Notice and Debug - Add to the list/*{{{*/
123 #define GEMessage(NAME, TYPE) \
124 bool 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; \
134 }
135 GEMessage(Fatal, FATAL)
136 GEMessage(Error, ERROR)
137 GEMessage(Warning, WARNING)
138 GEMessage(Notice, NOTICE)
139 GEMessage(Debug, DEBUG)
140 #undef GEMessage
141 /*}}}*/
142 // GlobalError::Insert - Add a errotype message to the list /*{{{*/
143 bool GlobalError::Insert(MsgType const &type, const char *Description,...)
144 {
145 va_list args;
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;
154 }
155 /*}}}*/
156 // GlobalError::Insert - Insert a new item at the end /*{{{*/
157 bool GlobalError::Insert(MsgType type, const char* Description,
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;
167 free(S);
168 return true;
169 }
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
180 free(S);
181 return false;
182 }
183 /*}}}*/
184 // GlobalError::PopMessage - Pulls a single message out /*{{{*/
185 bool 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();
199 m != Messages.end(); ++m)
200 if (m->Type == ERROR || m->Type == FATAL)
201 return Ret;
202
203 PendingFlag = false;
204 return Ret;
205 }
206 /*}}}*/
207 // GlobalError::DumpErrors - Dump all of the errors/warns to cerr /*{{{*/
208 void GlobalError::DumpErrors(std::ostream &out, MsgType const &threshold,
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
215 for (std::list<Item>::const_iterator m = Messages.begin();
216 m != Messages.end(); ++m)
217 if (m->Type >= threshold)
218 out << (*m) << std::endl;
219 Discard();
220 }
221 /*}}}*/
222 // GlobalError::Discard - Discard /*{{{*/
223 void GlobalError::Discard() {
224 Messages.clear();
225 PendingFlag = false;
226 };
227 /*}}}*/
228 // GlobalError::empty - does our error list include anything? /*{{{*/
229 bool 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();
237 m != Messages.end(); ++m)
238 if (m->Type >= trashhold)
239 return false;
240
241 return true;
242 }
243 /*}}}*/
244 // GlobalError::PushToStack /*{{{*/
245 void GlobalError::PushToStack() {
246 MsgStack pack(Messages, PendingFlag);
247 Stacks.push_back(pack);
248 Discard();
249 }
250 /*}}}*/
251 // GlobalError::RevertToStack /*{{{*/
252 void 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 /*{{{*/
261 void 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 /*}}}*/