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