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