1 | /*@-boundsread@*/ |
---|
2 | /** \ingroup rpmio |
---|
3 | * \file rpmio/rpmlog.c |
---|
4 | */ |
---|
5 | |
---|
6 | #include "system.h" |
---|
7 | #include <stdarg.h> |
---|
8 | #include "rpmlog.h" |
---|
9 | #include "debug.h" |
---|
10 | |
---|
11 | #ifndef va_copy |
---|
12 | # ifdef __va_copy |
---|
13 | # define va_copy(DEST,SRC) __va_copy((DEST),(SRC)) |
---|
14 | # else |
---|
15 | # ifdef HAVE_VA_LIST_AS_ARRAY |
---|
16 | # define va_copy(DEST,SRC) (*(DEST) = *(SRC)) |
---|
17 | # else |
---|
18 | # define va_copy(DEST,SRC) ((DEST) = (SRC)) |
---|
19 | # endif |
---|
20 | # endif |
---|
21 | #endif |
---|
22 | |
---|
23 | /*@access rpmlogRec @*/ |
---|
24 | |
---|
25 | /*@unchecked@*/ |
---|
26 | static int nrecs = 0; |
---|
27 | /*@unchecked@*/ |
---|
28 | static /*@only@*/ /*@null@*/ rpmlogRec recs = NULL; |
---|
29 | |
---|
30 | /** |
---|
31 | * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. |
---|
32 | * @param p memory to free |
---|
33 | * @retval NULL always |
---|
34 | */ |
---|
35 | /*@unused@*/ static inline /*@null@*/ void * |
---|
36 | _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies p@*/ |
---|
37 | { |
---|
38 | if (p != NULL) free((void *)p); |
---|
39 | return NULL; |
---|
40 | } |
---|
41 | |
---|
42 | int rpmlogGetNrecs(void) |
---|
43 | { |
---|
44 | return nrecs; |
---|
45 | } |
---|
46 | |
---|
47 | int rpmlogCode(void) |
---|
48 | { |
---|
49 | if (recs != NULL && nrecs > 0) |
---|
50 | return recs[nrecs-1].code; |
---|
51 | return -1; |
---|
52 | } |
---|
53 | |
---|
54 | |
---|
55 | const char * rpmlogMessage(void) |
---|
56 | { |
---|
57 | if (recs != NULL && nrecs > 0) |
---|
58 | return recs[nrecs-1].message; |
---|
59 | return _("(no error)"); |
---|
60 | } |
---|
61 | |
---|
62 | /*@-modfilesys@*/ |
---|
63 | void rpmlogPrint(FILE *f) |
---|
64 | { |
---|
65 | int i; |
---|
66 | |
---|
67 | if (f == NULL) |
---|
68 | f = stderr; |
---|
69 | |
---|
70 | if (recs) |
---|
71 | for (i = 0; i < nrecs; i++) { |
---|
72 | rpmlogRec rec = recs + i; |
---|
73 | if (rec->message && *rec->message) |
---|
74 | fprintf(f, " %s", rec->message); |
---|
75 | } |
---|
76 | } |
---|
77 | /*@=modfilesys@*/ |
---|
78 | |
---|
79 | void rpmlogClose (void) |
---|
80 | /*@globals recs, nrecs @*/ |
---|
81 | /*@modifies recs, nrecs @*/ |
---|
82 | { |
---|
83 | int i; |
---|
84 | |
---|
85 | if (recs) |
---|
86 | for (i = 0; i < nrecs; i++) { |
---|
87 | rpmlogRec rec = recs + i; |
---|
88 | rec->message = _free(rec->message); |
---|
89 | } |
---|
90 | recs = _free(recs); |
---|
91 | nrecs = 0; |
---|
92 | } |
---|
93 | |
---|
94 | void rpmlogOpen (/*@unused@*/ const char *ident, /*@unused@*/ int option, |
---|
95 | /*@unused@*/ int facility) |
---|
96 | { |
---|
97 | } |
---|
98 | |
---|
99 | /*@unchecked@*/ |
---|
100 | static unsigned rpmlogMask = RPMLOG_UPTO( RPMLOG_NOTICE ); |
---|
101 | |
---|
102 | /*@unchecked@*/ |
---|
103 | static /*@unused@*/ unsigned rpmlogFacility = RPMLOG_USER; |
---|
104 | |
---|
105 | int rpmlogSetMask (int mask) |
---|
106 | /*@globals rpmlogMask @*/ |
---|
107 | /*@modifies rpmlogMask @*/ |
---|
108 | { |
---|
109 | int omask = rpmlogMask; |
---|
110 | if (mask) |
---|
111 | rpmlogMask = mask; |
---|
112 | return omask; |
---|
113 | } |
---|
114 | |
---|
115 | /*@unchecked@*/ |
---|
116 | static /*@null@*/ rpmlogCallback _rpmlogCallback = NULL; |
---|
117 | |
---|
118 | rpmlogCallback rpmlogSetCallback(rpmlogCallback cb) |
---|
119 | /*@globals _rpmlogCallback @*/ |
---|
120 | /*@modifies _rpmlogCallback @*/ |
---|
121 | { |
---|
122 | rpmlogCallback ocb = _rpmlogCallback; |
---|
123 | _rpmlogCallback = cb; |
---|
124 | return ocb; |
---|
125 | } |
---|
126 | |
---|
127 | /*@unchecked@*/ /*@null@*/ |
---|
128 | static FILE * _stdlog = NULL; |
---|
129 | |
---|
130 | FILE * rpmlogSetFile(FILE * fp) |
---|
131 | /*@globals _stdlog @*/ |
---|
132 | /*@modifies _stdlog @*/ |
---|
133 | { |
---|
134 | FILE * ofp = _stdlog; |
---|
135 | _stdlog = fp; |
---|
136 | return ofp; |
---|
137 | } |
---|
138 | |
---|
139 | /*@-readonlytrans@*/ /* FIX: double indirection. */ |
---|
140 | /*@observer@*/ /*@unchecked@*/ |
---|
141 | static char *rpmlogMsgPrefix[] = { |
---|
142 | N_("fatal error: "),/*!< RPMLOG_EMERG */ |
---|
143 | N_("fatal error: "),/*!< RPMLOG_ALERT */ |
---|
144 | N_("fatal error: "),/*!< RPMLOG_CRIT */ |
---|
145 | N_("error: "), /*!< RPMLOG_ERR */ |
---|
146 | N_("warning: "), /*!< RPMLOG_WARNING */ |
---|
147 | "", /*!< RPMLOG_NOTICE */ |
---|
148 | "", /*!< RPMLOG_INFO */ |
---|
149 | "D: ", /*!< RPMLOG_DEBUG */ |
---|
150 | }; |
---|
151 | /*@=readonlytrans@*/ |
---|
152 | |
---|
153 | #if !defined(HAVE_VSNPRINTF) |
---|
154 | static inline int vsnprintf(char * buf, /*@unused@*/ int nb, |
---|
155 | const char * fmt, va_list ap) |
---|
156 | { |
---|
157 | return vsprintf(buf, fmt, ap); |
---|
158 | } |
---|
159 | #endif |
---|
160 | |
---|
161 | /*@-modfilesys@*/ |
---|
162 | /*@-compmempass@*/ /* FIX: rpmlogMsgPrefix[] dependent, not unqualified */ |
---|
163 | /*@-nullstate@*/ /* FIX: rpmlogMsgPrefix[] may be NULL */ |
---|
164 | static void vrpmlog (unsigned code, const char *fmt, va_list ap) |
---|
165 | /*@globals nrecs, recs, internalState @*/ |
---|
166 | /*@modifies nrecs, recs, internalState @*/ |
---|
167 | { |
---|
168 | unsigned pri = RPMLOG_PRI(code); |
---|
169 | unsigned mask = RPMLOG_MASK(pri); |
---|
170 | /*@unused@*/ unsigned fac = RPMLOG_FAC(code); |
---|
171 | char *msgbuf, *msg; |
---|
172 | int msgnb = BUFSIZ, nb; |
---|
173 | FILE * msgout = (_stdlog ? _stdlog : stderr); |
---|
174 | |
---|
175 | if ((mask & rpmlogMask) == 0) |
---|
176 | return; |
---|
177 | |
---|
178 | /*@-boundswrite@*/ |
---|
179 | msgbuf = xmalloc(msgnb); |
---|
180 | *msgbuf = '\0'; |
---|
181 | |
---|
182 | /* Allocate a sufficently large buffer for output. */ |
---|
183 | while (1) { |
---|
184 | va_list apc; |
---|
185 | /*@-sysunrecog -usedef@*/ va_copy(apc, ap); /*@=sysunrecog =usedef@*/ |
---|
186 | nb = vsnprintf(msgbuf, msgnb, fmt, apc); |
---|
187 | if (nb > -1 && nb < msgnb) |
---|
188 | break; |
---|
189 | if (nb > -1) /* glibc 2.1 (and later) */ |
---|
190 | msgnb = nb+1; |
---|
191 | else /* glibc 2.0 */ |
---|
192 | msgnb *= 2; |
---|
193 | msgbuf = xrealloc(msgbuf, msgnb); |
---|
194 | /*@-mods@*/ |
---|
195 | va_end(apc); |
---|
196 | /*@=mods@*/ |
---|
197 | } |
---|
198 | msgbuf[msgnb - 1] = '\0'; |
---|
199 | msg = msgbuf; |
---|
200 | |
---|
201 | /* Save copy of all messages at warning (or below == "more important"). */ |
---|
202 | /*@-branchstate@*/ |
---|
203 | if (pri <= RPMLOG_WARNING) { |
---|
204 | |
---|
205 | if (recs == NULL) |
---|
206 | recs = xmalloc((nrecs+2) * sizeof(*recs)); |
---|
207 | else |
---|
208 | recs = xrealloc(recs, (nrecs+2) * sizeof(*recs)); |
---|
209 | recs[nrecs].code = code; |
---|
210 | recs[nrecs].message = msg = xrealloc(msgbuf, strlen(msgbuf)+1); |
---|
211 | msgbuf = NULL; /* XXX don't free at exit. */ |
---|
212 | recs[nrecs+1].code = 0; |
---|
213 | recs[nrecs+1].message = NULL; |
---|
214 | ++nrecs; |
---|
215 | |
---|
216 | if (_rpmlogCallback) { |
---|
217 | /*@-noeffectuncon@*/ /* FIX: useless callback */ |
---|
218 | _rpmlogCallback(); |
---|
219 | /*@=noeffectuncon@*/ |
---|
220 | return; /* XXX Preserve legacy rpmError behavior. */ |
---|
221 | } |
---|
222 | } |
---|
223 | /*@=branchstate@*/ |
---|
224 | /*@=boundswrite@*/ |
---|
225 | |
---|
226 | /* rpmMessage behavior */ |
---|
227 | |
---|
228 | switch (pri) { |
---|
229 | case RPMLOG_INFO: |
---|
230 | case RPMLOG_NOTICE: |
---|
231 | msgout = (_stdlog ? _stdlog : stdout); |
---|
232 | break; |
---|
233 | |
---|
234 | case RPMLOG_EMERG: |
---|
235 | case RPMLOG_ALERT: |
---|
236 | case RPMLOG_CRIT: |
---|
237 | case RPMLOG_ERR: /* XXX Legacy rpmError behavior used stdout w/o prefix. */ |
---|
238 | case RPMLOG_WARNING: |
---|
239 | case RPMLOG_DEBUG: |
---|
240 | break; |
---|
241 | } |
---|
242 | |
---|
243 | if (rpmlogMsgPrefix[pri] && *rpmlogMsgPrefix[pri]) |
---|
244 | (void) fputs(_(rpmlogMsgPrefix[pri]), msgout); |
---|
245 | |
---|
246 | (void) fputs(msg, msgout); |
---|
247 | (void) fflush(msgout); |
---|
248 | msgbuf = _free(msgbuf); |
---|
249 | if (pri <= RPMLOG_CRIT) |
---|
250 | exit(EXIT_FAILURE); |
---|
251 | } |
---|
252 | /*@=compmempass =nullstate@*/ |
---|
253 | /*@=modfilesys@*/ |
---|
254 | |
---|
255 | void rpmlog (int code, const char *fmt, ...) |
---|
256 | { |
---|
257 | va_list ap; |
---|
258 | |
---|
259 | va_start(ap, fmt); |
---|
260 | /*@-internalglobs@*/ /* FIX: shrug */ |
---|
261 | vrpmlog(code, fmt, ap); |
---|
262 | /*@=internalglobs@*/ |
---|
263 | va_end(ap); |
---|
264 | } |
---|
265 | |
---|
266 | int rpmErrorCode(void) |
---|
267 | { |
---|
268 | return rpmlogCode(); |
---|
269 | } |
---|
270 | |
---|
271 | const char * rpmErrorString(void) |
---|
272 | { |
---|
273 | return rpmlogMessage(); |
---|
274 | } |
---|
275 | |
---|
276 | rpmlogCallback rpmErrorSetCallback(rpmlogCallback cb) |
---|
277 | { |
---|
278 | return rpmlogSetCallback(cb); |
---|
279 | } |
---|
280 | /*@=boundsread@*/ |
---|