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