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